Version 2.14.0-375.0.dev

Merge commit '9ec112a509d98dd63ea38ca5a004489a5f8ff65c' into 'dev'
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/data_driven_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/data_driven_test.dart
index e983738..4022696 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/data_driven_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/data_driven_test.dart
@@ -440,7 +440,7 @@
   Future<void> test_rename_removed() async {
     setPackageContent('''
 class C {
-  C.new([C c]);
+  C.updated([C c]);
 }
 ''');
     addPackageDataFile('''
@@ -454,7 +454,7 @@
     inClass: 'C'
   changes:
     - kind: 'rename'
-      newName: 'new'
+      newName: 'updated'
 ''');
     await resolveTestCode('''
 import '$importUri';
@@ -462,7 +462,7 @@
 ''');
     await assertHasFix('''
 import '$importUri';
-C c() => C.new(C.new());
+C c() => C.updated(C.updated());
 ''');
   }
 }
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index ae8a8fc..549e1bc 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -948,6 +948,10 @@
 
   static ConstructorElement? getNamedConstructorFromList(
       String name, List<ConstructorElement> constructors) {
+    if (name == 'new') {
+      // An unnamed constructor declared with `C.new(` is modeled as unnamed.
+      name = '';
+    }
     for (ConstructorElement element in constructors) {
       if (element.name == name) {
         return element;
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index 9de1a34..5c7a513 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -282,19 +282,6 @@
     );
   }
 
-  void _reportUndefinedMethod(
-      MethodInvocationImpl node,
-      String name,
-      ClassElement typeReference,
-      List<WhyNotPromotedGetter> whyNotPromotedList) {
-    _setDynamicResolution(node, whyNotPromotedList: whyNotPromotedList);
-    _resolver.errorReporter.reportErrorForNode(
-      CompileTimeErrorCode.UNDEFINED_METHOD,
-      node.methodName,
-      [name, typeReference.displayName],
-    );
-  }
-
   void _reportUseOfVoidType(MethodInvocationImpl node, AstNode errorNode,
       List<WhyNotPromotedGetter> whyNotPromotedList) {
     _setDynamicResolution(node, whyNotPromotedList: whyNotPromotedList);
@@ -779,7 +766,26 @@
       return;
     }
 
-    _reportUndefinedMethod(node, name, receiver, whyNotPromotedList);
+    _setDynamicResolution(node, whyNotPromotedList: whyNotPromotedList);
+    if (nameNode.name == 'new') {
+      // Attempting to invoke the unnamed constructor via `C.new(`.
+      if (_resolver.isConstructorTearoffsEnabled) {
+        _resolver.errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.NEW_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT,
+          nameNode,
+          [receiver.displayName],
+        );
+      } else {
+        // [ParserErrorCode.EXPERIMENT_NOT_ENABLED] is reported by the parser.
+        // Do not report extra errors.
+      }
+    } else {
+      _resolver.errorReporter.reportErrorForNode(
+        CompileTimeErrorCode.UNDEFINED_METHOD,
+        node.methodName,
+        [name, receiver.displayName],
+      );
+    }
   }
 
   /// If the given [type] is a type parameter, replace with its bound.
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 09b83ed..6a09580 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -376,11 +376,8 @@
         InstanceCreationExpressionResolver(this);
   }
 
-  /// Return the element representing the function containing the current node,
-  /// or `null` if the current node is not contained in a function.
-  ///
-  /// @return the element representing the function containing the current node
-  ExecutableElement? get enclosingFunction => _enclosingFunction;
+  bool get isConstructorTearoffsEnabled =>
+      _featureSet.isEnabled(Feature.constructor_tearoffs);
 
   /// Return the object providing promoted or declared types of variables.
   LocalVariableTypeProvider get localVariableTypeProvider {
@@ -2431,6 +2428,12 @@
         ),
         nameScope = nameScope ?? LibraryScope(definingLibrary);
 
+  /// Return the element representing the function containing the current node,
+  /// or `null` if the current node is not contained in a function.
+  ///
+  /// @return the element representing the function containing the current node
+  ExecutableElement? get enclosingFunction => _enclosingFunction;
+
   /// Return the implicit label scope in which the current node is being
   /// resolved.
   ImplicitLabelScope get implicitLabelScope => _implicitLabelScope;
diff --git a/pkg/analyzer/lib/src/generated/testing/element_factory.dart b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
index 6045950..ed9b4f8 100644
--- a/pkg/analyzer/lib/src/generated/testing/element_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
@@ -106,9 +106,11 @@
   static ConstructorElementImpl constructorElement(
       ClassElement definingClass, String? name, bool isConst,
       [List<DartType> argumentTypes = const []]) {
-    ConstructorElementImpl constructor = name == null
-        ? ConstructorElementImpl("", -1)
-        : ConstructorElementImpl(name, 0);
+    var offset = name == null ? -1 : 0;
+    // An unnamed constructor declared with `C.new(` is modeled as unnamed.
+    var constructor = name == null || name == 'new'
+        ? ConstructorElementImpl('', offset)
+        : ConstructorElementImpl(name, offset);
     if (name != null) {
       if (name.isEmpty) {
         constructor.nameEnd = definingClass.name.length;
diff --git a/pkg/analyzer/lib/src/summary2/element_builder.dart b/pkg/analyzer/lib/src/summary2/element_builder.dart
index 7bb241f..b5b366b 100644
--- a/pkg/analyzer/lib/src/summary2/element_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/element_builder.dart
@@ -172,6 +172,10 @@
   ) {
     var nameNode = node.name ?? node.returnType;
     var name = node.name?.name ?? '';
+    if (name == 'new') {
+      // An unnamed constructor declared with `C.new(` is modeled as unnamed.
+      name = '';
+    }
     var nameOffset = nameNode.offset;
 
     var element = ConstructorElementImpl(name, nameOffset);
diff --git a/pkg/analyzer/test/src/dart/resolution/instance_creation_test.dart b/pkg/analyzer/test/src/dart/resolution/instance_creation_test.dart
index 206f003..4d27277 100644
--- a/pkg/analyzer/test/src/dart/resolution/instance_creation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/instance_creation_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/error/syntactic_errors.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -10,6 +11,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(InstanceCreationTest);
+    defineReflectiveTests(InstanceCreationWithoutConstructorTearoffsTest);
   });
 }
 
@@ -426,4 +428,75 @@
       expectedSubstitution: {'T': 'String'},
     );
   }
+
+  test_unnamed_declaredNew() async {
+    await assertNoErrorsInCode('''
+class A {
+  A.new(int a);
+}
+
+void f() {
+  A(0);
+}
+
+''');
+
+    var creation = findNode.instanceCreation('A(0)');
+    assertInstanceCreation(creation, findElement.class_('A'), 'A');
+  }
+
+  test_unnamedViaNew_declaredNew() async {
+    await assertNoErrorsInCode('''
+class A {
+  A.new(int a);
+}
+
+void f() {
+  A.new(0);
+}
+
+''');
+
+    var creation = findNode.instanceCreation('A.new(0)');
+    assertInstanceCreation(creation, findElement.class_('A'), 'A');
+  }
+
+  test_unnamedViaNew_declaredUnnamed() async {
+    await assertNoErrorsInCode('''
+class A {
+  A(int a);
+}
+
+void f() {
+  A.new(0);
+}
+
+''');
+
+    var creation = findNode.instanceCreation('A.new(0)');
+    assertInstanceCreation(creation, findElement.class_('A'), 'A');
+  }
+}
+
+@reflectiveTest
+class InstanceCreationWithoutConstructorTearoffsTest
+    extends PubPackageResolutionTest with WithoutConstructorTearoffsMixin {
+  test_unnamedViaNew() async {
+    await assertErrorsInCode('''
+class A {
+  A(int a);
+}
+
+void f() {
+  A.new(0);
+}
+
+''', [
+      error(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 40, 3),
+    ]);
+
+    // Resolution should continue even though the experiment is not enabled.
+    var creation = findNode.instanceCreation('A.new(0)');
+    assertInstanceCreation(creation, findElement.class_('A'), 'A');
+  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/new_with_undefined_constructor_test.dart b/pkg/analyzer/test/src/diagnostics/new_with_undefined_constructor_test.dart
index 602e5ff..4ebf06c 100644
--- a/pkg/analyzer/test/src/diagnostics/new_with_undefined_constructor_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/new_with_undefined_constructor_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/error/syntactic_errors.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -10,11 +11,16 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(NewWithUndefinedConstructorTest);
+    defineReflectiveTests(
+        NewWithUndefinedConstructorWithoutConstructorTearoffsTest);
   });
 }
 
 @reflectiveTest
-class NewWithUndefinedConstructorTest extends PubPackageResolutionTest {
+class NewWithUndefinedConstructorTest extends PubPackageResolutionTest
+    with NewWithUndefinedConstructorTestCases {}
+
+mixin NewWithUndefinedConstructorTestCases on PubPackageResolutionTest {
   test_default() async {
     await assertErrorsInCode('''
 class A {
@@ -28,6 +34,43 @@
     ]);
   }
 
+  test_default_noKeyword() async {
+    await assertErrorsInCode('''
+class A {
+  A.name() {}
+}
+f() {
+  A();
+}
+''', [
+      error(CompileTimeErrorCode.NEW_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT, 34, 1),
+    ]);
+  }
+
+  test_default_unnamedViaNew() async {
+    await assertErrorsInCode('''
+class A {
+  A.name() {}
+}
+f() {
+  A.new();
+}
+''', [
+      error(CompileTimeErrorCode.NEW_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT, 36, 3),
+    ]);
+  }
+
+  test_defaultViaNew() async {
+    await assertNoErrorsInCode('''
+class A {
+  A.new() {}
+}
+f() {
+  A();
+}
+''');
+  }
+
   test_defined_named() async {
     await assertNoErrorsInCode(r'''
 class A {
@@ -111,3 +154,33 @@
     ]);
   }
 }
+
+@reflectiveTest
+class NewWithUndefinedConstructorWithoutConstructorTearoffsTest
+    extends PubPackageResolutionTest with WithoutConstructorTearoffsMixin {
+  test_defaultViaNew() async {
+    await assertErrorsInCode('''
+class A {
+  A.new() {}
+}
+f() {
+  A();
+}
+''', [
+      error(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 14, 3),
+    ]);
+  }
+
+  test_unnamedViaNew() async {
+    await assertErrorsInCode('''
+class A {
+  A.named() {}
+}
+f() {
+  A.new();
+}
+''', [
+      error(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 37, 3),
+    ]);
+  }
+}
diff --git a/pkg/compiler/README.md b/pkg/compiler/README.md
index 6c9621a..3f493c5 100644
--- a/pkg/compiler/README.md
+++ b/pkg/compiler/README.md
@@ -351,11 +351,11 @@
     representation of JSInt31, JSArray, and other implementation-specific
     elements.
 
-* `lib/src/deferred_load.dart`: general analysis for deferred loading. This is
-  where we compute how to split the code in different JS chunks or fragments.
-  This is run after resolution, but at a time when no code is generated yet, so
-  the decisions made here are used later on by the emitter to dump code into
-  different files.
+* `lib/src/deferred_load/deferred_load.dart`: general analysis for deferred
+  loading. This is where we compute how to split the code in different JS chunks
+  or fragments.  This is run after resolution, but at a time when no code is
+  generated yet, so the decisions made here are used later on by the emitter to
+  dump code into different files.
 
 * `lib/src/dump_info.dart`: a special phase used to create a .info.json file.
   This file contains lots of information computed by dart2js including decisions
diff --git a/pkg/compiler/lib/src/backend_strategy.dart b/pkg/compiler/lib/src/backend_strategy.dart
index 92966bc..add5771 100644
--- a/pkg/compiler/lib/src/backend_strategy.dart
+++ b/pkg/compiler/lib/src/backend_strategy.dart
@@ -7,7 +7,7 @@
 import 'common.dart';
 import 'common/codegen.dart';
 import 'common/tasks.dart';
-import 'deferred_load.dart' show OutputUnitData;
+import 'deferred_load/deferred_load.dart' show OutputUnitData;
 import 'enqueue.dart';
 import 'elements/entities.dart';
 import 'inferrer/types.dart';
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index 93bf848..bec3d57 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -9,7 +9,7 @@
 import '../common.dart';
 import '../common_elements.dart';
 import '../constants/values.dart';
-import '../deferred_load.dart';
+import '../deferred_load/deferred_load.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart' show DartType, InterfaceType;
 import '../inferrer/abstract_value_domain.dart';
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 126df97..d9303a6 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -18,7 +18,7 @@
 import 'common/work.dart' show WorkItem;
 import 'common.dart';
 import 'common_elements.dart' show ElementEnvironment;
-import 'deferred_load.dart' show DeferredLoadTask, OutputUnitData;
+import 'deferred_load/deferred_load.dart' show DeferredLoadTask, OutputUnitData;
 import 'diagnostics/code_location.dart';
 import 'diagnostics/messages.dart' show Message, MessageTemplate;
 import 'dump_info.dart' show DumpInfoTask;
diff --git a/pkg/compiler/lib/src/constants/values.dart b/pkg/compiler/lib/src/constants/values.dart
index 86636d0..4ef3a07 100644
--- a/pkg/compiler/lib/src/constants/values.dart
+++ b/pkg/compiler/lib/src/constants/values.dart
@@ -8,7 +8,7 @@
 import '../common_elements.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart';
-import '../deferred_load.dart' show OutputUnit;
+import '../deferred_load/deferred_load.dart' show OutputUnit;
 import '../js/js.dart' as js;
 import '../util/util.dart';
 
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load/deferred_load.dart
similarity index 98%
rename from pkg/compiler/lib/src/deferred_load.dart
rename to pkg/compiler/lib/src/deferred_load/deferred_load.dart
index 892e6b6..bf7a202 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load/deferred_load.dart
@@ -10,31 +10,31 @@
 import 'package:kernel/ast.dart' as ir;
 import 'package:kernel/type_environment.dart' as ir;
 
-import '../compiler_new.dart' show OutputType;
-import 'common/metrics.dart' show Metric, Metrics, CountMetric, DurationMetric;
-import 'common/tasks.dart' show CompilerTask;
-import 'common.dart';
-import 'common_elements.dart' show CommonElements, KElementEnvironment;
-import 'compiler.dart' show Compiler;
-import 'constants/values.dart'
+import '../../compiler_new.dart' show OutputType;
+import '../common/metrics.dart' show Metric, Metrics, CountMetric, DurationMetric;
+import '../common/tasks.dart' show CompilerTask;
+import '../common.dart';
+import '../common_elements.dart' show CommonElements, KElementEnvironment;
+import '../compiler.dart' show Compiler;
+import '../constants/values.dart'
     show
         ConstantValue,
         ConstructedConstantValue,
         DeferredGlobalConstantValue,
         InstantiationConstantValue;
-import 'elements/types.dart';
-import 'elements/entities.dart';
-import 'ir/util.dart';
-import 'kernel/kelements.dart' show KLocalFunction;
-import 'kernel/element_map.dart';
-import 'serialization/serialization.dart';
-import 'options.dart';
-import 'universe/use.dart';
-import 'universe/world_impact.dart'
+import '../elements/types.dart';
+import '../elements/entities.dart';
+import '../ir/util.dart';
+import '../kernel/kelements.dart' show KLocalFunction;
+import '../kernel/element_map.dart';
+import '../serialization/serialization.dart';
+import '../options.dart';
+import '../universe/use.dart';
+import '../universe/world_impact.dart'
     show ImpactUseCase, WorldImpact, WorldImpactVisitorImpl;
-import 'util/maplet.dart';
-import 'util/util.dart' show makeUnique;
-import 'world.dart' show KClosedWorld;
+import '../util/maplet.dart';
+import '../util/util.dart' show makeUnique;
+import '../world.dart' show KClosedWorld;
 
 /// A "hunk" of the program that will be loaded whenever one of its [imports]
 /// are loaded.
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index aff886a..c6448fb 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -19,7 +19,7 @@
 import 'common_elements.dart' show JElementEnvironment;
 import 'compiler.dart' show Compiler;
 import 'constants/values.dart' show ConstantValue, InterceptorConstantValue;
-import 'deferred_load.dart' show OutputUnit, deferredPartFileName;
+import 'deferred_load/deferred_load.dart' show OutputUnit, deferredPartFileName;
 import 'elements/entities.dart';
 import 'inferrer/abstract_value_domain.dart';
 import 'inferrer/types.dart'
diff --git a/pkg/compiler/lib/src/frontend_strategy.dart b/pkg/compiler/lib/src/frontend_strategy.dart
index 3ea0ee2..5fb4571 100644
--- a/pkg/compiler/lib/src/frontend_strategy.dart
+++ b/pkg/compiler/lib/src/frontend_strategy.dart
@@ -8,7 +8,7 @@
 import 'common/tasks.dart';
 import 'common_elements.dart';
 import 'compiler.dart' show Compiler;
-import 'deferred_load.dart' show DeferredLoadTask;
+import 'deferred_load/deferred_load.dart' show DeferredLoadTask;
 import 'elements/entities.dart';
 import 'enqueue.dart';
 import 'js_backend/native_data.dart';
diff --git a/pkg/compiler/lib/src/helpers/helpers.dart b/pkg/compiler/lib/src/helpers/helpers.dart
index a59366a..9828b7f 100644
--- a/pkg/compiler/lib/src/helpers/helpers.dart
+++ b/pkg/compiler/lib/src/helpers/helpers.dart
@@ -7,9 +7,10 @@
 
 library dart2js.helpers;
 
+import 'package:kernel/text/indentation.dart' show Indentation;
+
 import '../common.dart';
 import '../diagnostics/invariant.dart' show DEBUG_MODE;
-import '../util/util.dart';
 
 export 'debug_collection.dart';
 export 'expensive_map.dart';
@@ -89,6 +90,7 @@
 
 /// Implementation of [reportHere]
 _reportHere(DiagnosticReporter reporter, Spannable node, String debugMessage) {
+  // ignore: deprecated_member_use_from_same_package
   reporter.reportInfoMessage(
       node, MessageKind.GENERIC, {'text': 'HERE: $debugMessage'});
 }
diff --git a/pkg/compiler/lib/src/helpers/stats.dart b/pkg/compiler/lib/src/helpers/stats.dart
index e524b54..7ca7960 100644
--- a/pkg/compiler/lib/src/helpers/stats.dart
+++ b/pkg/compiler/lib/src/helpers/stats.dart
@@ -6,6 +6,8 @@
 import 'dart:collection';
 import 'dart:convert';
 
+import 'package:kernel/text/indentation.dart' show Indentation;
+
 import '../../compiler.dart';
 import '../common.dart';
 import '../compiler.dart' show Compiler;
diff --git a/pkg/compiler/lib/src/ir/closure.dart b/pkg/compiler/lib/src/ir/closure.dart
index f129216..39ceeb5 100644
--- a/pkg/compiler/lib/src/ir/closure.dart
+++ b/pkg/compiler/lib/src/ir/closure.dart
@@ -399,6 +399,11 @@
   }
 
   @override
+  R accept1<R, A>(ir.Visitor1<R, A> v, A arg) {
+    throw new UnsupportedError('TypeVariableTypeWithContext.accept1');
+  }
+
+  @override
   visitChildren(ir.Visitor v) {
     throw new UnsupportedError('TypeVariableTypeWithContext.visitChildren');
   }
diff --git a/pkg/compiler/lib/src/js/js_debug.dart b/pkg/compiler/lib/src/js/js_debug.dart
index 9eaca9f..f37ce23 100644
--- a/pkg/compiler/lib/src/js/js_debug.dart
+++ b/pkg/compiler/lib/src/js/js_debug.dart
@@ -7,9 +7,9 @@
 library js.debug;
 
 import 'package:js_ast/js_ast.dart';
+import 'package:kernel/text/indentation.dart' show Indentation, Tagging;
 
 import '../io/code_output.dart' show BufferedCodeOutput;
-import '../util/util.dart' show Indentation, Tagging;
 
 /// Unparse the JavaScript [node].
 String nodeToString(Node node, {bool pretty: false}) {
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index d17db87..8d15b8c 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -6,7 +6,7 @@
 
 import '../common.dart';
 import '../common/codegen.dart';
-import '../deferred_load.dart' show DeferredLoadTask;
+import '../deferred_load/deferred_load.dart' show DeferredLoadTask;
 import '../dump_info.dart' show DumpInfoTask;
 import '../elements/entities.dart';
 import '../enqueue.dart' show ResolutionEnqueuer;
diff --git a/pkg/compiler/lib/src/js_backend/resolution_listener.dart b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
index faff4b7..0239d25 100644
--- a/pkg/compiler/lib/src/js_backend/resolution_listener.dart
+++ b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
@@ -7,7 +7,7 @@
 import '../common/names.dart' show Identifiers;
 import '../common_elements.dart' show KCommonElements, KElementEnvironment;
 import '../constants/values.dart';
-import '../deferred_load.dart';
+import '../deferred_load/deferred_load.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../enqueue.dart' show Enqueuer, EnqueuerListener;
diff --git a/pkg/compiler/lib/src/js_backend/specialized_checks.dart b/pkg/compiler/lib/src/js_backend/specialized_checks.dart
index dfaabfd..41e8ea7 100644
--- a/pkg/compiler/lib/src/js_backend/specialized_checks.dart
+++ b/pkg/compiler/lib/src/js_backend/specialized_checks.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import '../common_elements.dart' show ElementEnvironment, JCommonElements;
-import '../deferred_load.dart';
+import '../deferred_load/deferred_load.dart';
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../js_backend/interceptor_data.dart' show InterceptorData;
diff --git a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
index 6525880..0a0a8f7 100644
--- a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
+++ b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
@@ -9,7 +9,7 @@
 import '../common/tasks.dart' show CompilerTask;
 import '../compiler.dart' show Compiler;
 import '../constants/values.dart';
-import '../deferred_load.dart' show OutputUnit;
+import '../deferred_load/deferred_load.dart' show OutputUnit;
 import '../elements/entities.dart';
 import '../js/js.dart' as jsAst;
 import '../js_backend/backend.dart' show CodegenInputs;
diff --git a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
index 4923f10..6e1cfaa 100644
--- a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
+++ b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
@@ -7,7 +7,7 @@
 import 'package:js_ast/src/precedence.dart' as js_precedence;
 
 import '../common.dart';
-import '../deferred_load.dart' show OutputUnit;
+import '../deferred_load/deferred_load.dart' show OutputUnit;
 
 import '../elements/types.dart';
 import '../js/js.dart' as jsAst;
diff --git a/pkg/compiler/lib/src/js_emitter/model.dart b/pkg/compiler/lib/src/js_emitter/model.dart
index 156ccb1..147a80c 100644
--- a/pkg/compiler/lib/src/js_emitter/model.dart
+++ b/pkg/compiler/lib/src/js_emitter/model.dart
@@ -6,7 +6,7 @@
 
 import '../common_elements.dart';
 import '../constants/values.dart' show ConstantValue;
-import '../deferred_load.dart' show OutputUnit;
+import '../deferred_load/deferred_load.dart' show OutputUnit;
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../js/js.dart' as js show Expression, Name, Statement, TokenFinalizer;
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index b6144a9..f11fd8b 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
@@ -9,7 +9,7 @@
 import '../../constants/values.dart'
     show ConstantValue, InterceptorConstantValue;
 import '../../common_elements.dart' show JCommonElements, JElementEnvironment;
-import '../../deferred_load.dart'
+import '../../deferred_load/deferred_load.dart'
     show deferredPartFileName, OutputUnit, OutputUnitData;
 import '../../elements/entities.dart';
 import '../../elements/types.dart';
diff --git a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
index d9bfaab..d77743f 100644
--- a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
@@ -5,7 +5,7 @@
 library dart2js.js_emitter.runtime_type_generator;
 
 import '../common_elements.dart' show CommonElements;
-import '../deferred_load.dart' show OutputUnit, OutputUnitData;
+import '../deferred_load/deferred_load.dart' show OutputUnit, OutputUnitData;
 import '../elements/entities.dart';
 import '../elements/types.dart';
 import '../js/js.dart' as jsAst;
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
index 0d7a896..3ca343dd 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
@@ -8,7 +8,7 @@
 import '../../common.dart';
 import '../../common/codegen.dart';
 import '../../constants/values.dart';
-import '../../deferred_load.dart' show OutputUnit;
+import '../../deferred_load/deferred_load.dart' show OutputUnit;
 import '../../dump_info.dart';
 import '../../elements/entities.dart';
 import '../../io/source_information.dart';
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart
index 9fae89c..58fc707 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_merger.dart
@@ -4,7 +4,7 @@
 
 import 'dart:collection';
 import '../../common_elements.dart' show ElementEnvironment;
-import '../../deferred_load.dart'
+import '../../deferred_load/deferred_load.dart'
     show ImportDescription, OutputUnit, OutputUnitData, deferredPartFileName;
 import '../../elements/entities.dart';
 import '../../js/js.dart' as js;
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
index 6f7e3fd..f905d82 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
@@ -37,7 +37,7 @@
 import '../../constants/values.dart'
     show ConstantValue, FunctionConstantValue, LateSentinelConstantValue;
 import '../../common_elements.dart' show CommonElements, JElementEnvironment;
-import '../../deferred_load.dart' show OutputUnit;
+import '../../deferred_load/deferred_load.dart' show OutputUnit;
 import '../../dump_info.dart';
 import '../../elements/entities.dart';
 import '../../elements/types.dart';
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 33024bc..a2f7118 100644
--- a/pkg/compiler/lib/src/js_model/element_map_impl.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_impl.dart
@@ -9,7 +9,7 @@
 import 'package:kernel/class_hierarchy.dart' as ir;
 import 'package:kernel/core_types.dart' as ir;
 import 'package:kernel/src/bounds_checks.dart' as ir;
-
+import 'package:kernel/text/debug_printer.dart';
 import 'package:kernel/type_environment.dart' as ir;
 
 import '../closure.dart' show BoxLocal, ThisLocal;
@@ -17,7 +17,7 @@
 import '../common/names.dart';
 import '../common_elements.dart';
 import '../constants/values.dart';
-import '../deferred_load.dart';
+import '../deferred_load/deferred_load.dart';
 import '../elements/entities.dart';
 import '../elements/entity_utils.dart' as utils;
 import '../elements/indexed.dart';
@@ -27,7 +27,6 @@
 import '../ir/cached_static_type.dart';
 import '../ir/closure.dart';
 import '../ir/constants.dart';
-import '../ir/debug.dart';
 import '../ir/element_map.dart';
 import '../ir/types.dart';
 import '../ir/visitors.dart';
diff --git a/pkg/compiler/lib/src/js_model/js_strategy.dart b/pkg/compiler/lib/src/js_model/js_strategy.dart
index 431efc6..c24a46b 100644
--- a/pkg/compiler/lib/src/js_model/js_strategy.dart
+++ b/pkg/compiler/lib/src/js_model/js_strategy.dart
@@ -13,7 +13,7 @@
 import '../common/work.dart';
 import '../common_elements.dart' show CommonElements, ElementEnvironment;
 import '../compiler.dart';
-import '../deferred_load.dart' hide WorkItem;
+import '../deferred_load/deferred_load.dart' hide WorkItem;
 import '../dump_info.dart';
 import '../elements/entities.dart';
 import '../enqueue.dart';
diff --git a/pkg/compiler/lib/src/js_model/js_world.dart b/pkg/compiler/lib/src/js_model/js_world.dart
index 66f8efc..f2c3c08 100644
--- a/pkg/compiler/lib/src/js_model/js_world.dart
+++ b/pkg/compiler/lib/src/js_model/js_world.dart
@@ -9,7 +9,7 @@
 import '../common.dart';
 import '../common/names.dart';
 import '../common_elements.dart' show JCommonElements, JElementEnvironment;
-import '../deferred_load.dart';
+import '../deferred_load/deferred_load.dart';
 import '../elements/entities.dart';
 import '../elements/entity_utils.dart' as utils;
 import '../elements/names.dart';
diff --git a/pkg/compiler/lib/src/js_model/js_world_builder.dart b/pkg/compiler/lib/src/js_model/js_world_builder.dart
index f125f55..087d57a 100644
--- a/pkg/compiler/lib/src/js_model/js_world_builder.dart
+++ b/pkg/compiler/lib/src/js_model/js_world_builder.dart
@@ -9,7 +9,7 @@
 import '../common_elements.dart';
 import '../constants/constant_system.dart' as constant_system;
 import '../constants/values.dart';
-import '../deferred_load.dart';
+import '../deferred_load/deferred_load.dart';
 import '../elements/entities.dart';
 import '../elements/indexed.dart';
 import '../elements/names.dart';
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index d568cea..7bf5db7 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -11,6 +11,7 @@
 import 'package:kernel/class_hierarchy.dart' as ir;
 import 'package:kernel/core_types.dart' as ir;
 import 'package:kernel/src/bounds_checks.dart' as ir;
+import 'package:kernel/text/debug_printer.dart';
 import 'package:kernel/type_environment.dart' as ir;
 
 import '../common.dart';
@@ -26,7 +27,6 @@
 import '../frontend_strategy.dart';
 import '../ir/annotations.dart';
 import '../ir/constants.dart';
-import '../ir/debug.dart';
 import '../ir/element_map.dart';
 import '../ir/impact.dart';
 import '../ir/impact_data.dart';
diff --git a/pkg/compiler/lib/src/kernel/kernel_strategy.dart b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
index eb961d7..43b81f4 100644
--- a/pkg/compiler/lib/src/kernel/kernel_strategy.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
@@ -15,7 +15,7 @@
 import '../common/work.dart';
 import '../common_elements.dart';
 import '../compiler.dart';
-import '../deferred_load.dart' show DeferredLoadTask;
+import '../deferred_load/deferred_load.dart' show DeferredLoadTask;
 import '../elements/entities.dart';
 import '../enqueue.dart';
 import '../environment.dart' as env;
diff --git a/pkg/compiler/lib/src/serialization/serialization.dart b/pkg/compiler/lib/src/serialization/serialization.dart
index e684b95..590efec 100644
--- a/pkg/compiler/lib/src/serialization/serialization.dart
+++ b/pkg/compiler/lib/src/serialization/serialization.dart
@@ -9,7 +9,7 @@
 import '../closure.dart';
 import '../constants/constant_system.dart' as constant_system;
 import '../constants/values.dart';
-import '../deferred_load.dart';
+import '../deferred_load/deferred_load.dart';
 import '../diagnostics/source_span.dart';
 import '../elements/entities.dart';
 import '../elements/indexed.dart';
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 643baf7..9afc681 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -12,7 +12,7 @@
 import '../common_elements.dart';
 import '../constants/constant_system.dart' as constant_system;
 import '../constants/values.dart';
-import '../deferred_load.dart';
+import '../deferred_load/deferred_load.dart';
 import '../dump_info.dart';
 import '../elements/entities.dart';
 import '../elements/jumps.dart';
diff --git a/pkg/compiler/lib/src/tracer.dart b/pkg/compiler/lib/src/tracer.dart
index a02c499..c2c5c5f 100644
--- a/pkg/compiler/lib/src/tracer.dart
+++ b/pkg/compiler/lib/src/tracer.dart
@@ -4,11 +4,12 @@
 
 library tracer;
 
+import 'package:kernel/text/indentation.dart' show Indentation;
+
 import '../compiler_new.dart' as api;
 import 'options.dart' show CompilerOptions;
 import 'ssa/nodes.dart' as ssa show HGraph;
 import 'ssa/ssa_tracer.dart' show HTracer;
-import 'util/util.dart' show Indentation;
 import 'world.dart' show JClosedWorld;
 
 String TRACE_FILTER_PATTERN_FOR_TEST;
diff --git a/pkg/compiler/lib/src/util/util.dart b/pkg/compiler/lib/src/util/util.dart
index 703bf10..6a7894f 100644
--- a/pkg/compiler/lib/src/util/util.dart
+++ b/pkg/compiler/lib/src/util/util.dart
@@ -7,13 +7,11 @@
 library dart2js.util;
 
 import 'package:front_end/src/api_unstable/dart2js.dart'
-    show $BACKSLASH, $CR, $DEL, $DQ, $LF, $LS, $PS, $TAB, Link;
+    show $BACKSLASH, $CR, $DEL, $DQ, $LF, $LS, $PS, $TAB;
 
 export 'maplet.dart';
 export 'setlet.dart';
 
-part 'indentation.dart';
-
 /// Helper functions for creating hash codes.
 class Hashing {
   /// If an integer is masked by this constant, the result is guaranteed to be
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index e1f8a31..a17fc60 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -12,7 +12,7 @@
         JElementEnvironment,
         KCommonElements,
         KElementEnvironment;
-import 'deferred_load.dart';
+import 'deferred_load/deferred_load.dart';
 import 'diagnostics/diagnostic_listener.dart';
 import 'elements/entities.dart';
 import 'elements/names.dart';
diff --git a/pkg/compiler/test/analyses/dart2js_allowed.json b/pkg/compiler/test/analyses/dart2js_allowed.json
index 807fcb7..9048e82 100644
--- a/pkg/compiler/test/analyses/dart2js_allowed.json
+++ b/pkg/compiler/test/analyses/dart2js_allowed.json
@@ -43,7 +43,7 @@
     "Dynamic invocation of 'toSet'.": 1,
     "Dynamic invocation of 'toList'.": 1
   },
-  "pkg/compiler/lib/src/deferred_load.dart": {
+  "pkg/compiler/lib/src/deferred_load/deferred_load.dart": {
     "Dynamic access of 'memberContext'.": 1,
     "Dynamic access of 'name'.": 1
   },
diff --git a/pkg/compiler/test/deferred/constant_emission_test_helper.dart b/pkg/compiler/test/deferred/constant_emission_test_helper.dart
index d8fc00a..0f05dc3 100644
--- a/pkg/compiler/test/deferred/constant_emission_test_helper.dart
+++ b/pkg/compiler/test/deferred/constant_emission_test_helper.dart
@@ -9,7 +9,7 @@
 
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/constants/values.dart';
-import 'package:compiler/src/deferred_load.dart';
+import 'package:compiler/src/deferred_load/deferred_load.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/elements/types.dart';
 import 'package:compiler/src/js_emitter/model.dart';
diff --git a/pkg/compiler/test/deferred/load_graph_segmentation_test.dart b/pkg/compiler/test/deferred/load_graph_segmentation_test.dart
index 161a92b..64ec62d 100644
--- a/pkg/compiler/test/deferred/load_graph_segmentation_test.dart
+++ b/pkg/compiler/test/deferred/load_graph_segmentation_test.dart
@@ -10,7 +10,7 @@
 
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/compiler.dart';
-import 'package:compiler/src/deferred_load.dart';
+import 'package:compiler/src/deferred_load/deferred_load.dart';
 import 'package:compiler/src/js_emitter/startup_emitter/fragment_merger.dart';
 import 'package:expect/expect.dart';
 import '../helpers/memory_compiler.dart';
diff --git a/pkg/compiler/test/deferred_loading/deferred_loading_test.dart b/pkg/compiler/test/deferred_loading/deferred_loading_test.dart
index 7ef31f8..aecbf54 100644
--- a/pkg/compiler/test/deferred_loading/deferred_loading_test.dart
+++ b/pkg/compiler/test/deferred_loading/deferred_loading_test.dart
@@ -6,7 +6,7 @@
 
 import 'dart:io' hide Link;
 import 'package:async_helper/async_helper.dart';
-import 'package:compiler/src/deferred_load.dart';
+import 'package:compiler/src/deferred_load/deferred_load.dart';
 import '../equivalence/id_equivalence_helper.dart';
 import 'deferred_loading_test_helper.dart';
 
diff --git a/pkg/compiler/test/deferred_loading/deferred_loading_test_helper.dart b/pkg/compiler/test/deferred_loading/deferred_loading_test_helper.dart
index 8028c05..73271f9 100644
--- a/pkg/compiler/test/deferred_loading/deferred_loading_test_helper.dart
+++ b/pkg/compiler/test/deferred_loading/deferred_loading_test_helper.dart
@@ -8,7 +8,7 @@
 import 'package:compiler/src/closure.dart';
 import 'package:compiler/src/common.dart';
 import 'package:compiler/src/compiler.dart';
-import 'package:compiler/src/deferred_load.dart';
+import 'package:compiler/src/deferred_load/deferred_load.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/ir/util.dart';
 import 'package:compiler/src/js_model/element_map.dart';
diff --git a/pkg/compiler/test/helpers/program_lookup.dart b/pkg/compiler/test/helpers/program_lookup.dart
index 1c98822..c6f3393 100644
--- a/pkg/compiler/test/helpers/program_lookup.dart
+++ b/pkg/compiler/test/helpers/program_lookup.dart
@@ -6,7 +6,7 @@
 
 import 'package:expect/expect.dart';
 import 'package:compiler/src/common_elements.dart';
-import 'package:compiler/src/deferred_load.dart';
+import 'package:compiler/src/deferred_load/deferred_load.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/js_backend/namer.dart';
 import 'package:compiler/src/js_emitter/model.dart';
diff --git a/pkg/dartdev/lib/src/analysis_server.dart b/pkg/dartdev/lib/src/analysis_server.dart
index 9768d39..a17a169 100644
--- a/pkg/dartdev/lib/src/analysis_server.dart
+++ b/pkg/dartdev/lib/src/analysis_server.dart
@@ -293,12 +293,14 @@
     return messages.map((message) => DiagnosticMessage(message)).toList();
   }
 
-  // TODO(jwren) add some tests to verify that the results are what we are
-  // expecting, 'other' is not always on the RHS of the subtraction in the
-  // implementation.
   @override
   int compareTo(AnalysisError other) {
-    // Sort in order of file path, error location, severity, and message.
+    // Sort in order of severity, file path, error location, and message.
+    final int diff = _severityLevel.index - other._severityLevel.index;
+    if (diff != 0) {
+      return diff;
+    }
+
     if (file != other.file) {
       return file.compareTo(other.file);
     }
@@ -307,11 +309,6 @@
       return offset - other.offset;
     }
 
-    final int diff = other._severityLevel.index - _severityLevel.index;
-    if (diff != 0) {
-      return diff;
-    }
-
     return message.compareTo(other.message);
   }
 
diff --git a/pkg/dartdev/lib/src/commands/analyze.dart b/pkg/dartdev/lib/src/commands/analyze.dart
index 0c1d925..27fbf53 100644
--- a/pkg/dartdev/lib/src/commands/analyze.dart
+++ b/pkg/dartdev/lib/src/commands/analyze.dart
@@ -127,8 +127,6 @@
 
     progress?.finish(showTiming: true);
 
-    errors.sort();
-
     if (errors.isEmpty) {
       if (!machineFormat) {
         log.stdout('No issues found!');
@@ -136,6 +134,8 @@
       return 0;
     }
 
+    errors.sort();
+
     if (machineFormat) {
       emitMachineFormat(log, errors);
     } else if (jsonFormat) {
diff --git a/pkg/dartdev/test/commands/analyze_test.dart b/pkg/dartdev/test/commands/analyze_test.dart
index 293c139..d2a43e3 100644
--- a/pkg/dartdev/test/commands/analyze_test.dart
+++ b/pkg/dartdev/test/commands/analyze_test.dart
@@ -56,6 +56,119 @@
       expect(error.contextMessages, hasLength(2));
     });
   });
+
+  group('sorting', () {
+    test('severity', () {
+      var errors = <AnalysisError>[
+        AnalysisError({
+          'severity': 'INFO',
+          'location': {
+            'file': 'a.dart',
+          }
+        }),
+        AnalysisError({
+          'severity': 'WARNING',
+          'location': {
+            'file': 'a.dart',
+          }
+        }),
+        AnalysisError({
+          'severity': 'ERROR',
+          'location': {
+            'file': 'a.dart',
+          }
+        })
+      ];
+
+      errors.sort();
+
+      expect(errors, hasLength(3));
+      expect(errors[0].isError, isTrue);
+      expect(errors[1].isWarning, isTrue);
+      expect(errors[2].isInfo, isTrue);
+    });
+
+    test('file', () {
+      var errors = <AnalysisError>[
+        AnalysisError({
+          'severity': 'INFO',
+          'location': {
+            'file': 'c.dart',
+          }
+        }),
+        AnalysisError({
+          'severity': 'INFO',
+          'location': {
+            'file': 'b.dart',
+          }
+        }),
+        AnalysisError({
+          'severity': 'INFO',
+          'location': {
+            'file': 'a.dart',
+          }
+        })
+      ];
+
+      errors.sort();
+
+      expect(errors, hasLength(3));
+      expect(errors[0].file, equals('a.dart'));
+      expect(errors[1].file, equals('b.dart'));
+      expect(errors[2].file, equals('c.dart'));
+    });
+
+    test('offset', () {
+      var errors = <AnalysisError>[
+        AnalysisError({
+          'severity': 'INFO',
+          'location': {'file': 'a.dart', 'offset': 8}
+        }),
+        AnalysisError({
+          'severity': 'INFO',
+          'location': {'file': 'a.dart', 'offset': 6}
+        }),
+        AnalysisError({
+          'severity': 'INFO',
+          'location': {'file': 'a.dart', 'offset': 4}
+        })
+      ];
+
+      errors.sort();
+
+      expect(errors, hasLength(3));
+      expect(errors[0].offset, equals(4));
+      expect(errors[1].offset, equals(6));
+      expect(errors[2].offset, equals(8));
+    });
+
+    test('message', () {
+      var errors = <AnalysisError>[
+        AnalysisError({
+          'severity': 'INFO',
+          'location': {'file': 'a.dart', 'offset': 8},
+          'message': 'C'
+        }),
+        AnalysisError({
+          'severity': 'INFO',
+          'location': {'file': 'a.dart', 'offset': 6},
+          'message': 'B'
+        }),
+        AnalysisError({
+          'severity': 'INFO',
+          'location': {'file': 'a.dart', 'offset': 4},
+          'message': 'A'
+        })
+      ];
+
+      errors.sort();
+
+      expect(errors, hasLength(3));
+      expect(errors[0].message, equals('A'));
+      expect(errors[1].message, equals('B'));
+      expect(errors[2].message, equals('C'));
+    });
+  });
 }
 
 void defineAnalyze() {
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index 2de20df..408d757 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -18,6 +18,7 @@
 import 'package:kernel/kernel.dart';
 import 'package:kernel/target/targets.dart';
 import 'package:kernel/text/ast_to_text.dart' as kernel show Printer;
+import 'package:kernel/text/debug_printer.dart';
 import 'package:path/path.dart' as p;
 import 'package:source_maps/source_maps.dart' show SourceMapBuilder;
 
@@ -88,7 +89,7 @@
     ..addOption('packages', help: 'The package spec file to use.')
     // TODO(jmesserly): is this still useful for us, or can we remove it now?
     ..addFlag('summarize-text',
-        help: 'Emit API summary in a .js.txt file.',
+        help: 'Emit API summary and AST in .js.txt and .ast.xml files.',
         defaultsTo: false,
         hide: true)
     ..addFlag('track-widget-creation',
@@ -413,6 +414,8 @@
     var sb = StringBuffer();
     kernel.Printer(sb).writeComponentFile(component);
     outFiles.add(File(outPaths.first + '.txt').writeAsString(sb.toString()));
+    outFiles.add(File(outPaths.first.split('.')[0] + '.ast.xml')
+        .writeAsString(DebugPrinter.prettyPrint(compiledLibraries)));
   }
 
   final importToSummary = Map<Library, Component>.identity();
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 d365898..5bc55d2 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -1315,8 +1315,7 @@
     } else {
       bool sentinelInserted = false;
       if (nodeCache.containsKey(node)) {
-        bool isRecursiveFunctionCall =
-            node is InstanceInvocation ||
+        bool isRecursiveFunctionCall = node is InstanceInvocation ||
             node is FunctionInvocation ||
             node is LocalFunctionInvocation ||
             node is StaticInvocation;
@@ -4201,11 +4200,21 @@
   }
 
   @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) {
+    throw new UnimplementedError();
+  }
+
+  @override
   R acceptReference<R>(Visitor<R> v) {
     throw new UnimplementedError();
   }
 
   @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) {
+    throw new UnimplementedError();
+  }
+
+  @override
   Expression asExpression() {
     throw new UnimplementedError();
   }
@@ -4261,11 +4270,21 @@
   }
 
   @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) {
+    throw new UnimplementedError();
+  }
+
+  @override
   R acceptReference<R>(Visitor<R> v) {
     throw new UnimplementedError();
   }
 
   @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) {
+    throw new UnimplementedError();
+  }
+
+  @override
   Expression asExpression() {
     throw new UnimplementedError();
   }
@@ -4318,11 +4337,21 @@
   }
 
   @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) {
+    throw new UnimplementedError();
+  }
+
+  @override
   R acceptReference<R>(Visitor<R> v) {
     throw new UnimplementedError();
   }
 
   @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) {
+    throw new UnimplementedError();
+  }
+
+  @override
   Expression asExpression() {
     throw new UnimplementedError();
   }
@@ -4375,11 +4404,21 @@
   }
 
   @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) {
+    throw new UnimplementedError();
+  }
+
+  @override
   R acceptReference<R>(Visitor<R> v) {
     throw new UnimplementedError();
   }
 
   @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) {
+    throw new UnimplementedError();
+  }
+
+  @override
   Expression asExpression() {
     throw new UnimplementedError();
   }
diff --git a/pkg/front_end/test/generated_files_up_to_date_git_test.dart b/pkg/front_end/test/generated_files_up_to_date_git_test.dart
index 47f7548..0800570 100644
--- a/pkg/front_end/test/generated_files_up_to_date_git_test.dart
+++ b/pkg/front_end/test/generated_files_up_to_date_git_test.dart
@@ -13,16 +13,18 @@
     as generateDirectParserAstHelper;
 import "parser_test_listener_creator.dart" as generateParserTestListener;
 import "parser_test_parser_creator.dart" as generateParserTestParser;
+import '../tool/generate_ast_equivalence.dart' as generateAstEquivalence;
 import 'utils/io_utils.dart' show computeRepoDirUri;
 
 final Uri repoDir = computeRepoDirUri();
 
-main() {
+main() async {
   messages();
   experimentalFlags();
   directParserAstHelper();
   parserTestListener();
   parserTestParser();
+  await astEquivalence();
 }
 
 void parserTestParser() {
@@ -48,6 +50,14 @@
       "dart pkg/front_end/tool/_fasta/direct_parser_ast_helper_creator.dart");
 }
 
+Future<void> astEquivalence() async {
+  Uri generatedFile = generateAstEquivalence.computeEquivalenceUri(repoDir);
+  String generated =
+      await generateAstEquivalence.generateAstEquivalence(repoDir);
+  check(generated, generatedFile,
+      "dart pkg/front_end/tool/generate_ast_equivalence.dart");
+}
+
 void experimentalFlags() {
   {
     Uri generatedFile =
diff --git a/pkg/front_end/test/incremental_dart2js_load_from_dill_test.dart b/pkg/front_end/test/incremental_dart2js_load_from_dill_test.dart
index 1fb8ad1..4320981 100644
--- a/pkg/front_end/test/incremental_dart2js_load_from_dill_test.dart
+++ b/pkg/front_end/test/incremental_dart2js_load_from_dill_test.dart
@@ -13,7 +13,8 @@
 
 import 'package:kernel/binary/ast_from_binary.dart' show BinaryBuilder;
 
-import 'package:kernel/kernel.dart' show Component;
+import 'package:kernel/ast.dart';
+import 'package:kernel/src/equivalence.dart';
 import 'package:kernel/target/targets.dart';
 
 import 'incremental_suite.dart'
@@ -93,7 +94,19 @@
     List<int> normalDillData = new File.fromUri(normalDill).readAsBytesSync();
     List<int> initializedDillData =
         new File.fromUri(fullDillFromInitialized).readAsBytesSync();
-    checkIsEqual(normalDillData, initializedDillData);
+
+    Component component1 = new Component();
+    new BinaryBuilder(normalDillData).readComponent(component1);
+
+    Component component2 = new Component();
+    new BinaryBuilder(initializedDillData).readComponent(component2);
+    EquivalenceResult result =
+        checkEquivalence(component1, component2, strategy: const Strategy());
+    Expect.isTrue(result.isEquivalent, result.toString());
+
+    // TODO(johnniwinther): Reenable this check when the discrepancies have been
+    // fixed.
+    //checkIsEqual(normalDillData, initializedDillData);
 
     // Also try without invalidating anything.
     stopwatch.reset();
@@ -110,3 +123,49 @@
     checkIsEqual(normalDillData, initializedDillData);
   }
 }
+
+class Strategy extends EquivalenceStrategy {
+  const Strategy();
+
+  @override
+  bool checkClass_procedures(
+      EquivalenceVisitor visitor, Class node, Class other) {
+    // Check procedures as a set instead of a list to allow for reordering.
+    return visitor.checkSets(node.procedures.toSet(), other.procedures.toSet(),
+        visitor.matchNamedNodes, visitor.checkNodes, 'procedures');
+  }
+
+  bool _isMixinOrCloneReference(EquivalenceVisitor visitor, Reference a,
+      Reference b, String propertyName) {
+    if (a != null && b != null) {
+      ReferenceName thisName = ReferenceName.fromReference(a);
+      ReferenceName otherName = ReferenceName.fromReference(b);
+      if (thisName.kind == ReferenceNameKind.Member &&
+          otherName.kind == ReferenceNameKind.Member &&
+          thisName.memberName == otherName.memberName) {
+        String thisClassName = thisName.declarationName;
+        String otherClassName = otherName.declarationName;
+        if (thisClassName != null &&
+            otherClassName != null &&
+            thisClassName.contains('&${otherClassName}')) {
+          visitor.assumeReferences(a, b);
+        }
+      }
+    }
+    return visitor.checkReferences(a, b, propertyName);
+  }
+
+  @override
+  bool checkProcedure_stubTargetReference(
+      EquivalenceVisitor visitor, Procedure node, Procedure other) {
+    return _isMixinOrCloneReference(visitor, node.stubTargetReference,
+        other.stubTargetReference, 'stubTargetReference');
+  }
+
+  @override
+  bool checkInstanceGet_interfaceTargetReference(
+      EquivalenceVisitor visitor, InstanceGet node, InstanceGet other) {
+    return _isMixinOrCloneReference(visitor, node.interfaceTargetReference,
+        other.interfaceTargetReference, 'interfaceTargetReference');
+  }
+}
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index b0e58b2..7cc2003 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -62,6 +62,7 @@
 askesc
 aspect
 aspx
+asserting
 assigning
 assigns
 association
@@ -299,6 +300,7 @@
 deepest
 deeply
 def
+defaulting
 degrades
 degree
 del
@@ -388,12 +390,14 @@
 enforced
 enforces
 enforcing
+enters
 engineered
 enumerates
 env
 eof
 eq
 equation
+equivalences
 erased
 erasure
 es
@@ -580,6 +584,9 @@
 indirection
 individual
 inequality
+inequivalence
+inequivalences
+inequivalent
 influence
 informative
 infos
@@ -604,6 +611,7 @@
 int8
 integrate
 intentionally
+interested
 interim
 interior
 interleaved
@@ -786,6 +794,7 @@
 nk
 nnbd
 node's
+nominality
 nonimplementation
 norm
 normalization
@@ -821,6 +830,7 @@
 ogham
 oked
 op
+opens
 opt
 optimizations
 opting
@@ -1037,6 +1047,7 @@
 residue
 resource
 respond
+restoring
 restriction
 resumed
 ret
@@ -1062,6 +1073,7 @@
 rs
 runnable
 s
+sand
 sanitizing
 saw
 say
@@ -1107,6 +1119,7 @@
 siblings
 sides
 sigmund
+signaling
 significant
 simplify
 singleton
@@ -1205,12 +1218,14 @@
 sw
 swapped
 sweep
+symbolic
 synchronously
 syncs
 synth
 t
 tagged
 tagger
+tagging
 tags
 tailor
 taking
@@ -1413,6 +1428,7 @@
 wiki
 wikipedia
 wind
+wise
 wiser
 with1
 wn
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index bb193c9..150c716 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -45,6 +45,7 @@
 asserter
 assure
 asterisk
+atomic
 auth
 authority
 autobianchi
@@ -148,6 +149,7 @@
 calloc
 camel
 capitalized
+categorization
 causal
 cb
 cc
@@ -204,6 +206,7 @@
 confirm
 consecutive
 considering
+consist
 constrains
 consts
 contract
@@ -250,6 +253,7 @@
 ddart
 dds
 debugger
+declarative
 decrease
 decrements
 dectcem
@@ -283,6 +287,7 @@
 disallowed
 disconnect
 discovering
+discrepancies
 dispatcher
 dispose
 dist
@@ -314,10 +319,12 @@
 elegantly
 ell
 emethod
+enters
 entrypoint
 entrypoints
 eoo
 epoch
+equivalences
 erase
 erased
 err
@@ -538,6 +545,7 @@
 insufficient
 intdiv
 interactive
+interested
 internet
 interpolate
 introducer
@@ -670,6 +678,8 @@
 nil
 ninja
 noisy
+nominal
+nominality
 nondefault
 nonexisting
 noo
@@ -770,6 +780,8 @@
 redirections
 rediscover
 reducer
+reenable
+referential
 referring
 reflectee
 refusing
@@ -781,6 +793,7 @@
 reload
 remap
 remaps
+renames
 rendition
 reorder
 reordering
@@ -803,6 +816,7 @@
 rows
 runtimes
 rv
+sand
 saves
 scans
 scheduler
@@ -816,6 +830,7 @@
 selection
 semifuzz
 sensitive
+serves
 services
 setter1a
 setter1b
@@ -829,6 +844,7 @@
 shortest
 shot
 sigint
+signaling
 signalled
 sigwinch
 slashes
@@ -951,6 +967,8 @@
 verbatim
 versioned
 vf
+visitor0
+visitor1
 vp
 vt
 vte
@@ -964,6 +982,7 @@
 wherever
 whiskers
 wins
+wise
 wording
 workflow
 worlds
diff --git a/pkg/front_end/tool/ast_model.dart b/pkg/front_end/tool/ast_model.dart
new file mode 100644
index 0000000..14f981f
--- /dev/null
+++ b/pkg/front_end/tool/ast_model.dart
@@ -0,0 +1,771 @@
+// 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.
+
+// @dart = 2.9
+
+import 'package:_fe_analyzer_shared/src/messages/diagnostic_message.dart';
+import 'package:front_end/src/api_prototype/front_end.dart';
+import 'package:front_end/src/api_prototype/kernel_generator.dart';
+import 'package:front_end/src/api_prototype/terminal_color_support.dart';
+import 'package:front_end/src/api_unstable/ddc.dart';
+import 'package:front_end/src/compute_platform_binaries_location.dart';
+import 'package:front_end/src/fasta/kernel/kernel_api.dart';
+import 'package:front_end/src/kernel_generator_impl.dart';
+import 'package:kernel/ast.dart';
+import 'package:kernel/class_hierarchy.dart';
+import 'package:kernel/core_types.dart';
+import 'package:kernel/src/printer.dart';
+import 'package:kernel/type_environment.dart';
+
+final Uri astLibraryUri = Uri.parse('package:kernel/ast.dart');
+final Uri canonicalNameLibraryUri =
+    Uri.parse('package:kernel/canonical_name.dart');
+Uri computePackageConfig(Uri repoDir) =>
+    repoDir.resolve('.dart_tool/package_config.json');
+
+/// Map from names of node classes that declares nominal entities that are _not_
+/// referenced through a [Reference] to their identifying name, if any.
+///
+/// For these classes, [_fieldRuleMap] must defined whether fields of these
+/// types should be consider declarations or references to the declarations.
+///
+/// If the identifying name is non-null, this is used to determine the
+/// nominality. For instance the name of a variable declaration is taking as
+/// defining its identity.
+const Map<String, String> _declarativeClassesNames = const {
+  'VariableDeclaration': 'name',
+  'TypeParameter': 'name',
+  'LabeledStatement': null,
+  'SwitchCase': null,
+};
+
+/// Names of non-node, non-enum classes that should be treated as atomic
+/// values.
+const Set<String> _utilityClassesAsValues = const {
+  'Version',
+};
+
+/// Names of subclasses of [Node] that do _not_ have `visitX` or `defaultX`
+/// methods.
+const Set<String> _classesWithoutVisitMethods = const {
+  'InvocationExpression',
+  'InstanceInvocationExpression',
+  'NamedNode',
+  'PrimitiveConstant',
+};
+
+/// Names of subclasses of [NamedNode] that do _not_ have `visitXReference` or
+/// `defaultXReference` methods.
+const Set<String> _classesWithoutVisitReference = const {
+  'NamedNode',
+  'Library',
+  'PrimitiveConstant',
+};
+
+/// Map of [FieldRule]s. These consist of a map for each class name, with
+/// `null` used for "any class". For each class, a map from field names to
+/// [FieldRule] define exceptions to how a field should be treated.
+///
+/// If a field name maps to `null`, the field is not included in the [AstModel].
+const Map<String /*?*/, Map<String, FieldRule /*?*/ >> _fieldRuleMap = {
+  null: {
+    'hashCode': null,
+    'parent': null,
+  },
+  'Component': {
+    'root': null,
+    '_mainMethodName': FieldRule(name: 'mainMethodName'),
+    '_mode': FieldRule(name: 'mode'),
+  },
+  'Library': {
+    '_languageVersion': FieldRule(name: 'languageVersion'),
+    '_libraryId': null,
+    '_classes': FieldRule(name: 'classes'),
+    '_typedefs': FieldRule(name: 'typedefs'),
+    '_extensions': FieldRule(name: 'extensions'),
+    '_fields': FieldRule(name: 'fields'),
+    '_procedures': FieldRule(name: 'procedures'),
+  },
+  'Class': {
+    'typeParameters': FieldRule(isDeclaration: true),
+    '_constructorsView': null,
+    '_constructorsInternal': FieldRule(name: 'constructors'),
+    '_fieldsView': null,
+    '_fieldsInternal': FieldRule(name: 'fields'),
+    '_proceduresView': null,
+    '_proceduresInternal': FieldRule(name: 'procedures'),
+    '_redirectingFactoriesView': null,
+    '_redirectingFactoriesInternal':
+        FieldRule(name: 'redirectingFactories'),
+    'lazyBuilder': null,
+    'dirty': null,
+  },
+  'Extension': {
+    'typeParameters': FieldRule(isDeclaration: true),
+  },
+  'Field': {
+    'reference': FieldRule(name: 'getterReference'),
+  },
+  'TypeParameter': {
+    '_variance': FieldRule(name: 'variance'),
+  },
+  'FunctionNode': {
+    '_body': FieldRule(name: 'body'),
+    'typeParameters': FieldRule(isDeclaration: true),
+    'positionalParameters': FieldRule(isDeclaration: true),
+    'namedParameters': FieldRule(isDeclaration: true),
+  },
+  'Typedef': {
+    'typeParameters': FieldRule(isDeclaration: true),
+    'typeParametersOfFunctionType': FieldRule(isDeclaration: false),
+    'positionalParameters': FieldRule(isDeclaration: false),
+    'namedParameters': FieldRule(isDeclaration: false),
+  },
+  'TypedefTearOff': {
+    'typeParameters': FieldRule(isDeclaration: true),
+  },
+  'TypedefTearOffConstant': {
+    'parameters': FieldRule(isDeclaration: true),
+  },
+  'LocalInitializer': {
+    'variable': FieldRule(isDeclaration: true),
+  },
+  'Let': {
+    'variable': FieldRule(isDeclaration: true),
+  },
+  'VariableGet': {
+    'variable': FieldRule(isDeclaration: false),
+  },
+  'VariableSet': {
+    'variable': FieldRule(isDeclaration: false),
+  },
+  'LocalFunctionInvocation': {
+    'variable': FieldRule(isDeclaration: false),
+  },
+  'BreakStatement': {
+    'target': FieldRule(isDeclaration: false),
+  },
+  'ForStatement': {
+    'variables': FieldRule(isDeclaration: true),
+  },
+  'ForInStatement': {
+    'variable': FieldRule(isDeclaration: true),
+  },
+  'SwitchStatement': {
+    'cases': FieldRule(isDeclaration: true),
+  },
+  'ContinueSwitchStatement': {
+    'target': FieldRule(isDeclaration: false),
+  },
+  'Catch': {
+    'exception': FieldRule(isDeclaration: true),
+    'stackTrace': FieldRule(isDeclaration: true),
+  },
+  'FunctionDeclaration': {
+    'variable': FieldRule(isDeclaration: true),
+  },
+  'FunctionType': {
+    'typeParameters': FieldRule(isDeclaration: true),
+  },
+  'TypeParameterType': {
+    'parameter': FieldRule(isDeclaration: false),
+  },
+};
+
+/// Data that determines exceptions to how fields are used.
+class FieldRule {
+  /// If non-null, the field should be accessed by this name.
+  ///
+  /// This is for instance used for private fields accessed through a public
+  /// getter.
+  final String name;
+
+  /// For fields contain ast class of kind `AstClassKind.declarative`, this
+  /// value defines whether the field should be treated as a declaration or
+  /// a reference to the declaration.
+  final bool isDeclaration;
+
+  const FieldRule({this.name, this.isDeclaration});
+}
+
+/// Return the [FieldRule] to use for the [field] in [AstClass].
+FieldRule getFieldRule(AstClass astClass, Field field) {
+  String name = field.name.text;
+  Map<String, FieldRule> leafClassMap = _fieldRuleMap[astClass.name];
+  if (leafClassMap != null && leafClassMap.containsKey(name)) {
+    return leafClassMap[name];
+  }
+  Map<String, FieldRule> enclosingClassMap =
+      _fieldRuleMap[field.enclosingClass.name];
+  if (enclosingClassMap != null && enclosingClassMap.containsKey(name)) {
+    return enclosingClassMap[name];
+  }
+  Map<String, FieldRule> defaultClassMap = _fieldRuleMap[null];
+  if (defaultClassMap != null && defaultClassMap.containsKey(name)) {
+    return defaultClassMap[name];
+  }
+  return new FieldRule(name: name);
+}
+
+/// Categorization of classes declared in 'package:kernel/ast.dart'.
+enum AstClassKind {
+  /// The root [Node] class.
+  root,
+
+  /// An abstract node class that is a superclass of a public class. Most of
+  /// these have a corresponding `defaultX` visitor method.
+  ///
+  /// For instance [Statement] and [Expression].
+  inner,
+
+  /// A concrete node class. These are the classes for which we have `visitX`
+  /// methods.
+  ///
+  /// For instance [Procedure] and [VariableGet].
+  public,
+
+  /// A concrete node class that serves only as an implementation of public
+  /// node class.
+  ///
+  /// For instance [PrivateName] and [PublicName] that implements the public
+  /// node [Name].
+  implementation,
+
+  /// A node class that serves as an interface.
+  ///
+  /// For instance `FileUriNode`.
+  interface,
+
+  /// A named node class that declares a nominal entity that is used with a
+  /// reference.
+  named,
+
+  /// A node class that declares a nominal entity but used without reference.
+  ///
+  /// For instance [VariableDeclaration] which introduces a new entity when it
+  /// occurs in a [Block] but is used as a reference when it occurs in a
+  /// [VariableGet].
+  declarative,
+
+  /// A none-node class that should be treated as a composite structure.
+  ///
+  /// For instance [ConstantMapEntry] which is a tuple of a [Constant] key and
+  /// a [Constant] value.
+  utilityAsStructure,
+
+  /// A none-node class that should be treated as an atomic value.
+  ///
+  /// For instance enum classes.
+  utilityAsValue,
+}
+
+class AstClass {
+  final Class node;
+  AstClassKind _kind;
+  final String declarativeName;
+
+  AstClass superclass;
+  List<AstClass> interfaces = [];
+  List<AstClass> subclasses = [];
+  List<AstClass> subtypes = [];
+
+  List<AstField> fields = [];
+
+  AstClass(this.node,
+      {this.superclass, AstClassKind kind, this.declarativeName})
+      : _kind = kind {
+    if (superclass != null) {
+      superclass.subclasses.add(this);
+    }
+  }
+
+  String get name => node.name;
+
+  AstClassKind get kind {
+    if (_kind == null) {
+      if (node.isAbstract) {
+        if (subclasses.isNotEmpty) {
+          if (subclasses.every(
+              (element) => element.kind == AstClassKind.implementation)) {
+            _kind = AstClassKind.public;
+          } else {
+            _kind = AstClassKind.inner;
+          }
+        } else {
+          _kind = AstClassKind.interface;
+        }
+      } else {
+        if (node.name.startsWith('_')) {
+          _kind = AstClassKind.implementation;
+        } else {
+          _kind = AstClassKind.public;
+        }
+      }
+    }
+    return _kind;
+  }
+
+  /// Returns `true` if this class has a `visitX` or `defaultX` method.
+  ///
+  /// This is only valid for subclass of [Node].
+  bool get hasVisitMethod {
+    switch (kind) {
+      case AstClassKind.root:
+      case AstClassKind.inner:
+      case AstClassKind.public:
+      case AstClassKind.named:
+      case AstClassKind.declarative:
+        return !_classesWithoutVisitMethods.contains(name);
+      case AstClassKind.implementation:
+      case AstClassKind.interface:
+      case AstClassKind.utilityAsStructure:
+      case AstClassKind.utilityAsValue:
+        return false;
+    }
+    throw new UnsupportedError("Unexpected $kind");
+  }
+
+  /// Returns `true` if this class has a `visitXReference` or
+  /// `defaultXReference` method.
+  ///
+  /// This is only valid for subclass of [NamedNode] or [Constant].
+  bool get hasVisitReferenceMethod {
+    switch (kind) {
+      case AstClassKind.root:
+      case AstClassKind.inner:
+      case AstClassKind.public:
+      case AstClassKind.named:
+      case AstClassKind.declarative:
+        return !_classesWithoutVisitReference.contains(name);
+      case AstClassKind.implementation:
+      case AstClassKind.interface:
+      case AstClassKind.utilityAsStructure:
+      case AstClassKind.utilityAsValue:
+        return false;
+    }
+    throw new UnsupportedError("Unexpected $kind");
+  }
+
+  String dump([String indent = ""]) {
+    StringBuffer sb = new StringBuffer();
+    sb.writeln('${indent}${node.name} ($kind)');
+    for (AstField field in fields) {
+      sb.write(field.dump('${indent}    '));
+    }
+    for (AstClass subclass in subclasses) {
+      sb.write(subclass.dump('${indent}  '));
+    }
+    return sb.toString();
+  }
+
+  String toString() => '${runtimeType}(${name})';
+}
+
+/// Categorization of field types.
+enum AstFieldKind {
+  /// An atomic non-node value.
+  ///
+  /// For instance an [int] value.
+  value,
+
+  /// A [Node] value that is part of the tree.
+  ///
+  /// For instance an [Expression] value.
+  node,
+
+  /// A [Reference] value.
+  reference,
+
+  /// A reference to a declarative [Node].
+  ///
+  /// For instance the reference to [VariableDeclaration] in [VariableGet].
+  use,
+
+  /// A list of values.
+  list,
+
+  /// A set of values.
+  set,
+
+  /// A map of values.
+  map,
+
+  /// A non-node composite value.
+  ///
+  /// For instance a [ConstantMapEntry] that must be treat as a tuple of
+  /// a [Constant] key and a [Constant] value.
+  utility,
+}
+
+/// Structural description of a field type.
+class FieldType {
+  final DartType type;
+  final AstFieldKind kind;
+
+  FieldType(this.type, this.kind);
+
+  String toString() => 'FieldType($type,$kind)';
+}
+
+class ListFieldType extends FieldType {
+  final FieldType elementType;
+
+  ListFieldType(DartType type, this.elementType)
+      : super(type, AstFieldKind.list);
+
+  String toString() => 'ListFieldType($type,$elementType)';
+}
+
+class SetFieldType extends FieldType {
+  final FieldType elementType;
+
+  SetFieldType(DartType type, this.elementType) : super(type, AstFieldKind.set);
+
+  String toString() => 'SetFieldType($type,$elementType)';
+}
+
+class MapFieldType extends FieldType {
+  final FieldType keyType;
+  final FieldType valueType;
+
+  MapFieldType(DartType type, this.keyType, this.valueType)
+      : super(type, AstFieldKind.map);
+
+  String toString() => 'MapFieldType($type,$keyType,$valueType)';
+}
+
+class UtilityFieldType extends FieldType {
+  final AstClass astClass;
+
+  UtilityFieldType(DartType type, this.astClass)
+      : super(type, AstFieldKind.utility);
+
+  String toString() => 'UtilityFieldType($type,$astClass)';
+}
+
+class AstField {
+  final Field node;
+  final String name;
+  final FieldType type;
+
+  AstField(this.node, this.name, this.type);
+
+  String dump([String indent = ""]) {
+    StringBuffer sb = new StringBuffer();
+    sb.writeln('$indent$name $type');
+    return sb.toString();
+  }
+
+  String toString() => '${runtimeType}(${name})';
+}
+
+class AstModel {
+  final AstClass nodeClass;
+  final AstClass namedNodeClass;
+  final AstClass constantClass;
+
+  AstModel(this.nodeClass, this.namedNodeClass, this.constantClass);
+
+  /// Returns an [Iterable] for all declarative [Node] classes in the AST model.
+  Iterable<AstClass> get declarativeClasses {
+    return classes.where((cls) => cls.kind == AstClassKind.declarative);
+  }
+
+  /// Returns an [Iterable] for all [Node] (sub)classes in the AST model.
+  Iterable<AstClass> get classes sync* {
+    Iterable<AstClass> visitClass(AstClass cls) sync* {
+      yield cls;
+      for (AstClass subclass in cls.subclasses) {
+        yield* visitClass(subclass);
+      }
+    }
+
+    yield* visitClass(nodeClass);
+  }
+}
+
+/// Computes the [AstModel] from 'package:kernel/ast' using [repoDir] to locate
+/// the package config file.
+///
+/// If [printDump] is `true`, a dump of the model printed to stdout.
+Future<AstModel> deriveAstModel(Uri repoDir, {bool printDump: false}) async {
+  CompilerOptions options = new CompilerOptions();
+  options.sdkRoot = computePlatformBinariesLocation(forceBuildDir: true);
+  options.packagesFileUri = computePackageConfig(repoDir);
+  options.onDiagnostic = (DiagnosticMessage message) {
+    printDiagnosticMessage(message, print);
+  };
+
+  InternalCompilerResult compilerResult = await kernelForProgramInternal(
+      astLibraryUri, options,
+      retainDataForTesting: true, requireMain: false);
+  ClassHierarchy classHierarchy = compilerResult.classHierarchy;
+  CoreTypes coreTypes = compilerResult.coreTypes;
+  TypeEnvironment typeEnvironment =
+      new TypeEnvironment(coreTypes, classHierarchy);
+
+  Library astLibrary = compilerResult.component.libraries
+      .singleWhere((library) => library.importUri == astLibraryUri);
+
+  bool errorsFound = false;
+  void reportError(String message) {
+    print(message);
+    errorsFound = true;
+  }
+
+  Map<String, String> declarativeClassesNames = {..._declarativeClassesNames};
+  Set<String> classesWithoutVisitMethods = _classesWithoutVisitMethods.toSet();
+  Set<String> classesWithoutVisitReference =
+      _classesWithoutVisitReference.toSet();
+  Map<String, Map<String, FieldRule>> fieldRuleMap = {..._fieldRuleMap};
+  Map<String, FieldRule> nullFieldRules = {...?fieldRuleMap.remove(null)};
+  for (Class cls in astLibrary.classes) {
+    declarativeClassesNames.remove(cls.name);
+    classesWithoutVisitMethods.remove(cls.name);
+    classesWithoutVisitReference.remove(cls.name);
+    Map<String, FieldRule> fieldRules = {...?fieldRuleMap.remove(cls.name)};
+    Set<String> renames = {};
+    Class parent = cls;
+    while (parent != null && parent.enclosingLibrary == astLibrary) {
+      for (Field field in parent.fields) {
+        bool hasFieldRule = fieldRules.containsKey(field.name.text);
+        FieldRule fieldRule = fieldRules.remove(field.name.text);
+        if (fieldRule != null) {
+          if (fieldRule.name != null) {
+            renames.add(fieldRule.name);
+          }
+        }
+        if (!hasFieldRule) {
+          if (!cls.isEnum && !field.isStatic && field.name.isPrivate) {
+            reportError(
+                'Private field `${field.name.text}` in ${parent.name} must '
+                'have a field rule.');
+          }
+        }
+        if (nullFieldRules.containsKey(field.name.text)) {
+          FieldRule nullFieldRule = nullFieldRules.remove(field.name.text);
+          if (nullFieldRule != null) {
+            reportError('Only `null` is allowed for class `null`.');
+          }
+        }
+      }
+      parent = parent.superclass;
+    }
+    for (Procedure procedure in cls.procedures) {
+      renames.remove(procedure.name.text);
+    }
+    if (renames.isNotEmpty) {
+      reportError('Unknown procedure(s) for field redirections in '
+          '${cls.name}: ${renames}');
+    }
+    if (fieldRules.isNotEmpty) {
+      reportError(
+          'Unknown field(s) for rules in ${cls.name}: ${fieldRules.keys}');
+    }
+  }
+  if (declarativeClassesNames.isNotEmpty) {
+    reportError('Unknown declarative classes: ${declarativeClassesNames}');
+  }
+  if (classesWithoutVisitMethods.isNotEmpty) {
+    reportError('Unknown classes without visit methods: '
+        '${classesWithoutVisitMethods}');
+  }
+  if (classesWithoutVisitReference.isNotEmpty) {
+    reportError('Unknown classes without visit reference methods: '
+        '${classesWithoutVisitReference}');
+  }
+  if (fieldRuleMap.isNotEmpty) {
+    reportError('Unknown classes with field rules: ${fieldRuleMap.keys}');
+  }
+
+  Class classNode = astLibrary.classes.singleWhere((cls) => cls.name == 'Node');
+  DartType nullableNodeType =
+      classNode.getThisType(coreTypes, Nullability.nullable);
+
+  Class classNamedNode =
+      astLibrary.classes.singleWhere((cls) => cls.name == 'NamedNode');
+
+  Class classConstant =
+      astLibrary.classes.singleWhere((cls) => cls.name == 'Constant');
+
+  Library canonicalNameLibrary = compilerResult.component.libraries
+      .singleWhere((library) => library.importUri == canonicalNameLibraryUri);
+
+  Class referenceClass = canonicalNameLibrary.classes
+      .singleWhere((cls) => cls.name == 'Reference');
+  DartType nullableReferenceType =
+      referenceClass.getThisType(coreTypes, Nullability.nullable);
+
+  Set<Class> declarativeClasses = {};
+  Set<DartType> declarativeTypes = {};
+  for (String name in _declarativeClassesNames.keys) {
+    Class cls = astLibrary.classes.singleWhere((cls) => cls.name == name);
+    declarativeClasses.add(cls);
+    declarativeTypes.add(cls.getThisType(coreTypes, Nullability.nullable));
+  }
+
+  Map<Class, AstClass> classMap = {};
+
+  /// Computes the [AstClass] corresponding to [node] if [node] is declared in
+  /// 'package:kernel/ast.dart'.
+  AstClass computeAstClass(Class node) {
+    if (node == null) return null;
+    if (node.enclosingLibrary != astLibrary) return null;
+
+    AstClass astClass = classMap[node];
+    if (astClass == null) {
+      if (node == classNode) {
+        astClass = new AstClass(node, kind: AstClassKind.root);
+      } else if (classHierarchy.isSubtypeOf(node, classNode)) {
+        AstClass superclass = computeAstClass(node.superclass);
+        AstClassKind kind;
+        String declarativeName;
+        if (!node.isAbstract &&
+            classHierarchy.isSubtypeOf(node, classNamedNode)) {
+          kind = AstClassKind.named;
+        } else if (declarativeClasses.contains(node)) {
+          kind = AstClassKind.declarative;
+          declarativeName = _declarativeClassesNames[node.name];
+        }
+        astClass = new AstClass(node,
+            superclass: superclass,
+            kind: kind,
+            declarativeName: declarativeName);
+        for (Supertype supertype in node.implementedTypes) {
+          AstClass astSupertype = computeAstClass(supertype.classNode);
+          if (astSupertype != null) {
+            astClass.interfaces.add(astSupertype);
+            astSupertype.subtypes.add(astClass);
+          }
+        }
+      } else if (node.isEnum || _utilityClassesAsValues.contains(node.name)) {
+        astClass = new AstClass(node, kind: AstClassKind.utilityAsValue);
+      } else {
+        AstClass superclass = computeAstClass(node.superclass);
+        astClass = new AstClass(node,
+            superclass: superclass, kind: AstClassKind.utilityAsStructure);
+      }
+      if (astClass != null) {
+        classMap[node] = astClass;
+      }
+    }
+    return astClass;
+  }
+
+  for (Class cls in astLibrary.classes) {
+    computeAstClass(cls);
+  }
+
+  for (AstClass astClass in classMap.values) {
+    void computeAstField(Field field, Substitution substitution) {
+      if (field.isStatic) {
+        return;
+      }
+      FieldRule rule = getFieldRule(astClass, field);
+      if (rule == null) {
+        return;
+      }
+      DartType type = substitution.substituteType(field.type);
+
+      FieldType computeFieldType(DartType type) {
+        bool isDeclarativeType = false;
+        for (InterfaceType declarativeType in declarativeTypes) {
+          if (type is InterfaceType &&
+              typeEnvironment.isSubtypeOf(
+                  type, declarativeType, SubtypeCheckMode.withNullabilities)) {
+            isDeclarativeType = true;
+            break;
+          }
+        }
+        if (isDeclarativeType) {
+          if (rule.isDeclaration == null) {
+            reportError(
+                "No field rule for '${field.name}' in ${astClass.name}.\n"
+                "The field type contains the declarative type "
+                "'${type.toText(defaultAstTextStrategy)}' "
+                "and a rule must therefore specify "
+                "whether this constitutes declarative or referential use.");
+          }
+          if (!rule.isDeclaration) {
+            return new FieldType(type, AstFieldKind.use);
+          }
+        }
+        if (type is InterfaceType &&
+            typeEnvironment.isSubtypeOf(type, coreTypes.listNullableRawType,
+                SubtypeCheckMode.withNullabilities)) {
+          DartType elementType = typeEnvironment
+              .getTypeArgumentsAsInstanceOf(type, coreTypes.listClass)
+              .single;
+          return new ListFieldType(type, computeFieldType(elementType));
+        } else if (type is InterfaceType &&
+            typeEnvironment.isSubtypeOf(type, coreTypes.setNullableRawType,
+                SubtypeCheckMode.withNullabilities)) {
+          DartType elementType = typeEnvironment
+              .getTypeArgumentsAsInstanceOf(type, coreTypes.setClass)
+              .single;
+          return new SetFieldType(type, computeFieldType(elementType));
+        } else if (type is InterfaceType &&
+            typeEnvironment.isSubtypeOf(type, coreTypes.mapNullableRawType,
+                SubtypeCheckMode.withNullabilities)) {
+          List<DartType> typeArguments = typeEnvironment
+              .getTypeArgumentsAsInstanceOf(type, coreTypes.mapClass);
+          return new MapFieldType(type, computeFieldType(typeArguments[0]),
+              computeFieldType(typeArguments[1]));
+        } else if (type is InterfaceType &&
+            typeEnvironment.isSubtypeOf(
+                type, nullableNodeType, SubtypeCheckMode.withNullabilities)) {
+          return new FieldType(type, AstFieldKind.node);
+        } else if (type is InterfaceType &&
+            typeEnvironment.isSubtypeOf(type, nullableReferenceType,
+                SubtypeCheckMode.withNullabilities)) {
+          return new FieldType(type, AstFieldKind.reference);
+        } else {
+          if (type is InterfaceType) {
+            AstClass astClass = classMap[type.classNode];
+            if (astClass != null &&
+                astClass.kind == AstClassKind.utilityAsStructure) {
+              return new UtilityFieldType(type, astClass);
+            }
+          }
+          return new FieldType(type, AstFieldKind.value);
+        }
+      }
+
+      FieldType fieldType;
+      fieldType ??= computeFieldType(type);
+      astClass.fields
+          .add(new AstField(field, rule.name ?? field.name.text, fieldType));
+    }
+
+    AstClass parent = astClass;
+    Substitution substitution = Substitution.empty;
+    while (parent != null) {
+      for (Field field in parent.node.fields) {
+        computeAstField(field, substitution);
+      }
+      parent = parent.superclass;
+      if (parent != null) {
+        substitution = Substitution.fromSupertype(
+            classHierarchy.getClassAsInstanceOf(astClass.node, parent.node));
+      }
+    }
+  }
+
+  AstClass astClassNode = classMap[classNode];
+  AstClass astClassNamedNode = classMap[classNamedNode];
+  AstClass astClassConstant = classMap[classConstant];
+
+  if (printDump) {
+    print(classMap[classNode].dump());
+    for (AstClass astClass in classMap.values) {
+      if (astClass != astClassNode && astClass.superclass == null) {
+        print(astClass.dump());
+      }
+    }
+  }
+  if (errorsFound) {
+    throw 'Errors found';
+  }
+  return new AstModel(astClassNode, astClassNamedNode, astClassConstant);
+}
diff --git a/pkg/front_end/tool/generate_ast_equivalence.dart b/pkg/front_end/tool/generate_ast_equivalence.dart
new file mode 100644
index 0000000..87349d6
--- /dev/null
+++ b/pkg/front_end/tool/generate_ast_equivalence.dart
@@ -0,0 +1,956 @@
+// 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.
+
+// @dart = 2.9
+
+import 'dart:io';
+
+import 'ast_model.dart';
+import 'visitor_generator.dart';
+
+Uri computeEquivalenceUri(Uri repoDir) {
+  return repoDir.resolve('pkg/kernel/lib/src/equivalence.dart');
+}
+
+main(List<String> args) async {
+  Uri output = args.isEmpty
+      ? computeEquivalenceUri(Uri.base)
+      : new File(args[0]).absolute.uri;
+  String result = await generateAstEquivalence(Uri.base);
+  new File.fromUri(output).writeAsStringSync(result);
+}
+
+Future<String> generateAstEquivalence(Uri repoDir) async {
+  AstModel astModel = await deriveAstModel(repoDir);
+  return generateVisitor(astModel, new EquivalenceVisitorStrategy());
+}
+
+class EquivalenceVisitorStrategy extends Visitor1Strategy {
+  Map<AstClass, String> _classStrategyMembers = {};
+  Map<AstField, String> _fieldStrategyMembers = {};
+
+  EquivalenceVisitorStrategy();
+
+  @override
+  String get argumentType => 'Node';
+
+  @override
+  String get argumentName => 'other';
+
+  @override
+  String get returnType => 'bool';
+
+  @override
+  String get visitorName => 'EquivalenceVisitor';
+
+  String get strategyName => 'EquivalenceStrategy';
+
+  String get internalCheckValues => '_checkValues';
+
+  String get checkValues => 'checkValues';
+
+  String get matchValues => 'matchValues';
+
+  String get internalCheckNodes => '_checkNodes';
+
+  String get checkNodes => 'checkNodes';
+
+  String get shallowMatchNodes => 'shallowMatchNodes';
+
+  String get deepMatchNodes => 'deepMatchNodes';
+
+  String get internalCheckReferences => '_checkReferences';
+
+  String get checkReferences => 'checkReferences';
+
+  String get matchReferences => 'matchReferences';
+
+  String get deepMatchReferences => 'deeplyMatchReferences';
+
+  String get matchNamedNodes => 'matchNamedNodes';
+
+  String get assumeReferences => 'assumeReferences';
+
+  String get checkAssumedReferences => 'checkAssumedReferences';
+
+  String get checkDeclarations => 'checkDeclarations';
+
+  String get internalCheckDeclarations => '_checkDeclarations';
+
+  String get shallowMatchDeclarations => 'matchDeclarations';
+
+  String get deepMatchDeclarations => 'deepMatchDeclarations';
+
+  String get assumeDeclarations => 'assumeDeclarations';
+
+  String get checkAssumedDeclarations => 'checkAssumedDeclarations';
+
+  String get checkLists => 'checkLists';
+
+  String get matchLists => 'matchLists';
+
+  String get checkSets => 'checkSets';
+
+  String get matchSets => 'matchSets';
+
+  String get checkMaps => 'checkMaps';
+
+  String get matchMaps => 'matchMaps';
+
+  String get checkingState => '_checkingState';
+
+  String get resultOnInequivalence => 'resultOnInequivalence';
+
+  String get registerInequivalence => 'registerInequivalence';
+
+  String classCheckName(AstClass astClass) => 'check${astClass.name}';
+
+  String fieldCheckName(AstClass astClass, AstField field) =>
+      'check${astClass.name}_${field.name}';
+
+  @override
+  void handleDefaultVisit(AstClass astClass, StringBuffer sb) {
+    sb.writeln('''
+    return false;''');
+  }
+
+  /// Compute the expression code for shallow matching two values of type
+  /// [fieldType].
+  ///
+  /// Shallow matching is used to pair value when checking sets and maps. The
+  /// checking doesn't traverse the AST deeply and inequivalences are not
+  /// registered.
+  ///
+  /// [prefix] is used as the receiver of the invocation.
+  String computeMatchingHelper(FieldType fieldType, [String prefix = '']) {
+    String thisName = 'a';
+    String otherName = 'b';
+    switch (fieldType.kind) {
+      case AstFieldKind.value:
+        return '$prefix$matchValues';
+      case AstFieldKind.node:
+        return '$prefix$shallowMatchNodes';
+      case AstFieldKind.reference:
+        return '$prefix$matchReferences';
+      case AstFieldKind.use:
+        return '$prefix$shallowMatchDeclarations';
+      case AstFieldKind.list:
+        ListFieldType listFieldType = fieldType;
+        String elementEquivalence =
+            computeMatchingHelper(listFieldType.elementType);
+        return '($thisName, $otherName) => $prefix$matchLists('
+            '$thisName, $otherName, $elementEquivalence)';
+      case AstFieldKind.set:
+        SetFieldType setFieldType = fieldType;
+        String elementMatching =
+            computeMatchingHelper(setFieldType.elementType);
+        String elementEquivalence =
+            computeEquivalenceHelper(setFieldType.elementType);
+        return '($thisName, $otherName) => $prefix$checkSets('
+            '$thisName, $otherName, $elementMatching, $elementEquivalence)';
+      case AstFieldKind.map:
+        MapFieldType mapFieldType = fieldType;
+        String keyMatching = computeMatchingHelper(mapFieldType.keyType);
+        String keyEquivalence = computeEquivalenceHelper(mapFieldType.keyType);
+        String valueEquivalence =
+            computeEquivalenceHelper(mapFieldType.valueType);
+        return '($thisName,  $otherName) => $prefix$checkMaps('
+            '$thisName, $otherName, $keyMatching, '
+            '$keyEquivalence, $valueEquivalence)';
+      case AstFieldKind.utility:
+        StringBuffer sb = new StringBuffer();
+        UtilityFieldType utilityFieldType = fieldType;
+        registerAstClassEquivalence(utilityFieldType.astClass);
+        sb.writeln('''($thisName, $otherName, _) {
+    if (identical($thisName, $otherName)) return true;
+    if ($thisName is! ${utilityFieldType.astClass.name}) return false;
+    if ($otherName is! ${utilityFieldType.astClass.name}) return false;
+    return ${classCheckName(utilityFieldType.astClass)}(
+        visitor,
+        $thisName,
+        $otherName);
+  }''');
+        return sb.toString();
+    }
+    throw ArgumentError("Unexpected field type ${fieldType}");
+  }
+
+  /// Computes the expression code for checking the equivalence of two fields
+  /// of type [fieldType].
+  ///
+  /// Checking is used to check the AST for equivalence and inequivalences are
+  /// registered.
+  ///
+  /// [prefix] is used as the receiver of the invocation.
+  String computeEquivalenceHelper(FieldType fieldType, [String prefix = '']) {
+    String thisName = 'a';
+    String otherName = 'b';
+    switch (fieldType.kind) {
+      case AstFieldKind.value:
+        return '$prefix$checkValues';
+      case AstFieldKind.node:
+        return '$prefix$checkNodes';
+      case AstFieldKind.reference:
+        return '$prefix$checkReferences';
+      case AstFieldKind.use:
+        return '$prefix$checkDeclarations';
+      case AstFieldKind.list:
+        ListFieldType listFieldType = fieldType;
+        String elementEquivalence =
+            computeEquivalenceHelper(listFieldType.elementType);
+        return '($thisName, $otherName) => $prefix$checkLists('
+            '$thisName, $otherName, $elementEquivalence)';
+      case AstFieldKind.set:
+        SetFieldType setFieldType = fieldType;
+        String elementMatching =
+            computeMatchingHelper(setFieldType.elementType);
+        String elementEquivalence =
+            computeEquivalenceHelper(setFieldType.elementType);
+        return '($thisName, $otherName) => $prefix$checkSets('
+            '$thisName, $otherName, $elementMatching, $elementEquivalence)';
+      case AstFieldKind.map:
+        MapFieldType mapFieldType = fieldType;
+        String keyMatching = computeMatchingHelper(mapFieldType.keyType);
+        String keyEquivalence = computeEquivalenceHelper(mapFieldType.keyType);
+        String valueEquivalence =
+            computeEquivalenceHelper(mapFieldType.valueType);
+        return '($thisName, $otherName) => $prefix$checkMaps('
+            '$thisName, $otherName, $keyMatching, '
+            '$keyEquivalence, $valueEquivalence)';
+      case AstFieldKind.utility:
+        StringBuffer sb = new StringBuffer();
+        UtilityFieldType utilityFieldType = fieldType;
+        registerAstClassEquivalence(utilityFieldType.astClass);
+        sb.writeln('''($thisName, $otherName, _) {
+    if (identical($thisName, $otherName)) return true;
+    if ($thisName is! ${utilityFieldType.astClass.name}) return false;
+    if ($otherName is! ${utilityFieldType.astClass.name}) return false;
+    return ${classCheckName(utilityFieldType.astClass)}(
+        visitor,
+        $thisName,
+        $otherName);
+  }''');
+        return sb.toString();
+    }
+    throw ArgumentError("Unexpected field type ${fieldType}");
+  }
+
+  /// Registers that a strategy method is needed for checking [astClass].
+  ///
+  /// If the method has not already been generated, it is generated and stored
+  /// in [_classStrategyMembers].
+  void registerAstClassEquivalence(AstClass astClass) {
+    if (_classStrategyMembers.containsKey(astClass)) return;
+
+    String thisName = 'node';
+    String otherName = 'other';
+    StringBuffer classStrategy = new StringBuffer();
+    classStrategy.writeln('''
+  bool ${classCheckName(astClass)}(
+      $visitorName visitor,
+      ${astClass.name}? $thisName,
+      Object? $otherName) {''');
+
+    classStrategy.writeln('''
+    if (identical($thisName, $otherName)) return true;
+    if ($thisName is! ${astClass.name}) return false;
+    if ($otherName is! ${astClass.name}) return false;''');
+    if (astClass.kind == AstClassKind.named) {
+      classStrategy.writeln('''
+    if (!visitor.$matchNamedNodes($thisName, $otherName)) {
+      return false;
+    }''');
+    } else if (astClass.kind == AstClassKind.declarative) {
+      classStrategy.writeln('''
+    if (!visitor.$checkDeclarations($thisName, $otherName, '')) {
+      return false;
+    }''');
+    }
+
+    if (astClass.kind != AstClassKind.utilityAsStructure) {
+      classStrategy.writeln('''
+    visitor.pushNodeState($thisName, $otherName);''');
+    }
+    classStrategy.writeln('''
+    bool result = true;''');
+    for (AstField field in astClass.fields) {
+      registerAstFieldEquivalence(astClass, field);
+      classStrategy.writeln('''
+    if (!${fieldCheckName(astClass, field)}(visitor, $thisName, $otherName)) {
+      result = visitor.$resultOnInequivalence;
+    }''');
+    }
+
+    if (astClass.kind != AstClassKind.utilityAsStructure) {
+      classStrategy.writeln('''
+    visitor.popState();''');
+    }
+
+    classStrategy.writeln('''
+    return result;
+  }''');
+
+    _classStrategyMembers[astClass] = classStrategy.toString();
+  }
+
+  /// Registers that a strategy method is needed for checking [field] in
+  /// [astClass].
+  ///
+  /// If the method has not already been generated, it is generated and stored
+  /// in [_fieldStrategyMembers].
+  void registerAstFieldEquivalence(AstClass astClass, AstField field) {
+    if (_fieldStrategyMembers.containsKey(field)) return;
+
+    String thisName = 'node';
+    String otherName = 'other';
+    StringBuffer fieldStrategy = new StringBuffer();
+    fieldStrategy.writeln('''
+  bool ${fieldCheckName(astClass, field)}(
+      $visitorName visitor,
+      ${astClass.name} $thisName,
+      ${astClass.name} $otherName) {''');
+
+    switch (field.type.kind) {
+      case AstFieldKind.value:
+        fieldStrategy.writeln('''
+    return visitor.$checkValues(
+        $thisName.${field.name},
+        $otherName.${field.name},
+        '${field.name}');''');
+        break;
+      case AstFieldKind.node:
+        fieldStrategy.writeln('''
+    return visitor.$checkNodes(
+        $thisName.${field.name},
+        $otherName.${field.name},
+        '${field.name}');''');
+        break;
+      case AstFieldKind.reference:
+        fieldStrategy.writeln('''
+    return visitor.$checkReferences(
+        $thisName.${field.name},
+        $otherName.${field.name},
+        '${field.name}');''');
+        break;
+      case AstFieldKind.use:
+        fieldStrategy.writeln('''
+    return visitor.$checkDeclarations(
+        $thisName.${field.name},
+        $otherName.${field.name},
+        '${field.name}');''');
+        break;
+      case AstFieldKind.list:
+        ListFieldType listFieldType = field.type;
+        fieldStrategy.writeln('''
+    return visitor.$checkLists(
+        $thisName.${field.name},
+        $otherName.${field.name},
+        ${computeEquivalenceHelper(listFieldType.elementType, 'visitor.')},
+        '${field.name}');''');
+        break;
+      case AstFieldKind.set:
+        SetFieldType setFieldType = field.type;
+        fieldStrategy.writeln('''
+    return visitor.$checkSets(
+        $thisName.${field.name},
+        $otherName.${field.name},
+        ${computeMatchingHelper(setFieldType.elementType, 'visitor.')},
+        ${computeEquivalenceHelper(setFieldType.elementType, 'visitor.')},
+        '${field.name}');''');
+        break;
+      case AstFieldKind.map:
+        MapFieldType mapFieldType = field.type;
+        fieldStrategy.writeln('''
+    return visitor.$checkMaps(
+        $thisName.${field.name},
+        $otherName.${field.name},
+        ${computeMatchingHelper(mapFieldType.keyType, 'visitor.')},
+        ${computeEquivalenceHelper(mapFieldType.keyType, 'visitor.')},
+        ${computeEquivalenceHelper(mapFieldType.valueType, 'visitor.')},
+        '${field.name}');''');
+        break;
+      case AstFieldKind.utility:
+        UtilityFieldType utilityFieldType = field.type;
+        registerAstClassEquivalence(utilityFieldType.astClass);
+        fieldStrategy.writeln('''
+    '${field.name}';
+    return ${classCheckName(utilityFieldType.astClass)}(
+        visitor,
+        $thisName.${field.name},
+        $otherName.${field.name});''');
+        break;
+    }
+    fieldStrategy.writeln('''
+  }''');
+    _fieldStrategyMembers[field] = fieldStrategy.toString();
+  }
+
+  @override
+  void handleVisit(AstClass astClass, StringBuffer sb) {
+    registerAstClassEquivalence(astClass);
+    sb.writeln('''
+    return strategy.${classCheckName(astClass)}(
+        this, node, $argumentName);''');
+  }
+
+  @override
+  void handleDefaultVisitReference(AstClass astClass, StringBuffer sb) {
+    sb.writeln('''
+    return false;''');
+  }
+
+  @override
+  void handleVisitReference(AstClass astClass, StringBuffer sb) {
+    sb.writeln('''
+    return false;''');
+  }
+
+  void generateHeader(AstModel astModel, StringBuffer sb) {
+    sb.writeln('''
+// 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.
+
+// NOTE: THIS FILE IS GENERATED. DO NOT EDIT.
+//
+// Run 'dart pkg/front_end/tool/generate_ast_equivalence.dart' to update.
+
+import 'package:kernel/ast.dart';
+import 'package:kernel/src/printer.dart';
+import 'union_find.dart';
+
+part 'equivalence_helpers.dart';
+
+/// Visitor that uses a $strategyName to compute AST node equivalence.
+///
+/// The visitor hold a current state that collects found inequivalences and
+/// current assumptions. The current state has two modes. In the asserting mode,
+/// the default, inequivalences are registered when found. In the non-asserting
+/// mode, inequivalences are _not_ registered. The latter is used to compute
+/// equivalences in sand boxed state, for instance to determine which elements
+/// to pair when checking equivalence of two sets.
+class $visitorName$visitorTypeParameters
+    implements Visitor1<$returnType, $argumentType> {
+  final $strategyName strategy;
+
+  $visitorName({
+      this.strategy: const $strategyName()});
+''');
+  }
+
+  @override
+  void generateFooter(AstModel astModel, StringBuffer sb) {
+    sb.writeln('''
+  /// Returns `true` if [a] and [b] are identical or equal.
+  bool $internalCheckValues<T>(T? a, T? b) {
+    return identical(a, b) || a == b;
+  }
+
+  /// Returns `true` if [a] and [b] are identical or equal and registers the
+  /// inequivalence otherwise.
+  bool $checkValues<T>(T? a, T? b, String propertyName) {
+    bool result = $internalCheckValues(a, b);
+    if (!result) {
+      registerInequivalence(
+          propertyName, 'Values \${a} and \${b} are not equivalent');
+    }
+    return result;
+  }
+
+  /// Returns `true` if [a] and [b] are identical or equal. Inequivalence is
+  /// _not_ registered.
+  bool $matchValues<T>(T? a, T? b) {
+    return $internalCheckValues(a, b);
+  }
+
+  /// Returns `true` if [a] and [b] are equivalent.
+  bool $internalCheckNodes<T extends Node>(T? a, T? b) {
+    if (identical(a, b)) return true;
+    if (a == null || b == null) {
+      return false;
+    } else {
+      return a.accept1(this, b);
+    }
+  }
+
+  /// Returns `true` if [a] and [b] are equivalent, as defined by the current
+  /// strategy, and registers the inequivalence otherwise.
+  bool $checkNodes<T extends Node>(T? a, T? b,
+      [String propertyName = '']) {
+    $checkingState.pushPropertyState(propertyName);
+    bool result = $internalCheckNodes(a, b);
+    $checkingState.popState();
+    if (!result) {
+      $registerInequivalence(
+          propertyName, 'Inequivalent nodes\\n1: \${a}\\n2: \${b}');
+    }
+    return result;
+  }
+
+  /// Returns `true` if [a] and [b] are identical or equal. Inequivalence is
+  /// _not_ registered.
+  bool $shallowMatchNodes<T extends Node>(T? a, T? b) {
+    return $internalCheckValues(a, b);
+  }
+
+  /// Returns `true` if [a] and [b] are equivalent, as defined by the current
+  /// strategy. Inequivalence is _not_ registered.
+  bool $deepMatchNodes<T extends Node>(T? a, T? b) {
+    CheckingState oldState = $checkingState;
+    $checkingState = $checkingState.toMatchingState();
+    bool result = $checkNodes(a, b);
+    $checkingState = oldState;
+    return result;
+  }
+
+  /// Returns `true` if [a] and [b] are equivalent, as defined by their
+  /// corresponding canonical names. Inequivalence is _not_ registered.
+  bool $matchNamedNodes(NamedNode? a, NamedNode? b) {
+    return identical(a, b) ||
+        a == null ||
+        b == null ||
+        new ReferenceName.fromNamedNode(a) ==
+            new ReferenceName.fromNamedNode(b);
+  }
+
+  /// Returns `true` if [a] and [b] are currently assumed to be equivalent.
+  bool $checkAssumedReferences(Reference? a, Reference? b) {
+    return $checkingState.$checkAssumedReferences(a, b);
+  }
+
+  /// Assume that [a] and [b] are equivalent, if possible.
+  ///
+  /// Returns `true` if [a] and [b] could be assumed to be equivalent. This
+  /// would not be the case if [a] xor [b] is `null`.
+  bool $assumeReferences(Reference? a, Reference? b) {
+    return $checkingState.$assumeReferences(a, b);
+  }
+
+  /// Returns `true` if [a] and [b] are equivalent, as defined by their
+  /// corresponding canonical names. Inequivalence is _not_ registered.
+  bool $matchReferences(Reference? a, Reference? b) {
+    return identical(a, b) ||
+        ReferenceName.fromReference(a) ==
+            ReferenceName.fromReference(b);
+  }
+
+  /// Returns `true` if [a] and [b] are equivalent, either by their
+  /// corresponding canonical names or by assumption. Inequivalence is _not_
+  /// registered.
+  bool $internalCheckReferences(Reference? a, Reference? b) {
+    if (identical(a, b)) {
+      return true;
+    } else if (a == null || b == null) {
+      return false;
+    } else if ($matchReferences(a, b)) {
+      return true;
+    } else if ($checkAssumedReferences(a, b)) {
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  /// Returns `true` if [a] and [b] are equivalent, either by their
+  /// corresponding canonical names or by assumption. Inequivalence is _not_
+  /// registered.
+  bool $deepMatchReferences(Reference? a, Reference? b) {
+    CheckingState oldState = $checkingState;
+    $checkingState = $checkingState.toMatchingState();
+    bool result = $checkReferences(a, b);
+    $checkingState = oldState;
+    return result;
+  }
+
+  /// Returns `true` if [a] and [b] are equivalent, either by their
+  /// corresponding canonical names or by assumption, and registers the
+  /// inequivalence otherwise.
+  bool $checkReferences(
+      Reference? a,
+      Reference? b,
+      [String propertyName = '']) {
+    bool result = $internalCheckReferences(a, b);
+    if (!result) {
+      $registerInequivalence(
+          propertyName, 'Inequivalent references:\\n1: \${a}\\n2: \${b}');
+    }
+    return result;
+  }
+
+  /// Returns `true` if declarations [a] and [b] are currently assumed to be
+  /// equivalent.
+  bool $checkAssumedDeclarations(dynamic a, dynamic b) {
+    return $checkingState.$checkAssumedDeclarations(a, b);
+  }
+
+  /// Assume that [a] and [b] are equivalent, if possible.
+  ///
+  /// Returns `true` if [a] and [b] could be assumed to be equivalent. This
+  /// would not be the case if [a] is already assumed to be equivalent to
+  /// another declaration.
+  bool $assumeDeclarations(dynamic a, dynamic b) {
+    return $checkingState.$assumeDeclarations(a, b);
+  }
+
+  bool $shallowMatchDeclarations(dynamic a, dynamic b) {''');
+
+    for (AstClass cls in astModel.declarativeClasses) {
+      if (cls.declarativeName != null) {
+        sb.write('''
+    if (a is ${cls.name}) {
+      return b is ${cls.name} &&
+          a.${cls.declarativeName} == b.${cls.declarativeName};
+    }
+''');
+      } else {
+        sb.write('''
+    if (a is ${cls.name}) {
+      return b is ${cls.name};
+    }
+''');
+      }
+    }
+    try {
+      try {
+        try {
+          sb.writeln('''
+          return false;
+  }
+
+  bool $internalCheckDeclarations(dynamic a, dynamic b) {
+          if (identical(a, b)) {
+            return true;
+          } else if (a == null || b == null) {
+            return false;
+          } else if ($checkAssumedDeclarations(a, b)) {
+            return true;
+          } else if ($shallowMatchDeclarations(a, b)) {
+            return $assumeDeclarations(a, b);
+          } else {
+            return false;
+          }
+  }
+
+  bool $deepMatchDeclarations(dynamic a, dynamic b) {
+          CheckingState oldState = $checkingState;
+          $checkingState = $checkingState.toMatchingState();
+          bool result = $checkDeclarations(a, b);
+          $checkingState = oldState;
+          return result;
+  }
+
+  bool $checkDeclarations(dynamic a, dynamic b,
+            [String propertyName = '']) {
+          bool result = $internalCheckDeclarations(a, b);
+          if (!result) {
+            result = $assumeDeclarations(a, b);
+          }
+          if (!result) {
+            $registerInequivalence(
+                propertyName, 'Declarations \${a} and \${b} are not equivalent');
+          }
+          return result;
+  }
+
+  /// Returns `true` if lists [a] and [b] are equivalent, using
+  /// [equivalentValues] to determine element-wise equivalence.
+  ///
+  /// If run in a checking state, the [propertyName] is used for registering
+  /// inequivalences.
+  bool $checkLists<E>(
+            List<E>? a,
+            List<E>? b,
+            bool Function(E?, E?, String) equivalentValues,
+            [String propertyName = '']) {
+          if (identical(a, b)) return true;
+          if (a == null || b == null) return false;
+          if (a.length != b.length) {
+            $registerInequivalence(
+              '\${propertyName}.length', 'Lists \${a} and \${b} are not equivalent');
+            return false;
+          }
+          for (int i = 0; i < a.length; i++) {
+            if (!equivalentValues(a[i], b[i], '\${propertyName}[\${i}]')) {
+              return false;
+            }
+          }
+          return true;
+  }
+
+  /// Returns `true` if lists [a] and [b] are equivalent, using
+  /// [equivalentValues] to determine element-wise equivalence.
+  ///
+  /// Inequivalence is _not_ registered.
+  bool $matchLists<E>(
+            List<E>? a,
+            List<E>? b,
+            bool Function(E?, E?, String) equivalentValues) {
+          CheckingState oldState = $checkingState;
+          $checkingState = $checkingState.toMatchingState();
+          bool result = $checkLists(a, b, equivalentValues);
+          $checkingState = oldState;
+          return result;
+  }
+
+  /// Returns `true` if sets [a] and [b] are equivalent, using
+  /// [matchingValues] to determine which elements that should be checked for
+  /// element-wise equivalence using [equivalentValues].
+  ///
+  /// If run in a checking state, the [propertyName] is used for registering
+  /// inequivalences.
+  bool $checkSets<E>(
+            Set<E>? a,
+            Set<E>? b,
+            bool Function(E?, E?) matchingValues,
+            bool Function(E?, E?, String) equivalentValues,
+            [String propertyName = '']) {
+          if (identical(a, b)) return true;
+          if (a == null || b == null) return false;
+          if (a.length != b.length) {
+            $registerInequivalence(
+                '\${propertyName}.length', 'Sets \${a} and \${b} are not equivalent');
+            return false;
+          }
+          b = b.toSet();
+          for (E aValue in a) {
+            bool hasFoundValue = false;
+            E? foundValue;
+            for (E bValue in b) {
+              if (matchingValues(aValue, bValue)) {
+                foundValue = bValue;
+                hasFoundValue = true;
+                if (!equivalentValues(aValue, bValue,
+                    '\${propertyName}[\${aValue}]')) {
+                  $registerInequivalence(
+                      '\${propertyName}[\${aValue}]',
+                      'Elements \${aValue} and \${bValue} are not equivalent');
+                  return false;
+                }
+                break;
+              }
+            }
+            if (hasFoundValue) {
+              b.remove(foundValue);
+            } else {
+              $registerInequivalence(
+                  '\${propertyName}[\${aValue}]',
+                  'Sets \${a} and \${b} are not equivalent, no equivalent value '
+                  'found for \$aValue');
+              return false;
+            }
+          }
+          return true;
+  }
+
+  /// Returns `true` if sets [a] and [b] are equivalent, using
+  /// [matchingValues] to determine which elements that should be checked for
+  /// element-wise equivalence using [equivalentValues].
+  ///
+  /// Inequivalence is _not_registered.
+  bool $matchSets<E>(
+            Set<E>? a,
+            Set<E>? b,
+            bool Function(E?, E?) matchingValues,
+            bool Function(E?, E?, String) equivalentValues) {
+          CheckingState oldState = $checkingState;
+          $checkingState = $checkingState.toMatchingState();
+          bool result = $checkSets(a, b, matchingValues, equivalentValues);
+          $checkingState = oldState;
+          return result;
+  }
+
+  /// Returns `true` if maps [a] and [b] are equivalent, using
+  /// [matchingKeys] to determine which entries that should be checked for
+  /// entry-wise equivalence using [equivalentKeys] and [equivalentValues] to
+  /// determine key and value equivalences, respectively.
+  ///
+  /// If run in a checking state, the [propertyName] is used for registering
+  /// inequivalences.
+  bool $checkMaps<K, V>(
+            Map<K, V>? a,
+            Map<K, V>? b,
+            bool Function(K?, K?) matchingKeys,
+            bool Function(K?, K?, String) equivalentKeys,
+            bool Function(V?, V?, String) equivalentValues,
+            [String propertyName = '']) {
+          if (identical(a, b)) return true;
+          if (a == null || b == null) return false;
+          if (a.length != b.length) {
+            $registerInequivalence(
+              '\${propertyName}.length',
+              'Maps \${a} and \${b} are not equivalent');
+            return false;
+          }
+          Set<K> bKeys = b.keys.toSet();
+          for (K aKey in a.keys) {
+            bool hasFoundKey = false;
+            K? foundKey;
+            for (K bKey in bKeys) {
+              if (matchingKeys(aKey, bKey)) {
+                foundKey = bKey;
+                hasFoundKey = true;
+                if (!equivalentKeys(aKey, bKey, '\${propertyName}[\${aKey}]')) {
+                  $registerInequivalence(
+                      '\${propertyName}[\${aKey}]',
+                      'Keys \${aKey} and \${bKey} are not equivalent');
+                  return false;
+                }
+                break;
+              }
+            }
+            if (hasFoundKey) {
+              bKeys.remove(foundKey);
+              if (!equivalentValues(a[aKey], b[foundKey],
+                  '\${propertyName}[\${aKey}]')) {
+                return false;
+              }
+            } else {
+              $registerInequivalence(
+                '\${propertyName}[\${aKey}]',
+                'Maps \${a} and \${b} are not equivalent, no equivalent key '
+                    'found for \$aKey');
+              return false;
+            }
+          }
+          return true;
+  }
+
+  /// Returns `true` if maps [a] and [b] are equivalent, using
+  /// [matchingKeys] to determine which entries that should be checked for
+  /// entry-wise equivalence using [equivalentKeys] and [equivalentValues] to
+  /// determine key and value equivalences, respectively.
+  ///
+  /// Inequivalence is _not_ registered.
+  bool $matchMaps<K, V>(
+            Map<K, V>? a,
+            Map<K, V>? b,
+            bool Function(K?, K?) matchingKeys,
+            bool Function(K?, K?, String) equivalentKeys,
+            bool Function(V?, V?, String) equivalentValues) {
+          CheckingState oldState = $checkingState;
+          $checkingState = $checkingState.toMatchingState();
+          bool result = $checkMaps(a, b, matchingKeys, equivalentKeys,
+              equivalentValues);
+          $checkingState = oldState;
+          return result;
+  }
+
+  /// The current state of the visitor.
+  ///
+  /// This holds the current assumptions, found inequivalences, and whether
+  /// inequivalences are currently registered.
+  CheckingState $checkingState = new CheckingState();
+
+  /// Runs [f] in a new state that holds all current assumptions. If
+  /// [isAsserting] is `true`, inequivalences are registered. Returns the
+  /// collected inequivalences.
+  ///
+  /// If [f] returns `false`, the returned result is marked as having
+  /// inequivalences even when non have being registered.
+  EquivalenceResult inSubState(bool Function() f, {bool isAsserting: false}) {
+    CheckingState _oldState = $checkingState;
+    $checkingState = $checkingState.createSubState(isAsserting: isAsserting);
+    bool hasInequivalences = f();
+    EquivalenceResult result =
+        $checkingState.toResult(hasInequivalences: hasInequivalences);
+    $checkingState = _oldState;
+    return result;
+  }
+
+  /// Registers that the visitor enters the property named [propertyName] and
+  /// the currently visited node.
+  void pushPropertyState(String propertyName) {
+    $checkingState.pushPropertyState(propertyName);
+  }
+
+  /// Registers that the visitor enters nodes [a] and [b].
+  void pushNodeState(Node a, Node b) {
+    $checkingState.pushNodeState(a, b);
+  }
+
+  /// Register that the visitor leave the current node or property.
+  void popState() {
+    $checkingState.popState();
+  }
+
+  /// Returns the value used as the result for property inequivalences.
+  ///
+  /// When inequivalences are currently registered, this is `true`, so that the
+  /// visitor will continue find inequivalences that are not directly related.
+  ///
+  /// An example is finding several child inequivalences on otherwise equivalent
+  /// nodes, like finding inequivalences deeply in the members of the second
+  /// library of a component even when inequivalences deeply in the members of
+  /// the first library. Had the return value been `false`, signaling that the
+  /// first libraries were inequivalent, which they technically are, given that
+  /// the contain inequivalent subnodes, the visitor would have stopped short in
+  /// checking the list of libraries, and the inequivalences in the second
+  /// library would not have been found.
+  ///
+  /// When inequivalences are _not_ currently registered, i.e. we are only
+  /// interested in the true/false value of the equivalence test, `false` is
+  /// used as the result value to stop the equivalence checking short.
+  bool get $resultOnInequivalence =>
+            $checkingState.$resultOnInequivalence;
+
+  /// Registers an equivalence on the [propertyName] with a detailed description
+  /// in [message].
+  void $registerInequivalence(String propertyName, String message) {
+          $checkingState.registerInequivalence(propertyName, message);
+  }
+
+  /// Returns the inequivalences found by the visitor.
+  EquivalenceResult toResult() => $checkingState.toResult();
+
+  ''');
+        } catch (e, s) {
+          print(s);
+        }
+      } catch (e, s) {
+        print(s);
+      }
+    } catch (e, s) {
+      print(s);
+    }
+    super.generateFooter(astModel, sb);
+    sb.writeln('''
+/// Checks [a] and [b] be for equivalence using [strategy].
+///
+/// Returns an [EquivalenceResult] containing the found inequivalences.
+EquivalenceResult checkEquivalence(
+    Node a,
+    Node b,
+    {$strategyName strategy: const $strategyName()}) {
+  EquivalenceVisitor visitor = new EquivalenceVisitor(
+      strategy: strategy);
+  visitor.$checkNodes(a, b, 'root');
+  return visitor.toResult();
+}
+''');
+
+    sb.writeln('''
+/// Strategy used for determining equivalence of AST nodes.
+///
+/// The strategy has a method for determining the equivalence of each AST node
+/// class, and a method for determining the equivalence of each property on each
+/// AST node class.
+///
+/// The base implementation enforces a full structural equivalence.
+///
+/// Custom strategies can be made by extending this strategy and override
+/// methods where exceptions to the structural equivalence are needed.
+class $strategyName {
+  const $strategyName();
+''');
+    _classStrategyMembers.forEach((key, value) {
+      sb.write(value);
+    });
+    _fieldStrategyMembers.forEach((key, value) {
+      sb.write(value);
+    });
+    sb.writeln(r'''
+}
+''');
+  }
+}
diff --git a/pkg/front_end/tool/visitor_generator.dart b/pkg/front_end/tool/visitor_generator.dart
new file mode 100644
index 0000000..ff3bace
--- /dev/null
+++ b/pkg/front_end/tool/visitor_generator.dart
@@ -0,0 +1,304 @@
+// 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.
+
+// @dart = 2.9
+
+import 'package:dart_style/dart_style.dart' show DartFormatter;
+
+import 'ast_model.dart';
+
+/// Generates a visitor library into [sb] based on [astModel] and [strategy].
+String generateVisitor(AstModel astModel, VisitorStrategy strategy) {
+  StringBuffer sb = new StringBuffer();
+  strategy.generateHeader(astModel, sb);
+
+  void addVisitNode(AstClass astClass) {
+    switch (astClass.kind) {
+      case AstClassKind.root:
+      case AstClassKind.inner:
+        if (astClass.hasVisitMethod) {
+          strategy.generateDefaultVisit(astClass, sb);
+        }
+        for (AstClass subclass in astClass.subclasses) {
+          addVisitNode(subclass);
+        }
+        break;
+      case AstClassKind.public:
+      case AstClassKind.named:
+      case AstClassKind.declarative:
+        if (astClass.hasVisitMethod) {
+          strategy.generateVisit(astClass, sb);
+        }
+        break;
+      case AstClassKind.implementation:
+      case AstClassKind.interface:
+      case AstClassKind.utilityAsStructure:
+      case AstClassKind.utilityAsValue:
+        break;
+    }
+  }
+
+  void addVisitReference(AstClass astClass) {
+    switch (astClass.kind) {
+      case AstClassKind.root:
+      case AstClassKind.inner:
+        if (astClass.hasVisitReferenceMethod) {
+          strategy.generateDefaultVisitReference(astClass, sb);
+        }
+        for (AstClass subclass in astClass.subclasses) {
+          addVisitReference(subclass);
+        }
+        break;
+      case AstClassKind.public:
+      case AstClassKind.named:
+      case AstClassKind.declarative:
+        if (astClass.hasVisitReferenceMethod) {
+          strategy.generateVisitReference(astClass, sb);
+        }
+        break;
+      case AstClassKind.implementation:
+      case AstClassKind.interface:
+      case AstClassKind.utilityAsStructure:
+      case AstClassKind.utilityAsValue:
+        break;
+    }
+  }
+
+  addVisitNode(astModel.nodeClass);
+  addVisitReference(astModel.namedNodeClass);
+  addVisitReference(astModel.constantClass);
+  strategy.generateFooter(astModel, sb);
+
+  String result = sb.toString();
+  result = new DartFormatter().format(result);
+  return result;
+}
+
+/// Strategy for generating a visitor in its own library based on an [AstModel].
+abstract class VisitorStrategy {
+  const VisitorStrategy();
+
+  /// Generates the header of the visitor library, including preamble, imports
+  /// and visitor class declaration start.
+  void generateHeader(AstModel astModel, StringBuffer sb);
+
+  /// Generates a `defaultX` visitor method for [astClass].
+  void generateDefaultVisit(AstClass astClass, StringBuffer sb);
+
+  /// Generates a `visitX` visitor method for [astClass].
+  void generateVisit(AstClass astClass, StringBuffer sb);
+
+  /// Generates a `defaultXReference` visitor method for [astClass].
+  void generateDefaultVisitReference(AstClass astClass, StringBuffer sb);
+
+  /// Generates a `visitXReference` visitor method for [astClass].
+  void generateVisitReference(AstClass astClass, StringBuffer sb);
+
+  /// Generates the footer of the visitor library, including the visitor class
+  /// declaration end.
+  void generateFooter(AstModel astModel, StringBuffer sb);
+}
+
+/// Base strategy for creating a [Visitor] implementation.
+abstract class Visitor0Strategy extends VisitorStrategy {
+  const Visitor0Strategy();
+
+  /// The name of the generated visitor class.
+  String get visitorName;
+
+  /// The type parameters of the generated visitor class.
+  String get visitorTypeParameters => '';
+
+  /// The return type for the visitor methods.
+  ///
+  /// The generated visitor will implement `Visitor<$returnType>`.
+  String get returnType;
+
+  void generateHeader(AstModel astModel, StringBuffer sb) {
+    sb.writeln('''
+import 'package:kernel/ast.dart';
+
+class $visitorName$visitorTypeParameters implements Visitor<$returnType> {''');
+  }
+
+  void generateFooter(AstModel astModel, StringBuffer sb) {
+    sb.writeln('''
+}''');
+  }
+
+  @override
+  void generateDefaultVisit(AstClass astClass, StringBuffer sb) {
+    sb.writeln('''
+  @override
+  ${returnType} default${astClass.name}(
+      ${astClass.name} node) {''');
+    handleDefaultVisit(astClass, sb);
+    sb.writeln('}');
+  }
+
+  /// Generates the body of a `defaultX` visitor method of [astClass].
+  void handleDefaultVisit(AstClass astClass, StringBuffer sb) {}
+
+  @override
+  void generateVisit(AstClass astClass, StringBuffer sb) {
+    sb.writeln('''
+  @override
+  ${returnType} visit${astClass.name}(
+      ${astClass.name} node) {''');
+    handleVisit(astClass, sb);
+    sb.writeln('}');
+  }
+
+  /// Generates the body of a `visitX` visitor method of [astClass].
+  void handleVisit(AstClass astClass, StringBuffer sb) {}
+
+  @override
+  void generateDefaultVisitReference(AstClass astClass, StringBuffer sb) {
+    sb.writeln(''''
+  @override
+  ${returnType} default${astClass.name}Reference(
+      '${astClass.name} node) {''');
+    handleDefaultVisitReference(astClass, sb);
+    sb.writeln('}');
+  }
+
+  /// Generates the body of a `defaultXReference` visitor method of [astClass].
+  void handleDefaultVisitReference(AstClass astClass, StringBuffer sb) {}
+
+  @override
+  void generateVisitReference(AstClass astClass, StringBuffer sb) {
+    sb.writeln('''
+  @override
+  ${returnType} visit${astClass.name}Reference(
+      ${astClass.name} node) {''');
+    handleVisitReference(astClass, sb);
+    sb.writeln('}');
+  }
+
+  /// Generates the body of a `visitXReference` visitor method of [astClass].
+  void handleVisitReference(AstClass astClass, StringBuffer sb) {}
+}
+
+/// Strategy for creating an empty `Visitor<void>` implementation.
+class VoidVisitor0Strategy extends Visitor0Strategy {
+  const VoidVisitor0Strategy();
+
+  @override
+  String get visitorName => 'VoidVisitor';
+
+  @override
+  String get returnType => 'void';
+}
+
+/// Base strategy for creating a [Visitor1] implementation.
+abstract class Visitor1Strategy extends VisitorStrategy {
+  const Visitor1Strategy();
+
+  /// The name of the generated visitor class.
+  String get visitorName;
+
+  /// The type parameters of the generated visitor class.
+  String get visitorTypeParameters => '';
+
+  /// The type of the argument of the visitor methods.
+  ///
+  /// The generated visitor will implement
+  /// `Visitor1<$returnType, $argumentType>`.
+  String get argumentType;
+
+  /// The name of the argument parameter name.
+  String get argumentName => 'arg';
+
+  /// The return type for the visitor methods.
+  ///
+  /// The generated visitor will implement
+  /// `Visitor1<$returnType, $argumentType>`.
+  String get returnType;
+
+  void generateHeader(AstModel astModel, StringBuffer sb) {
+    sb.writeln('''
+import 'package:kernel/ast.dart';
+
+class $visitorName$visitorTypeParameters
+    implements Visitor1<$returnType, $argumentType> {''');
+  }
+
+  void generateFooter(AstModel astModel, StringBuffer sb) {
+    sb.writeln('''
+}''');
+  }
+
+  @override
+  void generateDefaultVisit(AstClass astClass, StringBuffer sb) {
+    sb.writeln('''
+  @override
+  ${returnType} default${astClass.name}(
+      ${astClass.name} node, $argumentType $argumentName) {''');
+    handleDefaultVisit(astClass, sb);
+    sb.writeln('''
+  }''');
+  }
+
+  /// Generates the body of a `defaultX` visitor method of [astClass].
+  void handleDefaultVisit(AstClass astClass, StringBuffer sb) {}
+
+  @override
+  void generateVisit(AstClass astClass, StringBuffer sb) {
+    sb.writeln('''
+  @override
+  ${returnType} visit${astClass.name}(
+      ${astClass.name} node, $argumentType $argumentName) {''');
+    handleVisit(astClass, sb);
+    sb.writeln('''
+  }''');
+  }
+
+  /// Generates the body of a `visitX` visitor method of [astClass].
+  void handleVisit(AstClass astClass, StringBuffer sb) {}
+
+  @override
+  void generateDefaultVisitReference(AstClass astClass, StringBuffer sb) {
+    sb.writeln('''
+  @override
+  ${returnType} default${astClass.name}Reference(
+      ${astClass.name} node, $argumentType $argumentName) {''');
+    handleDefaultVisitReference(astClass, sb);
+    sb.writeln('''
+  }''');
+  }
+
+  /// Generates the body of a `defaultXReference` visitor method of [astClass].
+  void handleDefaultVisitReference(AstClass astClass, StringBuffer sb) {}
+
+  @override
+  void generateVisitReference(AstClass astClass, StringBuffer sb) {
+    sb.writeln('''
+  @override
+  ${returnType} visit${astClass.name}Reference(
+      ${astClass.name} node, $argumentType $argumentName) {''');
+    handleVisitReference(astClass, sb);
+    sb.writeln('''
+  }''');
+  }
+
+  /// Generates the body of a `visitXReference` visitor method of [astClass].
+  void handleVisitReference(AstClass astClass, StringBuffer sb) {}
+}
+
+/// Strategy for creating an empty `Visitor1<void,Null>` implementation.
+class VoidVisitor1Strategy extends Visitor1Strategy {
+  const VoidVisitor1Strategy();
+
+  @override
+  String get visitorName => 'VoidVisitor';
+
+  @override
+  String get returnType => 'void';
+
+  @override
+  String get argumentType => 'Null';
+
+  @override
+  String get argumentName => '_';
+}
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index 0ac7cb7..69df63a 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -92,6 +92,7 @@
   const Node();
 
   R accept<R>(Visitor<R> v);
+  R accept1<R, A>(Visitor1<R, A> v, A arg);
   void visitChildren(Visitor v);
 
   /// Returns the textual representation of this node for use in debugging.
@@ -1191,7 +1192,7 @@
   }
 
   List<RedirectingFactory> _redirectingFactoriesInternal;
-  DirtifyingList<RedirectingFactory>? _redirectingFactoryConstructorsView;
+  DirtifyingList<RedirectingFactory>? _redirectingFactoriesView;
 
   /// Redirecting factory constructors declared in the class.
   ///
@@ -1200,7 +1201,7 @@
     ensureLoaded();
     // If already dirty the caller just might as well add stuff directly too.
     if (dirty) return _redirectingFactoriesInternal;
-    return _redirectingFactoryConstructorsView ??=
+    return _redirectingFactoriesView ??=
         new DirtifyingList(this, _redirectingFactoriesInternal);
   }
 
@@ -1211,7 +1212,7 @@
   void set redirectingFactoryConstructorsInternal(
       List<RedirectingFactory> redirectingFactoryConstructors) {
     _redirectingFactoriesInternal = redirectingFactoryConstructors;
-    _redirectingFactoryConstructorsView = null;
+    _redirectingFactoriesView = null;
   }
 
   Class(
@@ -10201,6 +10202,9 @@
   R accept<R>(Visitor<R> v) => v.visitName(this);
 
   @override
+  R accept1<R, A>(Visitor1<R, A> v, A arg) => v.visitName(this, arg);
+
+  @override
   void visitChildren(Visitor v) {
     // DESIGN TODO: Should we visit the library as a library reference?
   }
@@ -11304,6 +11308,9 @@
   R accept<R>(Visitor<R> v) => v.visitNamedType(this);
 
   @override
+  R accept1<R, A>(Visitor1<R, A> v, A arg) => v.visitNamedType(this, arg);
+
+  @override
   void visitChildren(Visitor v) {
     type.accept(v);
   }
@@ -12059,6 +12066,9 @@
 
   R accept<R>(Visitor<R> v) => v.visitSupertype(this);
 
+  @override
+  R accept1<R, A>(Visitor1<R, A> v, A arg) => v.visitSupertype(this, arg);
+
   visitChildren(Visitor v) {
     classNode.acceptReference(v);
     visitList(typeArguments, v);
@@ -12112,31 +12122,46 @@
   ///
   /// (Note that a constant can be seen as a DAG (directed acyclic graph) and
   ///  not a tree!)
-  visitChildren(Visitor v);
+  @override
+  void visitChildren(Visitor v);
 
   /// Calls the `visit*Constant()` method on the visitor [v].
+  @override
   R accept<R>(ConstantVisitor<R> v);
 
+  /// Calls the `visit*Constant()` method on the visitor [v].
+  @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg);
+
   /// Calls the `visit*ConstantReference()` method on the visitor [v].
   R acceptReference<R>(Visitor<R> v);
 
+  /// Calls the `visit*ConstantReference()` method on the visitor [v].
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg);
+
   /// The Kernel AST will reference [Constant]s via [ConstantExpression]s.  The
   /// constants are not required to be canonicalized, but they have to be deeply
   /// comparable via hashCode/==!
+  @override
   int get hashCode;
+
+  @override
   bool operator ==(Object other);
 
+  @override
   String toString() => throw '$runtimeType';
 
   /// Returns a textual representation of the this constant.
   ///
   /// If [verbose] is `true`, qualified names will include the library name/uri.
+  @override
   String toText(AstTextStrategy strategy) {
     AstPrinter printer = new AstPrinter(strategy);
     printer.writeConstant(this);
     return printer.getText();
   }
 
+  @override
   void toTextInternal(AstPrinter printer);
 
   /// Gets the type of this constant.
@@ -12152,8 +12177,10 @@
 
   PrimitiveConstant(this.value);
 
+  @override
   int get hashCode => value.hashCode;
 
+  @override
   bool operator ==(Object other) =>
       other is PrimitiveConstant<T> && other.value == value;
 
@@ -12166,10 +12193,24 @@
 class NullConstant extends PrimitiveConstant<Null> {
   NullConstant() : super(null);
 
-  visitChildren(Visitor v) {}
+  @override
+  void visitChildren(Visitor v) {}
+
+  @override
   R accept<R>(ConstantVisitor<R> v) => v.visitNullConstant(this);
+
+  @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
+      v.visitNullConstant(this, arg);
+
+  @override
   R acceptReference<R>(Visitor<R> v) => v.visitNullConstantReference(this);
 
+  @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) =>
+      v.visitNullConstantReference(this, arg);
+
+  @override
   DartType getType(StaticTypeContext context) => const NullType();
 
   @override
@@ -12179,10 +12220,24 @@
 class BoolConstant extends PrimitiveConstant<bool> {
   BoolConstant(bool value) : super(value);
 
-  visitChildren(Visitor v) {}
+  @override
+  void visitChildren(Visitor v) {}
+
+  @override
   R accept<R>(ConstantVisitor<R> v) => v.visitBoolConstant(this);
+
+  @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
+      v.visitBoolConstant(this, arg);
+
+  @override
   R acceptReference<R>(Visitor<R> v) => v.visitBoolConstantReference(this);
 
+  @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) =>
+      v.visitBoolConstantReference(this, arg);
+
+  @override
   DartType getType(StaticTypeContext context) =>
       context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
 
@@ -12194,10 +12249,24 @@
 class IntConstant extends PrimitiveConstant<int> {
   IntConstant(int value) : super(value);
 
-  visitChildren(Visitor v) {}
+  @override
+  void visitChildren(Visitor v) {}
+
+  @override
   R accept<R>(ConstantVisitor<R> v) => v.visitIntConstant(this);
+
+  @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
+      v.visitIntConstant(this, arg);
+
+  @override
   R acceptReference<R>(Visitor<R> v) => v.visitIntConstantReference(this);
 
+  @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) =>
+      v.visitIntConstantReference(this, arg);
+
+  @override
   DartType getType(StaticTypeContext context) =>
       context.typeEnvironment.coreTypes.intRawType(context.nonNullable);
 
@@ -12209,14 +12278,31 @@
 class DoubleConstant extends PrimitiveConstant<double> {
   DoubleConstant(double value) : super(value);
 
-  visitChildren(Visitor v) {}
+  @override
+  void visitChildren(Visitor v) {}
+
+  @override
   R accept<R>(ConstantVisitor<R> v) => v.visitDoubleConstant(this);
+
+  @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
+      v.visitDoubleConstant(this, arg);
+
+  @override
   R acceptReference<R>(Visitor<R> v) => v.visitDoubleConstantReference(this);
 
+  @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) =>
+      v.visitDoubleConstantReference(this, arg);
+
+  @override
   int get hashCode => value.isNaN ? 199 : super.hashCode;
+
+  @override
   bool operator ==(Object other) =>
       other is DoubleConstant && identical(value, other.value);
 
+  @override
   DartType getType(StaticTypeContext context) =>
       context.typeEnvironment.coreTypes.doubleRawType(context.nonNullable);
 
@@ -12230,11 +12316,24 @@
     assert(value != null);
   }
 
-  visitChildren(Visitor v) {}
+  @override
+  void visitChildren(Visitor v) {}
+
+  @override
   R accept<R>(ConstantVisitor<R> v) => v.visitStringConstant(this);
+
+  @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
+      v.visitStringConstant(this, arg);
+
+  @override
   R acceptReference<R>(Visitor<R> v) => v.visitStringConstantReference(this);
 
   @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) =>
+      v.visitStringConstantReference(this, arg);
+
+  @override
   DartType getType(StaticTypeContext context) =>
       context.typeEnvironment.coreTypes.stringRawType(context.nonNullable);
 
@@ -12245,6 +12344,7 @@
     printer.write('"');
   }
 
+  @override
   String toString() => 'StringConstant(${toStringInternal()})';
 }
 
@@ -12254,22 +12354,37 @@
 
   SymbolConstant(this.name, this.libraryReference);
 
-  visitChildren(Visitor v) {}
+  @override
+  void visitChildren(Visitor v) {}
 
+  @override
   R accept<R>(ConstantVisitor<R> v) => v.visitSymbolConstant(this);
+
+  @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
+      v.visitSymbolConstant(this, arg);
+
+  @override
   R acceptReference<R>(Visitor<R> v) => v.visitSymbolConstantReference(this);
 
   @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) =>
+      v.visitSymbolConstantReference(this, arg);
+
+  @override
   String toString() => 'SymbolConstant(${toStringInternal()})';
 
+  @override
   int get hashCode => _Hash.hash2(name, libraryReference);
 
+  @override
   bool operator ==(Object other) =>
       identical(this, other) ||
       (other is SymbolConstant &&
           other.name == name &&
           other.libraryReference == libraryReference);
 
+  @override
   DartType getType(StaticTypeContext context) =>
       context.typeEnvironment.coreTypes.symbolRawType(context.nonNullable);
 
@@ -12291,7 +12406,8 @@
 
   MapConstant(this.keyType, this.valueType, this.entries);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     keyType.accept(v);
     valueType.accept(v);
     for (final ConstantMapEntry entry in entries) {
@@ -12300,10 +12416,21 @@
     }
   }
 
+  @override
   R accept<R>(ConstantVisitor<R> v) => v.visitMapConstant(this);
+
+  @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
+      v.visitMapConstant(this, arg);
+
+  @override
   R acceptReference<R>(Visitor<R> v) => v.visitMapConstantReference(this);
 
   @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) =>
+      v.visitMapConstantReference(this, arg);
+
+  @override
   void toTextInternal(AstPrinter printer) {
     printer.write('const <');
     printer.writeType(keyType);
@@ -12326,6 +12453,7 @@
   late final int hashCode = _Hash.combine2Finish(
       keyType.hashCode, valueType.hashCode, _Hash.combineListHash(entries));
 
+  @override
   bool operator ==(Object other) =>
       identical(this, other) ||
       (other is MapConstant &&
@@ -12333,6 +12461,7 @@
           other.valueType == valueType &&
           listEquals(other.entries, entries));
 
+  @override
   DartType getType(StaticTypeContext context) =>
       context.typeEnvironment.mapType(keyType, valueType, context.nonNullable);
 }
@@ -12373,17 +12502,29 @@
 
   ListConstant(this.typeArgument, this.entries);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     typeArgument.accept(v);
     for (final Constant constant in entries) {
       constant.acceptReference(v);
     }
   }
 
+  @override
   R accept<R>(ConstantVisitor<R> v) => v.visitListConstant(this);
+
+  @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
+      v.visitListConstant(this, arg);
+
+  @override
   R acceptReference<R>(Visitor<R> v) => v.visitListConstantReference(this);
 
   @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) =>
+      v.visitListConstantReference(this, arg);
+
+  @override
   void toTextInternal(AstPrinter printer) {
     printer.write('const <');
     printer.writeType(typeArgument);
@@ -12404,12 +12545,14 @@
   late final int hashCode = _Hash.combineFinish(
       typeArgument.hashCode, _Hash.combineListHash(entries));
 
+  @override
   bool operator ==(Object other) =>
       identical(this, other) ||
       (other is ListConstant &&
           other.typeArgument == typeArgument &&
           listEquals(other.entries, entries));
 
+  @override
   DartType getType(StaticTypeContext context) =>
       context.typeEnvironment.listType(typeArgument, context.nonNullable);
 }
@@ -12420,17 +12563,29 @@
 
   SetConstant(this.typeArgument, this.entries);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     typeArgument.accept(v);
     for (final Constant constant in entries) {
       constant.acceptReference(v);
     }
   }
 
+  @override
   R accept<R>(ConstantVisitor<R> v) => v.visitSetConstant(this);
+
+  @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
+      v.visitSetConstant(this, arg);
+
+  @override
   R acceptReference<R>(Visitor<R> v) => v.visitSetConstantReference(this);
 
   @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) =>
+      v.visitSetConstantReference(this, arg);
+
+  @override
   void toTextInternal(AstPrinter printer) {
     printer.write('const <');
     printer.writeType(typeArgument);
@@ -12451,12 +12606,14 @@
   late final int hashCode = _Hash.combineFinish(
       typeArgument.hashCode, _Hash.combineListHash(entries));
 
+  @override
   bool operator ==(Object other) =>
       identical(this, other) ||
       (other is SetConstant &&
           other.typeArgument == typeArgument &&
           listEquals(other.entries, entries));
 
+  @override
   DartType getType(StaticTypeContext context) =>
       context.typeEnvironment.setType(typeArgument, context.nonNullable);
 }
@@ -12482,9 +12639,19 @@
   }
 
   R accept<R>(ConstantVisitor<R> v) => v.visitInstanceConstant(this);
+
+  @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
+      v.visitInstanceConstant(this, arg);
+
+  @override
   R acceptReference<R>(Visitor<R> v) => v.visitInstanceConstantReference(this);
 
   @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) =>
+      v.visitInstanceConstantReference(this, arg);
+
+  @override
   void toTextInternal(AstPrinter printer) {
     printer.write('const ');
     printer.writeClassName(classReference);
@@ -12508,6 +12675,7 @@
   late final int hashCode = _Hash.combine2Finish(classReference.hashCode,
       listHashCode(typeArguments), _Hash.combineMapHashUnordered(fieldValues));
 
+  @override
   bool operator ==(Object other) {
     return identical(this, other) ||
         (other is InstanceConstant &&
@@ -12516,6 +12684,7 @@
             mapEquals(other.fieldValues, fieldValues));
   }
 
+  @override
   DartType getType(StaticTypeContext context) =>
       new InterfaceType(classNode, context.nonNullable, typeArguments);
 }
@@ -12526,16 +12695,28 @@
 
   InstantiationConstant(this.tearOffConstant, this.types);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     tearOffConstant.acceptReference(v);
     visitList(types, v);
   }
 
+  @override
   R accept<R>(ConstantVisitor<R> v) => v.visitInstantiationConstant(this);
+
+  @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
+      v.visitInstantiationConstant(this, arg);
+
+  @override
   R acceptReference<R>(Visitor<R> v) =>
       v.visitInstantiationConstantReference(this);
 
   @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) =>
+      v.visitInstantiationConstantReference(this, arg);
+
+  @override
   void toTextInternal(AstPrinter printer) {
     printer.writeConstant(tearOffConstant);
     printer.writeTypeArguments(types);
@@ -12544,15 +12725,18 @@
   @override
   String toString() => 'InstantiationConstant(${toStringInternal()})';
 
+  @override
   int get hashCode => _Hash.combineFinish(
       tearOffConstant.hashCode, _Hash.combineListHash(types));
 
+  @override
   bool operator ==(Object other) {
     return other is InstantiationConstant &&
         other.tearOffConstant == tearOffConstant &&
         listEquals(other.types, types);
   }
 
+  @override
   DartType getType(StaticTypeContext context) {
     final FunctionType type = tearOffConstant.getType(context) as FunctionType;
     final Map<TypeParameter, DartType> mapping = <TypeParameter, DartType>{};
@@ -12586,15 +12770,27 @@
   @override
   FunctionNode get function => target.function;
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     target.acceptReference(v);
   }
 
+  @override
   R accept<R>(ConstantVisitor<R> v) => v.visitStaticTearOffConstant(this);
+
+  @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
+      v.visitStaticTearOffConstant(this, arg);
+
+  @override
   R acceptReference<R>(Visitor<R> v) =>
       v.visitStaticTearOffConstantReference(this);
 
   @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) =>
+      v.visitStaticTearOffConstantReference(this, arg);
+
+  @override
   void toTextInternal(AstPrinter printer) {
     printer.writeMemberName(targetReference);
   }
@@ -12602,13 +12798,16 @@
   @override
   String toString() => 'StaticTearOffConstant(${toStringInternal()})';
 
+  @override
   int get hashCode => targetReference.hashCode;
 
+  @override
   bool operator ==(Object other) {
     return other is StaticTearOffConstant &&
         other.targetReference == targetReference;
   }
 
+  @override
   FunctionType getType(StaticTypeContext context) {
     return target.function.computeFunctionType(context.nonNullable);
   }
@@ -12640,10 +12839,18 @@
   R accept<R>(ConstantVisitor<R> v) => v.visitConstructorTearOffConstant(this);
 
   @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
+      v.visitConstructorTearOffConstant(this, arg);
+
+  @override
   R acceptReference<R>(Visitor<R> v) =>
       v.visitConstructorTearOffConstantReference(this);
 
   @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) =>
+      v.visitConstructorTearOffConstantReference(this, arg);
+
+  @override
   void toTextInternal(AstPrinter printer) {
     printer.writeMemberName(targetReference);
   }
@@ -12690,10 +12897,18 @@
       v.visitRedirectingFactoryTearOffConstant(this);
 
   @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
+      v.visitRedirectingFactoryTearOffConstant(this, arg);
+
+  @override
   R acceptReference<R>(Visitor<R> v) =>
       v.visitRedirectingFactoryTearOffConstantReference(this);
 
   @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) =>
+      v.visitRedirectingFactoryTearOffConstantReference(this, arg);
+
+  @override
   void toTextInternal(AstPrinter printer) {
     printer.writeMemberName(targetReference);
   }
@@ -12723,17 +12938,29 @@
 
   TypedefTearOffConstant(this.parameters, this.tearOffConstant, this.types);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     visitList(parameters, v);
     tearOffConstant.acceptReference(v);
     visitList(types, v);
   }
 
+  @override
   R accept<R>(ConstantVisitor<R> v) => v.visitTypedefTearOffConstant(this);
+
+  @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
+      v.visitTypedefTearOffConstant(this, arg);
+
+  @override
   R acceptReference<R>(Visitor<R> v) =>
       v.visitTypedefTearOffConstantReference(this);
 
   @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) =>
+      v.visitTypedefTearOffConstantReference(this, arg);
+
+  @override
   void toTextInternal(AstPrinter printer) {
     printer.writeTypeParameters(parameters);
     printer.writeConstant(tearOffConstant);
@@ -12802,15 +13029,27 @@
 
   TypeLiteralConstant(this.type);
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     type.accept(v);
   }
 
+  @override
   R accept<R>(ConstantVisitor<R> v) => v.visitTypeLiteralConstant(this);
+
+  @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
+      v.visitTypeLiteralConstant(this, arg);
+
+  @override
   R acceptReference<R>(Visitor<R> v) =>
       v.visitTypeLiteralConstantReference(this);
 
   @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) =>
+      v.visitTypeLiteralConstantReference(this, arg);
+
+  @override
   void toTextInternal(AstPrinter printer) {
     printer.writeType(type);
   }
@@ -12818,8 +13057,10 @@
   @override
   String toString() => 'TypeLiteralConstant(${toStringInternal()})';
 
+  @override
   int get hashCode => type.hashCode;
 
+  @override
   bool operator ==(Object other) {
     return other is TypeLiteralConstant && other.type == type;
   }
@@ -12835,14 +13076,26 @@
     expression.parent = null;
   }
 
-  visitChildren(Visitor v) {
+  @override
+  void visitChildren(Visitor v) {
     expression.accept(v);
   }
 
+  @override
   R accept<R>(ConstantVisitor<R> v) => v.visitUnevaluatedConstant(this);
+
+  @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
+      v.visitUnevaluatedConstant(this, arg);
+
+  @override
   R acceptReference<R>(Visitor<R> v) =>
       v.visitUnevaluatedConstantReference(this);
 
+  @override
+  R acceptReference1<R, A>(Visitor1<R, A> v, A arg) =>
+      v.visitUnevaluatedConstantReference(this, arg);
+
   DartType getType(StaticTypeContext context) =>
       expression.getStaticType(context);
 
diff --git a/pkg/kernel/lib/canonical_name.dart b/pkg/kernel/lib/canonical_name.dart
index 666a24f..6d7bd11 100644
--- a/pkg/kernel/lib/canonical_name.dart
+++ b/pkg/kernel/lib/canonical_name.dart
@@ -137,34 +137,34 @@
   }
 
   CanonicalName getChildFromField(Field field) {
-    return getChild('@getters').getChildFromQualifiedName(field.name);
+    return getChild(gettersName).getChildFromQualifiedName(field.name);
   }
 
   CanonicalName getChildFromFieldSetter(Field field) {
-    return getChild('@setters').getChildFromQualifiedName(field.name);
+    return getChild(settersName).getChildFromQualifiedName(field.name);
   }
 
   CanonicalName getChildFromConstructor(Constructor constructor) {
-    return getChild('@constructors')
+    return getChild(constructorsName)
         .getChildFromQualifiedName(constructor.name);
   }
 
   CanonicalName getChildFromRedirectingFactory(
-      RedirectingFactory redirectingFactoryConstructor) {
-    return getChild('@factories')
-        .getChildFromQualifiedName(redirectingFactoryConstructor.name);
+      RedirectingFactory redirectingFactory) {
+    return getChild(factoriesName)
+        .getChildFromQualifiedName(redirectingFactory.name);
   }
 
   CanonicalName getChildFromFieldWithName(Name name) {
-    return getChild('@getters').getChildFromQualifiedName(name);
+    return getChild(gettersName).getChildFromQualifiedName(name);
   }
 
   CanonicalName getChildFromFieldSetterWithName(Name name) {
-    return getChild('@setters').getChildFromQualifiedName(name);
+    return getChild(settersName).getChildFromQualifiedName(name);
   }
 
   CanonicalName getChildFromTypedef(Typedef typedef_) {
-    return getChild('@typedefs').getChild(typedef_.name);
+    return getChild(typedefsName).getChild(typedef_.name);
   }
 
   /// Take ownership of a child canonical name and its subtree.
@@ -279,14 +279,7 @@
     Iterable<CanonicalName>? parentChildren = parent.childrenOrNull;
     if (parentChildren != null) {
       for (CanonicalName child in parentChildren) {
-        if (child.name != '@methods' &&
-            child.name != '@typedefs' &&
-            child.name != '@fields' &&
-            child.name != '@=fields' &&
-            child.name != '@getters' &&
-            child.name != '@setters' &&
-            child.name != '@factories' &&
-            child.name != '@constructors') {
+        if (!isSymbolicName(child.name)) {
           bool checkReferenceNode = true;
           if (child._reference == null) {
             // OK for "if private: URI of library" part of "Qualified name"...
@@ -333,11 +326,46 @@
     return sb.toString();
   }
 
+  /// Symbolic name used for the [CanonicalName] node that holds all
+  /// constructors within a class.
+  static const String constructorsName = '@constructors';
+
+  /// Symbolic name used for the [CanonicalName] node that holds all factories
+  /// within a class.
+  static const String factoriesName = '@factories';
+
+  /// Symbolic name used for the [CanonicalName] node that holds all methods
+  /// within a library or a class.
+  static const String methodsName = '@methods';
+
+  /// Symbolic name used for the [CanonicalName] node that holds all getters and
+  /// readable fields within a library or class.
+  static const String gettersName = '@getters';
+
+  /// Symbolic name used for the [CanonicalName] node that holds all setters and
+  /// writable fields within a library or class.
+  static const String settersName = '@setters';
+
+  /// Symbolic name used for the [CanonicalName] node that holds all typedefs
+  /// within a library.
+  static const String typedefsName = '@typedefs';
+
+  static const Set<String> symbolicNames = {
+    constructorsName,
+    factoriesName,
+    methodsName,
+    gettersName,
+    settersName,
+    typedefsName,
+  };
+
+  static bool isSymbolicName(String name) => symbolicNames.contains(name);
+
   static String getProcedureQualifier(Procedure procedure) {
-    if (procedure.isGetter) return '@getters';
-    if (procedure.isSetter) return '@setters';
-    if (procedure.isFactory) return '@factories';
-    return '@methods';
+    if (procedure.isGetter) return gettersName;
+    if (procedure.isSetter) return settersName;
+    if (procedure.isFactory) return factoriesName;
+    return methodsName;
   }
 
   /// Returns `true` if [node] is orphaned through its [reference].
diff --git a/pkg/kernel/lib/src/equivalence.dart b/pkg/kernel/lib/src/equivalence.dart
new file mode 100644
index 0000000..a6667e8
--- /dev/null
+++ b/pkg/kernel/lib/src/equivalence.dart
@@ -0,0 +1,7220 @@
+// 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.
+
+// NOTE: THIS FILE IS GENERATED. DO NOT EDIT.
+//
+// Run 'dart pkg/front_end/tool/generate_ast_equivalence.dart' to update.
+
+import 'package:kernel/ast.dart';
+import 'package:kernel/src/printer.dart';
+import 'union_find.dart';
+
+part 'equivalence_helpers.dart';
+
+/// Visitor that uses a EquivalenceStrategy to compute AST node equivalence.
+///
+/// The visitor hold a current state that collects found inequivalences and
+/// current assumptions. The current state has two modes. In the asserting mode,
+/// the default, inequivalences are registered when found. In the non-asserting
+/// mode, inequivalences are _not_ registered. The latter is used to compute
+/// equivalences in sand boxed state, for instance to determine which elements
+/// to pair when checking equivalence of two sets.
+class EquivalenceVisitor implements Visitor1<bool, Node> {
+  final EquivalenceStrategy strategy;
+
+  EquivalenceVisitor({this.strategy: const EquivalenceStrategy()});
+
+  @override
+  bool defaultNode(Node node, Node other) {
+    return false;
+  }
+
+  @override
+  bool defaultTreeNode(TreeNode node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitLibrary(Library node, Node other) {
+    return strategy.checkLibrary(this, node, other);
+  }
+
+  @override
+  bool visitTypedef(Typedef node, Node other) {
+    return strategy.checkTypedef(this, node, other);
+  }
+
+  @override
+  bool visitClass(Class node, Node other) {
+    return strategy.checkClass(this, node, other);
+  }
+
+  @override
+  bool visitExtension(Extension node, Node other) {
+    return strategy.checkExtension(this, node, other);
+  }
+
+  @override
+  bool defaultMember(Member node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitField(Field node, Node other) {
+    return strategy.checkField(this, node, other);
+  }
+
+  @override
+  bool visitConstructor(Constructor node, Node other) {
+    return strategy.checkConstructor(this, node, other);
+  }
+
+  @override
+  bool visitRedirectingFactory(RedirectingFactory node, Node other) {
+    return strategy.checkRedirectingFactory(this, node, other);
+  }
+
+  @override
+  bool visitProcedure(Procedure node, Node other) {
+    return strategy.checkProcedure(this, node, other);
+  }
+
+  @override
+  bool visitLibraryDependency(LibraryDependency node, Node other) {
+    return strategy.checkLibraryDependency(this, node, other);
+  }
+
+  @override
+  bool visitLibraryPart(LibraryPart node, Node other) {
+    return strategy.checkLibraryPart(this, node, other);
+  }
+
+  @override
+  bool visitCombinator(Combinator node, Node other) {
+    return strategy.checkCombinator(this, node, other);
+  }
+
+  @override
+  bool defaultInitializer(Initializer node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitInvalidInitializer(InvalidInitializer node, Node other) {
+    return strategy.checkInvalidInitializer(this, node, other);
+  }
+
+  @override
+  bool visitFieldInitializer(FieldInitializer node, Node other) {
+    return strategy.checkFieldInitializer(this, node, other);
+  }
+
+  @override
+  bool visitSuperInitializer(SuperInitializer node, Node other) {
+    return strategy.checkSuperInitializer(this, node, other);
+  }
+
+  @override
+  bool visitRedirectingInitializer(RedirectingInitializer node, Node other) {
+    return strategy.checkRedirectingInitializer(this, node, other);
+  }
+
+  @override
+  bool visitLocalInitializer(LocalInitializer node, Node other) {
+    return strategy.checkLocalInitializer(this, node, other);
+  }
+
+  @override
+  bool visitAssertInitializer(AssertInitializer node, Node other) {
+    return strategy.checkAssertInitializer(this, node, other);
+  }
+
+  @override
+  bool visitFunctionNode(FunctionNode node, Node other) {
+    return strategy.checkFunctionNode(this, node, other);
+  }
+
+  @override
+  bool defaultExpression(Expression node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitInvalidExpression(InvalidExpression node, Node other) {
+    return strategy.checkInvalidExpression(this, node, other);
+  }
+
+  @override
+  bool visitVariableGet(VariableGet node, Node other) {
+    return strategy.checkVariableGet(this, node, other);
+  }
+
+  @override
+  bool visitVariableSet(VariableSet node, Node other) {
+    return strategy.checkVariableSet(this, node, other);
+  }
+
+  @override
+  bool visitDynamicGet(DynamicGet node, Node other) {
+    return strategy.checkDynamicGet(this, node, other);
+  }
+
+  @override
+  bool visitInstanceGet(InstanceGet node, Node other) {
+    return strategy.checkInstanceGet(this, node, other);
+  }
+
+  @override
+  bool visitFunctionTearOff(FunctionTearOff node, Node other) {
+    return strategy.checkFunctionTearOff(this, node, other);
+  }
+
+  @override
+  bool visitInstanceTearOff(InstanceTearOff node, Node other) {
+    return strategy.checkInstanceTearOff(this, node, other);
+  }
+
+  @override
+  bool visitDynamicSet(DynamicSet node, Node other) {
+    return strategy.checkDynamicSet(this, node, other);
+  }
+
+  @override
+  bool visitInstanceSet(InstanceSet node, Node other) {
+    return strategy.checkInstanceSet(this, node, other);
+  }
+
+  @override
+  bool visitSuperPropertyGet(SuperPropertyGet node, Node other) {
+    return strategy.checkSuperPropertyGet(this, node, other);
+  }
+
+  @override
+  bool visitSuperPropertySet(SuperPropertySet node, Node other) {
+    return strategy.checkSuperPropertySet(this, node, other);
+  }
+
+  @override
+  bool visitStaticGet(StaticGet node, Node other) {
+    return strategy.checkStaticGet(this, node, other);
+  }
+
+  @override
+  bool visitStaticTearOff(StaticTearOff node, Node other) {
+    return strategy.checkStaticTearOff(this, node, other);
+  }
+
+  @override
+  bool visitStaticSet(StaticSet node, Node other) {
+    return strategy.checkStaticSet(this, node, other);
+  }
+
+  @override
+  bool visitDynamicInvocation(DynamicInvocation node, Node other) {
+    return strategy.checkDynamicInvocation(this, node, other);
+  }
+
+  @override
+  bool visitInstanceInvocation(InstanceInvocation node, Node other) {
+    return strategy.checkInstanceInvocation(this, node, other);
+  }
+
+  @override
+  bool visitInstanceGetterInvocation(
+      InstanceGetterInvocation node, Node other) {
+    return strategy.checkInstanceGetterInvocation(this, node, other);
+  }
+
+  @override
+  bool visitFunctionInvocation(FunctionInvocation node, Node other) {
+    return strategy.checkFunctionInvocation(this, node, other);
+  }
+
+  @override
+  bool visitLocalFunctionInvocation(LocalFunctionInvocation node, Node other) {
+    return strategy.checkLocalFunctionInvocation(this, node, other);
+  }
+
+  @override
+  bool visitSuperMethodInvocation(SuperMethodInvocation node, Node other) {
+    return strategy.checkSuperMethodInvocation(this, node, other);
+  }
+
+  @override
+  bool visitStaticInvocation(StaticInvocation node, Node other) {
+    return strategy.checkStaticInvocation(this, node, other);
+  }
+
+  @override
+  bool visitConstructorInvocation(ConstructorInvocation node, Node other) {
+    return strategy.checkConstructorInvocation(this, node, other);
+  }
+
+  @override
+  bool visitEqualsNull(EqualsNull node, Node other) {
+    return strategy.checkEqualsNull(this, node, other);
+  }
+
+  @override
+  bool visitEqualsCall(EqualsCall node, Node other) {
+    return strategy.checkEqualsCall(this, node, other);
+  }
+
+  @override
+  bool visitInstantiation(Instantiation node, Node other) {
+    return strategy.checkInstantiation(this, node, other);
+  }
+
+  @override
+  bool visitNot(Not node, Node other) {
+    return strategy.checkNot(this, node, other);
+  }
+
+  @override
+  bool visitLogicalExpression(LogicalExpression node, Node other) {
+    return strategy.checkLogicalExpression(this, node, other);
+  }
+
+  @override
+  bool visitConditionalExpression(ConditionalExpression node, Node other) {
+    return strategy.checkConditionalExpression(this, node, other);
+  }
+
+  @override
+  bool visitStringConcatenation(StringConcatenation node, Node other) {
+    return strategy.checkStringConcatenation(this, node, other);
+  }
+
+  @override
+  bool visitListConcatenation(ListConcatenation node, Node other) {
+    return strategy.checkListConcatenation(this, node, other);
+  }
+
+  @override
+  bool visitSetConcatenation(SetConcatenation node, Node other) {
+    return strategy.checkSetConcatenation(this, node, other);
+  }
+
+  @override
+  bool visitMapConcatenation(MapConcatenation node, Node other) {
+    return strategy.checkMapConcatenation(this, node, other);
+  }
+
+  @override
+  bool visitInstanceCreation(InstanceCreation node, Node other) {
+    return strategy.checkInstanceCreation(this, node, other);
+  }
+
+  @override
+  bool visitFileUriExpression(FileUriExpression node, Node other) {
+    return strategy.checkFileUriExpression(this, node, other);
+  }
+
+  @override
+  bool visitIsExpression(IsExpression node, Node other) {
+    return strategy.checkIsExpression(this, node, other);
+  }
+
+  @override
+  bool visitAsExpression(AsExpression node, Node other) {
+    return strategy.checkAsExpression(this, node, other);
+  }
+
+  @override
+  bool visitNullCheck(NullCheck node, Node other) {
+    return strategy.checkNullCheck(this, node, other);
+  }
+
+  @override
+  bool defaultBasicLiteral(BasicLiteral node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitStringLiteral(StringLiteral node, Node other) {
+    return strategy.checkStringLiteral(this, node, other);
+  }
+
+  @override
+  bool visitIntLiteral(IntLiteral node, Node other) {
+    return strategy.checkIntLiteral(this, node, other);
+  }
+
+  @override
+  bool visitDoubleLiteral(DoubleLiteral node, Node other) {
+    return strategy.checkDoubleLiteral(this, node, other);
+  }
+
+  @override
+  bool visitBoolLiteral(BoolLiteral node, Node other) {
+    return strategy.checkBoolLiteral(this, node, other);
+  }
+
+  @override
+  bool visitNullLiteral(NullLiteral node, Node other) {
+    return strategy.checkNullLiteral(this, node, other);
+  }
+
+  @override
+  bool visitSymbolLiteral(SymbolLiteral node, Node other) {
+    return strategy.checkSymbolLiteral(this, node, other);
+  }
+
+  @override
+  bool visitTypeLiteral(TypeLiteral node, Node other) {
+    return strategy.checkTypeLiteral(this, node, other);
+  }
+
+  @override
+  bool visitThisExpression(ThisExpression node, Node other) {
+    return strategy.checkThisExpression(this, node, other);
+  }
+
+  @override
+  bool visitRethrow(Rethrow node, Node other) {
+    return strategy.checkRethrow(this, node, other);
+  }
+
+  @override
+  bool visitThrow(Throw node, Node other) {
+    return strategy.checkThrow(this, node, other);
+  }
+
+  @override
+  bool visitListLiteral(ListLiteral node, Node other) {
+    return strategy.checkListLiteral(this, node, other);
+  }
+
+  @override
+  bool visitSetLiteral(SetLiteral node, Node other) {
+    return strategy.checkSetLiteral(this, node, other);
+  }
+
+  @override
+  bool visitMapLiteral(MapLiteral node, Node other) {
+    return strategy.checkMapLiteral(this, node, other);
+  }
+
+  @override
+  bool visitAwaitExpression(AwaitExpression node, Node other) {
+    return strategy.checkAwaitExpression(this, node, other);
+  }
+
+  @override
+  bool visitFunctionExpression(FunctionExpression node, Node other) {
+    return strategy.checkFunctionExpression(this, node, other);
+  }
+
+  @override
+  bool visitConstantExpression(ConstantExpression node, Node other) {
+    return strategy.checkConstantExpression(this, node, other);
+  }
+
+  @override
+  bool visitLet(Let node, Node other) {
+    return strategy.checkLet(this, node, other);
+  }
+
+  @override
+  bool visitBlockExpression(BlockExpression node, Node other) {
+    return strategy.checkBlockExpression(this, node, other);
+  }
+
+  @override
+  bool visitLoadLibrary(LoadLibrary node, Node other) {
+    return strategy.checkLoadLibrary(this, node, other);
+  }
+
+  @override
+  bool visitCheckLibraryIsLoaded(CheckLibraryIsLoaded node, Node other) {
+    return strategy.checkCheckLibraryIsLoaded(this, node, other);
+  }
+
+  @override
+  bool visitConstructorTearOff(ConstructorTearOff node, Node other) {
+    return strategy.checkConstructorTearOff(this, node, other);
+  }
+
+  @override
+  bool visitRedirectingFactoryTearOff(
+      RedirectingFactoryTearOff node, Node other) {
+    return strategy.checkRedirectingFactoryTearOff(this, node, other);
+  }
+
+  @override
+  bool visitTypedefTearOff(TypedefTearOff node, Node other) {
+    return strategy.checkTypedefTearOff(this, node, other);
+  }
+
+  @override
+  bool visitArguments(Arguments node, Node other) {
+    return strategy.checkArguments(this, node, other);
+  }
+
+  @override
+  bool visitNamedExpression(NamedExpression node, Node other) {
+    return strategy.checkNamedExpression(this, node, other);
+  }
+
+  @override
+  bool visitMapLiteralEntry(MapLiteralEntry node, Node other) {
+    return strategy.checkMapLiteralEntry(this, node, other);
+  }
+
+  @override
+  bool defaultStatement(Statement node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitExpressionStatement(ExpressionStatement node, Node other) {
+    return strategy.checkExpressionStatement(this, node, other);
+  }
+
+  @override
+  bool visitBlock(Block node, Node other) {
+    return strategy.checkBlock(this, node, other);
+  }
+
+  @override
+  bool visitAssertBlock(AssertBlock node, Node other) {
+    return strategy.checkAssertBlock(this, node, other);
+  }
+
+  @override
+  bool visitEmptyStatement(EmptyStatement node, Node other) {
+    return strategy.checkEmptyStatement(this, node, other);
+  }
+
+  @override
+  bool visitAssertStatement(AssertStatement node, Node other) {
+    return strategy.checkAssertStatement(this, node, other);
+  }
+
+  @override
+  bool visitLabeledStatement(LabeledStatement node, Node other) {
+    return strategy.checkLabeledStatement(this, node, other);
+  }
+
+  @override
+  bool visitBreakStatement(BreakStatement node, Node other) {
+    return strategy.checkBreakStatement(this, node, other);
+  }
+
+  @override
+  bool visitWhileStatement(WhileStatement node, Node other) {
+    return strategy.checkWhileStatement(this, node, other);
+  }
+
+  @override
+  bool visitDoStatement(DoStatement node, Node other) {
+    return strategy.checkDoStatement(this, node, other);
+  }
+
+  @override
+  bool visitForStatement(ForStatement node, Node other) {
+    return strategy.checkForStatement(this, node, other);
+  }
+
+  @override
+  bool visitForInStatement(ForInStatement node, Node other) {
+    return strategy.checkForInStatement(this, node, other);
+  }
+
+  @override
+  bool visitSwitchStatement(SwitchStatement node, Node other) {
+    return strategy.checkSwitchStatement(this, node, other);
+  }
+
+  @override
+  bool visitContinueSwitchStatement(ContinueSwitchStatement node, Node other) {
+    return strategy.checkContinueSwitchStatement(this, node, other);
+  }
+
+  @override
+  bool visitIfStatement(IfStatement node, Node other) {
+    return strategy.checkIfStatement(this, node, other);
+  }
+
+  @override
+  bool visitReturnStatement(ReturnStatement node, Node other) {
+    return strategy.checkReturnStatement(this, node, other);
+  }
+
+  @override
+  bool visitTryCatch(TryCatch node, Node other) {
+    return strategy.checkTryCatch(this, node, other);
+  }
+
+  @override
+  bool visitTryFinally(TryFinally node, Node other) {
+    return strategy.checkTryFinally(this, node, other);
+  }
+
+  @override
+  bool visitYieldStatement(YieldStatement node, Node other) {
+    return strategy.checkYieldStatement(this, node, other);
+  }
+
+  @override
+  bool visitVariableDeclaration(VariableDeclaration node, Node other) {
+    return strategy.checkVariableDeclaration(this, node, other);
+  }
+
+  @override
+  bool visitFunctionDeclaration(FunctionDeclaration node, Node other) {
+    return strategy.checkFunctionDeclaration(this, node, other);
+  }
+
+  @override
+  bool visitSwitchCase(SwitchCase node, Node other) {
+    return strategy.checkSwitchCase(this, node, other);
+  }
+
+  @override
+  bool visitCatch(Catch node, Node other) {
+    return strategy.checkCatch(this, node, other);
+  }
+
+  @override
+  bool visitTypeParameter(TypeParameter node, Node other) {
+    return strategy.checkTypeParameter(this, node, other);
+  }
+
+  @override
+  bool visitComponent(Component node, Node other) {
+    return strategy.checkComponent(this, node, other);
+  }
+
+  @override
+  bool visitName(Name node, Node other) {
+    return strategy.checkName(this, node, other);
+  }
+
+  @override
+  bool defaultDartType(DartType node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitInvalidType(InvalidType node, Node other) {
+    return strategy.checkInvalidType(this, node, other);
+  }
+
+  @override
+  bool visitDynamicType(DynamicType node, Node other) {
+    return strategy.checkDynamicType(this, node, other);
+  }
+
+  @override
+  bool visitVoidType(VoidType node, Node other) {
+    return strategy.checkVoidType(this, node, other);
+  }
+
+  @override
+  bool visitNeverType(NeverType node, Node other) {
+    return strategy.checkNeverType(this, node, other);
+  }
+
+  @override
+  bool visitNullType(NullType node, Node other) {
+    return strategy.checkNullType(this, node, other);
+  }
+
+  @override
+  bool visitInterfaceType(InterfaceType node, Node other) {
+    return strategy.checkInterfaceType(this, node, other);
+  }
+
+  @override
+  bool visitFunctionType(FunctionType node, Node other) {
+    return strategy.checkFunctionType(this, node, other);
+  }
+
+  @override
+  bool visitTypedefType(TypedefType node, Node other) {
+    return strategy.checkTypedefType(this, node, other);
+  }
+
+  @override
+  bool visitFutureOrType(FutureOrType node, Node other) {
+    return strategy.checkFutureOrType(this, node, other);
+  }
+
+  @override
+  bool visitExtensionType(ExtensionType node, Node other) {
+    return strategy.checkExtensionType(this, node, other);
+  }
+
+  @override
+  bool visitTypeParameterType(TypeParameterType node, Node other) {
+    return strategy.checkTypeParameterType(this, node, other);
+  }
+
+  @override
+  bool visitNamedType(NamedType node, Node other) {
+    return strategy.checkNamedType(this, node, other);
+  }
+
+  @override
+  bool visitSupertype(Supertype node, Node other) {
+    return strategy.checkSupertype(this, node, other);
+  }
+
+  @override
+  bool defaultConstant(Constant node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitNullConstant(NullConstant node, Node other) {
+    return strategy.checkNullConstant(this, node, other);
+  }
+
+  @override
+  bool visitBoolConstant(BoolConstant node, Node other) {
+    return strategy.checkBoolConstant(this, node, other);
+  }
+
+  @override
+  bool visitIntConstant(IntConstant node, Node other) {
+    return strategy.checkIntConstant(this, node, other);
+  }
+
+  @override
+  bool visitDoubleConstant(DoubleConstant node, Node other) {
+    return strategy.checkDoubleConstant(this, node, other);
+  }
+
+  @override
+  bool visitStringConstant(StringConstant node, Node other) {
+    return strategy.checkStringConstant(this, node, other);
+  }
+
+  @override
+  bool visitSymbolConstant(SymbolConstant node, Node other) {
+    return strategy.checkSymbolConstant(this, node, other);
+  }
+
+  @override
+  bool visitMapConstant(MapConstant node, Node other) {
+    return strategy.checkMapConstant(this, node, other);
+  }
+
+  @override
+  bool visitListConstant(ListConstant node, Node other) {
+    return strategy.checkListConstant(this, node, other);
+  }
+
+  @override
+  bool visitSetConstant(SetConstant node, Node other) {
+    return strategy.checkSetConstant(this, node, other);
+  }
+
+  @override
+  bool visitInstanceConstant(InstanceConstant node, Node other) {
+    return strategy.checkInstanceConstant(this, node, other);
+  }
+
+  @override
+  bool visitInstantiationConstant(InstantiationConstant node, Node other) {
+    return strategy.checkInstantiationConstant(this, node, other);
+  }
+
+  @override
+  bool visitStaticTearOffConstant(StaticTearOffConstant node, Node other) {
+    return strategy.checkStaticTearOffConstant(this, node, other);
+  }
+
+  @override
+  bool visitConstructorTearOffConstant(
+      ConstructorTearOffConstant node, Node other) {
+    return strategy.checkConstructorTearOffConstant(this, node, other);
+  }
+
+  @override
+  bool visitRedirectingFactoryTearOffConstant(
+      RedirectingFactoryTearOffConstant node, Node other) {
+    return strategy.checkRedirectingFactoryTearOffConstant(this, node, other);
+  }
+
+  @override
+  bool visitTypedefTearOffConstant(TypedefTearOffConstant node, Node other) {
+    return strategy.checkTypedefTearOffConstant(this, node, other);
+  }
+
+  @override
+  bool visitTypeLiteralConstant(TypeLiteralConstant node, Node other) {
+    return strategy.checkTypeLiteralConstant(this, node, other);
+  }
+
+  @override
+  bool visitUnevaluatedConstant(UnevaluatedConstant node, Node other) {
+    return strategy.checkUnevaluatedConstant(this, node, other);
+  }
+
+  @override
+  bool visitTypedefReference(Typedef node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitClassReference(Class node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitExtensionReference(Extension node, Node other) {
+    return false;
+  }
+
+  @override
+  bool defaultMemberReference(Member node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitFieldReference(Field node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitConstructorReference(Constructor node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitRedirectingFactoryReference(RedirectingFactory node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitProcedureReference(Procedure node, Node other) {
+    return false;
+  }
+
+  @override
+  bool defaultConstantReference(Constant node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitNullConstantReference(NullConstant node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitBoolConstantReference(BoolConstant node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitIntConstantReference(IntConstant node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitDoubleConstantReference(DoubleConstant node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitStringConstantReference(StringConstant node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitSymbolConstantReference(SymbolConstant node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitMapConstantReference(MapConstant node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitListConstantReference(ListConstant node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitSetConstantReference(SetConstant node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitInstanceConstantReference(InstanceConstant node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitInstantiationConstantReference(
+      InstantiationConstant node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitStaticTearOffConstantReference(
+      StaticTearOffConstant node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitConstructorTearOffConstantReference(
+      ConstructorTearOffConstant node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitRedirectingFactoryTearOffConstantReference(
+      RedirectingFactoryTearOffConstant node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitTypedefTearOffConstantReference(
+      TypedefTearOffConstant node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitTypeLiteralConstantReference(TypeLiteralConstant node, Node other) {
+    return false;
+  }
+
+  @override
+  bool visitUnevaluatedConstantReference(UnevaluatedConstant node, Node other) {
+    return false;
+  }
+
+  /// Returns `true` if [a] and [b] are identical or equal.
+  bool _checkValues<T>(T? a, T? b) {
+    return identical(a, b) || a == b;
+  }
+
+  /// Returns `true` if [a] and [b] are identical or equal and registers the
+  /// inequivalence otherwise.
+  bool checkValues<T>(T? a, T? b, String propertyName) {
+    bool result = _checkValues(a, b);
+    if (!result) {
+      registerInequivalence(
+          propertyName, 'Values ${a} and ${b} are not equivalent');
+    }
+    return result;
+  }
+
+  /// Returns `true` if [a] and [b] are identical or equal. Inequivalence is
+  /// _not_ registered.
+  bool matchValues<T>(T? a, T? b) {
+    return _checkValues(a, b);
+  }
+
+  /// Returns `true` if [a] and [b] are equivalent.
+  bool _checkNodes<T extends Node>(T? a, T? b) {
+    if (identical(a, b)) return true;
+    if (a == null || b == null) {
+      return false;
+    } else {
+      return a.accept1(this, b);
+    }
+  }
+
+  /// Returns `true` if [a] and [b] are equivalent, as defined by the current
+  /// strategy, and registers the inequivalence otherwise.
+  bool checkNodes<T extends Node>(T? a, T? b, [String propertyName = '']) {
+    _checkingState.pushPropertyState(propertyName);
+    bool result = _checkNodes(a, b);
+    _checkingState.popState();
+    if (!result) {
+      registerInequivalence(
+          propertyName, 'Inequivalent nodes\n1: ${a}\n2: ${b}');
+    }
+    return result;
+  }
+
+  /// Returns `true` if [a] and [b] are identical or equal. Inequivalence is
+  /// _not_ registered.
+  bool shallowMatchNodes<T extends Node>(T? a, T? b) {
+    return _checkValues(a, b);
+  }
+
+  /// Returns `true` if [a] and [b] are equivalent, as defined by the current
+  /// strategy. Inequivalence is _not_ registered.
+  bool deepMatchNodes<T extends Node>(T? a, T? b) {
+    CheckingState oldState = _checkingState;
+    _checkingState = _checkingState.toMatchingState();
+    bool result = checkNodes(a, b);
+    _checkingState = oldState;
+    return result;
+  }
+
+  /// Returns `true` if [a] and [b] are equivalent, as defined by their
+  /// corresponding canonical names. Inequivalence is _not_ registered.
+  bool matchNamedNodes(NamedNode? a, NamedNode? b) {
+    return identical(a, b) ||
+        a == null ||
+        b == null ||
+        new ReferenceName.fromNamedNode(a) ==
+            new ReferenceName.fromNamedNode(b);
+  }
+
+  /// Returns `true` if [a] and [b] are currently assumed to be equivalent.
+  bool checkAssumedReferences(Reference? a, Reference? b) {
+    return _checkingState.checkAssumedReferences(a, b);
+  }
+
+  /// Assume that [a] and [b] are equivalent, if possible.
+  ///
+  /// Returns `true` if [a] and [b] could be assumed to be equivalent. This
+  /// would not be the case if [a] xor [b] is `null`.
+  bool assumeReferences(Reference? a, Reference? b) {
+    return _checkingState.assumeReferences(a, b);
+  }
+
+  /// Returns `true` if [a] and [b] are equivalent, as defined by their
+  /// corresponding canonical names. Inequivalence is _not_ registered.
+  bool matchReferences(Reference? a, Reference? b) {
+    return identical(a, b) ||
+        ReferenceName.fromReference(a) == ReferenceName.fromReference(b);
+  }
+
+  /// Returns `true` if [a] and [b] are equivalent, either by their
+  /// corresponding canonical names or by assumption. Inequivalence is _not_
+  /// registered.
+  bool _checkReferences(Reference? a, Reference? b) {
+    if (identical(a, b)) {
+      return true;
+    } else if (a == null || b == null) {
+      return false;
+    } else if (matchReferences(a, b)) {
+      return true;
+    } else if (checkAssumedReferences(a, b)) {
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  /// Returns `true` if [a] and [b] are equivalent, either by their
+  /// corresponding canonical names or by assumption. Inequivalence is _not_
+  /// registered.
+  bool deeplyMatchReferences(Reference? a, Reference? b) {
+    CheckingState oldState = _checkingState;
+    _checkingState = _checkingState.toMatchingState();
+    bool result = checkReferences(a, b);
+    _checkingState = oldState;
+    return result;
+  }
+
+  /// Returns `true` if [a] and [b] are equivalent, either by their
+  /// corresponding canonical names or by assumption, and registers the
+  /// inequivalence otherwise.
+  bool checkReferences(Reference? a, Reference? b, [String propertyName = '']) {
+    bool result = _checkReferences(a, b);
+    if (!result) {
+      registerInequivalence(
+          propertyName, 'Inequivalent references:\n1: ${a}\n2: ${b}');
+    }
+    return result;
+  }
+
+  /// Returns `true` if declarations [a] and [b] are currently assumed to be
+  /// equivalent.
+  bool checkAssumedDeclarations(dynamic a, dynamic b) {
+    return _checkingState.checkAssumedDeclarations(a, b);
+  }
+
+  /// Assume that [a] and [b] are equivalent, if possible.
+  ///
+  /// Returns `true` if [a] and [b] could be assumed to be equivalent. This
+  /// would not be the case if [a] is already assumed to be equivalent to
+  /// another declaration.
+  bool assumeDeclarations(dynamic a, dynamic b) {
+    return _checkingState.assumeDeclarations(a, b);
+  }
+
+  bool matchDeclarations(dynamic a, dynamic b) {
+    if (a is LabeledStatement) {
+      return b is LabeledStatement;
+    }
+    if (a is VariableDeclaration) {
+      return b is VariableDeclaration && a.name == b.name;
+    }
+    if (a is SwitchCase) {
+      return b is SwitchCase;
+    }
+    if (a is TypeParameter) {
+      return b is TypeParameter && a.name == b.name;
+    }
+    return false;
+  }
+
+  bool _checkDeclarations(dynamic a, dynamic b) {
+    if (identical(a, b)) {
+      return true;
+    } else if (a == null || b == null) {
+      return false;
+    } else if (checkAssumedDeclarations(a, b)) {
+      return true;
+    } else if (matchDeclarations(a, b)) {
+      return assumeDeclarations(a, b);
+    } else {
+      return false;
+    }
+  }
+
+  bool deepMatchDeclarations(dynamic a, dynamic b) {
+    CheckingState oldState = _checkingState;
+    _checkingState = _checkingState.toMatchingState();
+    bool result = checkDeclarations(a, b);
+    _checkingState = oldState;
+    return result;
+  }
+
+  bool checkDeclarations(dynamic a, dynamic b, [String propertyName = '']) {
+    bool result = _checkDeclarations(a, b);
+    if (!result) {
+      result = assumeDeclarations(a, b);
+    }
+    if (!result) {
+      registerInequivalence(
+          propertyName, 'Declarations ${a} and ${b} are not equivalent');
+    }
+    return result;
+  }
+
+  /// Returns `true` if lists [a] and [b] are equivalent, using
+  /// [equivalentValues] to determine element-wise equivalence.
+  ///
+  /// If run in a checking state, the [propertyName] is used for registering
+  /// inequivalences.
+  bool checkLists<E>(
+      List<E>? a, List<E>? b, bool Function(E?, E?, String) equivalentValues,
+      [String propertyName = '']) {
+    if (identical(a, b)) return true;
+    if (a == null || b == null) return false;
+    if (a.length != b.length) {
+      registerInequivalence(
+          '${propertyName}.length', 'Lists ${a} and ${b} are not equivalent');
+      return false;
+    }
+    for (int i = 0; i < a.length; i++) {
+      if (!equivalentValues(a[i], b[i], '${propertyName}[${i}]')) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /// Returns `true` if lists [a] and [b] are equivalent, using
+  /// [equivalentValues] to determine element-wise equivalence.
+  ///
+  /// Inequivalence is _not_ registered.
+  bool matchLists<E>(
+      List<E>? a, List<E>? b, bool Function(E?, E?, String) equivalentValues) {
+    CheckingState oldState = _checkingState;
+    _checkingState = _checkingState.toMatchingState();
+    bool result = checkLists(a, b, equivalentValues);
+    _checkingState = oldState;
+    return result;
+  }
+
+  /// Returns `true` if sets [a] and [b] are equivalent, using
+  /// [matchingValues] to determine which elements that should be checked for
+  /// element-wise equivalence using [equivalentValues].
+  ///
+  /// If run in a checking state, the [propertyName] is used for registering
+  /// inequivalences.
+  bool checkSets<E>(Set<E>? a, Set<E>? b, bool Function(E?, E?) matchingValues,
+      bool Function(E?, E?, String) equivalentValues,
+      [String propertyName = '']) {
+    if (identical(a, b)) return true;
+    if (a == null || b == null) return false;
+    if (a.length != b.length) {
+      registerInequivalence(
+          '${propertyName}.length', 'Sets ${a} and ${b} are not equivalent');
+      return false;
+    }
+    b = b.toSet();
+    for (E aValue in a) {
+      bool hasFoundValue = false;
+      E? foundValue;
+      for (E bValue in b) {
+        if (matchingValues(aValue, bValue)) {
+          foundValue = bValue;
+          hasFoundValue = true;
+          if (!equivalentValues(aValue, bValue, '${propertyName}[${aValue}]')) {
+            registerInequivalence('${propertyName}[${aValue}]',
+                'Elements ${aValue} and ${bValue} are not equivalent');
+            return false;
+          }
+          break;
+        }
+      }
+      if (hasFoundValue) {
+        b.remove(foundValue);
+      } else {
+        registerInequivalence(
+            '${propertyName}[${aValue}]',
+            'Sets ${a} and ${b} are not equivalent, no equivalent value '
+                'found for $aValue');
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /// Returns `true` if sets [a] and [b] are equivalent, using
+  /// [matchingValues] to determine which elements that should be checked for
+  /// element-wise equivalence using [equivalentValues].
+  ///
+  /// Inequivalence is _not_registered.
+  bool matchSets<E>(Set<E>? a, Set<E>? b, bool Function(E?, E?) matchingValues,
+      bool Function(E?, E?, String) equivalentValues) {
+    CheckingState oldState = _checkingState;
+    _checkingState = _checkingState.toMatchingState();
+    bool result = checkSets(a, b, matchingValues, equivalentValues);
+    _checkingState = oldState;
+    return result;
+  }
+
+  /// Returns `true` if maps [a] and [b] are equivalent, using
+  /// [matchingKeys] to determine which entries that should be checked for
+  /// entry-wise equivalence using [equivalentKeys] and [equivalentValues] to
+  /// determine key and value equivalences, respectively.
+  ///
+  /// If run in a checking state, the [propertyName] is used for registering
+  /// inequivalences.
+  bool checkMaps<K, V>(
+      Map<K, V>? a,
+      Map<K, V>? b,
+      bool Function(K?, K?) matchingKeys,
+      bool Function(K?, K?, String) equivalentKeys,
+      bool Function(V?, V?, String) equivalentValues,
+      [String propertyName = '']) {
+    if (identical(a, b)) return true;
+    if (a == null || b == null) return false;
+    if (a.length != b.length) {
+      registerInequivalence(
+          '${propertyName}.length', 'Maps ${a} and ${b} are not equivalent');
+      return false;
+    }
+    Set<K> bKeys = b.keys.toSet();
+    for (K aKey in a.keys) {
+      bool hasFoundKey = false;
+      K? foundKey;
+      for (K bKey in bKeys) {
+        if (matchingKeys(aKey, bKey)) {
+          foundKey = bKey;
+          hasFoundKey = true;
+          if (!equivalentKeys(aKey, bKey, '${propertyName}[${aKey}]')) {
+            registerInequivalence('${propertyName}[${aKey}]',
+                'Keys ${aKey} and ${bKey} are not equivalent');
+            return false;
+          }
+          break;
+        }
+      }
+      if (hasFoundKey) {
+        bKeys.remove(foundKey);
+        if (!equivalentValues(
+            a[aKey], b[foundKey], '${propertyName}[${aKey}]')) {
+          return false;
+        }
+      } else {
+        registerInequivalence(
+            '${propertyName}[${aKey}]',
+            'Maps ${a} and ${b} are not equivalent, no equivalent key '
+                'found for $aKey');
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /// Returns `true` if maps [a] and [b] are equivalent, using
+  /// [matchingKeys] to determine which entries that should be checked for
+  /// entry-wise equivalence using [equivalentKeys] and [equivalentValues] to
+  /// determine key and value equivalences, respectively.
+  ///
+  /// Inequivalence is _not_ registered.
+  bool matchMaps<K, V>(
+      Map<K, V>? a,
+      Map<K, V>? b,
+      bool Function(K?, K?) matchingKeys,
+      bool Function(K?, K?, String) equivalentKeys,
+      bool Function(V?, V?, String) equivalentValues) {
+    CheckingState oldState = _checkingState;
+    _checkingState = _checkingState.toMatchingState();
+    bool result =
+        checkMaps(a, b, matchingKeys, equivalentKeys, equivalentValues);
+    _checkingState = oldState;
+    return result;
+  }
+
+  /// The current state of the visitor.
+  ///
+  /// This holds the current assumptions, found inequivalences, and whether
+  /// inequivalences are currently registered.
+  CheckingState _checkingState = new CheckingState();
+
+  /// Runs [f] in a new state that holds all current assumptions. If
+  /// [isAsserting] is `true`, inequivalences are registered. Returns the
+  /// collected inequivalences.
+  ///
+  /// If [f] returns `false`, the returned result is marked as having
+  /// inequivalences even when non have being registered.
+  EquivalenceResult inSubState(bool Function() f, {bool isAsserting: false}) {
+    CheckingState _oldState = _checkingState;
+    _checkingState = _checkingState.createSubState(isAsserting: isAsserting);
+    bool hasInequivalences = f();
+    EquivalenceResult result =
+        _checkingState.toResult(hasInequivalences: hasInequivalences);
+    _checkingState = _oldState;
+    return result;
+  }
+
+  /// Registers that the visitor enters the property named [propertyName] and
+  /// the currently visited node.
+  void pushPropertyState(String propertyName) {
+    _checkingState.pushPropertyState(propertyName);
+  }
+
+  /// Registers that the visitor enters nodes [a] and [b].
+  void pushNodeState(Node a, Node b) {
+    _checkingState.pushNodeState(a, b);
+  }
+
+  /// Register that the visitor leave the current node or property.
+  void popState() {
+    _checkingState.popState();
+  }
+
+  /// Returns the value used as the result for property inequivalences.
+  ///
+  /// When inequivalences are currently registered, this is `true`, so that the
+  /// visitor will continue find inequivalences that are not directly related.
+  ///
+  /// An example is finding several child inequivalences on otherwise equivalent
+  /// nodes, like finding inequivalences deeply in the members of the second
+  /// library of a component even when inequivalences deeply in the members of
+  /// the first library. Had the return value been `false`, signaling that the
+  /// first libraries were inequivalent, which they technically are, given that
+  /// the contain inequivalent subnodes, the visitor would have stopped short in
+  /// checking the list of libraries, and the inequivalences in the second
+  /// library would not have been found.
+  ///
+  /// When inequivalences are _not_ currently registered, i.e. we are only
+  /// interested in the true/false value of the equivalence test, `false` is
+  /// used as the result value to stop the equivalence checking short.
+  bool get resultOnInequivalence => _checkingState.resultOnInequivalence;
+
+  /// Registers an equivalence on the [propertyName] with a detailed description
+  /// in [message].
+  void registerInequivalence(String propertyName, String message) {
+    _checkingState.registerInequivalence(propertyName, message);
+  }
+
+  /// Returns the inequivalences found by the visitor.
+  EquivalenceResult toResult() => _checkingState.toResult();
+}
+
+/// Checks [a] and [b] be for equivalence using [strategy].
+///
+/// Returns an [EquivalenceResult] containing the found inequivalences.
+EquivalenceResult checkEquivalence(Node a, Node b,
+    {EquivalenceStrategy strategy: const EquivalenceStrategy()}) {
+  EquivalenceVisitor visitor = new EquivalenceVisitor(strategy: strategy);
+  visitor.checkNodes(a, b, 'root');
+  return visitor.toResult();
+}
+
+/// Strategy used for determining equivalence of AST nodes.
+///
+/// The strategy has a method for determining the equivalence of each AST node
+/// class, and a method for determining the equivalence of each property on each
+/// AST node class.
+///
+/// The base implementation enforces a full structural equivalence.
+///
+/// Custom strategies can be made by extending this strategy and override
+/// methods where exceptions to the structural equivalence are needed.
+class EquivalenceStrategy {
+  const EquivalenceStrategy();
+
+  bool checkLibrary(EquivalenceVisitor visitor, Library? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! Library) return false;
+    if (other is! Library) return false;
+    if (!visitor.matchNamedNodes(node, other)) {
+      return false;
+    }
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkLibrary_importUri(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibrary_fileUri(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibrary_languageVersion(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibrary_flags(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibrary_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibrary_problemsAsJson(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibrary_annotations(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibrary_dependencies(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibrary_additionalExports(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibrary_parts(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibrary_typedefs(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibrary_classes(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibrary_extensions(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibrary_procedures(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibrary_fields(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibrary_reference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibrary_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkTypedef(EquivalenceVisitor visitor, Typedef? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! Typedef) return false;
+    if (other is! Typedef) return false;
+    if (!visitor.matchNamedNodes(node, other)) {
+      return false;
+    }
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkTypedef_fileUri(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypedef_annotations(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypedef_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypedef_typeParameters(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypedef_type(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypedef_typeParametersOfFunctionType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypedef_positionalParameters(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypedef_namedParameters(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypedef_reference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypedef_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkClass(EquivalenceVisitor visitor, Class? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! Class) return false;
+    if (other is! Class) return false;
+    if (!visitor.matchNamedNodes(node, other)) {
+      return false;
+    }
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkClass_startFileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkClass_fileEndOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkClass_annotations(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkClass_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkClass_flags(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkClass_fileUri(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkClass_typeParameters(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkClass_supertype(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkClass_mixedInType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkClass_implementedTypes(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkClass_fields(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkClass_constructors(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkClass_procedures(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkClass_redirectingFactories(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkClass_reference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkClass_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkExtensionMemberDescriptor(EquivalenceVisitor visitor,
+      ExtensionMemberDescriptor? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! ExtensionMemberDescriptor) return false;
+    if (other is! ExtensionMemberDescriptor) return false;
+    bool result = true;
+    if (!checkExtensionMemberDescriptor_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkExtensionMemberDescriptor_kind(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkExtensionMemberDescriptor_flags(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkExtensionMemberDescriptor_member(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    return result;
+  }
+
+  bool checkExtension(
+      EquivalenceVisitor visitor, Extension? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! Extension) return false;
+    if (other is! Extension) return false;
+    if (!visitor.matchNamedNodes(node, other)) {
+      return false;
+    }
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkExtension_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkExtension_fileUri(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkExtension_typeParameters(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkExtension_onType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkExtension_members(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkExtension_annotations(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkExtension_flags(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkExtension_reference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkExtension_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkField(EquivalenceVisitor visitor, Field? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! Field) return false;
+    if (other is! Field) return false;
+    if (!visitor.matchNamedNodes(node, other)) {
+      return false;
+    }
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkField_type(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkField_flags(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkField_initializer(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkField_setterReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkField_fileEndOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkField_annotations(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkField_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkField_fileUri(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkField_transformerFlags(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkField_getterReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkField_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkConstructor(
+      EquivalenceVisitor visitor, Constructor? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! Constructor) return false;
+    if (other is! Constructor) return false;
+    if (!visitor.matchNamedNodes(node, other)) {
+      return false;
+    }
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkConstructor_startFileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConstructor_flags(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConstructor_function(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConstructor_initializers(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConstructor_fileEndOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConstructor_annotations(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConstructor_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConstructor_fileUri(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConstructor_transformerFlags(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConstructor_reference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConstructor_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkRedirectingFactory(
+      EquivalenceVisitor visitor, RedirectingFactory? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! RedirectingFactory) return false;
+    if (other is! RedirectingFactory) return false;
+    if (!visitor.matchNamedNodes(node, other)) {
+      return false;
+    }
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkRedirectingFactory_flags(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkRedirectingFactory_typeArguments(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkRedirectingFactory_targetReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkRedirectingFactory_function(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkRedirectingFactory_fileEndOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkRedirectingFactory_annotations(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkRedirectingFactory_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkRedirectingFactory_fileUri(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkRedirectingFactory_transformerFlags(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkRedirectingFactory_reference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkRedirectingFactory_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkProcedure(
+      EquivalenceVisitor visitor, Procedure? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! Procedure) return false;
+    if (other is! Procedure) return false;
+    if (!visitor.matchNamedNodes(node, other)) {
+      return false;
+    }
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkProcedure_startFileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkProcedure_kind(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkProcedure_flags(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkProcedure_function(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkProcedure_stubKind(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkProcedure_stubTargetReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkProcedure_fileEndOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkProcedure_annotations(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkProcedure_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkProcedure_fileUri(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkProcedure_transformerFlags(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkProcedure_reference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkProcedure_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkLibraryDependency(
+      EquivalenceVisitor visitor, LibraryDependency? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! LibraryDependency) return false;
+    if (other is! LibraryDependency) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkLibraryDependency_flags(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibraryDependency_annotations(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibraryDependency_importedLibraryReference(
+        visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibraryDependency_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibraryDependency_combinators(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibraryDependency_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkLibraryPart(
+      EquivalenceVisitor visitor, LibraryPart? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! LibraryPart) return false;
+    if (other is! LibraryPart) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkLibraryPart_annotations(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibraryPart_partUri(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLibraryPart_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkCombinator(
+      EquivalenceVisitor visitor, Combinator? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! Combinator) return false;
+    if (other is! Combinator) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkCombinator_isShow(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkCombinator_names(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkCombinator_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkInvalidInitializer(
+      EquivalenceVisitor visitor, InvalidInitializer? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! InvalidInitializer) return false;
+    if (other is! InvalidInitializer) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkInvalidInitializer_isSynthetic(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInvalidInitializer_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkFieldInitializer(
+      EquivalenceVisitor visitor, FieldInitializer? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! FieldInitializer) return false;
+    if (other is! FieldInitializer) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkFieldInitializer_fieldReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFieldInitializer_value(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFieldInitializer_isSynthetic(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFieldInitializer_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkSuperInitializer(
+      EquivalenceVisitor visitor, SuperInitializer? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! SuperInitializer) return false;
+    if (other is! SuperInitializer) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkSuperInitializer_targetReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSuperInitializer_arguments(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSuperInitializer_isSynthetic(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSuperInitializer_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkRedirectingInitializer(
+      EquivalenceVisitor visitor, RedirectingInitializer? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! RedirectingInitializer) return false;
+    if (other is! RedirectingInitializer) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkRedirectingInitializer_targetReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkRedirectingInitializer_arguments(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkRedirectingInitializer_isSynthetic(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkRedirectingInitializer_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkLocalInitializer(
+      EquivalenceVisitor visitor, LocalInitializer? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! LocalInitializer) return false;
+    if (other is! LocalInitializer) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkLocalInitializer_variable(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLocalInitializer_isSynthetic(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLocalInitializer_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkAssertInitializer(
+      EquivalenceVisitor visitor, AssertInitializer? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! AssertInitializer) return false;
+    if (other is! AssertInitializer) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkAssertInitializer_statement(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkAssertInitializer_isSynthetic(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkAssertInitializer_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkFunctionNode(
+      EquivalenceVisitor visitor, FunctionNode? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! FunctionNode) return false;
+    if (other is! FunctionNode) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkFunctionNode_fileEndOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionNode_asyncMarker(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionNode_dartAsyncMarker(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionNode_typeParameters(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionNode_requiredParameterCount(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionNode_positionalParameters(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionNode_namedParameters(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionNode_returnType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionNode_body(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionNode_futureValueType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionNode_lazyBuilder(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionNode_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkInvalidExpression(
+      EquivalenceVisitor visitor, InvalidExpression? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! InvalidExpression) return false;
+    if (other is! InvalidExpression) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkInvalidExpression_message(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInvalidExpression_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkVariableGet(
+      EquivalenceVisitor visitor, VariableGet? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! VariableGet) return false;
+    if (other is! VariableGet) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkVariableGet_variable(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkVariableGet_promotedType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkVariableGet_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkVariableSet(
+      EquivalenceVisitor visitor, VariableSet? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! VariableSet) return false;
+    if (other is! VariableSet) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkVariableSet_variable(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkVariableSet_value(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkVariableSet_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkDynamicGet(
+      EquivalenceVisitor visitor, DynamicGet? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! DynamicGet) return false;
+    if (other is! DynamicGet) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkDynamicGet_kind(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkDynamicGet_receiver(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkDynamicGet_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkDynamicGet_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkInstanceGet(
+      EquivalenceVisitor visitor, InstanceGet? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! InstanceGet) return false;
+    if (other is! InstanceGet) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkInstanceGet_kind(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceGet_receiver(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceGet_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceGet_resultType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceGet_interfaceTargetReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceGet_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkFunctionTearOff(
+      EquivalenceVisitor visitor, FunctionTearOff? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! FunctionTearOff) return false;
+    if (other is! FunctionTearOff) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkFunctionTearOff_receiver(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionTearOff_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkInstanceTearOff(
+      EquivalenceVisitor visitor, InstanceTearOff? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! InstanceTearOff) return false;
+    if (other is! InstanceTearOff) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkInstanceTearOff_kind(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceTearOff_receiver(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceTearOff_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceTearOff_resultType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceTearOff_interfaceTargetReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceTearOff_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkDynamicSet(
+      EquivalenceVisitor visitor, DynamicSet? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! DynamicSet) return false;
+    if (other is! DynamicSet) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkDynamicSet_kind(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkDynamicSet_receiver(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkDynamicSet_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkDynamicSet_value(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkDynamicSet_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkInstanceSet(
+      EquivalenceVisitor visitor, InstanceSet? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! InstanceSet) return false;
+    if (other is! InstanceSet) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkInstanceSet_kind(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceSet_receiver(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceSet_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceSet_value(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceSet_interfaceTargetReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceSet_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkSuperPropertyGet(
+      EquivalenceVisitor visitor, SuperPropertyGet? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! SuperPropertyGet) return false;
+    if (other is! SuperPropertyGet) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkSuperPropertyGet_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSuperPropertyGet_interfaceTargetReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSuperPropertyGet_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkSuperPropertySet(
+      EquivalenceVisitor visitor, SuperPropertySet? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! SuperPropertySet) return false;
+    if (other is! SuperPropertySet) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkSuperPropertySet_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSuperPropertySet_value(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSuperPropertySet_interfaceTargetReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSuperPropertySet_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkStaticGet(
+      EquivalenceVisitor visitor, StaticGet? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! StaticGet) return false;
+    if (other is! StaticGet) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkStaticGet_targetReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkStaticGet_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkStaticTearOff(
+      EquivalenceVisitor visitor, StaticTearOff? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! StaticTearOff) return false;
+    if (other is! StaticTearOff) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkStaticTearOff_targetReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkStaticTearOff_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkStaticSet(
+      EquivalenceVisitor visitor, StaticSet? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! StaticSet) return false;
+    if (other is! StaticSet) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkStaticSet_targetReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkStaticSet_value(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkStaticSet_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkDynamicInvocation(
+      EquivalenceVisitor visitor, DynamicInvocation? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! DynamicInvocation) return false;
+    if (other is! DynamicInvocation) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkDynamicInvocation_kind(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkDynamicInvocation_receiver(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkDynamicInvocation_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkDynamicInvocation_arguments(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkDynamicInvocation_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkInstanceInvocation(
+      EquivalenceVisitor visitor, InstanceInvocation? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! InstanceInvocation) return false;
+    if (other is! InstanceInvocation) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkInstanceInvocation_kind(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceInvocation_receiver(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceInvocation_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceInvocation_arguments(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceInvocation_flags(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceInvocation_functionType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceInvocation_interfaceTargetReference(
+        visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceInvocation_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkInstanceGetterInvocation(EquivalenceVisitor visitor,
+      InstanceGetterInvocation? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! InstanceGetterInvocation) return false;
+    if (other is! InstanceGetterInvocation) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkInstanceGetterInvocation_kind(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceGetterInvocation_receiver(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceGetterInvocation_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceGetterInvocation_arguments(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceGetterInvocation_flags(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceGetterInvocation_functionType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceGetterInvocation_interfaceTargetReference(
+        visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceGetterInvocation_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkFunctionInvocation(
+      EquivalenceVisitor visitor, FunctionInvocation? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! FunctionInvocation) return false;
+    if (other is! FunctionInvocation) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkFunctionInvocation_kind(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionInvocation_receiver(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionInvocation_arguments(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionInvocation_functionType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionInvocation_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkLocalFunctionInvocation(EquivalenceVisitor visitor,
+      LocalFunctionInvocation? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! LocalFunctionInvocation) return false;
+    if (other is! LocalFunctionInvocation) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkLocalFunctionInvocation_variable(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLocalFunctionInvocation_arguments(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLocalFunctionInvocation_functionType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLocalFunctionInvocation_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkSuperMethodInvocation(
+      EquivalenceVisitor visitor, SuperMethodInvocation? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! SuperMethodInvocation) return false;
+    if (other is! SuperMethodInvocation) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkSuperMethodInvocation_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSuperMethodInvocation_arguments(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSuperMethodInvocation_interfaceTargetReference(
+        visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSuperMethodInvocation_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkStaticInvocation(
+      EquivalenceVisitor visitor, StaticInvocation? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! StaticInvocation) return false;
+    if (other is! StaticInvocation) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkStaticInvocation_targetReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkStaticInvocation_arguments(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkStaticInvocation_isConst(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkStaticInvocation_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkConstructorInvocation(
+      EquivalenceVisitor visitor, ConstructorInvocation? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! ConstructorInvocation) return false;
+    if (other is! ConstructorInvocation) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkConstructorInvocation_targetReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConstructorInvocation_arguments(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConstructorInvocation_isConst(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConstructorInvocation_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkEqualsNull(
+      EquivalenceVisitor visitor, EqualsNull? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! EqualsNull) return false;
+    if (other is! EqualsNull) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkEqualsNull_expression(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkEqualsNull_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkEqualsCall(
+      EquivalenceVisitor visitor, EqualsCall? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! EqualsCall) return false;
+    if (other is! EqualsCall) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkEqualsCall_left(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkEqualsCall_right(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkEqualsCall_functionType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkEqualsCall_interfaceTargetReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkEqualsCall_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkInstantiation(
+      EquivalenceVisitor visitor, Instantiation? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! Instantiation) return false;
+    if (other is! Instantiation) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkInstantiation_expression(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstantiation_typeArguments(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstantiation_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkNot(EquivalenceVisitor visitor, Not? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! Not) return false;
+    if (other is! Not) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkNot_operand(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkNot_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkLogicalExpression(
+      EquivalenceVisitor visitor, LogicalExpression? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! LogicalExpression) return false;
+    if (other is! LogicalExpression) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkLogicalExpression_left(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLogicalExpression_operatorEnum(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLogicalExpression_right(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLogicalExpression_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkConditionalExpression(
+      EquivalenceVisitor visitor, ConditionalExpression? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! ConditionalExpression) return false;
+    if (other is! ConditionalExpression) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkConditionalExpression_condition(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConditionalExpression_then(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConditionalExpression_otherwise(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConditionalExpression_staticType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConditionalExpression_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkStringConcatenation(
+      EquivalenceVisitor visitor, StringConcatenation? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! StringConcatenation) return false;
+    if (other is! StringConcatenation) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkStringConcatenation_expressions(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkStringConcatenation_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkListConcatenation(
+      EquivalenceVisitor visitor, ListConcatenation? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! ListConcatenation) return false;
+    if (other is! ListConcatenation) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkListConcatenation_typeArgument(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkListConcatenation_lists(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkListConcatenation_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkSetConcatenation(
+      EquivalenceVisitor visitor, SetConcatenation? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! SetConcatenation) return false;
+    if (other is! SetConcatenation) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkSetConcatenation_typeArgument(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSetConcatenation_sets(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSetConcatenation_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkMapConcatenation(
+      EquivalenceVisitor visitor, MapConcatenation? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! MapConcatenation) return false;
+    if (other is! MapConcatenation) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkMapConcatenation_keyType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkMapConcatenation_valueType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkMapConcatenation_maps(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkMapConcatenation_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkInstanceCreation(
+      EquivalenceVisitor visitor, InstanceCreation? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! InstanceCreation) return false;
+    if (other is! InstanceCreation) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkInstanceCreation_classReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceCreation_typeArguments(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceCreation_fieldValues(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceCreation_asserts(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceCreation_unusedArguments(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceCreation_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkFileUriExpression(
+      EquivalenceVisitor visitor, FileUriExpression? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! FileUriExpression) return false;
+    if (other is! FileUriExpression) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkFileUriExpression_fileUri(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFileUriExpression_expression(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFileUriExpression_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkIsExpression(
+      EquivalenceVisitor visitor, IsExpression? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! IsExpression) return false;
+    if (other is! IsExpression) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkIsExpression_flags(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkIsExpression_operand(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkIsExpression_type(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkIsExpression_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkAsExpression(
+      EquivalenceVisitor visitor, AsExpression? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! AsExpression) return false;
+    if (other is! AsExpression) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkAsExpression_flags(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkAsExpression_operand(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkAsExpression_type(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkAsExpression_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkNullCheck(
+      EquivalenceVisitor visitor, NullCheck? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! NullCheck) return false;
+    if (other is! NullCheck) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkNullCheck_operand(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkNullCheck_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkStringLiteral(
+      EquivalenceVisitor visitor, StringLiteral? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! StringLiteral) return false;
+    if (other is! StringLiteral) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkStringLiteral_value(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkStringLiteral_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkIntLiteral(
+      EquivalenceVisitor visitor, IntLiteral? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! IntLiteral) return false;
+    if (other is! IntLiteral) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkIntLiteral_value(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkIntLiteral_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkDoubleLiteral(
+      EquivalenceVisitor visitor, DoubleLiteral? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! DoubleLiteral) return false;
+    if (other is! DoubleLiteral) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkDoubleLiteral_value(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkDoubleLiteral_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkBoolLiteral(
+      EquivalenceVisitor visitor, BoolLiteral? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! BoolLiteral) return false;
+    if (other is! BoolLiteral) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkBoolLiteral_value(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkBoolLiteral_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkNullLiteral(
+      EquivalenceVisitor visitor, NullLiteral? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! NullLiteral) return false;
+    if (other is! NullLiteral) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkNullLiteral_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkSymbolLiteral(
+      EquivalenceVisitor visitor, SymbolLiteral? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! SymbolLiteral) return false;
+    if (other is! SymbolLiteral) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkSymbolLiteral_value(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSymbolLiteral_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkTypeLiteral(
+      EquivalenceVisitor visitor, TypeLiteral? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! TypeLiteral) return false;
+    if (other is! TypeLiteral) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkTypeLiteral_type(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypeLiteral_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkThisExpression(
+      EquivalenceVisitor visitor, ThisExpression? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! ThisExpression) return false;
+    if (other is! ThisExpression) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkThisExpression_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkRethrow(EquivalenceVisitor visitor, Rethrow? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! Rethrow) return false;
+    if (other is! Rethrow) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkRethrow_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkThrow(EquivalenceVisitor visitor, Throw? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! Throw) return false;
+    if (other is! Throw) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkThrow_expression(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkThrow_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkListLiteral(
+      EquivalenceVisitor visitor, ListLiteral? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! ListLiteral) return false;
+    if (other is! ListLiteral) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkListLiteral_isConst(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkListLiteral_typeArgument(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkListLiteral_expressions(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkListLiteral_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkSetLiteral(
+      EquivalenceVisitor visitor, SetLiteral? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! SetLiteral) return false;
+    if (other is! SetLiteral) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkSetLiteral_isConst(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSetLiteral_typeArgument(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSetLiteral_expressions(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSetLiteral_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkMapLiteral(
+      EquivalenceVisitor visitor, MapLiteral? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! MapLiteral) return false;
+    if (other is! MapLiteral) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkMapLiteral_isConst(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkMapLiteral_keyType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkMapLiteral_valueType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkMapLiteral_entries(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkMapLiteral_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkAwaitExpression(
+      EquivalenceVisitor visitor, AwaitExpression? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! AwaitExpression) return false;
+    if (other is! AwaitExpression) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkAwaitExpression_operand(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkAwaitExpression_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkFunctionExpression(
+      EquivalenceVisitor visitor, FunctionExpression? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! FunctionExpression) return false;
+    if (other is! FunctionExpression) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkFunctionExpression_function(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionExpression_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkConstantExpression(
+      EquivalenceVisitor visitor, ConstantExpression? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! ConstantExpression) return false;
+    if (other is! ConstantExpression) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkConstantExpression_constant(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConstantExpression_type(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConstantExpression_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkLet(EquivalenceVisitor visitor, Let? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! Let) return false;
+    if (other is! Let) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkLet_variable(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLet_body(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLet_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkBlockExpression(
+      EquivalenceVisitor visitor, BlockExpression? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! BlockExpression) return false;
+    if (other is! BlockExpression) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkBlockExpression_body(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkBlockExpression_value(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkBlockExpression_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkLoadLibrary(
+      EquivalenceVisitor visitor, LoadLibrary? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! LoadLibrary) return false;
+    if (other is! LoadLibrary) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkLoadLibrary_import(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLoadLibrary_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkCheckLibraryIsLoaded(
+      EquivalenceVisitor visitor, CheckLibraryIsLoaded? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! CheckLibraryIsLoaded) return false;
+    if (other is! CheckLibraryIsLoaded) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkCheckLibraryIsLoaded_import(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkCheckLibraryIsLoaded_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkConstructorTearOff(
+      EquivalenceVisitor visitor, ConstructorTearOff? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! ConstructorTearOff) return false;
+    if (other is! ConstructorTearOff) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkConstructorTearOff_targetReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConstructorTearOff_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkRedirectingFactoryTearOff(EquivalenceVisitor visitor,
+      RedirectingFactoryTearOff? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! RedirectingFactoryTearOff) return false;
+    if (other is! RedirectingFactoryTearOff) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkRedirectingFactoryTearOff_targetReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkRedirectingFactoryTearOff_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkTypedefTearOff(
+      EquivalenceVisitor visitor, TypedefTearOff? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! TypedefTearOff) return false;
+    if (other is! TypedefTearOff) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkTypedefTearOff_typeParameters(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypedefTearOff_expression(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypedefTearOff_typeArguments(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypedefTearOff_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkArguments(
+      EquivalenceVisitor visitor, Arguments? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! Arguments) return false;
+    if (other is! Arguments) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkArguments_types(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkArguments_positional(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkArguments_named(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkArguments_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkNamedExpression(
+      EquivalenceVisitor visitor, NamedExpression? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! NamedExpression) return false;
+    if (other is! NamedExpression) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkNamedExpression_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkNamedExpression_value(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkNamedExpression_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkMapLiteralEntry(
+      EquivalenceVisitor visitor, MapLiteralEntry? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! MapLiteralEntry) return false;
+    if (other is! MapLiteralEntry) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkMapLiteralEntry_key(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkMapLiteralEntry_value(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkMapLiteralEntry_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkExpressionStatement(
+      EquivalenceVisitor visitor, ExpressionStatement? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! ExpressionStatement) return false;
+    if (other is! ExpressionStatement) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkExpressionStatement_expression(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkExpressionStatement_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkBlock(EquivalenceVisitor visitor, Block? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! Block) return false;
+    if (other is! Block) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkBlock_statements(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkBlock_fileEndOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkBlock_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkAssertBlock(
+      EquivalenceVisitor visitor, AssertBlock? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! AssertBlock) return false;
+    if (other is! AssertBlock) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkAssertBlock_statements(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkAssertBlock_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkEmptyStatement(
+      EquivalenceVisitor visitor, EmptyStatement? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! EmptyStatement) return false;
+    if (other is! EmptyStatement) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkEmptyStatement_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkAssertStatement(
+      EquivalenceVisitor visitor, AssertStatement? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! AssertStatement) return false;
+    if (other is! AssertStatement) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkAssertStatement_condition(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkAssertStatement_message(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkAssertStatement_conditionStartOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkAssertStatement_conditionEndOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkAssertStatement_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkLabeledStatement(
+      EquivalenceVisitor visitor, LabeledStatement? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! LabeledStatement) return false;
+    if (other is! LabeledStatement) return false;
+    if (!visitor.checkDeclarations(node, other, '')) {
+      return false;
+    }
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkLabeledStatement_body(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkLabeledStatement_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkBreakStatement(
+      EquivalenceVisitor visitor, BreakStatement? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! BreakStatement) return false;
+    if (other is! BreakStatement) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkBreakStatement_target(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkBreakStatement_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkWhileStatement(
+      EquivalenceVisitor visitor, WhileStatement? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! WhileStatement) return false;
+    if (other is! WhileStatement) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkWhileStatement_condition(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkWhileStatement_body(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkWhileStatement_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkDoStatement(
+      EquivalenceVisitor visitor, DoStatement? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! DoStatement) return false;
+    if (other is! DoStatement) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkDoStatement_body(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkDoStatement_condition(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkDoStatement_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkForStatement(
+      EquivalenceVisitor visitor, ForStatement? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! ForStatement) return false;
+    if (other is! ForStatement) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkForStatement_variables(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkForStatement_condition(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkForStatement_updates(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkForStatement_body(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkForStatement_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkForInStatement(
+      EquivalenceVisitor visitor, ForInStatement? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! ForInStatement) return false;
+    if (other is! ForInStatement) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkForInStatement_bodyOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkForInStatement_variable(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkForInStatement_iterable(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkForInStatement_body(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkForInStatement_isAsync(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkForInStatement_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkSwitchStatement(
+      EquivalenceVisitor visitor, SwitchStatement? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! SwitchStatement) return false;
+    if (other is! SwitchStatement) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkSwitchStatement_expression(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSwitchStatement_cases(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSwitchStatement_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkContinueSwitchStatement(EquivalenceVisitor visitor,
+      ContinueSwitchStatement? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! ContinueSwitchStatement) return false;
+    if (other is! ContinueSwitchStatement) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkContinueSwitchStatement_target(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkContinueSwitchStatement_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkIfStatement(
+      EquivalenceVisitor visitor, IfStatement? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! IfStatement) return false;
+    if (other is! IfStatement) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkIfStatement_condition(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkIfStatement_then(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkIfStatement_otherwise(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkIfStatement_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkReturnStatement(
+      EquivalenceVisitor visitor, ReturnStatement? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! ReturnStatement) return false;
+    if (other is! ReturnStatement) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkReturnStatement_expression(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkReturnStatement_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkTryCatch(
+      EquivalenceVisitor visitor, TryCatch? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! TryCatch) return false;
+    if (other is! TryCatch) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkTryCatch_body(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTryCatch_catches(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTryCatch_isSynthetic(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTryCatch_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkTryFinally(
+      EquivalenceVisitor visitor, TryFinally? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! TryFinally) return false;
+    if (other is! TryFinally) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkTryFinally_body(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTryFinally_finalizer(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTryFinally_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkYieldStatement(
+      EquivalenceVisitor visitor, YieldStatement? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! YieldStatement) return false;
+    if (other is! YieldStatement) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkYieldStatement_expression(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkYieldStatement_flags(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkYieldStatement_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkVariableDeclaration(
+      EquivalenceVisitor visitor, VariableDeclaration? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! VariableDeclaration) return false;
+    if (other is! VariableDeclaration) return false;
+    if (!visitor.checkDeclarations(node, other, '')) {
+      return false;
+    }
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkVariableDeclaration_fileEqualsOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkVariableDeclaration_annotations(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkVariableDeclaration_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkVariableDeclaration_flags(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkVariableDeclaration_type(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkVariableDeclaration_binaryOffsetNoTag(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkVariableDeclaration_initializer(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkVariableDeclaration_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkFunctionDeclaration(
+      EquivalenceVisitor visitor, FunctionDeclaration? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! FunctionDeclaration) return false;
+    if (other is! FunctionDeclaration) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkFunctionDeclaration_variable(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionDeclaration_function(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionDeclaration_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkSwitchCase(
+      EquivalenceVisitor visitor, SwitchCase? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! SwitchCase) return false;
+    if (other is! SwitchCase) return false;
+    if (!visitor.checkDeclarations(node, other, '')) {
+      return false;
+    }
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkSwitchCase_expressions(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSwitchCase_expressionOffsets(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSwitchCase_body(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSwitchCase_isDefault(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSwitchCase_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkCatch(EquivalenceVisitor visitor, Catch? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! Catch) return false;
+    if (other is! Catch) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkCatch_guard(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkCatch_exception(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkCatch_stackTrace(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkCatch_body(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkCatch_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkTypeParameter(
+      EquivalenceVisitor visitor, TypeParameter? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! TypeParameter) return false;
+    if (other is! TypeParameter) return false;
+    if (!visitor.checkDeclarations(node, other, '')) {
+      return false;
+    }
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkTypeParameter_flags(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypeParameter_annotations(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypeParameter_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypeParameter_bound(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypeParameter_defaultType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypeParameter_variance(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypeParameter_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkSource(EquivalenceVisitor visitor, Source? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! Source) return false;
+    if (other is! Source) return false;
+    bool result = true;
+    if (!checkSource_lineStarts(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSource_source(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSource_importUri(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSource_fileUri(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSource_constantCoverageConstructors(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSource_cachedText(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    return result;
+  }
+
+  bool checkMetadataRepository(
+      EquivalenceVisitor visitor, MetadataRepository? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! MetadataRepository) return false;
+    if (other is! MetadataRepository) return false;
+    bool result = true;
+    return result;
+  }
+
+  bool checkComponent(
+      EquivalenceVisitor visitor, Component? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! Component) return false;
+    if (other is! Component) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkComponent_problemsAsJson(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkComponent_libraries(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkComponent_uriToSource(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkComponent_metadata(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkComponent_mainMethodName(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkComponent_mode(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkComponent_fileOffset(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkName(EquivalenceVisitor visitor, Name? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! Name) return false;
+    if (other is! Name) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkName_text(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkInvalidType(
+      EquivalenceVisitor visitor, InvalidType? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! InvalidType) return false;
+    if (other is! InvalidType) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    visitor.popState();
+    return result;
+  }
+
+  bool checkDynamicType(
+      EquivalenceVisitor visitor, DynamicType? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! DynamicType) return false;
+    if (other is! DynamicType) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    visitor.popState();
+    return result;
+  }
+
+  bool checkVoidType(
+      EquivalenceVisitor visitor, VoidType? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! VoidType) return false;
+    if (other is! VoidType) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    visitor.popState();
+    return result;
+  }
+
+  bool checkNeverType(
+      EquivalenceVisitor visitor, NeverType? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! NeverType) return false;
+    if (other is! NeverType) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkNeverType_declaredNullability(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkNullType(
+      EquivalenceVisitor visitor, NullType? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! NullType) return false;
+    if (other is! NullType) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    visitor.popState();
+    return result;
+  }
+
+  bool checkInterfaceType(
+      EquivalenceVisitor visitor, InterfaceType? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! InterfaceType) return false;
+    if (other is! InterfaceType) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkInterfaceType_className(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInterfaceType_declaredNullability(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInterfaceType_typeArguments(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkFunctionType(
+      EquivalenceVisitor visitor, FunctionType? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! FunctionType) return false;
+    if (other is! FunctionType) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkFunctionType_typeParameters(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionType_requiredParameterCount(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionType_positionalParameters(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionType_namedParameters(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionType_declaredNullability(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionType_typedefType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFunctionType_returnType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkTypedefType(
+      EquivalenceVisitor visitor, TypedefType? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! TypedefType) return false;
+    if (other is! TypedefType) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkTypedefType_declaredNullability(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypedefType_typedefReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypedefType_typeArguments(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkFutureOrType(
+      EquivalenceVisitor visitor, FutureOrType? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! FutureOrType) return false;
+    if (other is! FutureOrType) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkFutureOrType_typeArgument(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkFutureOrType_declaredNullability(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkExtensionType(
+      EquivalenceVisitor visitor, ExtensionType? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! ExtensionType) return false;
+    if (other is! ExtensionType) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkExtensionType_extensionReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkExtensionType_declaredNullability(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkExtensionType_typeArguments(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkExtensionType_onType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkTypeParameterType(
+      EquivalenceVisitor visitor, TypeParameterType? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! TypeParameterType) return false;
+    if (other is! TypeParameterType) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkTypeParameterType_declaredNullability(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypeParameterType_parameter(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypeParameterType_promotedBound(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkNamedType(
+      EquivalenceVisitor visitor, NamedType? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! NamedType) return false;
+    if (other is! NamedType) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkNamedType_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkNamedType_type(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkNamedType_isRequired(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkSupertype(
+      EquivalenceVisitor visitor, Supertype? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! Supertype) return false;
+    if (other is! Supertype) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkSupertype_className(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSupertype_typeArguments(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkNullConstant(
+      EquivalenceVisitor visitor, NullConstant? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! NullConstant) return false;
+    if (other is! NullConstant) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkNullConstant_value(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkBoolConstant(
+      EquivalenceVisitor visitor, BoolConstant? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! BoolConstant) return false;
+    if (other is! BoolConstant) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkBoolConstant_value(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkIntConstant(
+      EquivalenceVisitor visitor, IntConstant? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! IntConstant) return false;
+    if (other is! IntConstant) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkIntConstant_value(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkDoubleConstant(
+      EquivalenceVisitor visitor, DoubleConstant? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! DoubleConstant) return false;
+    if (other is! DoubleConstant) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkDoubleConstant_value(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkStringConstant(
+      EquivalenceVisitor visitor, StringConstant? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! StringConstant) return false;
+    if (other is! StringConstant) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkStringConstant_value(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkSymbolConstant(
+      EquivalenceVisitor visitor, SymbolConstant? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! SymbolConstant) return false;
+    if (other is! SymbolConstant) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkSymbolConstant_name(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSymbolConstant_libraryReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkConstantMapEntry(
+      EquivalenceVisitor visitor, ConstantMapEntry? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! ConstantMapEntry) return false;
+    if (other is! ConstantMapEntry) return false;
+    bool result = true;
+    if (!checkConstantMapEntry_key(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkConstantMapEntry_value(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    return result;
+  }
+
+  bool checkMapConstant(
+      EquivalenceVisitor visitor, MapConstant? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! MapConstant) return false;
+    if (other is! MapConstant) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkMapConstant_keyType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkMapConstant_valueType(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkMapConstant_entries(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkListConstant(
+      EquivalenceVisitor visitor, ListConstant? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! ListConstant) return false;
+    if (other is! ListConstant) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkListConstant_typeArgument(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkListConstant_entries(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkSetConstant(
+      EquivalenceVisitor visitor, SetConstant? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! SetConstant) return false;
+    if (other is! SetConstant) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkSetConstant_typeArgument(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkSetConstant_entries(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkInstanceConstant(
+      EquivalenceVisitor visitor, InstanceConstant? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! InstanceConstant) return false;
+    if (other is! InstanceConstant) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkInstanceConstant_classReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceConstant_typeArguments(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstanceConstant_fieldValues(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkInstantiationConstant(
+      EquivalenceVisitor visitor, InstantiationConstant? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! InstantiationConstant) return false;
+    if (other is! InstantiationConstant) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkInstantiationConstant_tearOffConstant(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkInstantiationConstant_types(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkStaticTearOffConstant(
+      EquivalenceVisitor visitor, StaticTearOffConstant? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! StaticTearOffConstant) return false;
+    if (other is! StaticTearOffConstant) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkStaticTearOffConstant_targetReference(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkConstructorTearOffConstant(EquivalenceVisitor visitor,
+      ConstructorTearOffConstant? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! ConstructorTearOffConstant) return false;
+    if (other is! ConstructorTearOffConstant) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkConstructorTearOffConstant_targetReference(
+        visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkRedirectingFactoryTearOffConstant(EquivalenceVisitor visitor,
+      RedirectingFactoryTearOffConstant? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! RedirectingFactoryTearOffConstant) return false;
+    if (other is! RedirectingFactoryTearOffConstant) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkRedirectingFactoryTearOffConstant_targetReference(
+        visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkTypedefTearOffConstant(
+      EquivalenceVisitor visitor, TypedefTearOffConstant? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! TypedefTearOffConstant) return false;
+    if (other is! TypedefTearOffConstant) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkTypedefTearOffConstant_parameters(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypedefTearOffConstant_tearOffConstant(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    if (!checkTypedefTearOffConstant_types(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkTypeLiteralConstant(
+      EquivalenceVisitor visitor, TypeLiteralConstant? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! TypeLiteralConstant) return false;
+    if (other is! TypeLiteralConstant) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkTypeLiteralConstant_type(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkUnevaluatedConstant(
+      EquivalenceVisitor visitor, UnevaluatedConstant? node, Object? other) {
+    if (identical(node, other)) return true;
+    if (node is! UnevaluatedConstant) return false;
+    if (other is! UnevaluatedConstant) return false;
+    visitor.pushNodeState(node, other);
+    bool result = true;
+    if (!checkUnevaluatedConstant_expression(visitor, node, other)) {
+      result = visitor.resultOnInequivalence;
+    }
+    visitor.popState();
+    return result;
+  }
+
+  bool checkLibrary_importUri(
+      EquivalenceVisitor visitor, Library node, Library other) {
+    return visitor.checkValues(node.importUri, other.importUri, 'importUri');
+  }
+
+  bool checkLibrary_fileUri(
+      EquivalenceVisitor visitor, Library node, Library other) {
+    return visitor.checkValues(node.fileUri, other.fileUri, 'fileUri');
+  }
+
+  bool checkLibrary_languageVersion(
+      EquivalenceVisitor visitor, Library node, Library other) {
+    return visitor.checkValues(
+        node.languageVersion, other.languageVersion, 'languageVersion');
+  }
+
+  bool checkLibrary_flags(
+      EquivalenceVisitor visitor, Library node, Library other) {
+    return visitor.checkValues(node.flags, other.flags, 'flags');
+  }
+
+  bool checkLibrary_name(
+      EquivalenceVisitor visitor, Library node, Library other) {
+    return visitor.checkValues(node.name, other.name, 'name');
+  }
+
+  bool checkLibrary_problemsAsJson(
+      EquivalenceVisitor visitor, Library node, Library other) {
+    return visitor.checkLists(node.problemsAsJson, other.problemsAsJson,
+        visitor.checkValues, 'problemsAsJson');
+  }
+
+  bool checkLibrary_annotations(
+      EquivalenceVisitor visitor, Library node, Library other) {
+    return visitor.checkLists(
+        node.annotations, other.annotations, visitor.checkNodes, 'annotations');
+  }
+
+  bool checkLibrary_dependencies(
+      EquivalenceVisitor visitor, Library node, Library other) {
+    return visitor.checkLists(node.dependencies, other.dependencies,
+        visitor.checkNodes, 'dependencies');
+  }
+
+  bool checkLibrary_additionalExports(
+      EquivalenceVisitor visitor, Library node, Library other) {
+    return visitor.checkLists(node.additionalExports, other.additionalExports,
+        visitor.checkReferences, 'additionalExports');
+  }
+
+  bool checkLibrary_parts(
+      EquivalenceVisitor visitor, Library node, Library other) {
+    return visitor.checkLists(
+        node.parts, other.parts, visitor.checkNodes, 'parts');
+  }
+
+  bool checkLibrary_typedefs(
+      EquivalenceVisitor visitor, Library node, Library other) {
+    return visitor.checkLists(
+        node.typedefs, other.typedefs, visitor.checkNodes, 'typedefs');
+  }
+
+  bool checkLibrary_classes(
+      EquivalenceVisitor visitor, Library node, Library other) {
+    return visitor.checkLists(
+        node.classes, other.classes, visitor.checkNodes, 'classes');
+  }
+
+  bool checkLibrary_extensions(
+      EquivalenceVisitor visitor, Library node, Library other) {
+    return visitor.checkLists(
+        node.extensions, other.extensions, visitor.checkNodes, 'extensions');
+  }
+
+  bool checkLibrary_procedures(
+      EquivalenceVisitor visitor, Library node, Library other) {
+    return visitor.checkLists(
+        node.procedures, other.procedures, visitor.checkNodes, 'procedures');
+  }
+
+  bool checkLibrary_fields(
+      EquivalenceVisitor visitor, Library node, Library other) {
+    return visitor.checkLists(
+        node.fields, other.fields, visitor.checkNodes, 'fields');
+  }
+
+  bool checkLibrary_reference(
+      EquivalenceVisitor visitor, Library node, Library other) {
+    return visitor.checkReferences(
+        node.reference, other.reference, 'reference');
+  }
+
+  bool checkLibrary_fileOffset(
+      EquivalenceVisitor visitor, Library node, Library other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkTypedef_fileUri(
+      EquivalenceVisitor visitor, Typedef node, Typedef other) {
+    return visitor.checkValues(node.fileUri, other.fileUri, 'fileUri');
+  }
+
+  bool checkTypedef_annotations(
+      EquivalenceVisitor visitor, Typedef node, Typedef other) {
+    return visitor.checkLists(
+        node.annotations, other.annotations, visitor.checkNodes, 'annotations');
+  }
+
+  bool checkTypedef_name(
+      EquivalenceVisitor visitor, Typedef node, Typedef other) {
+    return visitor.checkValues(node.name, other.name, 'name');
+  }
+
+  bool checkTypedef_typeParameters(
+      EquivalenceVisitor visitor, Typedef node, Typedef other) {
+    return visitor.checkLists(node.typeParameters, other.typeParameters,
+        visitor.checkNodes, 'typeParameters');
+  }
+
+  bool checkTypedef_type(
+      EquivalenceVisitor visitor, Typedef node, Typedef other) {
+    return visitor.checkNodes(node.type, other.type, 'type');
+  }
+
+  bool checkTypedef_typeParametersOfFunctionType(
+      EquivalenceVisitor visitor, Typedef node, Typedef other) {
+    return visitor.checkLists(
+        node.typeParametersOfFunctionType,
+        other.typeParametersOfFunctionType,
+        visitor.checkDeclarations,
+        'typeParametersOfFunctionType');
+  }
+
+  bool checkTypedef_positionalParameters(
+      EquivalenceVisitor visitor, Typedef node, Typedef other) {
+    return visitor.checkLists(
+        node.positionalParameters,
+        other.positionalParameters,
+        visitor.checkDeclarations,
+        'positionalParameters');
+  }
+
+  bool checkTypedef_namedParameters(
+      EquivalenceVisitor visitor, Typedef node, Typedef other) {
+    return visitor.checkLists(node.namedParameters, other.namedParameters,
+        visitor.checkDeclarations, 'namedParameters');
+  }
+
+  bool checkTypedef_reference(
+      EquivalenceVisitor visitor, Typedef node, Typedef other) {
+    return visitor.checkReferences(
+        node.reference, other.reference, 'reference');
+  }
+
+  bool checkTypedef_fileOffset(
+      EquivalenceVisitor visitor, Typedef node, Typedef other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkClass_startFileOffset(
+      EquivalenceVisitor visitor, Class node, Class other) {
+    return visitor.checkValues(
+        node.startFileOffset, other.startFileOffset, 'startFileOffset');
+  }
+
+  bool checkClass_fileEndOffset(
+      EquivalenceVisitor visitor, Class node, Class other) {
+    return visitor.checkValues(
+        node.fileEndOffset, other.fileEndOffset, 'fileEndOffset');
+  }
+
+  bool checkClass_annotations(
+      EquivalenceVisitor visitor, Class node, Class other) {
+    return visitor.checkLists(
+        node.annotations, other.annotations, visitor.checkNodes, 'annotations');
+  }
+
+  bool checkClass_name(EquivalenceVisitor visitor, Class node, Class other) {
+    return visitor.checkValues(node.name, other.name, 'name');
+  }
+
+  bool checkClass_flags(EquivalenceVisitor visitor, Class node, Class other) {
+    return visitor.checkValues(node.flags, other.flags, 'flags');
+  }
+
+  bool checkClass_fileUri(EquivalenceVisitor visitor, Class node, Class other) {
+    return visitor.checkValues(node.fileUri, other.fileUri, 'fileUri');
+  }
+
+  bool checkClass_typeParameters(
+      EquivalenceVisitor visitor, Class node, Class other) {
+    return visitor.checkLists(node.typeParameters, other.typeParameters,
+        visitor.checkNodes, 'typeParameters');
+  }
+
+  bool checkClass_supertype(
+      EquivalenceVisitor visitor, Class node, Class other) {
+    return visitor.checkNodes(node.supertype, other.supertype, 'supertype');
+  }
+
+  bool checkClass_mixedInType(
+      EquivalenceVisitor visitor, Class node, Class other) {
+    return visitor.checkNodes(
+        node.mixedInType, other.mixedInType, 'mixedInType');
+  }
+
+  bool checkClass_implementedTypes(
+      EquivalenceVisitor visitor, Class node, Class other) {
+    return visitor.checkLists(node.implementedTypes, other.implementedTypes,
+        visitor.checkNodes, 'implementedTypes');
+  }
+
+  bool checkClass_fields(EquivalenceVisitor visitor, Class node, Class other) {
+    return visitor.checkLists(
+        node.fields, other.fields, visitor.checkNodes, 'fields');
+  }
+
+  bool checkClass_constructors(
+      EquivalenceVisitor visitor, Class node, Class other) {
+    return visitor.checkLists(node.constructors, other.constructors,
+        visitor.checkNodes, 'constructors');
+  }
+
+  bool checkClass_procedures(
+      EquivalenceVisitor visitor, Class node, Class other) {
+    return visitor.checkLists(
+        node.procedures, other.procedures, visitor.checkNodes, 'procedures');
+  }
+
+  bool checkClass_redirectingFactories(
+      EquivalenceVisitor visitor, Class node, Class other) {
+    return visitor.checkLists(node.redirectingFactories,
+        other.redirectingFactories, visitor.checkNodes, 'redirectingFactories');
+  }
+
+  bool checkClass_reference(
+      EquivalenceVisitor visitor, Class node, Class other) {
+    return visitor.checkReferences(
+        node.reference, other.reference, 'reference');
+  }
+
+  bool checkClass_fileOffset(
+      EquivalenceVisitor visitor, Class node, Class other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkExtension_name(
+      EquivalenceVisitor visitor, Extension node, Extension other) {
+    return visitor.checkValues(node.name, other.name, 'name');
+  }
+
+  bool checkExtension_fileUri(
+      EquivalenceVisitor visitor, Extension node, Extension other) {
+    return visitor.checkValues(node.fileUri, other.fileUri, 'fileUri');
+  }
+
+  bool checkExtension_typeParameters(
+      EquivalenceVisitor visitor, Extension node, Extension other) {
+    return visitor.checkLists(node.typeParameters, other.typeParameters,
+        visitor.checkNodes, 'typeParameters');
+  }
+
+  bool checkExtension_onType(
+      EquivalenceVisitor visitor, Extension node, Extension other) {
+    return visitor.checkNodes(node.onType, other.onType, 'onType');
+  }
+
+  bool checkExtensionMemberDescriptor_name(EquivalenceVisitor visitor,
+      ExtensionMemberDescriptor node, ExtensionMemberDescriptor other) {
+    return visitor.checkNodes(node.name, other.name, 'name');
+  }
+
+  bool checkExtensionMemberDescriptor_kind(EquivalenceVisitor visitor,
+      ExtensionMemberDescriptor node, ExtensionMemberDescriptor other) {
+    return visitor.checkValues(node.kind, other.kind, 'kind');
+  }
+
+  bool checkExtensionMemberDescriptor_flags(EquivalenceVisitor visitor,
+      ExtensionMemberDescriptor node, ExtensionMemberDescriptor other) {
+    return visitor.checkValues(node.flags, other.flags, 'flags');
+  }
+
+  bool checkExtensionMemberDescriptor_member(EquivalenceVisitor visitor,
+      ExtensionMemberDescriptor node, ExtensionMemberDescriptor other) {
+    return visitor.checkReferences(node.member, other.member, 'member');
+  }
+
+  bool checkExtension_members(
+      EquivalenceVisitor visitor, Extension node, Extension other) {
+    return visitor.checkLists(node.members, other.members, (a, b, _) {
+      if (identical(a, b)) return true;
+      if (a is! ExtensionMemberDescriptor) return false;
+      if (b is! ExtensionMemberDescriptor) return false;
+      return checkExtensionMemberDescriptor(visitor, a, b);
+    }, 'members');
+  }
+
+  bool checkExtension_annotations(
+      EquivalenceVisitor visitor, Extension node, Extension other) {
+    return visitor.checkLists(
+        node.annotations, other.annotations, visitor.checkNodes, 'annotations');
+  }
+
+  bool checkExtension_flags(
+      EquivalenceVisitor visitor, Extension node, Extension other) {
+    return visitor.checkValues(node.flags, other.flags, 'flags');
+  }
+
+  bool checkExtension_reference(
+      EquivalenceVisitor visitor, Extension node, Extension other) {
+    return visitor.checkReferences(
+        node.reference, other.reference, 'reference');
+  }
+
+  bool checkExtension_fileOffset(
+      EquivalenceVisitor visitor, Extension node, Extension other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkField_type(EquivalenceVisitor visitor, Field node, Field other) {
+    return visitor.checkNodes(node.type, other.type, 'type');
+  }
+
+  bool checkField_flags(EquivalenceVisitor visitor, Field node, Field other) {
+    return visitor.checkValues(node.flags, other.flags, 'flags');
+  }
+
+  bool checkField_initializer(
+      EquivalenceVisitor visitor, Field node, Field other) {
+    return visitor.checkNodes(
+        node.initializer, other.initializer, 'initializer');
+  }
+
+  bool checkField_setterReference(
+      EquivalenceVisitor visitor, Field node, Field other) {
+    return visitor.checkReferences(
+        node.setterReference, other.setterReference, 'setterReference');
+  }
+
+  bool checkField_fileEndOffset(
+      EquivalenceVisitor visitor, Field node, Field other) {
+    return visitor.checkValues(
+        node.fileEndOffset, other.fileEndOffset, 'fileEndOffset');
+  }
+
+  bool checkField_annotations(
+      EquivalenceVisitor visitor, Field node, Field other) {
+    return visitor.checkLists(
+        node.annotations, other.annotations, visitor.checkNodes, 'annotations');
+  }
+
+  bool checkField_name(EquivalenceVisitor visitor, Field node, Field other) {
+    return visitor.checkNodes(node.name, other.name, 'name');
+  }
+
+  bool checkField_fileUri(EquivalenceVisitor visitor, Field node, Field other) {
+    return visitor.checkValues(node.fileUri, other.fileUri, 'fileUri');
+  }
+
+  bool checkField_transformerFlags(
+      EquivalenceVisitor visitor, Field node, Field other) {
+    return visitor.checkValues(
+        node.transformerFlags, other.transformerFlags, 'transformerFlags');
+  }
+
+  bool checkField_getterReference(
+      EquivalenceVisitor visitor, Field node, Field other) {
+    return visitor.checkReferences(
+        node.getterReference, other.getterReference, 'getterReference');
+  }
+
+  bool checkField_fileOffset(
+      EquivalenceVisitor visitor, Field node, Field other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkConstructor_startFileOffset(
+      EquivalenceVisitor visitor, Constructor node, Constructor other) {
+    return visitor.checkValues(
+        node.startFileOffset, other.startFileOffset, 'startFileOffset');
+  }
+
+  bool checkConstructor_flags(
+      EquivalenceVisitor visitor, Constructor node, Constructor other) {
+    return visitor.checkValues(node.flags, other.flags, 'flags');
+  }
+
+  bool checkConstructor_function(
+      EquivalenceVisitor visitor, Constructor node, Constructor other) {
+    return visitor.checkNodes(node.function, other.function, 'function');
+  }
+
+  bool checkConstructor_initializers(
+      EquivalenceVisitor visitor, Constructor node, Constructor other) {
+    return visitor.checkLists(node.initializers, other.initializers,
+        visitor.checkNodes, 'initializers');
+  }
+
+  bool checkConstructor_fileEndOffset(
+      EquivalenceVisitor visitor, Constructor node, Constructor other) {
+    return visitor.checkValues(
+        node.fileEndOffset, other.fileEndOffset, 'fileEndOffset');
+  }
+
+  bool checkConstructor_annotations(
+      EquivalenceVisitor visitor, Constructor node, Constructor other) {
+    return visitor.checkLists(
+        node.annotations, other.annotations, visitor.checkNodes, 'annotations');
+  }
+
+  bool checkConstructor_name(
+      EquivalenceVisitor visitor, Constructor node, Constructor other) {
+    return visitor.checkNodes(node.name, other.name, 'name');
+  }
+
+  bool checkConstructor_fileUri(
+      EquivalenceVisitor visitor, Constructor node, Constructor other) {
+    return visitor.checkValues(node.fileUri, other.fileUri, 'fileUri');
+  }
+
+  bool checkConstructor_transformerFlags(
+      EquivalenceVisitor visitor, Constructor node, Constructor other) {
+    return visitor.checkValues(
+        node.transformerFlags, other.transformerFlags, 'transformerFlags');
+  }
+
+  bool checkConstructor_reference(
+      EquivalenceVisitor visitor, Constructor node, Constructor other) {
+    return visitor.checkReferences(
+        node.reference, other.reference, 'reference');
+  }
+
+  bool checkConstructor_fileOffset(
+      EquivalenceVisitor visitor, Constructor node, Constructor other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkRedirectingFactory_flags(EquivalenceVisitor visitor,
+      RedirectingFactory node, RedirectingFactory other) {
+    return visitor.checkValues(node.flags, other.flags, 'flags');
+  }
+
+  bool checkRedirectingFactory_typeArguments(EquivalenceVisitor visitor,
+      RedirectingFactory node, RedirectingFactory other) {
+    return visitor.checkLists(node.typeArguments, other.typeArguments,
+        visitor.checkNodes, 'typeArguments');
+  }
+
+  bool checkRedirectingFactory_targetReference(EquivalenceVisitor visitor,
+      RedirectingFactory node, RedirectingFactory other) {
+    return visitor.checkReferences(
+        node.targetReference, other.targetReference, 'targetReference');
+  }
+
+  bool checkRedirectingFactory_function(EquivalenceVisitor visitor,
+      RedirectingFactory node, RedirectingFactory other) {
+    return visitor.checkNodes(node.function, other.function, 'function');
+  }
+
+  bool checkRedirectingFactory_fileEndOffset(EquivalenceVisitor visitor,
+      RedirectingFactory node, RedirectingFactory other) {
+    return visitor.checkValues(
+        node.fileEndOffset, other.fileEndOffset, 'fileEndOffset');
+  }
+
+  bool checkRedirectingFactory_annotations(EquivalenceVisitor visitor,
+      RedirectingFactory node, RedirectingFactory other) {
+    return visitor.checkLists(
+        node.annotations, other.annotations, visitor.checkNodes, 'annotations');
+  }
+
+  bool checkRedirectingFactory_name(EquivalenceVisitor visitor,
+      RedirectingFactory node, RedirectingFactory other) {
+    return visitor.checkNodes(node.name, other.name, 'name');
+  }
+
+  bool checkRedirectingFactory_fileUri(EquivalenceVisitor visitor,
+      RedirectingFactory node, RedirectingFactory other) {
+    return visitor.checkValues(node.fileUri, other.fileUri, 'fileUri');
+  }
+
+  bool checkRedirectingFactory_transformerFlags(EquivalenceVisitor visitor,
+      RedirectingFactory node, RedirectingFactory other) {
+    return visitor.checkValues(
+        node.transformerFlags, other.transformerFlags, 'transformerFlags');
+  }
+
+  bool checkRedirectingFactory_reference(EquivalenceVisitor visitor,
+      RedirectingFactory node, RedirectingFactory other) {
+    return visitor.checkReferences(
+        node.reference, other.reference, 'reference');
+  }
+
+  bool checkRedirectingFactory_fileOffset(EquivalenceVisitor visitor,
+      RedirectingFactory node, RedirectingFactory other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkProcedure_startFileOffset(
+      EquivalenceVisitor visitor, Procedure node, Procedure other) {
+    return visitor.checkValues(
+        node.startFileOffset, other.startFileOffset, 'startFileOffset');
+  }
+
+  bool checkProcedure_kind(
+      EquivalenceVisitor visitor, Procedure node, Procedure other) {
+    return visitor.checkValues(node.kind, other.kind, 'kind');
+  }
+
+  bool checkProcedure_flags(
+      EquivalenceVisitor visitor, Procedure node, Procedure other) {
+    return visitor.checkValues(node.flags, other.flags, 'flags');
+  }
+
+  bool checkProcedure_function(
+      EquivalenceVisitor visitor, Procedure node, Procedure other) {
+    return visitor.checkNodes(node.function, other.function, 'function');
+  }
+
+  bool checkProcedure_stubKind(
+      EquivalenceVisitor visitor, Procedure node, Procedure other) {
+    return visitor.checkValues(node.stubKind, other.stubKind, 'stubKind');
+  }
+
+  bool checkProcedure_stubTargetReference(
+      EquivalenceVisitor visitor, Procedure node, Procedure other) {
+    return visitor.checkReferences(node.stubTargetReference,
+        other.stubTargetReference, 'stubTargetReference');
+  }
+
+  bool checkProcedure_fileEndOffset(
+      EquivalenceVisitor visitor, Procedure node, Procedure other) {
+    return visitor.checkValues(
+        node.fileEndOffset, other.fileEndOffset, 'fileEndOffset');
+  }
+
+  bool checkProcedure_annotations(
+      EquivalenceVisitor visitor, Procedure node, Procedure other) {
+    return visitor.checkLists(
+        node.annotations, other.annotations, visitor.checkNodes, 'annotations');
+  }
+
+  bool checkProcedure_name(
+      EquivalenceVisitor visitor, Procedure node, Procedure other) {
+    return visitor.checkNodes(node.name, other.name, 'name');
+  }
+
+  bool checkProcedure_fileUri(
+      EquivalenceVisitor visitor, Procedure node, Procedure other) {
+    return visitor.checkValues(node.fileUri, other.fileUri, 'fileUri');
+  }
+
+  bool checkProcedure_transformerFlags(
+      EquivalenceVisitor visitor, Procedure node, Procedure other) {
+    return visitor.checkValues(
+        node.transformerFlags, other.transformerFlags, 'transformerFlags');
+  }
+
+  bool checkProcedure_reference(
+      EquivalenceVisitor visitor, Procedure node, Procedure other) {
+    return visitor.checkReferences(
+        node.reference, other.reference, 'reference');
+  }
+
+  bool checkProcedure_fileOffset(
+      EquivalenceVisitor visitor, Procedure node, Procedure other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkLibraryDependency_flags(EquivalenceVisitor visitor,
+      LibraryDependency node, LibraryDependency other) {
+    return visitor.checkValues(node.flags, other.flags, 'flags');
+  }
+
+  bool checkLibraryDependency_annotations(EquivalenceVisitor visitor,
+      LibraryDependency node, LibraryDependency other) {
+    return visitor.checkLists(
+        node.annotations, other.annotations, visitor.checkNodes, 'annotations');
+  }
+
+  bool checkLibraryDependency_importedLibraryReference(
+      EquivalenceVisitor visitor,
+      LibraryDependency node,
+      LibraryDependency other) {
+    return visitor.checkReferences(node.importedLibraryReference,
+        other.importedLibraryReference, 'importedLibraryReference');
+  }
+
+  bool checkLibraryDependency_name(EquivalenceVisitor visitor,
+      LibraryDependency node, LibraryDependency other) {
+    return visitor.checkValues(node.name, other.name, 'name');
+  }
+
+  bool checkLibraryDependency_combinators(EquivalenceVisitor visitor,
+      LibraryDependency node, LibraryDependency other) {
+    return visitor.checkLists(
+        node.combinators, other.combinators, visitor.checkNodes, 'combinators');
+  }
+
+  bool checkLibraryDependency_fileOffset(EquivalenceVisitor visitor,
+      LibraryDependency node, LibraryDependency other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkLibraryPart_annotations(
+      EquivalenceVisitor visitor, LibraryPart node, LibraryPart other) {
+    return visitor.checkLists(
+        node.annotations, other.annotations, visitor.checkNodes, 'annotations');
+  }
+
+  bool checkLibraryPart_partUri(
+      EquivalenceVisitor visitor, LibraryPart node, LibraryPart other) {
+    return visitor.checkValues(node.partUri, other.partUri, 'partUri');
+  }
+
+  bool checkLibraryPart_fileOffset(
+      EquivalenceVisitor visitor, LibraryPart node, LibraryPart other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkCombinator_isShow(
+      EquivalenceVisitor visitor, Combinator node, Combinator other) {
+    return visitor.checkValues(node.isShow, other.isShow, 'isShow');
+  }
+
+  bool checkCombinator_names(
+      EquivalenceVisitor visitor, Combinator node, Combinator other) {
+    return visitor.checkLists(
+        node.names, other.names, visitor.checkValues, 'names');
+  }
+
+  bool checkCombinator_fileOffset(
+      EquivalenceVisitor visitor, Combinator node, Combinator other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkInvalidInitializer_isSynthetic(EquivalenceVisitor visitor,
+      InvalidInitializer node, InvalidInitializer other) {
+    return visitor.checkValues(
+        node.isSynthetic, other.isSynthetic, 'isSynthetic');
+  }
+
+  bool checkInvalidInitializer_fileOffset(EquivalenceVisitor visitor,
+      InvalidInitializer node, InvalidInitializer other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkFieldInitializer_fieldReference(EquivalenceVisitor visitor,
+      FieldInitializer node, FieldInitializer other) {
+    return visitor.checkReferences(
+        node.fieldReference, other.fieldReference, 'fieldReference');
+  }
+
+  bool checkFieldInitializer_value(EquivalenceVisitor visitor,
+      FieldInitializer node, FieldInitializer other) {
+    return visitor.checkNodes(node.value, other.value, 'value');
+  }
+
+  bool checkFieldInitializer_isSynthetic(EquivalenceVisitor visitor,
+      FieldInitializer node, FieldInitializer other) {
+    return visitor.checkValues(
+        node.isSynthetic, other.isSynthetic, 'isSynthetic');
+  }
+
+  bool checkFieldInitializer_fileOffset(EquivalenceVisitor visitor,
+      FieldInitializer node, FieldInitializer other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkSuperInitializer_targetReference(EquivalenceVisitor visitor,
+      SuperInitializer node, SuperInitializer other) {
+    return visitor.checkReferences(
+        node.targetReference, other.targetReference, 'targetReference');
+  }
+
+  bool checkSuperInitializer_arguments(EquivalenceVisitor visitor,
+      SuperInitializer node, SuperInitializer other) {
+    return visitor.checkNodes(node.arguments, other.arguments, 'arguments');
+  }
+
+  bool checkSuperInitializer_isSynthetic(EquivalenceVisitor visitor,
+      SuperInitializer node, SuperInitializer other) {
+    return visitor.checkValues(
+        node.isSynthetic, other.isSynthetic, 'isSynthetic');
+  }
+
+  bool checkSuperInitializer_fileOffset(EquivalenceVisitor visitor,
+      SuperInitializer node, SuperInitializer other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkRedirectingInitializer_targetReference(EquivalenceVisitor visitor,
+      RedirectingInitializer node, RedirectingInitializer other) {
+    return visitor.checkReferences(
+        node.targetReference, other.targetReference, 'targetReference');
+  }
+
+  bool checkRedirectingInitializer_arguments(EquivalenceVisitor visitor,
+      RedirectingInitializer node, RedirectingInitializer other) {
+    return visitor.checkNodes(node.arguments, other.arguments, 'arguments');
+  }
+
+  bool checkRedirectingInitializer_isSynthetic(EquivalenceVisitor visitor,
+      RedirectingInitializer node, RedirectingInitializer other) {
+    return visitor.checkValues(
+        node.isSynthetic, other.isSynthetic, 'isSynthetic');
+  }
+
+  bool checkRedirectingInitializer_fileOffset(EquivalenceVisitor visitor,
+      RedirectingInitializer node, RedirectingInitializer other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkLocalInitializer_variable(EquivalenceVisitor visitor,
+      LocalInitializer node, LocalInitializer other) {
+    return visitor.checkNodes(node.variable, other.variable, 'variable');
+  }
+
+  bool checkLocalInitializer_isSynthetic(EquivalenceVisitor visitor,
+      LocalInitializer node, LocalInitializer other) {
+    return visitor.checkValues(
+        node.isSynthetic, other.isSynthetic, 'isSynthetic');
+  }
+
+  bool checkLocalInitializer_fileOffset(EquivalenceVisitor visitor,
+      LocalInitializer node, LocalInitializer other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkAssertInitializer_statement(EquivalenceVisitor visitor,
+      AssertInitializer node, AssertInitializer other) {
+    return visitor.checkNodes(node.statement, other.statement, 'statement');
+  }
+
+  bool checkAssertInitializer_isSynthetic(EquivalenceVisitor visitor,
+      AssertInitializer node, AssertInitializer other) {
+    return visitor.checkValues(
+        node.isSynthetic, other.isSynthetic, 'isSynthetic');
+  }
+
+  bool checkAssertInitializer_fileOffset(EquivalenceVisitor visitor,
+      AssertInitializer node, AssertInitializer other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkFunctionNode_fileEndOffset(
+      EquivalenceVisitor visitor, FunctionNode node, FunctionNode other) {
+    return visitor.checkValues(
+        node.fileEndOffset, other.fileEndOffset, 'fileEndOffset');
+  }
+
+  bool checkFunctionNode_asyncMarker(
+      EquivalenceVisitor visitor, FunctionNode node, FunctionNode other) {
+    return visitor.checkValues(
+        node.asyncMarker, other.asyncMarker, 'asyncMarker');
+  }
+
+  bool checkFunctionNode_dartAsyncMarker(
+      EquivalenceVisitor visitor, FunctionNode node, FunctionNode other) {
+    return visitor.checkValues(
+        node.dartAsyncMarker, other.dartAsyncMarker, 'dartAsyncMarker');
+  }
+
+  bool checkFunctionNode_typeParameters(
+      EquivalenceVisitor visitor, FunctionNode node, FunctionNode other) {
+    return visitor.checkLists(node.typeParameters, other.typeParameters,
+        visitor.checkNodes, 'typeParameters');
+  }
+
+  bool checkFunctionNode_requiredParameterCount(
+      EquivalenceVisitor visitor, FunctionNode node, FunctionNode other) {
+    return visitor.checkValues(node.requiredParameterCount,
+        other.requiredParameterCount, 'requiredParameterCount');
+  }
+
+  bool checkFunctionNode_positionalParameters(
+      EquivalenceVisitor visitor, FunctionNode node, FunctionNode other) {
+    return visitor.checkLists(node.positionalParameters,
+        other.positionalParameters, visitor.checkNodes, 'positionalParameters');
+  }
+
+  bool checkFunctionNode_namedParameters(
+      EquivalenceVisitor visitor, FunctionNode node, FunctionNode other) {
+    return visitor.checkLists(node.namedParameters, other.namedParameters,
+        visitor.checkNodes, 'namedParameters');
+  }
+
+  bool checkFunctionNode_returnType(
+      EquivalenceVisitor visitor, FunctionNode node, FunctionNode other) {
+    return visitor.checkNodes(node.returnType, other.returnType, 'returnType');
+  }
+
+  bool checkFunctionNode_body(
+      EquivalenceVisitor visitor, FunctionNode node, FunctionNode other) {
+    return visitor.checkNodes(node.body, other.body, 'body');
+  }
+
+  bool checkFunctionNode_futureValueType(
+      EquivalenceVisitor visitor, FunctionNode node, FunctionNode other) {
+    return visitor.checkNodes(
+        node.futureValueType, other.futureValueType, 'futureValueType');
+  }
+
+  bool checkFunctionNode_lazyBuilder(
+      EquivalenceVisitor visitor, FunctionNode node, FunctionNode other) {
+    return visitor.checkValues(
+        node.lazyBuilder, other.lazyBuilder, 'lazyBuilder');
+  }
+
+  bool checkFunctionNode_fileOffset(
+      EquivalenceVisitor visitor, FunctionNode node, FunctionNode other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkInvalidExpression_message(EquivalenceVisitor visitor,
+      InvalidExpression node, InvalidExpression other) {
+    return visitor.checkValues(node.message, other.message, 'message');
+  }
+
+  bool checkInvalidExpression_fileOffset(EquivalenceVisitor visitor,
+      InvalidExpression node, InvalidExpression other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkVariableGet_variable(
+      EquivalenceVisitor visitor, VariableGet node, VariableGet other) {
+    return visitor.checkDeclarations(node.variable, other.variable, 'variable');
+  }
+
+  bool checkVariableGet_promotedType(
+      EquivalenceVisitor visitor, VariableGet node, VariableGet other) {
+    return visitor.checkNodes(
+        node.promotedType, other.promotedType, 'promotedType');
+  }
+
+  bool checkVariableGet_fileOffset(
+      EquivalenceVisitor visitor, VariableGet node, VariableGet other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkVariableSet_variable(
+      EquivalenceVisitor visitor, VariableSet node, VariableSet other) {
+    return visitor.checkDeclarations(node.variable, other.variable, 'variable');
+  }
+
+  bool checkVariableSet_value(
+      EquivalenceVisitor visitor, VariableSet node, VariableSet other) {
+    return visitor.checkNodes(node.value, other.value, 'value');
+  }
+
+  bool checkVariableSet_fileOffset(
+      EquivalenceVisitor visitor, VariableSet node, VariableSet other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkDynamicGet_kind(
+      EquivalenceVisitor visitor, DynamicGet node, DynamicGet other) {
+    return visitor.checkValues(node.kind, other.kind, 'kind');
+  }
+
+  bool checkDynamicGet_receiver(
+      EquivalenceVisitor visitor, DynamicGet node, DynamicGet other) {
+    return visitor.checkNodes(node.receiver, other.receiver, 'receiver');
+  }
+
+  bool checkDynamicGet_name(
+      EquivalenceVisitor visitor, DynamicGet node, DynamicGet other) {
+    return visitor.checkNodes(node.name, other.name, 'name');
+  }
+
+  bool checkDynamicGet_fileOffset(
+      EquivalenceVisitor visitor, DynamicGet node, DynamicGet other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkInstanceGet_kind(
+      EquivalenceVisitor visitor, InstanceGet node, InstanceGet other) {
+    return visitor.checkValues(node.kind, other.kind, 'kind');
+  }
+
+  bool checkInstanceGet_receiver(
+      EquivalenceVisitor visitor, InstanceGet node, InstanceGet other) {
+    return visitor.checkNodes(node.receiver, other.receiver, 'receiver');
+  }
+
+  bool checkInstanceGet_name(
+      EquivalenceVisitor visitor, InstanceGet node, InstanceGet other) {
+    return visitor.checkNodes(node.name, other.name, 'name');
+  }
+
+  bool checkInstanceGet_resultType(
+      EquivalenceVisitor visitor, InstanceGet node, InstanceGet other) {
+    return visitor.checkNodes(node.resultType, other.resultType, 'resultType');
+  }
+
+  bool checkInstanceGet_interfaceTargetReference(
+      EquivalenceVisitor visitor, InstanceGet node, InstanceGet other) {
+    return visitor.checkReferences(node.interfaceTargetReference,
+        other.interfaceTargetReference, 'interfaceTargetReference');
+  }
+
+  bool checkInstanceGet_fileOffset(
+      EquivalenceVisitor visitor, InstanceGet node, InstanceGet other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkFunctionTearOff_receiver(
+      EquivalenceVisitor visitor, FunctionTearOff node, FunctionTearOff other) {
+    return visitor.checkNodes(node.receiver, other.receiver, 'receiver');
+  }
+
+  bool checkFunctionTearOff_fileOffset(
+      EquivalenceVisitor visitor, FunctionTearOff node, FunctionTearOff other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkInstanceTearOff_kind(
+      EquivalenceVisitor visitor, InstanceTearOff node, InstanceTearOff other) {
+    return visitor.checkValues(node.kind, other.kind, 'kind');
+  }
+
+  bool checkInstanceTearOff_receiver(
+      EquivalenceVisitor visitor, InstanceTearOff node, InstanceTearOff other) {
+    return visitor.checkNodes(node.receiver, other.receiver, 'receiver');
+  }
+
+  bool checkInstanceTearOff_name(
+      EquivalenceVisitor visitor, InstanceTearOff node, InstanceTearOff other) {
+    return visitor.checkNodes(node.name, other.name, 'name');
+  }
+
+  bool checkInstanceTearOff_resultType(
+      EquivalenceVisitor visitor, InstanceTearOff node, InstanceTearOff other) {
+    return visitor.checkNodes(node.resultType, other.resultType, 'resultType');
+  }
+
+  bool checkInstanceTearOff_interfaceTargetReference(
+      EquivalenceVisitor visitor, InstanceTearOff node, InstanceTearOff other) {
+    return visitor.checkReferences(node.interfaceTargetReference,
+        other.interfaceTargetReference, 'interfaceTargetReference');
+  }
+
+  bool checkInstanceTearOff_fileOffset(
+      EquivalenceVisitor visitor, InstanceTearOff node, InstanceTearOff other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkDynamicSet_kind(
+      EquivalenceVisitor visitor, DynamicSet node, DynamicSet other) {
+    return visitor.checkValues(node.kind, other.kind, 'kind');
+  }
+
+  bool checkDynamicSet_receiver(
+      EquivalenceVisitor visitor, DynamicSet node, DynamicSet other) {
+    return visitor.checkNodes(node.receiver, other.receiver, 'receiver');
+  }
+
+  bool checkDynamicSet_name(
+      EquivalenceVisitor visitor, DynamicSet node, DynamicSet other) {
+    return visitor.checkNodes(node.name, other.name, 'name');
+  }
+
+  bool checkDynamicSet_value(
+      EquivalenceVisitor visitor, DynamicSet node, DynamicSet other) {
+    return visitor.checkNodes(node.value, other.value, 'value');
+  }
+
+  bool checkDynamicSet_fileOffset(
+      EquivalenceVisitor visitor, DynamicSet node, DynamicSet other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkInstanceSet_kind(
+      EquivalenceVisitor visitor, InstanceSet node, InstanceSet other) {
+    return visitor.checkValues(node.kind, other.kind, 'kind');
+  }
+
+  bool checkInstanceSet_receiver(
+      EquivalenceVisitor visitor, InstanceSet node, InstanceSet other) {
+    return visitor.checkNodes(node.receiver, other.receiver, 'receiver');
+  }
+
+  bool checkInstanceSet_name(
+      EquivalenceVisitor visitor, InstanceSet node, InstanceSet other) {
+    return visitor.checkNodes(node.name, other.name, 'name');
+  }
+
+  bool checkInstanceSet_value(
+      EquivalenceVisitor visitor, InstanceSet node, InstanceSet other) {
+    return visitor.checkNodes(node.value, other.value, 'value');
+  }
+
+  bool checkInstanceSet_interfaceTargetReference(
+      EquivalenceVisitor visitor, InstanceSet node, InstanceSet other) {
+    return visitor.checkReferences(node.interfaceTargetReference,
+        other.interfaceTargetReference, 'interfaceTargetReference');
+  }
+
+  bool checkInstanceSet_fileOffset(
+      EquivalenceVisitor visitor, InstanceSet node, InstanceSet other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkSuperPropertyGet_name(EquivalenceVisitor visitor,
+      SuperPropertyGet node, SuperPropertyGet other) {
+    return visitor.checkNodes(node.name, other.name, 'name');
+  }
+
+  bool checkSuperPropertyGet_interfaceTargetReference(
+      EquivalenceVisitor visitor,
+      SuperPropertyGet node,
+      SuperPropertyGet other) {
+    return visitor.checkReferences(node.interfaceTargetReference,
+        other.interfaceTargetReference, 'interfaceTargetReference');
+  }
+
+  bool checkSuperPropertyGet_fileOffset(EquivalenceVisitor visitor,
+      SuperPropertyGet node, SuperPropertyGet other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkSuperPropertySet_name(EquivalenceVisitor visitor,
+      SuperPropertySet node, SuperPropertySet other) {
+    return visitor.checkNodes(node.name, other.name, 'name');
+  }
+
+  bool checkSuperPropertySet_value(EquivalenceVisitor visitor,
+      SuperPropertySet node, SuperPropertySet other) {
+    return visitor.checkNodes(node.value, other.value, 'value');
+  }
+
+  bool checkSuperPropertySet_interfaceTargetReference(
+      EquivalenceVisitor visitor,
+      SuperPropertySet node,
+      SuperPropertySet other) {
+    return visitor.checkReferences(node.interfaceTargetReference,
+        other.interfaceTargetReference, 'interfaceTargetReference');
+  }
+
+  bool checkSuperPropertySet_fileOffset(EquivalenceVisitor visitor,
+      SuperPropertySet node, SuperPropertySet other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkStaticGet_targetReference(
+      EquivalenceVisitor visitor, StaticGet node, StaticGet other) {
+    return visitor.checkReferences(
+        node.targetReference, other.targetReference, 'targetReference');
+  }
+
+  bool checkStaticGet_fileOffset(
+      EquivalenceVisitor visitor, StaticGet node, StaticGet other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkStaticTearOff_targetReference(
+      EquivalenceVisitor visitor, StaticTearOff node, StaticTearOff other) {
+    return visitor.checkReferences(
+        node.targetReference, other.targetReference, 'targetReference');
+  }
+
+  bool checkStaticTearOff_fileOffset(
+      EquivalenceVisitor visitor, StaticTearOff node, StaticTearOff other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkStaticSet_targetReference(
+      EquivalenceVisitor visitor, StaticSet node, StaticSet other) {
+    return visitor.checkReferences(
+        node.targetReference, other.targetReference, 'targetReference');
+  }
+
+  bool checkStaticSet_value(
+      EquivalenceVisitor visitor, StaticSet node, StaticSet other) {
+    return visitor.checkNodes(node.value, other.value, 'value');
+  }
+
+  bool checkStaticSet_fileOffset(
+      EquivalenceVisitor visitor, StaticSet node, StaticSet other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkDynamicInvocation_kind(EquivalenceVisitor visitor,
+      DynamicInvocation node, DynamicInvocation other) {
+    return visitor.checkValues(node.kind, other.kind, 'kind');
+  }
+
+  bool checkDynamicInvocation_receiver(EquivalenceVisitor visitor,
+      DynamicInvocation node, DynamicInvocation other) {
+    return visitor.checkNodes(node.receiver, other.receiver, 'receiver');
+  }
+
+  bool checkDynamicInvocation_name(EquivalenceVisitor visitor,
+      DynamicInvocation node, DynamicInvocation other) {
+    return visitor.checkNodes(node.name, other.name, 'name');
+  }
+
+  bool checkDynamicInvocation_arguments(EquivalenceVisitor visitor,
+      DynamicInvocation node, DynamicInvocation other) {
+    return visitor.checkNodes(node.arguments, other.arguments, 'arguments');
+  }
+
+  bool checkDynamicInvocation_fileOffset(EquivalenceVisitor visitor,
+      DynamicInvocation node, DynamicInvocation other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkInstanceInvocation_kind(EquivalenceVisitor visitor,
+      InstanceInvocation node, InstanceInvocation other) {
+    return visitor.checkValues(node.kind, other.kind, 'kind');
+  }
+
+  bool checkInstanceInvocation_receiver(EquivalenceVisitor visitor,
+      InstanceInvocation node, InstanceInvocation other) {
+    return visitor.checkNodes(node.receiver, other.receiver, 'receiver');
+  }
+
+  bool checkInstanceInvocation_name(EquivalenceVisitor visitor,
+      InstanceInvocation node, InstanceInvocation other) {
+    return visitor.checkNodes(node.name, other.name, 'name');
+  }
+
+  bool checkInstanceInvocation_arguments(EquivalenceVisitor visitor,
+      InstanceInvocation node, InstanceInvocation other) {
+    return visitor.checkNodes(node.arguments, other.arguments, 'arguments');
+  }
+
+  bool checkInstanceInvocation_flags(EquivalenceVisitor visitor,
+      InstanceInvocation node, InstanceInvocation other) {
+    return visitor.checkValues(node.flags, other.flags, 'flags');
+  }
+
+  bool checkInstanceInvocation_functionType(EquivalenceVisitor visitor,
+      InstanceInvocation node, InstanceInvocation other) {
+    return visitor.checkNodes(
+        node.functionType, other.functionType, 'functionType');
+  }
+
+  bool checkInstanceInvocation_interfaceTargetReference(
+      EquivalenceVisitor visitor,
+      InstanceInvocation node,
+      InstanceInvocation other) {
+    return visitor.checkReferences(node.interfaceTargetReference,
+        other.interfaceTargetReference, 'interfaceTargetReference');
+  }
+
+  bool checkInstanceInvocation_fileOffset(EquivalenceVisitor visitor,
+      InstanceInvocation node, InstanceInvocation other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkInstanceGetterInvocation_kind(EquivalenceVisitor visitor,
+      InstanceGetterInvocation node, InstanceGetterInvocation other) {
+    return visitor.checkValues(node.kind, other.kind, 'kind');
+  }
+
+  bool checkInstanceGetterInvocation_receiver(EquivalenceVisitor visitor,
+      InstanceGetterInvocation node, InstanceGetterInvocation other) {
+    return visitor.checkNodes(node.receiver, other.receiver, 'receiver');
+  }
+
+  bool checkInstanceGetterInvocation_name(EquivalenceVisitor visitor,
+      InstanceGetterInvocation node, InstanceGetterInvocation other) {
+    return visitor.checkNodes(node.name, other.name, 'name');
+  }
+
+  bool checkInstanceGetterInvocation_arguments(EquivalenceVisitor visitor,
+      InstanceGetterInvocation node, InstanceGetterInvocation other) {
+    return visitor.checkNodes(node.arguments, other.arguments, 'arguments');
+  }
+
+  bool checkInstanceGetterInvocation_flags(EquivalenceVisitor visitor,
+      InstanceGetterInvocation node, InstanceGetterInvocation other) {
+    return visitor.checkValues(node.flags, other.flags, 'flags');
+  }
+
+  bool checkInstanceGetterInvocation_functionType(EquivalenceVisitor visitor,
+      InstanceGetterInvocation node, InstanceGetterInvocation other) {
+    return visitor.checkNodes(
+        node.functionType, other.functionType, 'functionType');
+  }
+
+  bool checkInstanceGetterInvocation_interfaceTargetReference(
+      EquivalenceVisitor visitor,
+      InstanceGetterInvocation node,
+      InstanceGetterInvocation other) {
+    return visitor.checkReferences(node.interfaceTargetReference,
+        other.interfaceTargetReference, 'interfaceTargetReference');
+  }
+
+  bool checkInstanceGetterInvocation_fileOffset(EquivalenceVisitor visitor,
+      InstanceGetterInvocation node, InstanceGetterInvocation other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkFunctionInvocation_kind(EquivalenceVisitor visitor,
+      FunctionInvocation node, FunctionInvocation other) {
+    return visitor.checkValues(node.kind, other.kind, 'kind');
+  }
+
+  bool checkFunctionInvocation_receiver(EquivalenceVisitor visitor,
+      FunctionInvocation node, FunctionInvocation other) {
+    return visitor.checkNodes(node.receiver, other.receiver, 'receiver');
+  }
+
+  bool checkFunctionInvocation_arguments(EquivalenceVisitor visitor,
+      FunctionInvocation node, FunctionInvocation other) {
+    return visitor.checkNodes(node.arguments, other.arguments, 'arguments');
+  }
+
+  bool checkFunctionInvocation_functionType(EquivalenceVisitor visitor,
+      FunctionInvocation node, FunctionInvocation other) {
+    return visitor.checkNodes(
+        node.functionType, other.functionType, 'functionType');
+  }
+
+  bool checkFunctionInvocation_fileOffset(EquivalenceVisitor visitor,
+      FunctionInvocation node, FunctionInvocation other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkLocalFunctionInvocation_variable(EquivalenceVisitor visitor,
+      LocalFunctionInvocation node, LocalFunctionInvocation other) {
+    return visitor.checkDeclarations(node.variable, other.variable, 'variable');
+  }
+
+  bool checkLocalFunctionInvocation_arguments(EquivalenceVisitor visitor,
+      LocalFunctionInvocation node, LocalFunctionInvocation other) {
+    return visitor.checkNodes(node.arguments, other.arguments, 'arguments');
+  }
+
+  bool checkLocalFunctionInvocation_functionType(EquivalenceVisitor visitor,
+      LocalFunctionInvocation node, LocalFunctionInvocation other) {
+    return visitor.checkNodes(
+        node.functionType, other.functionType, 'functionType');
+  }
+
+  bool checkLocalFunctionInvocation_fileOffset(EquivalenceVisitor visitor,
+      LocalFunctionInvocation node, LocalFunctionInvocation other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkSuperMethodInvocation_name(EquivalenceVisitor visitor,
+      SuperMethodInvocation node, SuperMethodInvocation other) {
+    return visitor.checkNodes(node.name, other.name, 'name');
+  }
+
+  bool checkSuperMethodInvocation_arguments(EquivalenceVisitor visitor,
+      SuperMethodInvocation node, SuperMethodInvocation other) {
+    return visitor.checkNodes(node.arguments, other.arguments, 'arguments');
+  }
+
+  bool checkSuperMethodInvocation_interfaceTargetReference(
+      EquivalenceVisitor visitor,
+      SuperMethodInvocation node,
+      SuperMethodInvocation other) {
+    return visitor.checkReferences(node.interfaceTargetReference,
+        other.interfaceTargetReference, 'interfaceTargetReference');
+  }
+
+  bool checkSuperMethodInvocation_fileOffset(EquivalenceVisitor visitor,
+      SuperMethodInvocation node, SuperMethodInvocation other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkStaticInvocation_targetReference(EquivalenceVisitor visitor,
+      StaticInvocation node, StaticInvocation other) {
+    return visitor.checkReferences(
+        node.targetReference, other.targetReference, 'targetReference');
+  }
+
+  bool checkStaticInvocation_arguments(EquivalenceVisitor visitor,
+      StaticInvocation node, StaticInvocation other) {
+    return visitor.checkNodes(node.arguments, other.arguments, 'arguments');
+  }
+
+  bool checkStaticInvocation_isConst(EquivalenceVisitor visitor,
+      StaticInvocation node, StaticInvocation other) {
+    return visitor.checkValues(node.isConst, other.isConst, 'isConst');
+  }
+
+  bool checkStaticInvocation_fileOffset(EquivalenceVisitor visitor,
+      StaticInvocation node, StaticInvocation other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkConstructorInvocation_targetReference(EquivalenceVisitor visitor,
+      ConstructorInvocation node, ConstructorInvocation other) {
+    return visitor.checkReferences(
+        node.targetReference, other.targetReference, 'targetReference');
+  }
+
+  bool checkConstructorInvocation_arguments(EquivalenceVisitor visitor,
+      ConstructorInvocation node, ConstructorInvocation other) {
+    return visitor.checkNodes(node.arguments, other.arguments, 'arguments');
+  }
+
+  bool checkConstructorInvocation_isConst(EquivalenceVisitor visitor,
+      ConstructorInvocation node, ConstructorInvocation other) {
+    return visitor.checkValues(node.isConst, other.isConst, 'isConst');
+  }
+
+  bool checkConstructorInvocation_fileOffset(EquivalenceVisitor visitor,
+      ConstructorInvocation node, ConstructorInvocation other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkEqualsNull_expression(
+      EquivalenceVisitor visitor, EqualsNull node, EqualsNull other) {
+    return visitor.checkNodes(node.expression, other.expression, 'expression');
+  }
+
+  bool checkEqualsNull_fileOffset(
+      EquivalenceVisitor visitor, EqualsNull node, EqualsNull other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkEqualsCall_left(
+      EquivalenceVisitor visitor, EqualsCall node, EqualsCall other) {
+    return visitor.checkNodes(node.left, other.left, 'left');
+  }
+
+  bool checkEqualsCall_right(
+      EquivalenceVisitor visitor, EqualsCall node, EqualsCall other) {
+    return visitor.checkNodes(node.right, other.right, 'right');
+  }
+
+  bool checkEqualsCall_functionType(
+      EquivalenceVisitor visitor, EqualsCall node, EqualsCall other) {
+    return visitor.checkNodes(
+        node.functionType, other.functionType, 'functionType');
+  }
+
+  bool checkEqualsCall_interfaceTargetReference(
+      EquivalenceVisitor visitor, EqualsCall node, EqualsCall other) {
+    return visitor.checkReferences(node.interfaceTargetReference,
+        other.interfaceTargetReference, 'interfaceTargetReference');
+  }
+
+  bool checkEqualsCall_fileOffset(
+      EquivalenceVisitor visitor, EqualsCall node, EqualsCall other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkInstantiation_expression(
+      EquivalenceVisitor visitor, Instantiation node, Instantiation other) {
+    return visitor.checkNodes(node.expression, other.expression, 'expression');
+  }
+
+  bool checkInstantiation_typeArguments(
+      EquivalenceVisitor visitor, Instantiation node, Instantiation other) {
+    return visitor.checkLists(node.typeArguments, other.typeArguments,
+        visitor.checkNodes, 'typeArguments');
+  }
+
+  bool checkInstantiation_fileOffset(
+      EquivalenceVisitor visitor, Instantiation node, Instantiation other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkNot_operand(EquivalenceVisitor visitor, Not node, Not other) {
+    return visitor.checkNodes(node.operand, other.operand, 'operand');
+  }
+
+  bool checkNot_fileOffset(EquivalenceVisitor visitor, Not node, Not other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkLogicalExpression_left(EquivalenceVisitor visitor,
+      LogicalExpression node, LogicalExpression other) {
+    return visitor.checkNodes(node.left, other.left, 'left');
+  }
+
+  bool checkLogicalExpression_operatorEnum(EquivalenceVisitor visitor,
+      LogicalExpression node, LogicalExpression other) {
+    return visitor.checkValues(
+        node.operatorEnum, other.operatorEnum, 'operatorEnum');
+  }
+
+  bool checkLogicalExpression_right(EquivalenceVisitor visitor,
+      LogicalExpression node, LogicalExpression other) {
+    return visitor.checkNodes(node.right, other.right, 'right');
+  }
+
+  bool checkLogicalExpression_fileOffset(EquivalenceVisitor visitor,
+      LogicalExpression node, LogicalExpression other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkConditionalExpression_condition(EquivalenceVisitor visitor,
+      ConditionalExpression node, ConditionalExpression other) {
+    return visitor.checkNodes(node.condition, other.condition, 'condition');
+  }
+
+  bool checkConditionalExpression_then(EquivalenceVisitor visitor,
+      ConditionalExpression node, ConditionalExpression other) {
+    return visitor.checkNodes(node.then, other.then, 'then');
+  }
+
+  bool checkConditionalExpression_otherwise(EquivalenceVisitor visitor,
+      ConditionalExpression node, ConditionalExpression other) {
+    return visitor.checkNodes(node.otherwise, other.otherwise, 'otherwise');
+  }
+
+  bool checkConditionalExpression_staticType(EquivalenceVisitor visitor,
+      ConditionalExpression node, ConditionalExpression other) {
+    return visitor.checkNodes(node.staticType, other.staticType, 'staticType');
+  }
+
+  bool checkConditionalExpression_fileOffset(EquivalenceVisitor visitor,
+      ConditionalExpression node, ConditionalExpression other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkStringConcatenation_expressions(EquivalenceVisitor visitor,
+      StringConcatenation node, StringConcatenation other) {
+    return visitor.checkLists(
+        node.expressions, other.expressions, visitor.checkNodes, 'expressions');
+  }
+
+  bool checkStringConcatenation_fileOffset(EquivalenceVisitor visitor,
+      StringConcatenation node, StringConcatenation other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkListConcatenation_typeArgument(EquivalenceVisitor visitor,
+      ListConcatenation node, ListConcatenation other) {
+    return visitor.checkNodes(
+        node.typeArgument, other.typeArgument, 'typeArgument');
+  }
+
+  bool checkListConcatenation_lists(EquivalenceVisitor visitor,
+      ListConcatenation node, ListConcatenation other) {
+    return visitor.checkLists(
+        node.lists, other.lists, visitor.checkNodes, 'lists');
+  }
+
+  bool checkListConcatenation_fileOffset(EquivalenceVisitor visitor,
+      ListConcatenation node, ListConcatenation other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkSetConcatenation_typeArgument(EquivalenceVisitor visitor,
+      SetConcatenation node, SetConcatenation other) {
+    return visitor.checkNodes(
+        node.typeArgument, other.typeArgument, 'typeArgument');
+  }
+
+  bool checkSetConcatenation_sets(EquivalenceVisitor visitor,
+      SetConcatenation node, SetConcatenation other) {
+    return visitor.checkLists(
+        node.sets, other.sets, visitor.checkNodes, 'sets');
+  }
+
+  bool checkSetConcatenation_fileOffset(EquivalenceVisitor visitor,
+      SetConcatenation node, SetConcatenation other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkMapConcatenation_keyType(EquivalenceVisitor visitor,
+      MapConcatenation node, MapConcatenation other) {
+    return visitor.checkNodes(node.keyType, other.keyType, 'keyType');
+  }
+
+  bool checkMapConcatenation_valueType(EquivalenceVisitor visitor,
+      MapConcatenation node, MapConcatenation other) {
+    return visitor.checkNodes(node.valueType, other.valueType, 'valueType');
+  }
+
+  bool checkMapConcatenation_maps(EquivalenceVisitor visitor,
+      MapConcatenation node, MapConcatenation other) {
+    return visitor.checkLists(
+        node.maps, other.maps, visitor.checkNodes, 'maps');
+  }
+
+  bool checkMapConcatenation_fileOffset(EquivalenceVisitor visitor,
+      MapConcatenation node, MapConcatenation other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkInstanceCreation_classReference(EquivalenceVisitor visitor,
+      InstanceCreation node, InstanceCreation other) {
+    return visitor.checkReferences(
+        node.classReference, other.classReference, 'classReference');
+  }
+
+  bool checkInstanceCreation_typeArguments(EquivalenceVisitor visitor,
+      InstanceCreation node, InstanceCreation other) {
+    return visitor.checkLists(node.typeArguments, other.typeArguments,
+        visitor.checkNodes, 'typeArguments');
+  }
+
+  bool checkInstanceCreation_fieldValues(EquivalenceVisitor visitor,
+      InstanceCreation node, InstanceCreation other) {
+    return visitor.checkMaps(
+        node.fieldValues,
+        other.fieldValues,
+        visitor.matchReferences,
+        visitor.checkReferences,
+        visitor.checkNodes,
+        'fieldValues');
+  }
+
+  bool checkInstanceCreation_asserts(EquivalenceVisitor visitor,
+      InstanceCreation node, InstanceCreation other) {
+    return visitor.checkLists(
+        node.asserts, other.asserts, visitor.checkNodes, 'asserts');
+  }
+
+  bool checkInstanceCreation_unusedArguments(EquivalenceVisitor visitor,
+      InstanceCreation node, InstanceCreation other) {
+    return visitor.checkLists(node.unusedArguments, other.unusedArguments,
+        visitor.checkNodes, 'unusedArguments');
+  }
+
+  bool checkInstanceCreation_fileOffset(EquivalenceVisitor visitor,
+      InstanceCreation node, InstanceCreation other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkFileUriExpression_fileUri(EquivalenceVisitor visitor,
+      FileUriExpression node, FileUriExpression other) {
+    return visitor.checkValues(node.fileUri, other.fileUri, 'fileUri');
+  }
+
+  bool checkFileUriExpression_expression(EquivalenceVisitor visitor,
+      FileUriExpression node, FileUriExpression other) {
+    return visitor.checkNodes(node.expression, other.expression, 'expression');
+  }
+
+  bool checkFileUriExpression_fileOffset(EquivalenceVisitor visitor,
+      FileUriExpression node, FileUriExpression other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkIsExpression_flags(
+      EquivalenceVisitor visitor, IsExpression node, IsExpression other) {
+    return visitor.checkValues(node.flags, other.flags, 'flags');
+  }
+
+  bool checkIsExpression_operand(
+      EquivalenceVisitor visitor, IsExpression node, IsExpression other) {
+    return visitor.checkNodes(node.operand, other.operand, 'operand');
+  }
+
+  bool checkIsExpression_type(
+      EquivalenceVisitor visitor, IsExpression node, IsExpression other) {
+    return visitor.checkNodes(node.type, other.type, 'type');
+  }
+
+  bool checkIsExpression_fileOffset(
+      EquivalenceVisitor visitor, IsExpression node, IsExpression other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkAsExpression_flags(
+      EquivalenceVisitor visitor, AsExpression node, AsExpression other) {
+    return visitor.checkValues(node.flags, other.flags, 'flags');
+  }
+
+  bool checkAsExpression_operand(
+      EquivalenceVisitor visitor, AsExpression node, AsExpression other) {
+    return visitor.checkNodes(node.operand, other.operand, 'operand');
+  }
+
+  bool checkAsExpression_type(
+      EquivalenceVisitor visitor, AsExpression node, AsExpression other) {
+    return visitor.checkNodes(node.type, other.type, 'type');
+  }
+
+  bool checkAsExpression_fileOffset(
+      EquivalenceVisitor visitor, AsExpression node, AsExpression other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkNullCheck_operand(
+      EquivalenceVisitor visitor, NullCheck node, NullCheck other) {
+    return visitor.checkNodes(node.operand, other.operand, 'operand');
+  }
+
+  bool checkNullCheck_fileOffset(
+      EquivalenceVisitor visitor, NullCheck node, NullCheck other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkStringLiteral_value(
+      EquivalenceVisitor visitor, StringLiteral node, StringLiteral other) {
+    return visitor.checkValues(node.value, other.value, 'value');
+  }
+
+  bool checkStringLiteral_fileOffset(
+      EquivalenceVisitor visitor, StringLiteral node, StringLiteral other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkIntLiteral_value(
+      EquivalenceVisitor visitor, IntLiteral node, IntLiteral other) {
+    return visitor.checkValues(node.value, other.value, 'value');
+  }
+
+  bool checkIntLiteral_fileOffset(
+      EquivalenceVisitor visitor, IntLiteral node, IntLiteral other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkDoubleLiteral_value(
+      EquivalenceVisitor visitor, DoubleLiteral node, DoubleLiteral other) {
+    return visitor.checkValues(node.value, other.value, 'value');
+  }
+
+  bool checkDoubleLiteral_fileOffset(
+      EquivalenceVisitor visitor, DoubleLiteral node, DoubleLiteral other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkBoolLiteral_value(
+      EquivalenceVisitor visitor, BoolLiteral node, BoolLiteral other) {
+    return visitor.checkValues(node.value, other.value, 'value');
+  }
+
+  bool checkBoolLiteral_fileOffset(
+      EquivalenceVisitor visitor, BoolLiteral node, BoolLiteral other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkNullLiteral_fileOffset(
+      EquivalenceVisitor visitor, NullLiteral node, NullLiteral other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkSymbolLiteral_value(
+      EquivalenceVisitor visitor, SymbolLiteral node, SymbolLiteral other) {
+    return visitor.checkValues(node.value, other.value, 'value');
+  }
+
+  bool checkSymbolLiteral_fileOffset(
+      EquivalenceVisitor visitor, SymbolLiteral node, SymbolLiteral other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkTypeLiteral_type(
+      EquivalenceVisitor visitor, TypeLiteral node, TypeLiteral other) {
+    return visitor.checkNodes(node.type, other.type, 'type');
+  }
+
+  bool checkTypeLiteral_fileOffset(
+      EquivalenceVisitor visitor, TypeLiteral node, TypeLiteral other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkThisExpression_fileOffset(
+      EquivalenceVisitor visitor, ThisExpression node, ThisExpression other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkRethrow_fileOffset(
+      EquivalenceVisitor visitor, Rethrow node, Rethrow other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkThrow_expression(
+      EquivalenceVisitor visitor, Throw node, Throw other) {
+    return visitor.checkNodes(node.expression, other.expression, 'expression');
+  }
+
+  bool checkThrow_fileOffset(
+      EquivalenceVisitor visitor, Throw node, Throw other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkListLiteral_isConst(
+      EquivalenceVisitor visitor, ListLiteral node, ListLiteral other) {
+    return visitor.checkValues(node.isConst, other.isConst, 'isConst');
+  }
+
+  bool checkListLiteral_typeArgument(
+      EquivalenceVisitor visitor, ListLiteral node, ListLiteral other) {
+    return visitor.checkNodes(
+        node.typeArgument, other.typeArgument, 'typeArgument');
+  }
+
+  bool checkListLiteral_expressions(
+      EquivalenceVisitor visitor, ListLiteral node, ListLiteral other) {
+    return visitor.checkLists(
+        node.expressions, other.expressions, visitor.checkNodes, 'expressions');
+  }
+
+  bool checkListLiteral_fileOffset(
+      EquivalenceVisitor visitor, ListLiteral node, ListLiteral other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkSetLiteral_isConst(
+      EquivalenceVisitor visitor, SetLiteral node, SetLiteral other) {
+    return visitor.checkValues(node.isConst, other.isConst, 'isConst');
+  }
+
+  bool checkSetLiteral_typeArgument(
+      EquivalenceVisitor visitor, SetLiteral node, SetLiteral other) {
+    return visitor.checkNodes(
+        node.typeArgument, other.typeArgument, 'typeArgument');
+  }
+
+  bool checkSetLiteral_expressions(
+      EquivalenceVisitor visitor, SetLiteral node, SetLiteral other) {
+    return visitor.checkLists(
+        node.expressions, other.expressions, visitor.checkNodes, 'expressions');
+  }
+
+  bool checkSetLiteral_fileOffset(
+      EquivalenceVisitor visitor, SetLiteral node, SetLiteral other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkMapLiteral_isConst(
+      EquivalenceVisitor visitor, MapLiteral node, MapLiteral other) {
+    return visitor.checkValues(node.isConst, other.isConst, 'isConst');
+  }
+
+  bool checkMapLiteral_keyType(
+      EquivalenceVisitor visitor, MapLiteral node, MapLiteral other) {
+    return visitor.checkNodes(node.keyType, other.keyType, 'keyType');
+  }
+
+  bool checkMapLiteral_valueType(
+      EquivalenceVisitor visitor, MapLiteral node, MapLiteral other) {
+    return visitor.checkNodes(node.valueType, other.valueType, 'valueType');
+  }
+
+  bool checkMapLiteral_entries(
+      EquivalenceVisitor visitor, MapLiteral node, MapLiteral other) {
+    return visitor.checkLists(
+        node.entries, other.entries, visitor.checkNodes, 'entries');
+  }
+
+  bool checkMapLiteral_fileOffset(
+      EquivalenceVisitor visitor, MapLiteral node, MapLiteral other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkAwaitExpression_operand(
+      EquivalenceVisitor visitor, AwaitExpression node, AwaitExpression other) {
+    return visitor.checkNodes(node.operand, other.operand, 'operand');
+  }
+
+  bool checkAwaitExpression_fileOffset(
+      EquivalenceVisitor visitor, AwaitExpression node, AwaitExpression other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkFunctionExpression_function(EquivalenceVisitor visitor,
+      FunctionExpression node, FunctionExpression other) {
+    return visitor.checkNodes(node.function, other.function, 'function');
+  }
+
+  bool checkFunctionExpression_fileOffset(EquivalenceVisitor visitor,
+      FunctionExpression node, FunctionExpression other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkConstantExpression_constant(EquivalenceVisitor visitor,
+      ConstantExpression node, ConstantExpression other) {
+    return visitor.checkNodes(node.constant, other.constant, 'constant');
+  }
+
+  bool checkConstantExpression_type(EquivalenceVisitor visitor,
+      ConstantExpression node, ConstantExpression other) {
+    return visitor.checkNodes(node.type, other.type, 'type');
+  }
+
+  bool checkConstantExpression_fileOffset(EquivalenceVisitor visitor,
+      ConstantExpression node, ConstantExpression other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkLet_variable(EquivalenceVisitor visitor, Let node, Let other) {
+    return visitor.checkNodes(node.variable, other.variable, 'variable');
+  }
+
+  bool checkLet_body(EquivalenceVisitor visitor, Let node, Let other) {
+    return visitor.checkNodes(node.body, other.body, 'body');
+  }
+
+  bool checkLet_fileOffset(EquivalenceVisitor visitor, Let node, Let other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkBlockExpression_body(
+      EquivalenceVisitor visitor, BlockExpression node, BlockExpression other) {
+    return visitor.checkNodes(node.body, other.body, 'body');
+  }
+
+  bool checkBlockExpression_value(
+      EquivalenceVisitor visitor, BlockExpression node, BlockExpression other) {
+    return visitor.checkNodes(node.value, other.value, 'value');
+  }
+
+  bool checkBlockExpression_fileOffset(
+      EquivalenceVisitor visitor, BlockExpression node, BlockExpression other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkLoadLibrary_import(
+      EquivalenceVisitor visitor, LoadLibrary node, LoadLibrary other) {
+    return visitor.checkNodes(node.import, other.import, 'import');
+  }
+
+  bool checkLoadLibrary_fileOffset(
+      EquivalenceVisitor visitor, LoadLibrary node, LoadLibrary other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkCheckLibraryIsLoaded_import(EquivalenceVisitor visitor,
+      CheckLibraryIsLoaded node, CheckLibraryIsLoaded other) {
+    return visitor.checkNodes(node.import, other.import, 'import');
+  }
+
+  bool checkCheckLibraryIsLoaded_fileOffset(EquivalenceVisitor visitor,
+      CheckLibraryIsLoaded node, CheckLibraryIsLoaded other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkConstructorTearOff_targetReference(EquivalenceVisitor visitor,
+      ConstructorTearOff node, ConstructorTearOff other) {
+    return visitor.checkReferences(
+        node.targetReference, other.targetReference, 'targetReference');
+  }
+
+  bool checkConstructorTearOff_fileOffset(EquivalenceVisitor visitor,
+      ConstructorTearOff node, ConstructorTearOff other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkRedirectingFactoryTearOff_targetReference(
+      EquivalenceVisitor visitor,
+      RedirectingFactoryTearOff node,
+      RedirectingFactoryTearOff other) {
+    return visitor.checkReferences(
+        node.targetReference, other.targetReference, 'targetReference');
+  }
+
+  bool checkRedirectingFactoryTearOff_fileOffset(EquivalenceVisitor visitor,
+      RedirectingFactoryTearOff node, RedirectingFactoryTearOff other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkTypedefTearOff_typeParameters(
+      EquivalenceVisitor visitor, TypedefTearOff node, TypedefTearOff other) {
+    return visitor.checkLists(node.typeParameters, other.typeParameters,
+        visitor.checkNodes, 'typeParameters');
+  }
+
+  bool checkTypedefTearOff_expression(
+      EquivalenceVisitor visitor, TypedefTearOff node, TypedefTearOff other) {
+    return visitor.checkNodes(node.expression, other.expression, 'expression');
+  }
+
+  bool checkTypedefTearOff_typeArguments(
+      EquivalenceVisitor visitor, TypedefTearOff node, TypedefTearOff other) {
+    return visitor.checkLists(node.typeArguments, other.typeArguments,
+        visitor.checkNodes, 'typeArguments');
+  }
+
+  bool checkTypedefTearOff_fileOffset(
+      EquivalenceVisitor visitor, TypedefTearOff node, TypedefTearOff other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkArguments_types(
+      EquivalenceVisitor visitor, Arguments node, Arguments other) {
+    return visitor.checkLists(
+        node.types, other.types, visitor.checkNodes, 'types');
+  }
+
+  bool checkArguments_positional(
+      EquivalenceVisitor visitor, Arguments node, Arguments other) {
+    return visitor.checkLists(
+        node.positional, other.positional, visitor.checkNodes, 'positional');
+  }
+
+  bool checkArguments_named(
+      EquivalenceVisitor visitor, Arguments node, Arguments other) {
+    return visitor.checkLists(
+        node.named, other.named, visitor.checkNodes, 'named');
+  }
+
+  bool checkArguments_fileOffset(
+      EquivalenceVisitor visitor, Arguments node, Arguments other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkNamedExpression_name(
+      EquivalenceVisitor visitor, NamedExpression node, NamedExpression other) {
+    return visitor.checkValues(node.name, other.name, 'name');
+  }
+
+  bool checkNamedExpression_value(
+      EquivalenceVisitor visitor, NamedExpression node, NamedExpression other) {
+    return visitor.checkNodes(node.value, other.value, 'value');
+  }
+
+  bool checkNamedExpression_fileOffset(
+      EquivalenceVisitor visitor, NamedExpression node, NamedExpression other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkMapLiteralEntry_key(
+      EquivalenceVisitor visitor, MapLiteralEntry node, MapLiteralEntry other) {
+    return visitor.checkNodes(node.key, other.key, 'key');
+  }
+
+  bool checkMapLiteralEntry_value(
+      EquivalenceVisitor visitor, MapLiteralEntry node, MapLiteralEntry other) {
+    return visitor.checkNodes(node.value, other.value, 'value');
+  }
+
+  bool checkMapLiteralEntry_fileOffset(
+      EquivalenceVisitor visitor, MapLiteralEntry node, MapLiteralEntry other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkExpressionStatement_expression(EquivalenceVisitor visitor,
+      ExpressionStatement node, ExpressionStatement other) {
+    return visitor.checkNodes(node.expression, other.expression, 'expression');
+  }
+
+  bool checkExpressionStatement_fileOffset(EquivalenceVisitor visitor,
+      ExpressionStatement node, ExpressionStatement other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkBlock_statements(
+      EquivalenceVisitor visitor, Block node, Block other) {
+    return visitor.checkLists(
+        node.statements, other.statements, visitor.checkNodes, 'statements');
+  }
+
+  bool checkBlock_fileEndOffset(
+      EquivalenceVisitor visitor, Block node, Block other) {
+    return visitor.checkValues(
+        node.fileEndOffset, other.fileEndOffset, 'fileEndOffset');
+  }
+
+  bool checkBlock_fileOffset(
+      EquivalenceVisitor visitor, Block node, Block other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkAssertBlock_statements(
+      EquivalenceVisitor visitor, AssertBlock node, AssertBlock other) {
+    return visitor.checkLists(
+        node.statements, other.statements, visitor.checkNodes, 'statements');
+  }
+
+  bool checkAssertBlock_fileOffset(
+      EquivalenceVisitor visitor, AssertBlock node, AssertBlock other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkEmptyStatement_fileOffset(
+      EquivalenceVisitor visitor, EmptyStatement node, EmptyStatement other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkAssertStatement_condition(
+      EquivalenceVisitor visitor, AssertStatement node, AssertStatement other) {
+    return visitor.checkNodes(node.condition, other.condition, 'condition');
+  }
+
+  bool checkAssertStatement_message(
+      EquivalenceVisitor visitor, AssertStatement node, AssertStatement other) {
+    return visitor.checkNodes(node.message, other.message, 'message');
+  }
+
+  bool checkAssertStatement_conditionStartOffset(
+      EquivalenceVisitor visitor, AssertStatement node, AssertStatement other) {
+    return visitor.checkValues(node.conditionStartOffset,
+        other.conditionStartOffset, 'conditionStartOffset');
+  }
+
+  bool checkAssertStatement_conditionEndOffset(
+      EquivalenceVisitor visitor, AssertStatement node, AssertStatement other) {
+    return visitor.checkValues(node.conditionEndOffset,
+        other.conditionEndOffset, 'conditionEndOffset');
+  }
+
+  bool checkAssertStatement_fileOffset(
+      EquivalenceVisitor visitor, AssertStatement node, AssertStatement other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkLabeledStatement_body(EquivalenceVisitor visitor,
+      LabeledStatement node, LabeledStatement other) {
+    return visitor.checkNodes(node.body, other.body, 'body');
+  }
+
+  bool checkLabeledStatement_fileOffset(EquivalenceVisitor visitor,
+      LabeledStatement node, LabeledStatement other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkBreakStatement_target(
+      EquivalenceVisitor visitor, BreakStatement node, BreakStatement other) {
+    return visitor.checkDeclarations(node.target, other.target, 'target');
+  }
+
+  bool checkBreakStatement_fileOffset(
+      EquivalenceVisitor visitor, BreakStatement node, BreakStatement other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkWhileStatement_condition(
+      EquivalenceVisitor visitor, WhileStatement node, WhileStatement other) {
+    return visitor.checkNodes(node.condition, other.condition, 'condition');
+  }
+
+  bool checkWhileStatement_body(
+      EquivalenceVisitor visitor, WhileStatement node, WhileStatement other) {
+    return visitor.checkNodes(node.body, other.body, 'body');
+  }
+
+  bool checkWhileStatement_fileOffset(
+      EquivalenceVisitor visitor, WhileStatement node, WhileStatement other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkDoStatement_body(
+      EquivalenceVisitor visitor, DoStatement node, DoStatement other) {
+    return visitor.checkNodes(node.body, other.body, 'body');
+  }
+
+  bool checkDoStatement_condition(
+      EquivalenceVisitor visitor, DoStatement node, DoStatement other) {
+    return visitor.checkNodes(node.condition, other.condition, 'condition');
+  }
+
+  bool checkDoStatement_fileOffset(
+      EquivalenceVisitor visitor, DoStatement node, DoStatement other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkForStatement_variables(
+      EquivalenceVisitor visitor, ForStatement node, ForStatement other) {
+    return visitor.checkLists(
+        node.variables, other.variables, visitor.checkNodes, 'variables');
+  }
+
+  bool checkForStatement_condition(
+      EquivalenceVisitor visitor, ForStatement node, ForStatement other) {
+    return visitor.checkNodes(node.condition, other.condition, 'condition');
+  }
+
+  bool checkForStatement_updates(
+      EquivalenceVisitor visitor, ForStatement node, ForStatement other) {
+    return visitor.checkLists(
+        node.updates, other.updates, visitor.checkNodes, 'updates');
+  }
+
+  bool checkForStatement_body(
+      EquivalenceVisitor visitor, ForStatement node, ForStatement other) {
+    return visitor.checkNodes(node.body, other.body, 'body');
+  }
+
+  bool checkForStatement_fileOffset(
+      EquivalenceVisitor visitor, ForStatement node, ForStatement other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkForInStatement_bodyOffset(
+      EquivalenceVisitor visitor, ForInStatement node, ForInStatement other) {
+    return visitor.checkValues(node.bodyOffset, other.bodyOffset, 'bodyOffset');
+  }
+
+  bool checkForInStatement_variable(
+      EquivalenceVisitor visitor, ForInStatement node, ForInStatement other) {
+    return visitor.checkNodes(node.variable, other.variable, 'variable');
+  }
+
+  bool checkForInStatement_iterable(
+      EquivalenceVisitor visitor, ForInStatement node, ForInStatement other) {
+    return visitor.checkNodes(node.iterable, other.iterable, 'iterable');
+  }
+
+  bool checkForInStatement_body(
+      EquivalenceVisitor visitor, ForInStatement node, ForInStatement other) {
+    return visitor.checkNodes(node.body, other.body, 'body');
+  }
+
+  bool checkForInStatement_isAsync(
+      EquivalenceVisitor visitor, ForInStatement node, ForInStatement other) {
+    return visitor.checkValues(node.isAsync, other.isAsync, 'isAsync');
+  }
+
+  bool checkForInStatement_fileOffset(
+      EquivalenceVisitor visitor, ForInStatement node, ForInStatement other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkSwitchStatement_expression(
+      EquivalenceVisitor visitor, SwitchStatement node, SwitchStatement other) {
+    return visitor.checkNodes(node.expression, other.expression, 'expression');
+  }
+
+  bool checkSwitchStatement_cases(
+      EquivalenceVisitor visitor, SwitchStatement node, SwitchStatement other) {
+    return visitor.checkLists(
+        node.cases, other.cases, visitor.checkNodes, 'cases');
+  }
+
+  bool checkSwitchStatement_fileOffset(
+      EquivalenceVisitor visitor, SwitchStatement node, SwitchStatement other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkContinueSwitchStatement_target(EquivalenceVisitor visitor,
+      ContinueSwitchStatement node, ContinueSwitchStatement other) {
+    return visitor.checkDeclarations(node.target, other.target, 'target');
+  }
+
+  bool checkContinueSwitchStatement_fileOffset(EquivalenceVisitor visitor,
+      ContinueSwitchStatement node, ContinueSwitchStatement other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkIfStatement_condition(
+      EquivalenceVisitor visitor, IfStatement node, IfStatement other) {
+    return visitor.checkNodes(node.condition, other.condition, 'condition');
+  }
+
+  bool checkIfStatement_then(
+      EquivalenceVisitor visitor, IfStatement node, IfStatement other) {
+    return visitor.checkNodes(node.then, other.then, 'then');
+  }
+
+  bool checkIfStatement_otherwise(
+      EquivalenceVisitor visitor, IfStatement node, IfStatement other) {
+    return visitor.checkNodes(node.otherwise, other.otherwise, 'otherwise');
+  }
+
+  bool checkIfStatement_fileOffset(
+      EquivalenceVisitor visitor, IfStatement node, IfStatement other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkReturnStatement_expression(
+      EquivalenceVisitor visitor, ReturnStatement node, ReturnStatement other) {
+    return visitor.checkNodes(node.expression, other.expression, 'expression');
+  }
+
+  bool checkReturnStatement_fileOffset(
+      EquivalenceVisitor visitor, ReturnStatement node, ReturnStatement other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkTryCatch_body(
+      EquivalenceVisitor visitor, TryCatch node, TryCatch other) {
+    return visitor.checkNodes(node.body, other.body, 'body');
+  }
+
+  bool checkTryCatch_catches(
+      EquivalenceVisitor visitor, TryCatch node, TryCatch other) {
+    return visitor.checkLists(
+        node.catches, other.catches, visitor.checkNodes, 'catches');
+  }
+
+  bool checkTryCatch_isSynthetic(
+      EquivalenceVisitor visitor, TryCatch node, TryCatch other) {
+    return visitor.checkValues(
+        node.isSynthetic, other.isSynthetic, 'isSynthetic');
+  }
+
+  bool checkTryCatch_fileOffset(
+      EquivalenceVisitor visitor, TryCatch node, TryCatch other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkTryFinally_body(
+      EquivalenceVisitor visitor, TryFinally node, TryFinally other) {
+    return visitor.checkNodes(node.body, other.body, 'body');
+  }
+
+  bool checkTryFinally_finalizer(
+      EquivalenceVisitor visitor, TryFinally node, TryFinally other) {
+    return visitor.checkNodes(node.finalizer, other.finalizer, 'finalizer');
+  }
+
+  bool checkTryFinally_fileOffset(
+      EquivalenceVisitor visitor, TryFinally node, TryFinally other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkYieldStatement_expression(
+      EquivalenceVisitor visitor, YieldStatement node, YieldStatement other) {
+    return visitor.checkNodes(node.expression, other.expression, 'expression');
+  }
+
+  bool checkYieldStatement_flags(
+      EquivalenceVisitor visitor, YieldStatement node, YieldStatement other) {
+    return visitor.checkValues(node.flags, other.flags, 'flags');
+  }
+
+  bool checkYieldStatement_fileOffset(
+      EquivalenceVisitor visitor, YieldStatement node, YieldStatement other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkVariableDeclaration_fileEqualsOffset(EquivalenceVisitor visitor,
+      VariableDeclaration node, VariableDeclaration other) {
+    return visitor.checkValues(
+        node.fileEqualsOffset, other.fileEqualsOffset, 'fileEqualsOffset');
+  }
+
+  bool checkVariableDeclaration_annotations(EquivalenceVisitor visitor,
+      VariableDeclaration node, VariableDeclaration other) {
+    return visitor.checkLists(
+        node.annotations, other.annotations, visitor.checkNodes, 'annotations');
+  }
+
+  bool checkVariableDeclaration_name(EquivalenceVisitor visitor,
+      VariableDeclaration node, VariableDeclaration other) {
+    return visitor.checkValues(node.name, other.name, 'name');
+  }
+
+  bool checkVariableDeclaration_flags(EquivalenceVisitor visitor,
+      VariableDeclaration node, VariableDeclaration other) {
+    return visitor.checkValues(node.flags, other.flags, 'flags');
+  }
+
+  bool checkVariableDeclaration_type(EquivalenceVisitor visitor,
+      VariableDeclaration node, VariableDeclaration other) {
+    return visitor.checkNodes(node.type, other.type, 'type');
+  }
+
+  bool checkVariableDeclaration_binaryOffsetNoTag(EquivalenceVisitor visitor,
+      VariableDeclaration node, VariableDeclaration other) {
+    return visitor.checkValues(
+        node.binaryOffsetNoTag, other.binaryOffsetNoTag, 'binaryOffsetNoTag');
+  }
+
+  bool checkVariableDeclaration_initializer(EquivalenceVisitor visitor,
+      VariableDeclaration node, VariableDeclaration other) {
+    return visitor.checkNodes(
+        node.initializer, other.initializer, 'initializer');
+  }
+
+  bool checkVariableDeclaration_fileOffset(EquivalenceVisitor visitor,
+      VariableDeclaration node, VariableDeclaration other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkFunctionDeclaration_variable(EquivalenceVisitor visitor,
+      FunctionDeclaration node, FunctionDeclaration other) {
+    return visitor.checkNodes(node.variable, other.variable, 'variable');
+  }
+
+  bool checkFunctionDeclaration_function(EquivalenceVisitor visitor,
+      FunctionDeclaration node, FunctionDeclaration other) {
+    return visitor.checkNodes(node.function, other.function, 'function');
+  }
+
+  bool checkFunctionDeclaration_fileOffset(EquivalenceVisitor visitor,
+      FunctionDeclaration node, FunctionDeclaration other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkSwitchCase_expressions(
+      EquivalenceVisitor visitor, SwitchCase node, SwitchCase other) {
+    return visitor.checkLists(
+        node.expressions, other.expressions, visitor.checkNodes, 'expressions');
+  }
+
+  bool checkSwitchCase_expressionOffsets(
+      EquivalenceVisitor visitor, SwitchCase node, SwitchCase other) {
+    return visitor.checkLists(node.expressionOffsets, other.expressionOffsets,
+        visitor.checkValues, 'expressionOffsets');
+  }
+
+  bool checkSwitchCase_body(
+      EquivalenceVisitor visitor, SwitchCase node, SwitchCase other) {
+    return visitor.checkNodes(node.body, other.body, 'body');
+  }
+
+  bool checkSwitchCase_isDefault(
+      EquivalenceVisitor visitor, SwitchCase node, SwitchCase other) {
+    return visitor.checkValues(node.isDefault, other.isDefault, 'isDefault');
+  }
+
+  bool checkSwitchCase_fileOffset(
+      EquivalenceVisitor visitor, SwitchCase node, SwitchCase other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkCatch_guard(EquivalenceVisitor visitor, Catch node, Catch other) {
+    return visitor.checkNodes(node.guard, other.guard, 'guard');
+  }
+
+  bool checkCatch_exception(
+      EquivalenceVisitor visitor, Catch node, Catch other) {
+    return visitor.checkNodes(node.exception, other.exception, 'exception');
+  }
+
+  bool checkCatch_stackTrace(
+      EquivalenceVisitor visitor, Catch node, Catch other) {
+    return visitor.checkNodes(node.stackTrace, other.stackTrace, 'stackTrace');
+  }
+
+  bool checkCatch_body(EquivalenceVisitor visitor, Catch node, Catch other) {
+    return visitor.checkNodes(node.body, other.body, 'body');
+  }
+
+  bool checkCatch_fileOffset(
+      EquivalenceVisitor visitor, Catch node, Catch other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkTypeParameter_flags(
+      EquivalenceVisitor visitor, TypeParameter node, TypeParameter other) {
+    return visitor.checkValues(node.flags, other.flags, 'flags');
+  }
+
+  bool checkTypeParameter_annotations(
+      EquivalenceVisitor visitor, TypeParameter node, TypeParameter other) {
+    return visitor.checkLists(
+        node.annotations, other.annotations, visitor.checkNodes, 'annotations');
+  }
+
+  bool checkTypeParameter_name(
+      EquivalenceVisitor visitor, TypeParameter node, TypeParameter other) {
+    return visitor.checkValues(node.name, other.name, 'name');
+  }
+
+  bool checkTypeParameter_bound(
+      EquivalenceVisitor visitor, TypeParameter node, TypeParameter other) {
+    return visitor.checkNodes(node.bound, other.bound, 'bound');
+  }
+
+  bool checkTypeParameter_defaultType(
+      EquivalenceVisitor visitor, TypeParameter node, TypeParameter other) {
+    return visitor.checkNodes(
+        node.defaultType, other.defaultType, 'defaultType');
+  }
+
+  bool checkTypeParameter_variance(
+      EquivalenceVisitor visitor, TypeParameter node, TypeParameter other) {
+    return visitor.checkValues(node.variance, other.variance, 'variance');
+  }
+
+  bool checkTypeParameter_fileOffset(
+      EquivalenceVisitor visitor, TypeParameter node, TypeParameter other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkComponent_problemsAsJson(
+      EquivalenceVisitor visitor, Component node, Component other) {
+    return visitor.checkLists(node.problemsAsJson, other.problemsAsJson,
+        visitor.checkValues, 'problemsAsJson');
+  }
+
+  bool checkComponent_libraries(
+      EquivalenceVisitor visitor, Component node, Component other) {
+    return visitor.checkLists(
+        node.libraries, other.libraries, visitor.checkNodes, 'libraries');
+  }
+
+  bool checkSource_lineStarts(
+      EquivalenceVisitor visitor, Source node, Source other) {
+    return visitor.checkLists(
+        node.lineStarts, other.lineStarts, visitor.checkValues, 'lineStarts');
+  }
+
+  bool checkSource_source(
+      EquivalenceVisitor visitor, Source node, Source other) {
+    return visitor.checkLists(
+        node.source, other.source, visitor.checkValues, 'source');
+  }
+
+  bool checkSource_importUri(
+      EquivalenceVisitor visitor, Source node, Source other) {
+    return visitor.checkValues(node.importUri, other.importUri, 'importUri');
+  }
+
+  bool checkSource_fileUri(
+      EquivalenceVisitor visitor, Source node, Source other) {
+    return visitor.checkValues(node.fileUri, other.fileUri, 'fileUri');
+  }
+
+  bool checkSource_constantCoverageConstructors(
+      EquivalenceVisitor visitor, Source node, Source other) {
+    return visitor.checkSets(
+        node.constantCoverageConstructors,
+        other.constantCoverageConstructors,
+        visitor.matchReferences,
+        visitor.checkReferences,
+        'constantCoverageConstructors');
+  }
+
+  bool checkSource_cachedText(
+      EquivalenceVisitor visitor, Source node, Source other) {
+    return visitor.checkValues(node.cachedText, other.cachedText, 'cachedText');
+  }
+
+  bool checkComponent_uriToSource(
+      EquivalenceVisitor visitor, Component node, Component other) {
+    return visitor.checkMaps(node.uriToSource, other.uriToSource,
+        visitor.matchValues, visitor.checkValues, (a, b, _) {
+      if (identical(a, b)) return true;
+      if (a is! Source) return false;
+      if (b is! Source) return false;
+      return checkSource(visitor, a, b);
+    }, 'uriToSource');
+  }
+
+  bool checkComponent_metadata(
+      EquivalenceVisitor visitor, Component node, Component other) {
+    return visitor.checkMaps(
+        node.metadata, other.metadata, visitor.matchValues, visitor.checkValues,
+        (a, b, _) {
+      if (identical(a, b)) return true;
+      if (a is! MetadataRepository) return false;
+      if (b is! MetadataRepository) return false;
+      return checkMetadataRepository(visitor, a, b);
+    }, 'metadata');
+  }
+
+  bool checkComponent_mainMethodName(
+      EquivalenceVisitor visitor, Component node, Component other) {
+    return visitor.checkReferences(
+        node.mainMethodName, other.mainMethodName, 'mainMethodName');
+  }
+
+  bool checkComponent_mode(
+      EquivalenceVisitor visitor, Component node, Component other) {
+    return visitor.checkValues(node.mode, other.mode, 'mode');
+  }
+
+  bool checkComponent_fileOffset(
+      EquivalenceVisitor visitor, Component node, Component other) {
+    return visitor.checkValues(node.fileOffset, other.fileOffset, 'fileOffset');
+  }
+
+  bool checkName_text(EquivalenceVisitor visitor, Name node, Name other) {
+    return visitor.checkValues(node.text, other.text, 'text');
+  }
+
+  bool checkNeverType_declaredNullability(
+      EquivalenceVisitor visitor, NeverType node, NeverType other) {
+    return visitor.checkValues(node.declaredNullability,
+        other.declaredNullability, 'declaredNullability');
+  }
+
+  bool checkInterfaceType_className(
+      EquivalenceVisitor visitor, InterfaceType node, InterfaceType other) {
+    return visitor.checkReferences(
+        node.className, other.className, 'className');
+  }
+
+  bool checkInterfaceType_declaredNullability(
+      EquivalenceVisitor visitor, InterfaceType node, InterfaceType other) {
+    return visitor.checkValues(node.declaredNullability,
+        other.declaredNullability, 'declaredNullability');
+  }
+
+  bool checkInterfaceType_typeArguments(
+      EquivalenceVisitor visitor, InterfaceType node, InterfaceType other) {
+    return visitor.checkLists(node.typeArguments, other.typeArguments,
+        visitor.checkNodes, 'typeArguments');
+  }
+
+  bool checkFunctionType_typeParameters(
+      EquivalenceVisitor visitor, FunctionType node, FunctionType other) {
+    return visitor.checkLists(node.typeParameters, other.typeParameters,
+        visitor.checkNodes, 'typeParameters');
+  }
+
+  bool checkFunctionType_requiredParameterCount(
+      EquivalenceVisitor visitor, FunctionType node, FunctionType other) {
+    return visitor.checkValues(node.requiredParameterCount,
+        other.requiredParameterCount, 'requiredParameterCount');
+  }
+
+  bool checkFunctionType_positionalParameters(
+      EquivalenceVisitor visitor, FunctionType node, FunctionType other) {
+    return visitor.checkLists(node.positionalParameters,
+        other.positionalParameters, visitor.checkNodes, 'positionalParameters');
+  }
+
+  bool checkFunctionType_namedParameters(
+      EquivalenceVisitor visitor, FunctionType node, FunctionType other) {
+    return visitor.checkLists(node.namedParameters, other.namedParameters,
+        visitor.checkNodes, 'namedParameters');
+  }
+
+  bool checkFunctionType_declaredNullability(
+      EquivalenceVisitor visitor, FunctionType node, FunctionType other) {
+    return visitor.checkValues(node.declaredNullability,
+        other.declaredNullability, 'declaredNullability');
+  }
+
+  bool checkFunctionType_typedefType(
+      EquivalenceVisitor visitor, FunctionType node, FunctionType other) {
+    return visitor.checkNodes(
+        node.typedefType, other.typedefType, 'typedefType');
+  }
+
+  bool checkFunctionType_returnType(
+      EquivalenceVisitor visitor, FunctionType node, FunctionType other) {
+    return visitor.checkNodes(node.returnType, other.returnType, 'returnType');
+  }
+
+  bool checkTypedefType_declaredNullability(
+      EquivalenceVisitor visitor, TypedefType node, TypedefType other) {
+    return visitor.checkValues(node.declaredNullability,
+        other.declaredNullability, 'declaredNullability');
+  }
+
+  bool checkTypedefType_typedefReference(
+      EquivalenceVisitor visitor, TypedefType node, TypedefType other) {
+    return visitor.checkReferences(
+        node.typedefReference, other.typedefReference, 'typedefReference');
+  }
+
+  bool checkTypedefType_typeArguments(
+      EquivalenceVisitor visitor, TypedefType node, TypedefType other) {
+    return visitor.checkLists(node.typeArguments, other.typeArguments,
+        visitor.checkNodes, 'typeArguments');
+  }
+
+  bool checkFutureOrType_typeArgument(
+      EquivalenceVisitor visitor, FutureOrType node, FutureOrType other) {
+    return visitor.checkNodes(
+        node.typeArgument, other.typeArgument, 'typeArgument');
+  }
+
+  bool checkFutureOrType_declaredNullability(
+      EquivalenceVisitor visitor, FutureOrType node, FutureOrType other) {
+    return visitor.checkValues(node.declaredNullability,
+        other.declaredNullability, 'declaredNullability');
+  }
+
+  bool checkExtensionType_extensionReference(
+      EquivalenceVisitor visitor, ExtensionType node, ExtensionType other) {
+    return visitor.checkReferences(node.extensionReference,
+        other.extensionReference, 'extensionReference');
+  }
+
+  bool checkExtensionType_declaredNullability(
+      EquivalenceVisitor visitor, ExtensionType node, ExtensionType other) {
+    return visitor.checkValues(node.declaredNullability,
+        other.declaredNullability, 'declaredNullability');
+  }
+
+  bool checkExtensionType_typeArguments(
+      EquivalenceVisitor visitor, ExtensionType node, ExtensionType other) {
+    return visitor.checkLists(node.typeArguments, other.typeArguments,
+        visitor.checkNodes, 'typeArguments');
+  }
+
+  bool checkExtensionType_onType(
+      EquivalenceVisitor visitor, ExtensionType node, ExtensionType other) {
+    return visitor.checkNodes(node.onType, other.onType, 'onType');
+  }
+
+  bool checkTypeParameterType_declaredNullability(EquivalenceVisitor visitor,
+      TypeParameterType node, TypeParameterType other) {
+    return visitor.checkValues(node.declaredNullability,
+        other.declaredNullability, 'declaredNullability');
+  }
+
+  bool checkTypeParameterType_parameter(EquivalenceVisitor visitor,
+      TypeParameterType node, TypeParameterType other) {
+    return visitor.checkDeclarations(
+        node.parameter, other.parameter, 'parameter');
+  }
+
+  bool checkTypeParameterType_promotedBound(EquivalenceVisitor visitor,
+      TypeParameterType node, TypeParameterType other) {
+    return visitor.checkNodes(
+        node.promotedBound, other.promotedBound, 'promotedBound');
+  }
+
+  bool checkNamedType_name(
+      EquivalenceVisitor visitor, NamedType node, NamedType other) {
+    return visitor.checkValues(node.name, other.name, 'name');
+  }
+
+  bool checkNamedType_type(
+      EquivalenceVisitor visitor, NamedType node, NamedType other) {
+    return visitor.checkNodes(node.type, other.type, 'type');
+  }
+
+  bool checkNamedType_isRequired(
+      EquivalenceVisitor visitor, NamedType node, NamedType other) {
+    return visitor.checkValues(node.isRequired, other.isRequired, 'isRequired');
+  }
+
+  bool checkSupertype_className(
+      EquivalenceVisitor visitor, Supertype node, Supertype other) {
+    return visitor.checkReferences(
+        node.className, other.className, 'className');
+  }
+
+  bool checkSupertype_typeArguments(
+      EquivalenceVisitor visitor, Supertype node, Supertype other) {
+    return visitor.checkLists(node.typeArguments, other.typeArguments,
+        visitor.checkNodes, 'typeArguments');
+  }
+
+  bool checkNullConstant_value(
+      EquivalenceVisitor visitor, NullConstant node, NullConstant other) {
+    return visitor.checkValues(node.value, other.value, 'value');
+  }
+
+  bool checkBoolConstant_value(
+      EquivalenceVisitor visitor, BoolConstant node, BoolConstant other) {
+    return visitor.checkValues(node.value, other.value, 'value');
+  }
+
+  bool checkIntConstant_value(
+      EquivalenceVisitor visitor, IntConstant node, IntConstant other) {
+    return visitor.checkValues(node.value, other.value, 'value');
+  }
+
+  bool checkDoubleConstant_value(
+      EquivalenceVisitor visitor, DoubleConstant node, DoubleConstant other) {
+    return visitor.checkValues(node.value, other.value, 'value');
+  }
+
+  bool checkStringConstant_value(
+      EquivalenceVisitor visitor, StringConstant node, StringConstant other) {
+    return visitor.checkValues(node.value, other.value, 'value');
+  }
+
+  bool checkSymbolConstant_name(
+      EquivalenceVisitor visitor, SymbolConstant node, SymbolConstant other) {
+    return visitor.checkValues(node.name, other.name, 'name');
+  }
+
+  bool checkSymbolConstant_libraryReference(
+      EquivalenceVisitor visitor, SymbolConstant node, SymbolConstant other) {
+    return visitor.checkReferences(
+        node.libraryReference, other.libraryReference, 'libraryReference');
+  }
+
+  bool checkMapConstant_keyType(
+      EquivalenceVisitor visitor, MapConstant node, MapConstant other) {
+    return visitor.checkNodes(node.keyType, other.keyType, 'keyType');
+  }
+
+  bool checkMapConstant_valueType(
+      EquivalenceVisitor visitor, MapConstant node, MapConstant other) {
+    return visitor.checkNodes(node.valueType, other.valueType, 'valueType');
+  }
+
+  bool checkConstantMapEntry_key(EquivalenceVisitor visitor,
+      ConstantMapEntry node, ConstantMapEntry other) {
+    return visitor.checkNodes(node.key, other.key, 'key');
+  }
+
+  bool checkConstantMapEntry_value(EquivalenceVisitor visitor,
+      ConstantMapEntry node, ConstantMapEntry other) {
+    return visitor.checkNodes(node.value, other.value, 'value');
+  }
+
+  bool checkMapConstant_entries(
+      EquivalenceVisitor visitor, MapConstant node, MapConstant other) {
+    return visitor.checkLists(node.entries, other.entries, (a, b, _) {
+      if (identical(a, b)) return true;
+      if (a is! ConstantMapEntry) return false;
+      if (b is! ConstantMapEntry) return false;
+      return checkConstantMapEntry(visitor, a, b);
+    }, 'entries');
+  }
+
+  bool checkListConstant_typeArgument(
+      EquivalenceVisitor visitor, ListConstant node, ListConstant other) {
+    return visitor.checkNodes(
+        node.typeArgument, other.typeArgument, 'typeArgument');
+  }
+
+  bool checkListConstant_entries(
+      EquivalenceVisitor visitor, ListConstant node, ListConstant other) {
+    return visitor.checkLists(
+        node.entries, other.entries, visitor.checkNodes, 'entries');
+  }
+
+  bool checkSetConstant_typeArgument(
+      EquivalenceVisitor visitor, SetConstant node, SetConstant other) {
+    return visitor.checkNodes(
+        node.typeArgument, other.typeArgument, 'typeArgument');
+  }
+
+  bool checkSetConstant_entries(
+      EquivalenceVisitor visitor, SetConstant node, SetConstant other) {
+    return visitor.checkLists(
+        node.entries, other.entries, visitor.checkNodes, 'entries');
+  }
+
+  bool checkInstanceConstant_classReference(EquivalenceVisitor visitor,
+      InstanceConstant node, InstanceConstant other) {
+    return visitor.checkReferences(
+        node.classReference, other.classReference, 'classReference');
+  }
+
+  bool checkInstanceConstant_typeArguments(EquivalenceVisitor visitor,
+      InstanceConstant node, InstanceConstant other) {
+    return visitor.checkLists(node.typeArguments, other.typeArguments,
+        visitor.checkNodes, 'typeArguments');
+  }
+
+  bool checkInstanceConstant_fieldValues(EquivalenceVisitor visitor,
+      InstanceConstant node, InstanceConstant other) {
+    return visitor.checkMaps(
+        node.fieldValues,
+        other.fieldValues,
+        visitor.matchReferences,
+        visitor.checkReferences,
+        visitor.checkNodes,
+        'fieldValues');
+  }
+
+  bool checkInstantiationConstant_tearOffConstant(EquivalenceVisitor visitor,
+      InstantiationConstant node, InstantiationConstant other) {
+    return visitor.checkNodes(
+        node.tearOffConstant, other.tearOffConstant, 'tearOffConstant');
+  }
+
+  bool checkInstantiationConstant_types(EquivalenceVisitor visitor,
+      InstantiationConstant node, InstantiationConstant other) {
+    return visitor.checkLists(
+        node.types, other.types, visitor.checkNodes, 'types');
+  }
+
+  bool checkStaticTearOffConstant_targetReference(EquivalenceVisitor visitor,
+      StaticTearOffConstant node, StaticTearOffConstant other) {
+    return visitor.checkReferences(
+        node.targetReference, other.targetReference, 'targetReference');
+  }
+
+  bool checkConstructorTearOffConstant_targetReference(
+      EquivalenceVisitor visitor,
+      ConstructorTearOffConstant node,
+      ConstructorTearOffConstant other) {
+    return visitor.checkReferences(
+        node.targetReference, other.targetReference, 'targetReference');
+  }
+
+  bool checkRedirectingFactoryTearOffConstant_targetReference(
+      EquivalenceVisitor visitor,
+      RedirectingFactoryTearOffConstant node,
+      RedirectingFactoryTearOffConstant other) {
+    return visitor.checkReferences(
+        node.targetReference, other.targetReference, 'targetReference');
+  }
+
+  bool checkTypedefTearOffConstant_parameters(EquivalenceVisitor visitor,
+      TypedefTearOffConstant node, TypedefTearOffConstant other) {
+    return visitor.checkLists(
+        node.parameters, other.parameters, visitor.checkNodes, 'parameters');
+  }
+
+  bool checkTypedefTearOffConstant_tearOffConstant(EquivalenceVisitor visitor,
+      TypedefTearOffConstant node, TypedefTearOffConstant other) {
+    return visitor.checkNodes(
+        node.tearOffConstant, other.tearOffConstant, 'tearOffConstant');
+  }
+
+  bool checkTypedefTearOffConstant_types(EquivalenceVisitor visitor,
+      TypedefTearOffConstant node, TypedefTearOffConstant other) {
+    return visitor.checkLists(
+        node.types, other.types, visitor.checkNodes, 'types');
+  }
+
+  bool checkTypeLiteralConstant_type(EquivalenceVisitor visitor,
+      TypeLiteralConstant node, TypeLiteralConstant other) {
+    return visitor.checkNodes(node.type, other.type, 'type');
+  }
+
+  bool checkUnevaluatedConstant_expression(EquivalenceVisitor visitor,
+      UnevaluatedConstant node, UnevaluatedConstant other) {
+    return visitor.checkNodes(node.expression, other.expression, 'expression');
+  }
+}
diff --git a/pkg/kernel/lib/src/equivalence_helpers.dart b/pkg/kernel/lib/src/equivalence_helpers.dart
new file mode 100644
index 0000000..a7ccb27
--- /dev/null
+++ b/pkg/kernel/lib/src/equivalence_helpers.dart
@@ -0,0 +1,400 @@
+// 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.
+
+part of 'equivalence.dart';
+
+/// The node or property currently visited by the [EquivalenceVisitor].
+abstract class State {
+  const State();
+
+  State? get parent;
+}
+
+/// State for visiting two AST nodes in [EquivalenceVisitor].
+class NodeState extends State {
+  final State? parent;
+  final Node a;
+  final Node b;
+
+  NodeState(this.a, this.b, [this.parent]);
+}
+
+/// State for visiting an AST property in [EquivalenceVisitor]
+class PropertyState extends State {
+  final State? parent;
+  final String name;
+
+  PropertyState(this.name, [this.parent]);
+}
+
+/// The state of the equivalence visitor.
+///
+/// This holds the currently found inequivalences and the current assumptions.
+/// This also determines whether inequivalence are currently reported.
+class CheckingState {
+  /// If `true`, inequivalences are currently reported.
+  final bool isAsserting;
+
+  CheckingState(
+      {this.isAsserting: true,
+      UnionFind<Reference>? assumedReferences,
+      State? currentState})
+      : _assumedReferences = assumedReferences ?? new UnionFind<Reference>(),
+        _currentState = currentState;
+
+  /// Create a new [CheckingState] that inherits the [_currentState] and a copy
+  /// of the current assumptions. If [isAsserting] is `true`, the new state
+  /// will register inequivalences.
+  CheckingState createSubState({bool isAsserting: false}) {
+    return new CheckingState(
+        isAsserting: isAsserting,
+        assumedReferences: _assumedReferences.clone(),
+        currentState: _currentState)
+      .._assumedDeclarationMap.addAll(_assumedDeclarationMap);
+  }
+
+  /// Returns a state corresponding to the state which does _not_ register
+  /// inequivalences. If this state is already not registering inequivalences,
+  /// `this` is returned.
+  CheckingState toMatchingState() {
+    if (!isAsserting) return this;
+    return createSubState(isAsserting: false);
+  }
+
+  /// Returns that value that should be used as the result value when
+  /// inequivalence are found.
+  ///
+  /// See [EquivalenceVisitor.resultOnInequivalence] for details.
+  bool get resultOnInequivalence => isAsserting;
+
+  /// Map of [Reference]s that are assumed to be equivalent. The keys are
+  /// the [Reference]s on the left side of the equivalence relation.
+  UnionFind<Reference> _assumedReferences;
+
+  /// Returns `true` if [a] and [b] are currently assumed to be equivalent.
+  bool checkAssumedReferences(Reference? a, Reference? b) {
+    if (identical(a, b)) return true;
+    if (a == null || b == null) return false;
+    return _assumedReferences.valuesInSameSet(a, b);
+  }
+
+  /// Assume that [a] and [b] are equivalent, if possible.
+  ///
+  /// Returns `true` if [a] and [b] could be assumed to be equivalent. This
+  /// is not the case if either [a] or [b] is `null`.
+  bool assumeReferences(Reference? a, Reference? b) {
+    if (identical(a, b)) return true;
+    if (a == null || b == null) return false;
+    _assumedReferences.unionOfValues(a, b);
+    return true;
+  }
+
+  /// Map of declarations that are assumed to be equivalent.
+  Map<dynamic, dynamic> _assumedDeclarationMap = {};
+
+  /// Returns `true` if [a] and [b] are currently assumed to be equivalent.
+  bool checkAssumedDeclarations(dynamic a, dynamic b) {
+    if (identical(a, b)) return true;
+    if (a == null || b == null) return false;
+    return _assumedDeclarationMap.containsKey(a) &&
+        _assumedDeclarationMap[a] == b;
+  }
+
+  /// Assume that [a] and [b] are equivalent, if possible.
+  ///
+  /// Returns `true` if [a] and [b] could be assumed to be equivalent. This
+  /// would not be the case if [a] is already assumed to be equivalent to
+  /// another declaration.
+  bool assumeDeclarations(dynamic a, dynamic b) {
+    if (identical(a, b)) return true;
+    if (a == null || b == null) return false;
+    if (_assumedDeclarationMap.containsKey(a)) {
+      return _assumedDeclarationMap[a] == b;
+    } else {
+      _assumedDeclarationMap[a] = b;
+      return true;
+    }
+  }
+
+  /// The currently visited node or property.
+  State? _currentState;
+
+  /// Enters a new property state of a property named [propertyName].
+  void pushPropertyState(String propertyName) {
+    _currentState = new PropertyState(propertyName, _currentState);
+  }
+
+  /// Enters a new node state of nodes [a] and [b].
+  void pushNodeState(Node a, Node b) {
+    _currentState = new NodeState(a, b, _currentState);
+  }
+
+  /// Leaves the current node or property.
+  void popState() {
+    _currentState = _currentState?.parent;
+  }
+
+  /// List of registered inequivalences.
+  List<Inequivalence> _inequivalences = [];
+
+  /// Registers the inequivalence [message] on [propertyName].
+  void registerInequivalence(String propertyName, String message) {
+    _inequivalences.add(new Inequivalence(
+        new PropertyState(propertyName, _currentState), message));
+  }
+
+  /// Returns `true` if inequivalences have been registered.
+  bool get hasInequivalences => _inequivalences.isNotEmpty;
+
+  /// Returns the [EquivalenceResult] for the registered inequivalences. If
+  /// [hasInequivalences] is `true`, the result is marked has having
+  /// inequivalences, even when none have been registered.
+  EquivalenceResult toResult({bool hasInequivalences: false}) =>
+      new EquivalenceResult(
+          hasInequivalences: hasInequivalences,
+          registeredInequivalences: _inequivalences.toList());
+}
+
+/// The result of performing equivalence checking.
+class EquivalenceResult {
+  final bool hasInequivalences;
+  final List<Inequivalence> registeredInequivalences;
+
+  EquivalenceResult(
+      {this.hasInequivalences: false, required this.registeredInequivalences});
+
+  bool get isEquivalent =>
+      !hasInequivalences && registeredInequivalences.isEmpty;
+
+  @override
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    for (Inequivalence inequivalence in registeredInequivalences) {
+      sb.writeln(inequivalence);
+    }
+    return sb.toString();
+  }
+}
+
+/// A registered inequivalence holding the [state] at which is was found and
+/// details about the inequivalence.
+class Inequivalence {
+  final State state;
+  final String message;
+
+  Inequivalence(this.state, this.message);
+
+  @override
+  String toString() {
+    List<State> states = [];
+    State? state = this.state;
+    while (state != null) {
+      states.add(state);
+      state = state.parent;
+    }
+    StringBuffer sb = new StringBuffer();
+    sb.writeln(message);
+    String indent = ' ';
+    for (State state in states.reversed) {
+      if (state is NodeState) {
+        sb.writeln();
+        sb.write(indent);
+        indent = ' $indent';
+        if (state.a.runtimeType == state.b.runtimeType) {
+          if (state.a is NamedNode) {
+            sb.write(state.a.runtimeType);
+            sb.write('(');
+            sb.write(state.a.toText(defaultAstTextStrategy));
+            sb.write(')');
+          } else {
+            sb.write(state.a.runtimeType);
+          }
+        } else {
+          sb.write('(${state.a.runtimeType}/${state.b.runtimeType})');
+        }
+      } else if (state is PropertyState) {
+        sb.write('.${state.name}');
+      } else {
+        throw new UnsupportedError('Unexpected state ${state.runtimeType}');
+      }
+    }
+    return sb.toString();
+  }
+}
+
+/// Enum for different kinds of [ReferenceName]s.
+enum ReferenceNameKind {
+  /// A reference name without information.
+  Unknown,
+
+  /// A reference name of a library.
+  Library,
+
+  /// A reference name of a class or extension.
+  Declaration,
+
+  /// A reference name of a typedef or member.
+  Member,
+}
+
+/// Abstract representation of a [Reference] or [CanonicalName].
+///
+/// This is used to determine nominality of [Reference]s consistently,
+/// regardless of whether the [Reference] has an attached node or canonical
+/// name.
+class ReferenceName {
+  final ReferenceNameKind kind;
+  final ReferenceName? parent;
+  final String? name;
+  final String? uri;
+
+  ReferenceName.internal(this.kind, this.name, [this.parent, this.uri]);
+
+  factory ReferenceName.fromNamedNode(NamedNode node) {
+    if (node is Library) {
+      return new ReferenceName.internal(
+          ReferenceNameKind.Library, node.importUri.toString());
+    } else if (node is Extension) {
+      return new ReferenceName.internal(ReferenceNameKind.Declaration,
+          node.name, new ReferenceName.fromNamedNode(node.enclosingLibrary));
+    } else if (node is Class) {
+      return new ReferenceName.internal(ReferenceNameKind.Declaration,
+          node.name, new ReferenceName.fromNamedNode(node.enclosingLibrary));
+    } else if (node is Typedef) {
+      return new ReferenceName.internal(ReferenceNameKind.Member, node.name,
+          new ReferenceName.fromNamedNode(node.enclosingLibrary));
+    } else if (node is Member) {
+      Class? enclosingClass = node.enclosingClass;
+      Reference? libraryReference = node.name.libraryName;
+      String? uri;
+      if (libraryReference != null) {
+        Library? library = libraryReference.node as Library?;
+        if (library != null) {
+          uri = library.importUri.toString();
+        } else {
+          uri = libraryReference.canonicalName?.name;
+        }
+      }
+      if (enclosingClass != null) {
+        return new ReferenceName.internal(
+            ReferenceNameKind.Member,
+            node.name.text,
+            new ReferenceName.fromNamedNode(enclosingClass),
+            uri);
+      } else {
+        return new ReferenceName.internal(
+            ReferenceNameKind.Member,
+            node.name.text,
+            new ReferenceName.fromNamedNode(node.enclosingLibrary),
+            uri);
+      }
+    } else {
+      throw new ArgumentError(
+          'Unexpected named node ${node} (${node.runtimeType})');
+    }
+  }
+
+  factory ReferenceName.fromCanonicalName(CanonicalName canonicalName) {
+    List<CanonicalName> parents = [];
+    CanonicalName? parent = canonicalName;
+    while (parent != null) {
+      parents.add(parent);
+      parent = parent.parent;
+    }
+    parents = parents.reversed.toList();
+    ReferenceName? referenceName;
+    ReferenceNameKind kind = ReferenceNameKind.Declaration;
+    for (int index = 1; index < parents.length; index++) {
+      if (index == 1) {
+        // Library reference.
+        referenceName = new ReferenceName.internal(
+            ReferenceNameKind.Library, parents[index].name);
+      } else if (CanonicalName.isSymbolicName(parents[index].name)) {
+        // Skip symbolic names
+        kind = ReferenceNameKind.Member;
+      } else {
+        if (index + 2 == parents.length) {
+          // This is a private name.
+          referenceName = new ReferenceName.internal(ReferenceNameKind.Member,
+              parents[index + 1].name, referenceName, parents[index].name);
+          break;
+        } else {
+          referenceName = new ReferenceName.internal(
+              kind, parents[index].name, referenceName);
+        }
+      }
+    }
+    return referenceName ??
+        new ReferenceName.internal(ReferenceNameKind.Unknown, null);
+  }
+
+  String? get libraryUri {
+    if (kind == ReferenceNameKind.Library) {
+      return name;
+    } else {
+      return parent?.libraryUri;
+    }
+  }
+
+  String? get declarationName {
+    if (kind == ReferenceNameKind.Declaration) {
+      return name;
+    } else {
+      return parent?.declarationName;
+    }
+  }
+
+  String? get memberName {
+    if (kind == ReferenceNameKind.Member) {
+      return name;
+    }
+    return null;
+  }
+
+  String? get memberUri {
+    if (kind == ReferenceNameKind.Member) {
+      return uri;
+    }
+    return null;
+  }
+
+  static ReferenceName? fromReference(Reference? reference) {
+    if (reference == null) {
+      return null;
+    }
+    NamedNode? node = reference.node;
+    if (node != null) {
+      return new ReferenceName.fromNamedNode(node);
+    }
+    CanonicalName? canonicalName = reference.canonicalName;
+    if (canonicalName != null) {
+      return new ReferenceName.fromCanonicalName(canonicalName);
+    }
+    return new ReferenceName.internal(ReferenceNameKind.Unknown, null);
+  }
+
+  @override
+  int get hashCode =>
+      name.hashCode * 13 + uri.hashCode * 17 + parent.hashCode * 19;
+
+  @override
+  bool operator ==(Object other) {
+    if (identical(this, other)) return true;
+    return other is ReferenceName &&
+        name == other.name &&
+        uri == other.uri &&
+        parent == other.parent;
+  }
+
+  @override
+  String toString() {
+    if (parent != null) {
+      return '${parent}/$name';
+    } else if (name != null) {
+      return '/$name';
+    } else {
+      return '<null>';
+    }
+  }
+}
diff --git a/pkg/kernel/lib/src/union_find.dart b/pkg/kernel/lib/src/union_find.dart
new file mode 100644
index 0000000..4dffab0
--- /dev/null
+++ b/pkg/kernel/lib/src/union_find.dart
@@ -0,0 +1,76 @@
+// 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 'dart:collection';
+
+class UnionFindNode<T> {
+  final T value;
+  UnionFindNode<T>? parent;
+
+  UnionFindNode(this.value);
+}
+
+class UnionFind<T> {
+  final bool _useIdentity;
+  final Map<T, UnionFindNode<T>> _nodeMap;
+
+  UnionFind({bool useIdentity: false})
+      : _nodeMap = useIdentity ? new LinkedHashMap.identity() : {},
+        _useIdentity = useIdentity;
+
+  UnionFind<T> clone() {
+    UnionFind<T> newUnionFind = new UnionFind<T>(useIdentity: _useIdentity);
+    Map<UnionFindNode<T>, UnionFindNode<T>> oldToNewMap = {};
+
+    UnionFindNode<T> getNewNode(UnionFindNode<T> oldNode) {
+      UnionFindNode<T> newNode = newUnionFind[oldNode.value];
+      return oldToNewMap[oldNode] = newNode;
+    }
+
+    for (UnionFindNode<T> oldNode in _nodeMap.values) {
+      UnionFindNode<T> newNode = getNewNode(oldNode);
+      if (oldNode.parent != null) {
+        newNode.parent = getNewNode(oldNode.parent!);
+      }
+    }
+    return newUnionFind;
+  }
+
+  UnionFindNode<T> operator [](T value) =>
+      _nodeMap[value] ??= new UnionFindNode<T>(value);
+
+  Iterable<UnionFindNode<T>> get nodes => _nodeMap.values;
+
+  Iterable<T> get values => nodes.map((n) => n.value);
+
+  UnionFindNode<T> findNode(UnionFindNode<T> node) {
+    if (node.parent != null) {
+      return node.parent = findNode(node.parent!);
+    }
+    return node;
+  }
+
+  void unionOfValues(T a, T b) {
+    unionOfNodes(this[a], this[b]);
+  }
+
+  UnionFindNode<T> unionOfNodes(UnionFindNode<T> a, UnionFindNode<T> b) {
+    UnionFindNode<T> rootA = findNode(a);
+    UnionFindNode<T> rootB = findNode(b);
+    if (rootA != rootB) {
+      return rootB.parent = rootA;
+    }
+    return rootA;
+  }
+
+  bool valuesInSameSet(T a, T b) {
+    UnionFindNode<T>? node1 = _nodeMap[a];
+    UnionFindNode<T>? node2 = _nodeMap[b];
+    return node1 != null && node2 != null && nodesInSameSet(node1, node2);
+  }
+
+  bool nodesInSameSet(UnionFindNode<T> a, UnionFindNode<T> b) {
+    return findNode(a) == findNode(b);
+  }
+}
diff --git a/pkg/compiler/lib/src/ir/debug.dart b/pkg/kernel/lib/text/debug_printer.dart
similarity index 93%
rename from pkg/compiler/lib/src/ir/debug.dart
rename to pkg/kernel/lib/text/debug_printer.dart
index 3b9e11a..fa700c1 100644
--- a/pkg/compiler/lib/src/ir/debug.dart
+++ b/pkg/kernel/lib/text/debug_printer.dart
@@ -8,14 +8,14 @@
 
 import 'package:kernel/ast.dart';
 
-import '../util/util.dart' show Indentation, Tagging;
+import 'indentation.dart' show Indentation, Tagging;
 
 class DebugPrinter extends Visitor<void>
     with Indentation, Tagging<Node>, VisitorVoidMixin {
   @override
   StringBuffer sb = new StringBuffer();
 
-  void visitNodeWithChildren(Node node, String type, [Map params]) {
+  void visitNodeWithChildren(Node node, String type, [Map? params]) {
     openNode(node, type, params);
     node.visitChildren(this);
     closeNode();
@@ -102,7 +102,7 @@
 
   /// Pretty-prints given node tree into string.
   static String prettyPrint(Node node) {
-    var p = new DebugPrinter();
+    DebugPrinter p = new DebugPrinter();
     node.accept(p);
     return p.sb.toString();
   }
diff --git a/pkg/compiler/lib/src/util/indentation.dart b/pkg/kernel/lib/text/indentation.dart
similarity index 92%
rename from pkg/compiler/lib/src/util/indentation.dart
rename to pkg/kernel/lib/text/indentation.dart
index d792f2f..4c9c344 100644
--- a/pkg/compiler/lib/src/util/indentation.dart
+++ b/pkg/kernel/lib/text/indentation.dart
@@ -2,10 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart=2.12
-
-part of dart2js.util;
-
 /// Indentation utility class. Should be used as a mixin in most cases.
 class Indentation {
   /// The current indentation string.
@@ -48,7 +44,7 @@
   /// upon return of [f] and returning its result.
   indentBlock(Function f) {
     indentMore();
-    var result = f();
+    dynamic result = f();
     indentLess();
     return result;
   }
@@ -56,19 +52,17 @@
 
 abstract class Tagging<N> implements Indentation {
   StringBuffer sb = new StringBuffer();
-  Link<String> tagStack = const Link<String>();
+  List<String> tagStack = [];
 
   void pushTag(String tag) {
-    tagStack = tagStack.prepend(tag);
+    tagStack.add(tag);
     indentMore();
   }
 
   String popTag() {
     assert(!tagStack.isEmpty);
-    String tag = tagStack.head;
-    tagStack = tagStack.tail!;
     indentLess();
-    return tag;
+    return tagStack.removeLast();
   }
 
   /// Adds given string to result string.
@@ -135,5 +129,5 @@
   }
 
   /// Converts a parameter value into a string.
-  String valueToString(var value) => value;
+  String valueToString(dynamic value) => value;
 }
diff --git a/pkg/kernel/lib/visitor.dart b/pkg/kernel/lib/visitor.dart
index d7de1d7..5e5c959 100644
--- a/pkg/kernel/lib/visitor.dart
+++ b/pkg/kernel/lib/visitor.dart
@@ -590,6 +590,42 @@
   R visitUnevaluatedConstant(UnevaluatedConstant node) => defaultConstant(node);
 }
 
+abstract class ConstantVisitor1<R, A> {
+  const ConstantVisitor1();
+
+  R defaultConstant(Constant node, A arg);
+
+  R visitNullConstant(NullConstant node, A arg) => defaultConstant(node, arg);
+  R visitBoolConstant(BoolConstant node, A arg) => defaultConstant(node, arg);
+  R visitIntConstant(IntConstant node, A arg) => defaultConstant(node, arg);
+  R visitDoubleConstant(DoubleConstant node, A arg) =>
+      defaultConstant(node, arg);
+  R visitStringConstant(StringConstant node, A arg) =>
+      defaultConstant(node, arg);
+  R visitSymbolConstant(SymbolConstant node, A arg) =>
+      defaultConstant(node, arg);
+  R visitMapConstant(MapConstant node, A arg) => defaultConstant(node, arg);
+  R visitListConstant(ListConstant node, A arg) => defaultConstant(node, arg);
+  R visitSetConstant(SetConstant node, A arg) => defaultConstant(node, arg);
+  R visitInstanceConstant(InstanceConstant node, A arg) =>
+      defaultConstant(node, arg);
+  R visitInstantiationConstant(InstantiationConstant node, A arg) =>
+      defaultConstant(node, arg);
+  R visitStaticTearOffConstant(StaticTearOffConstant node, A arg) =>
+      defaultConstant(node, arg);
+  R visitTypedefTearOffConstant(TypedefTearOffConstant node, A arg) =>
+      defaultConstant(node, arg);
+  R visitConstructorTearOffConstant(ConstructorTearOffConstant node, A arg) =>
+      defaultConstant(node, arg);
+  R visitRedirectingFactoryTearOffConstant(
+          RedirectingFactoryTearOffConstant node, A arg) =>
+      defaultConstant(node, arg);
+  R visitTypeLiteralConstant(TypeLiteralConstant node, A arg) =>
+      defaultConstant(node, arg);
+  R visitUnevaluatedConstant(UnevaluatedConstant node, A arg) =>
+      defaultConstant(node, arg);
+}
+
 abstract class _ConstantCallback<R> {
   R defaultConstant(Constant node);
 
@@ -803,6 +839,21 @@
   }
 }
 
+abstract class MemberReferenceVisitor1<R, A> {
+  const MemberReferenceVisitor1();
+
+  R defaultMemberReference(Member node, A arg);
+
+  R visitFieldReference(Field node, A arg) => defaultMemberReference(node, arg);
+  R visitConstructorReference(Constructor node, A arg) =>
+      defaultMemberReference(node, arg);
+  R visitProcedureReference(Procedure node, A arg) =>
+      defaultMemberReference(node, arg);
+  R visitRedirectingFactoryReference(RedirectingFactory node, A arg) {
+    return defaultMemberReference(node, arg);
+  }
+}
+
 abstract class Visitor<R> extends TreeVisitor<R>
     implements
         DartTypeVisitor<R>,
@@ -915,6 +966,118 @@
   R visitNamedType(NamedType node) => defaultNode(node);
 }
 
+abstract class Visitor1<R, A> extends TreeVisitor1<R, A>
+    implements
+        DartTypeVisitor1<R, A>,
+        ConstantVisitor1<R, A>,
+        MemberReferenceVisitor1<R, A> {
+  const Visitor1();
+
+  /// The catch-all case, except for references.
+  R defaultNode(Node node, A arg);
+  R defaultTreeNode(TreeNode node, A arg) => defaultNode(node, arg);
+
+  // DartTypes
+  R defaultDartType(DartType node, A arg) => defaultNode(node, arg);
+  R visitInvalidType(InvalidType node, A arg) => defaultDartType(node, arg);
+  R visitDynamicType(DynamicType node, A arg) => defaultDartType(node, arg);
+  R visitVoidType(VoidType node, A arg) => defaultDartType(node, arg);
+  R visitInterfaceType(InterfaceType node, A arg) => defaultDartType(node, arg);
+  R visitFutureOrType(FutureOrType node, A arg) => defaultDartType(node, arg);
+  R visitFunctionType(FunctionType node, A arg) => defaultDartType(node, arg);
+  R visitTypeParameterType(TypeParameterType node, A arg) =>
+      defaultDartType(node, arg);
+  R visitTypedefType(TypedefType node, A arg) => defaultDartType(node, arg);
+  R visitNeverType(NeverType node, A arg) => defaultDartType(node, arg);
+  R visitNullType(NullType node, A arg) => defaultDartType(node, arg);
+  R visitExtensionType(ExtensionType node, A arg) => defaultDartType(node, arg);
+
+  // Constants
+  R defaultConstant(Constant node, A arg) => defaultNode(node, arg);
+  R visitNullConstant(NullConstant node, A arg) => defaultConstant(node, arg);
+  R visitBoolConstant(BoolConstant node, A arg) => defaultConstant(node, arg);
+  R visitIntConstant(IntConstant node, A arg) => defaultConstant(node, arg);
+  R visitDoubleConstant(DoubleConstant node, A arg) =>
+      defaultConstant(node, arg);
+  R visitStringConstant(StringConstant node, A arg) =>
+      defaultConstant(node, arg);
+  R visitSymbolConstant(SymbolConstant node, A arg) =>
+      defaultConstant(node, arg);
+  R visitMapConstant(MapConstant node, A arg) => defaultConstant(node, arg);
+  R visitListConstant(ListConstant node, A arg) => defaultConstant(node, arg);
+  R visitSetConstant(SetConstant node, A arg) => defaultConstant(node, arg);
+  R visitInstanceConstant(InstanceConstant node, A arg) =>
+      defaultConstant(node, arg);
+  R visitInstantiationConstant(InstantiationConstant node, A arg) =>
+      defaultConstant(node, arg);
+  R visitTypeLiteralConstant(TypeLiteralConstant node, A arg) =>
+      defaultConstant(node, arg);
+  R visitUnevaluatedConstant(UnevaluatedConstant node, A arg) =>
+      defaultConstant(node, arg);
+
+  // Class references
+  R visitClassReference(Class node, A arg);
+
+  R visitTypedefReference(Typedef node, A arg);
+
+  R visitExtensionReference(Extension node, A arg);
+
+  // Constant references
+  R defaultConstantReference(Constant node, A arg);
+
+  R visitNullConstantReference(NullConstant node, A arg) =>
+      defaultConstantReference(node, arg);
+  R visitBoolConstantReference(BoolConstant node, A arg) =>
+      defaultConstantReference(node, arg);
+  R visitIntConstantReference(IntConstant node, A arg) =>
+      defaultConstantReference(node, arg);
+  R visitDoubleConstantReference(DoubleConstant node, A arg) =>
+      defaultConstantReference(node, arg);
+  R visitStringConstantReference(StringConstant node, A arg) =>
+      defaultConstantReference(node, arg);
+  R visitSymbolConstantReference(SymbolConstant node, A arg) =>
+      defaultConstantReference(node, arg);
+  R visitMapConstantReference(MapConstant node, A arg) =>
+      defaultConstantReference(node, arg);
+  R visitListConstantReference(ListConstant node, A arg) =>
+      defaultConstantReference(node, arg);
+  R visitSetConstantReference(SetConstant node, A arg) =>
+      defaultConstantReference(node, arg);
+  R visitInstanceConstantReference(InstanceConstant node, A arg) =>
+      defaultConstantReference(node, arg);
+  R visitInstantiationConstantReference(InstantiationConstant node, A arg) =>
+      defaultConstantReference(node, arg);
+  R visitConstructorTearOffConstantReference(
+          ConstructorTearOffConstant node, A arg) =>
+      defaultConstantReference(node, arg);
+  R visitRedirectingFactoryTearOffConstantReference(
+          RedirectingFactoryTearOffConstant node, A arg) =>
+      defaultConstantReference(node, arg);
+  R visitStaticTearOffConstantReference(StaticTearOffConstant node, A arg) =>
+      defaultConstantReference(node, arg);
+  R visitTypedefTearOffConstantReference(TypedefTearOffConstant node, A arg) =>
+      defaultConstantReference(node, arg);
+  R visitTypeLiteralConstantReference(TypeLiteralConstant node, A arg) =>
+      defaultConstantReference(node, arg);
+  R visitUnevaluatedConstantReference(UnevaluatedConstant node, A arg) =>
+      defaultConstantReference(node, arg);
+
+  // Member references
+  R defaultMemberReference(Member node, A arg);
+
+  R visitFieldReference(Field node, A arg) => defaultMemberReference(node, arg);
+  R visitConstructorReference(Constructor node, A arg) =>
+      defaultMemberReference(node, arg);
+  R visitProcedureReference(Procedure node, A arg) =>
+      defaultMemberReference(node, arg);
+  R visitRedirectingFactoryReference(RedirectingFactory node, A arg) =>
+      defaultMemberReference(node, arg);
+
+  R visitName(Name node, A arg) => defaultNode(node, arg);
+  R visitSupertype(Supertype node, A arg) => defaultNode(node, arg);
+  R visitNamedType(NamedType node, A arg) => defaultNode(node, arg);
+}
+
 /// Visitor mixin that throws as its base case.
 mixin VisitorThrowingMixin<R> implements Visitor<R> {
   @override
diff --git a/pkg/kernel/test/convert_field_to_setter_getter.dart b/pkg/kernel/test/convert_field_to_setter_getter.dart
index 900dbf4..89f1fd9 100644
--- a/pkg/kernel/test/convert_field_to_setter_getter.dart
+++ b/pkg/kernel/test/convert_field_to_setter_getter.dart
@@ -40,13 +40,15 @@
   // Canonical names are now set: Verify that the field is marked as such,
   // canonical-name-wise.
   String getterCanonicalName = '${field.getterReference.canonicalName}';
-  if (field.getterReference.canonicalName!.parent!.name != "@getters") {
-    throw "Expected @getters parent, but had "
+  if (field.getterReference.canonicalName!.parent!.name !=
+      CanonicalName.gettersName) {
+    throw "Expected ${CanonicalName.gettersName} parent, but had "
         "${field.getterReference.canonicalName!.parent!.name}";
   }
   String setterCanonicalName = '${field.setterReference!.canonicalName}';
-  if (field.setterReference!.canonicalName!.parent!.name != "@setters") {
-    throw "Expected @setters parent, but had "
+  if (field.setterReference!.canonicalName!.parent!.name !=
+      CanonicalName.settersName) {
+    throw "Expected ${CanonicalName.settersName} parent, but had "
         "${field.setterReference!.canonicalName!.parent!.name}";
   }
 
diff --git a/pkg/kernel/test/equivalence_test.dart b/pkg/kernel/test/equivalence_test.dart
new file mode 100644
index 0000000..de5ec47
--- /dev/null
+++ b/pkg/kernel/test/equivalence_test.dart
@@ -0,0 +1,204 @@
+// 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:expect/expect.dart';
+import 'package:kernel/ast.dart';
+import 'package:kernel/src/equivalence.dart';
+
+final Component component1 = createComponent();
+final Component component2 = createComponent();
+
+List<Test> tests = [
+  Test(IntLiteral(0), IntLiteral(0)),
+  Test(IntLiteral(42), IntLiteral(42)),
+  Test(IntLiteral(0), IntLiteral(42), inequivalence: '''
+Values 0 and 42 are not equivalent
+.root
+ IntLiteral.value
+'''),
+  Test(StringLiteral('0'), StringLiteral('0')),
+  Test(StringLiteral('42'), StringLiteral('42')),
+  Test(StringLiteral('0'), StringLiteral('42'), inequivalence: '''
+Values 0 and 42 are not equivalent
+.root
+ StringLiteral.value
+'''),
+  Test(IntLiteral(0), IntLiteral(42), strategy: const IgnoreIntLiteralValue()),
+  Test(StringLiteral('0'), StringLiteral('42'),
+      strategy: const IgnoreIntLiteralValue(), inequivalence: '''
+Values 0 and 42 are not equivalent
+.root
+ StringLiteral.value
+'''),
+  Test(IntLiteral(0), StringLiteral('0'), inequivalence: '''
+Inequivalent nodes
+1: IntLiteral(0)
+2: StringLiteral("0")
+.root
+'''),
+  Test(Not(Not(Not(BoolLiteral(true)))), Not(Not(Not(BoolLiteral(true))))),
+  Test(Not(Not(BoolLiteral(true))), Not(Not(Not(BoolLiteral(true)))),
+      inequivalence: '''
+Inequivalent nodes
+1: BoolLiteral(true)
+2: Not(!true)
+.root
+ Not.operand
+  Not.operand
+'''),
+  Test(Not(Not(Not(BoolLiteral(true)))), Not(Not(BoolLiteral(true))),
+      inequivalence: '''
+Inequivalent nodes
+1: Not(!true)
+2: BoolLiteral(true)
+.root
+ Not.operand
+  Not.operand
+'''),
+  Test(Not(Not(Not(BoolLiteral(true)))), Not(Not(Not(BoolLiteral(false)))),
+      inequivalence: '''
+Values true and false are not equivalent
+.root
+ Not.operand
+  Not.operand
+   Not.operand
+    BoolLiteral.value
+'''),
+  Test(component1, component2),
+  Test(component1.libraries[0], component2.libraries[0]),
+  Test(component1.libraries[0], component2.libraries[0]),
+  Test(component1.libraries[0], component2.libraries[1], inequivalence: '''
+Inequivalent nodes
+1: library file://uri1/
+2: library file://uri2/
+.root
+'''),
+  Test(component1.libraries[1], component2.libraries[2], inequivalence: '''
+Inequivalent nodes
+1: library file://uri2/
+2: library file://uri3/
+.root
+'''),
+  Test(component1.libraries[1], component2.libraries[3], inequivalence: '''
+Values file://uri2/ and file://uri3/ are not equivalent
+.root
+ Library(library file://uri2/).fileUri
+'''),
+  Test(component1.libraries[0].procedures[0],
+      component2.libraries[0].procedures[1],
+      inequivalence: '''
+Inequivalent nodes
+1: foo
+2: bar
+.root
+'''),
+  // TODO(johnniwinther): Improve message for inequivalent references with the
+  // same simple name.
+  Test(component1.libraries[0].procedures[0],
+      component2.libraries[2].procedures[0],
+      inequivalence: '''
+Inequivalent nodes
+1: foo
+2: foo
+.root
+'''),
+  Test(StaticTearOff.byReference(Reference()),
+      StaticTearOff.byReference(Reference())),
+  Test(
+      StaticTearOff.byReference(
+          component1.libraries[0].procedures[0].reference),
+      StaticTearOff.byReference(
+          component2.libraries[0].procedures[0].reference)),
+  // TODO(johnniwinther): Improve message for inequivalent references with the
+  // same simple name.
+  Test(
+      StaticTearOff.byReference(
+          component1.libraries[0].procedures[0].reference),
+      StaticTearOff.byReference(
+          component2.libraries[2].procedures[0].reference),
+      inequivalence: '''
+Inequivalent references:
+1: Reference to foo
+2: Reference to foo
+.root
+ StaticTearOff.targetReference
+'''),
+];
+
+main() {
+  for (Test test in tests) {
+    EquivalenceResult result =
+        checkEquivalence(test.a, test.b, strategy: test.strategy);
+    if (test.isEquivalent) {
+      Expect.equals(result.isEquivalent, test.isEquivalent,
+          'Unexpected result for\n${test.a}\n${test.b}:\n$result');
+    } else if (result.isEquivalent) {
+      Expect.equals(
+          result.isEquivalent,
+          test.isEquivalent,
+          'Unexpected equivalence for\n${test.a}\n${test.b}:\n'
+          'Expected ${test.inequivalence}');
+    } else {
+      Expect.stringEquals(
+          result.toString(),
+          test.inequivalence!,
+          'Unexpected inequivalence result for\n${test.a}\n${test.b}:\n'
+          'Expected:\n---\n${test.inequivalence}\n---\n'
+          'Actual:\n---\n${result}\n---');
+    }
+  }
+}
+
+class Test {
+  final Node a;
+  final Node b;
+  final String? inequivalence;
+  final EquivalenceStrategy strategy;
+
+  Test(this.a, this.b,
+      {this.inequivalence, this.strategy = const EquivalenceStrategy()});
+
+  bool get isEquivalent => inequivalence == null;
+}
+
+class IgnoreIntLiteralValue extends EquivalenceStrategy {
+  const IgnoreIntLiteralValue();
+
+  @override
+  bool checkIntLiteral_value(
+          EquivalenceVisitor visitor, IntLiteral a, IntLiteral b) =>
+      true;
+}
+
+Component createComponent() {
+  Component component = new Component();
+  Uri uri1 = Uri.parse('file://uri1');
+  Uri uri2 = Uri.parse('file://uri2');
+  Uri uri3 = Uri.parse('file://uri3');
+  Library library1 = new Library(uri1, fileUri: uri1);
+  component.libraries.add(library1);
+  Procedure procedure1foo = new Procedure(
+      new Name('foo'), ProcedureKind.Method, new FunctionNode(null),
+      fileUri: uri1);
+  library1.addProcedure(procedure1foo);
+  Procedure procedure1bar = new Procedure(
+      new Name('bar'), ProcedureKind.Method, new FunctionNode(null),
+      fileUri: uri1);
+  library1.addProcedure(procedure1bar);
+
+  Library library2 = new Library(uri2, fileUri: uri2);
+  component.libraries.add(library2);
+
+  Library library3 = new Library(uri3, fileUri: uri2);
+  component.libraries.add(library3);
+  Procedure procedure3foo = new Procedure(
+      new Name('foo'), ProcedureKind.Method, new FunctionNode(null),
+      fileUri: uri1);
+  library3.addProcedure(procedure3foo);
+
+  Library library4 = new Library(uri2, fileUri: uri3);
+  component.libraries.add(library4);
+
+  return component;
+}
diff --git a/pkg/kernel/test/equivalent_dill_test.dart b/pkg/kernel/test/equivalent_dill_test.dart
new file mode 100644
index 0000000..baac8b3
--- /dev/null
+++ b/pkg/kernel/test/equivalent_dill_test.dart
@@ -0,0 +1,112 @@
+// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart = 2.9
+
+import 'dart:io';
+
+import 'package:kernel/binary/ast_from_binary.dart';
+import 'package:kernel/kernel.dart';
+import 'package:kernel/src/equivalence.dart';
+
+main(List<String> args) {
+  String resolvedExecutable = Platform.environment['resolvedExecutable'];
+  File exe =
+      new File(resolvedExecutable ?? Platform.resolvedExecutable).absolute;
+  int steps = 0;
+  Directory parent = exe.parent.parent;
+  while (true) {
+    Set<String> foundDirs = {};
+    for (FileSystemEntity entry in parent.listSync(recursive: false)) {
+      if (entry is Directory) {
+        List<String> pathSegments = entry.uri.pathSegments;
+        String name = pathSegments[pathSegments.length - 2];
+        foundDirs.add(name);
+      }
+    }
+    if (foundDirs.contains("pkg") &&
+        foundDirs.contains("tools") &&
+        foundDirs.contains("tests")) {
+      break;
+    }
+    steps++;
+    if (parent.uri == parent.parent.uri) {
+      throw "Reached end without finding the root.";
+    }
+    parent = parent.parent;
+  }
+  // We had to go $steps steps to reach the "root" --- now we should go 2 steps
+  // shorter to be in the "compiled dir".
+  parent = exe.parent;
+  for (int i = steps - 2; i >= 0; i--) {
+    parent = parent.parent;
+  }
+
+  List<File> dills = [];
+  for (FileSystemEntity entry in parent.listSync(recursive: false)) {
+    if (entry is File) {
+      if (entry.path.toLowerCase().endsWith(".dill")) {
+        dills.add(entry);
+      }
+    }
+  }
+  Directory sdk = new Directory.fromUri(parent.uri.resolve("dart-sdk/"));
+  for (FileSystemEntity entry in sdk.listSync(recursive: true)) {
+    if (entry is File) {
+      if (entry.path.toLowerCase().endsWith(".dill")) {
+        dills.add(entry);
+      }
+    }
+  }
+
+  print("Found ${dills.length} dills!");
+
+  List<File> errors = [];
+  for (File dill in dills) {
+    if (args.isNotEmpty &&
+        !args.any((arg) => dill.absolute.path.endsWith(arg))) {
+      print('Skipping $dill');
+      continue;
+    }
+    if (!canRead(dill)) {
+      errors.add(dill);
+    }
+  }
+  if (errors.isEmpty) {
+    print("Read all OK.");
+  } else {
+    print("Errors when reading:");
+    for (File error in errors) {
+      print(error);
+    }
+    exitCode = 1;
+  }
+}
+
+bool canRead(File dill) {
+  print("Reading $dill");
+  List<int> bytes = dill.readAsBytesSync();
+
+  try {
+    Component component1 = new Component();
+    new BinaryBuilder(bytes).readComponent(component1);
+
+    Component component2 = new Component();
+    new BinaryBuilder(bytes).readComponent(component2);
+
+    EquivalenceResult result = checkEquivalence(component1, component2);
+    if (!result.isEquivalent) {
+      print(result);
+    }
+    return result.isEquivalent;
+  } catch (e, st) {
+    print("Error for $dill:");
+    print(e);
+    print(st);
+    print("");
+    print("--------------------");
+    print("");
+    return false;
+  }
+}
diff --git a/pkg/compiler/test/model/indentation_test.dart b/pkg/kernel/test/indentation_test.dart
similarity index 88%
rename from pkg/compiler/test/model/indentation_test.dart
rename to pkg/kernel/test/indentation_test.dart
index 98a4f41..94bf983 100644
--- a/pkg/compiler/test/model/indentation_test.dart
+++ b/pkg/kernel/test/indentation_test.dart
@@ -2,10 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-// @dart = 2.7
-
-import "package:expect/expect.dart";
-import 'package:compiler/src/util/util.dart' show Indentation;
+import 'package:expect/expect.dart';
+import 'package:kernel/text/indentation.dart' show Indentation;
 
 main() {
   Indentation ind = new Indentation();
diff --git a/pkg/kernel/test/union_find_test.dart b/pkg/kernel/test/union_find_test.dart
new file mode 100644
index 0000000..2e5249d
--- /dev/null
+++ b/pkg/kernel/test/union_find_test.dart
@@ -0,0 +1,108 @@
+// 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:kernel/src/union_find.dart';
+
+testSame<T>(UnionFind<T> unionFind, T a, T b, bool expected) {
+  expect(expected, unionFind.nodesInSameSet(unionFind[a], unionFind[b]));
+}
+
+testSets<T>(UnionFind<T> unionFind, Set<Set<T>> sets) {
+  for (Set<T> set in sets) {
+    UnionFindNode<T> root = unionFind.findNode(unionFind[set.first]);
+    for (T value in unionFind.values) {
+      testSame(unionFind, value, root.value, set.contains(value));
+    }
+  }
+}
+
+testFind<T>(UnionFind<T> unionFind, T value, T expected) {
+  expect(expected, unionFind.findNode(unionFind[value]).value);
+}
+
+testUnion<T>(UnionFind<T> unionFind, T a, T b, T expected) {
+  expect(expected, unionFind.unionOfNodes(unionFind[a], unionFind[b]).value);
+}
+
+main() {
+  UnionFind<int> unionFind = new UnionFind();
+  // {0}
+  testFind(unionFind, 0, 0);
+  testSame(unionFind, 0, 0, true);
+  testSets(unionFind, {
+    {0}
+  });
+
+  // {0}, {1}
+  testFind(unionFind, 1, 1);
+  testSame(unionFind, 0, 1, false);
+  testSame(unionFind, 1, 0, false);
+  testSame(unionFind, 1, 1, true);
+  testSets(unionFind, {
+    {0},
+    {1}
+  });
+
+  // {0}, {1}, {2}
+  testFind(unionFind, 2, 2);
+  testSame(unionFind, 0, 2, false);
+  testSame(unionFind, 1, 2, false);
+  testSame(unionFind, 2, 2, true);
+  testSets(unionFind, {
+    {0},
+    {1},
+    {2}
+  });
+
+  // {0}, {1}, {2}
+  testUnion(unionFind, 0, 0, 0);
+  testSame(unionFind, 0, 0, true);
+  testSame(unionFind, 0, 1, false);
+  testSame(unionFind, 0, 2, false);
+  testSets(unionFind, {
+    {0},
+    {1},
+    {2}
+  });
+
+  // {0, 1}, {2}
+  testUnion(unionFind, 0, 1, 0);
+  testSame(unionFind, 0, 0, true);
+  testSame(unionFind, 0, 1, true);
+  testSame(unionFind, 1, 0, true);
+  testSame(unionFind, 0, 2, false);
+  testFind(unionFind, 0, 0);
+  testFind(unionFind, 1, 0);
+  testSets(unionFind, {
+    {0, 1},
+    {2}
+  });
+
+  // {0, 1}, {2, 3}
+  testUnion(unionFind, 2, 3, 2);
+  testSame(unionFind, 0, 0, true);
+  testSame(unionFind, 0, 1, true);
+  testSame(unionFind, 0, 2, false);
+  testSame(unionFind, 0, 3, false);
+  testSame(unionFind, 0, 0, true);
+  testSame(unionFind, 0, 1, true);
+  testSame(unionFind, 0, 2, false);
+  testSame(unionFind, 0, 3, false);
+  testFind(unionFind, 2, 2);
+  testFind(unionFind, 3, 2);
+  testSets(unionFind, {
+    {0, 1},
+    {2, 3}
+  });
+
+  // {0, 1, 2, 3}
+  testUnion(unionFind, 1, 2, 0);
+  testSets(unionFind, {
+    {0, 1, 2, 3}
+  });
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
diff --git a/tools/VERSION b/tools/VERSION
index cee8dd7..f0602be 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 14
 PATCH 0
-PRERELEASE 374
+PRERELEASE 375
 PRERELEASE_PATCH 0
\ No newline at end of file