Version 3.6.0-316.0.dev

Merge f223d01848651b3903c9b3ebb464d5b4f5dd3bc8 into dev
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index fd82aa9..d0960b6 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -523,6 +523,7 @@
 dso
 dsos
 dst
+dummies
 dummy
 dumping
 dupdate
@@ -1082,6 +1083,7 @@
 min
 mini
 minutes
+misc
 miss
 mistakes
 misuse
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index e535c05..506a255 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -106,15583 +106,19 @@
 export 'package:_fe_analyzer_shared/src/type_inference/type_analyzer_operations.dart'
     show Variance;
 
+part 'src/ast/constants.dart';
+part 'src/ast/components.dart';
+part 'src/ast/declarations.dart';
+part 'src/ast/dummies.dart';
+part 'src/ast/expressions.dart';
+part 'src/ast/functions.dart';
+part 'src/ast/helpers.dart';
+part 'src/ast/initializers.dart';
+part 'src/ast/libraries.dart';
+part 'src/ast/members.dart';
+part 'src/ast/misc.dart';
+part 'src/ast/names.dart';
 part 'src/ast/patterns.dart';
-
-/// Any type of node in the IR.
-abstract class Node {
-  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.
-  ///
-  /// [toString] should only be used for debugging, but should not leak.
-  ///
-  /// The data is generally bare-bones, but can easily be updated for your
-  /// specific debugging needs.
-  @override
-  String toString();
-
-  /// Returns the textual representation of this node for use in debugging.
-  ///
-  /// [toStringInternal] should only be used for debugging, but should not leak.
-  ///
-  /// The data is generally bare-bones, but can easily be updated for your
-  /// specific debugging needs.
-  ///
-  /// This method is called internally by toString methods to create conciser
-  /// textual representations.
-  String toStringInternal() => toText(defaultAstTextStrategy);
-
-  /// Returns the textual representation of this node for use in debugging.
-  ///
-  /// Note that this adds some nodes to a static map to ensure consistent
-  /// naming, but that it thus also leaks memory. [leakingDebugToString] should
-  /// thus only be used for debugging and short-running test tools.
-  ///
-  /// Synthetic names are cached globally to retain consistency across different
-  /// [leakingDebugToString] calls (hence the memory leak).
-  String leakingDebugToString() => astToText.debugNodeToString(this);
-
-  String toText(AstTextStrategy strategy) {
-    AstPrinter printer = new AstPrinter(strategy);
-    toTextInternal(printer);
-    return printer.getText();
-  }
-
-  void toTextInternal(AstPrinter printer);
-}
-
-/// A mutable AST node with a parent pointer.
-///
-/// This is anything other than [Name] and [DartType] nodes.
-abstract class TreeNode extends Node {
-  static int _hashCounter = 0;
-  @override
-  final int hashCode = _hashCounter = (_hashCounter + 1) & 0x3fffffff;
-  static const int noOffset = -1;
-
-  TreeNode? parent;
-
-  /// Offset in the source file the node comes from.
-  ///
-  /// Valid values are from 0 and up, or -1 ([noOffset]) if the file offset is
-  /// not available (this is the default if none is specifically set).
-  ///
-  /// This is an index into [Source.text].
-  int fileOffset = noOffset;
-
-  /// When the node has more offsets that just [fileOffset], the list of all
-  /// offsets.
-  List<int>? get fileOffsetsIfMultiple => null;
-
-  @override
-  R accept<R>(TreeVisitor<R> v);
-  @override
-  R accept1<R, A>(TreeVisitor1<R, A> v, A arg);
-  @override
-  void visitChildren(Visitor v);
-  void transformChildren(Transformer v);
-  void transformOrRemoveChildren(RemovingTransformer v);
-
-  /// Replaces [child] with [replacement].
-  ///
-  /// The caller is responsible for ensuring that the AST remains a tree.  In
-  /// particular, [replacement] should be an orphan or be part of an orphaned
-  /// subtree.
-  ///
-  /// Has no effect if [child] is not actually a child of this node.
-  ///
-  /// [replacement] must be non-null.
-  void replaceChild(TreeNode child, TreeNode replacement) {
-    transformChildren(new _ChildReplacer(child, replacement));
-  }
-
-  /// Inserts another node in place of this one.
-  ///
-  /// The caller is responsible for ensuring that the AST remains a tree.  In
-  /// particular, [replacement] should be an orphan or be part of an orphaned
-  /// subtree.
-  ///
-  /// [replacement] must be non-null.
-  void replaceWith(TreeNode replacement) {
-    parent!.replaceChild(this, replacement);
-    parent = null;
-  }
-
-  // TODO(johnniwinther): Make this non-nullable.
-  Component? get enclosingComponent => parent?.enclosingComponent;
-
-  /// Returns the best known source location of the given AST node, or `null` if
-  /// the node is orphaned.
-  ///
-  /// This getter is intended for diagnostics and debugging, and should be
-  /// avoided in production code.
-  Location? get location {
-    if (fileOffset == noOffset) return parent?.location;
-    return _getLocationInEnclosingFile(fileOffset);
-  }
-
-  Location? _getLocationInEnclosingFile(int offset) {
-    return parent?._getLocationInEnclosingFile(offset);
-  }
-}
-
-/// An AST node that can be referenced by other nodes.
-///
-/// There is a single [reference] belonging to this node, providing a level of
-/// indirection that is needed during serialization.
-abstract class NamedNode extends TreeNode {
-  final Reference reference;
-
-  NamedNode(Reference? reference)
-      : this.reference = reference ?? new Reference() {
-    this.reference.node = this;
-  }
-
-  /// This is an advanced feature.
-  ///
-  /// See [Component.relink] for a comprehensive description.
-  ///
-  /// Makes sure the reference in this named node points to itself.
-  void _relinkNode() {
-    this.reference.node = this;
-  }
-
-  /// Computes the canonical names for this node using the [parent] as the
-  /// canonical name of the parent node.
-  void bindCanonicalNames(CanonicalName parent);
-}
-
-abstract class FileUriNode extends TreeNode {
-  /// The URI of the source file this node was loaded from.
-  Uri get fileUri;
-
-  void set fileUri(Uri value);
-}
-
-abstract class Annotatable extends TreeNode {
-  List<Expression> get annotations;
-  void addAnnotation(Expression node);
-}
-
-// ------------------------------------------------------------------------
-//                      LIBRARIES and CLASSES
-// ------------------------------------------------------------------------
-
-enum NonNullableByDefaultCompiledMode { Strong, Weak, Invalid }
-
-class Library extends NamedNode
-    implements Annotatable, Comparable<Library>, FileUriNode {
-  /// An import path to this library.
-  ///
-  /// The [Uri] should have the `dart`, `package`, `app`, or `file` scheme.
-  ///
-  /// If the URI has the `app` scheme, it is relative to the application root.
-  Uri importUri;
-
-  /// The URI of the source file this library was loaded from.
-  @override
-  Uri fileUri;
-
-  Version? _languageVersion;
-  Version get languageVersion => _languageVersion ?? defaultLanguageVersion;
-
-  void setLanguageVersion(Version languageVersion) {
-    _languageVersion = languageVersion;
-  }
-
-  static const int SyntheticFlag = 1 << 0;
-
-  static const int NonNullableByDefaultModeBit1 = 1 << 1;
-  static const int NonNullableByDefaultModeBit2 = 1 << 2;
-  static const int IsUnsupportedFlag = 1 << 3;
-
-  int flags = 0;
-
-  /// If true, the library is synthetic, for instance library that doesn't
-  /// represents an actual file and is created as the result of error recovery.
-  bool get isSynthetic => flags & SyntheticFlag != 0;
-  void set isSynthetic(bool value) {
-    flags = value ? (flags | SyntheticFlag) : (flags & ~SyntheticFlag);
-  }
-
-  NonNullableByDefaultCompiledMode get nonNullableByDefaultCompiledMode {
-    bool bit1 = (flags & NonNullableByDefaultModeBit1) != 0;
-    bool bit2 = (flags & NonNullableByDefaultModeBit2) != 0;
-    if (!bit1 && !bit2) return NonNullableByDefaultCompiledMode.Strong;
-    if (bit1 && !bit2) return NonNullableByDefaultCompiledMode.Weak;
-    if (!bit1 && bit2) return NonNullableByDefaultCompiledMode.Invalid;
-    throw new StateError("Unused bit-pattern for compilation mode");
-  }
-
-  void set nonNullableByDefaultCompiledMode(
-      NonNullableByDefaultCompiledMode mode) {
-    switch (mode) {
-      case NonNullableByDefaultCompiledMode.Strong:
-        flags = (flags & ~NonNullableByDefaultModeBit1) &
-            ~NonNullableByDefaultModeBit2;
-        break;
-      case NonNullableByDefaultCompiledMode.Weak:
-        flags = (flags | NonNullableByDefaultModeBit1) &
-            ~NonNullableByDefaultModeBit2;
-        break;
-      case NonNullableByDefaultCompiledMode.Invalid:
-        flags = (flags & ~NonNullableByDefaultModeBit1) |
-            NonNullableByDefaultModeBit2;
-        break;
-    }
-  }
-
-  /// If true, the library is not supported through the 'dart.library.*' value
-  /// used in conditional imports and `bool.fromEnvironment` constants.
-  bool get isUnsupported => flags & IsUnsupportedFlag != 0;
-  void set isUnsupported(bool value) {
-    flags = value ? (flags | IsUnsupportedFlag) : (flags & ~IsUnsupportedFlag);
-  }
-
-  String? name;
-
-  /// Problems in this [Library] encoded as json objects.
-  ///
-  /// Note that this field can be null, and by convention should be null if the
-  /// list is empty.
-  List<String>? problemsAsJson;
-
-  @override
-  List<Expression> annotations;
-
-  List<LibraryDependency> dependencies;
-
-  /// References to nodes exported by `export` declarations that:
-  /// - aren't ambiguous, or
-  /// - aren't hidden by local declarations.
-  final List<Reference> additionalExports = <Reference>[];
-
-  @informative
-  List<LibraryPart> parts;
-
-  List<Typedef> _typedefs;
-  List<Class> _classes;
-  List<Extension> _extensions;
-  List<ExtensionTypeDeclaration> _extensionTypeDeclarations;
-  List<Procedure> _procedures;
-  List<Field> _fields;
-
-  Library(this.importUri,
-      {this.name,
-      List<Expression>? annotations,
-      List<LibraryDependency>? dependencies,
-      List<LibraryPart>? parts,
-      List<Typedef>? typedefs,
-      List<Class>? classes,
-      List<Extension>? extensions,
-      List<ExtensionTypeDeclaration>? extensionTypeDeclarations,
-      List<Procedure>? procedures,
-      List<Field>? fields,
-      required this.fileUri,
-      Reference? reference})
-      : this.annotations = annotations ?? <Expression>[],
-        this.dependencies = dependencies ?? <LibraryDependency>[],
-        this.parts = parts ?? <LibraryPart>[],
-        this._typedefs = typedefs ?? <Typedef>[],
-        this._classes = classes ?? <Class>[],
-        this._extensions = extensions ?? <Extension>[],
-        this._extensionTypeDeclarations =
-            extensionTypeDeclarations ?? <ExtensionTypeDeclaration>[],
-        this._procedures = procedures ?? <Procedure>[],
-        this._fields = fields ?? <Field>[],
-        super(reference) {
-    setParents(this.dependencies, this);
-    setParents(this.parts, this);
-    setParents(this._typedefs, this);
-    setParents(this._classes, this);
-    setParents(this._extensions, this);
-    setParents(this._procedures, this);
-    setParents(this._fields, this);
-  }
-
-  List<Typedef> get typedefs => _typedefs;
-
-  /// Internal. Should *ONLY* be used from within kernel.
-  ///
-  /// Used for adding typedefs when reading the dill file.
-  void set typedefsInternal(List<Typedef> typedefs) {
-    _typedefs = typedefs;
-  }
-
-  List<Class> get classes => _classes;
-
-  /// Internal. Should *ONLY* be used from within kernel.
-  ///
-  /// Used for adding classes when reading the dill file.
-  void set classesInternal(List<Class> classes) {
-    _classes = classes;
-  }
-
-  List<Extension> get extensions => _extensions;
-
-  /// Internal. Should *ONLY* be used from within kernel.
-  ///
-  /// Used for adding extensions when reading the dill file.
-  void set extensionsInternal(List<Extension> extensions) {
-    _extensions = extensions;
-  }
-
-  List<ExtensionTypeDeclaration> get extensionTypeDeclarations =>
-      _extensionTypeDeclarations;
-
-  /// Internal. Should *ONLY* be used from within kernel.
-  ///
-  /// Used for adding extension type declarations when reading the dill file.
-  void set extensionTypeDeclarationsInternal(
-      List<ExtensionTypeDeclaration> extensionTypeDeclarations) {
-    _extensionTypeDeclarations = extensionTypeDeclarations;
-  }
-
-  List<Procedure> get procedures => _procedures;
-
-  /// Internal. Should *ONLY* be used from within kernel.
-  ///
-  /// Used for adding procedures when reading the dill file.
-  void set proceduresInternal(List<Procedure> procedures) {
-    _procedures = procedures;
-  }
-
-  List<Field> get fields => _fields;
-
-  /// Internal. Should *ONLY* be used from within kernel.
-  ///
-  /// Used for adding fields when reading the dill file.
-  void set fieldsInternal(List<Field> fields) {
-    _fields = fields;
-  }
-
-  Nullability get nullable => Nullability.nullable;
-
-  Nullability get nonNullable => Nullability.nonNullable;
-
-  /// Returns the top-level fields and procedures defined in this library.
-  ///
-  /// This getter is for convenience, not efficiency.  Consider manually
-  /// iterating the members to speed up code in production.
-  Iterable<Member> get members =>
-      <Iterable<Member>>[fields, procedures].expand((x) => x);
-
-  void forEachMember(void action(Member element)) {
-    fields.forEach(action);
-    procedures.forEach(action);
-  }
-
-  @override
-  void addAnnotation(Expression node) {
-    node.parent = this;
-    annotations.add(node);
-  }
-
-  void addClass(Class class_) {
-    class_.parent = this;
-    classes.add(class_);
-  }
-
-  void addExtension(Extension extension) {
-    extension.parent = this;
-    extensions.add(extension);
-  }
-
-  void addExtensionTypeDeclaration(
-      ExtensionTypeDeclaration extensionTypeDeclaration) {
-    extensionTypeDeclaration.parent = this;
-    extensionTypeDeclarations.add(extensionTypeDeclaration);
-  }
-
-  void addField(Field field) {
-    field.parent = this;
-    fields.add(field);
-  }
-
-  void addProcedure(Procedure procedure) {
-    procedure.parent = this;
-    procedures.add(procedure);
-  }
-
-  void addTypedef(Typedef typedef_) {
-    typedef_.parent = this;
-    typedefs.add(typedef_);
-  }
-
-  @override
-  CanonicalName bindCanonicalNames(CanonicalName parent) {
-    return parent.getChildFromUri(importUri)..bindTo(reference);
-  }
-
-  /// Computes the canonical name for this library and all its members.
-  void ensureCanonicalNames(CanonicalName parent) {
-    CanonicalName canonicalName = bindCanonicalNames(parent);
-    for (int i = 0; i < typedefs.length; ++i) {
-      typedefs[i].bindCanonicalNames(canonicalName);
-    }
-    for (int i = 0; i < fields.length; ++i) {
-      fields[i].bindCanonicalNames(canonicalName);
-    }
-    for (int i = 0; i < procedures.length; ++i) {
-      procedures[i].bindCanonicalNames(canonicalName);
-    }
-    for (int i = 0; i < classes.length; ++i) {
-      classes[i].ensureCanonicalNames(canonicalName);
-    }
-    for (int i = 0; i < extensions.length; ++i) {
-      extensions[i].bindCanonicalNames(canonicalName);
-    }
-    for (int i = 0; i < extensionTypeDeclarations.length; ++i) {
-      extensionTypeDeclarations[i].ensureCanonicalNames(canonicalName);
-    }
-  }
-
-  /// This is an advanced feature. Use of this method should be coordinated
-  /// with the kernel team.
-  ///
-  /// See [Component.relink] for a comprehensive description.
-  ///
-  /// Makes sure all references in named nodes in this library points to said
-  /// named node.
-  void relink() {
-    _relinkNode();
-    for (int i = 0; i < typedefs.length; ++i) {
-      Typedef typedef_ = typedefs[i];
-      typedef_._relinkNode();
-    }
-    for (int i = 0; i < fields.length; ++i) {
-      Field field = fields[i];
-      field._relinkNode();
-    }
-    for (int i = 0; i < procedures.length; ++i) {
-      Procedure member = procedures[i];
-      member._relinkNode();
-    }
-    for (int i = 0; i < classes.length; ++i) {
-      Class class_ = classes[i];
-      class_.relink();
-    }
-    for (int i = 0; i < extensions.length; ++i) {
-      Extension extension = extensions[i];
-      extension._relinkNode();
-    }
-    for (int i = 0; i < extensionTypeDeclarations.length; ++i) {
-      ExtensionTypeDeclaration extensionTypeDeclaration =
-          extensionTypeDeclarations[i];
-      extensionTypeDeclaration.relink();
-    }
-  }
-
-  void addDependency(LibraryDependency node) {
-    dependencies.add(node..parent = this);
-  }
-
-  void addPart(LibraryPart node) {
-    parts.add(node..parent = this);
-  }
-
-  @override
-  R accept<R>(TreeVisitor<R> v) => v.visitLibrary(this);
-
-  @override
-  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitLibrary(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(annotations, v);
-    visitList(dependencies, v);
-    visitList(parts, v);
-    visitList(typedefs, v);
-    visitList(classes, v);
-    visitList(extensions, v);
-    visitList(extensionTypeDeclarations, v);
-    visitList(procedures, v);
-    visitList(fields, v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    v.transformList(annotations, this);
-    v.transformList(dependencies, this);
-    v.transformList(parts, this);
-    v.transformList(typedefs, this);
-    v.transformList(classes, this);
-    v.transformList(extensions, this);
-    v.transformList(extensionTypeDeclarations, this);
-    v.transformList(procedures, this);
-    v.transformList(fields, this);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    v.transformExpressionList(annotations, this);
-    v.transformLibraryDependencyList(dependencies, this);
-    v.transformLibraryPartList(parts, this);
-    v.transformTypedefList(typedefs, this);
-    v.transformClassList(classes, this);
-    v.transformExtensionList(extensions, this);
-    v.transformExtensionTypeDeclarationList(extensionTypeDeclarations, this);
-    v.transformProcedureList(procedures, this);
-    v.transformFieldList(fields, this);
-  }
-
-  static int _libraryIdCounter = 0;
-  int _libraryId = ++_libraryIdCounter;
-  int get libraryIdForTesting => _libraryId;
-
-  @override
-  int compareTo(Library other) => _libraryId - other._libraryId;
-
-  /// Returns a possibly synthesized name for this library, consistent with
-  /// the names across all [toString] calls.
-  @override
-  String toString() => libraryNameToString(this);
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write(libraryNameToString(this));
-  }
-
-  @override
-  Location? _getLocationInEnclosingFile(int offset) {
-    return _getLocationInComponent(enclosingComponent, fileUri, offset,
-        viaForErrorMessage: "Library");
-  }
-
-  @override
-  String leakingDebugToString() => astToText.debugLibraryToString(this);
-}
-
-/// An import or export declaration in a library.
-///
-/// It can represent any of the following forms,
-///
-///     import <url>;
-///     import <url> as <name>;
-///     import <url> deferred as <name>;
-///     export <url>;
-///
-/// optionally with metadata and [Combinators].
-class LibraryDependency extends TreeNode implements Annotatable {
-  int flags;
-
-  @override
-  final List<Expression> annotations;
-
-  Reference importedLibraryReference;
-
-  /// The name of the import prefix, if any, or `null` if this is not an import
-  /// with a prefix.
-  ///
-  /// Must be non-null for deferred imports, and must be null for exports.
-  String? name;
-
-  final List<Combinator> combinators;
-
-  LibraryDependency.deferredImport(Library importedLibrary, String name,
-      {List<Combinator>? combinators, List<Expression>? annotations})
-      : this.byReference(DeferredFlag, annotations ?? <Expression>[],
-            importedLibrary.reference, name, combinators ?? <Combinator>[]);
-
-  LibraryDependency.import(Library importedLibrary,
-      {String? name,
-      List<Combinator>? combinators,
-      List<Expression>? annotations})
-      : this.byReference(0, annotations ?? <Expression>[],
-            importedLibrary.reference, name, combinators ?? <Combinator>[]);
-
-  LibraryDependency.export(Library importedLibrary,
-      {List<Combinator>? combinators, List<Expression>? annotations})
-      : this.byReference(ExportFlag, annotations ?? <Expression>[],
-            importedLibrary.reference, null, combinators ?? <Combinator>[]);
-
-  LibraryDependency.byReference(this.flags, this.annotations,
-      this.importedLibraryReference, this.name, this.combinators) {
-    setParents(annotations, this);
-    setParents(combinators, this);
-  }
-
-  Library get enclosingLibrary => parent as Library;
-  Library get targetLibrary => importedLibraryReference.asLibrary;
-
-  static const int ExportFlag = 1 << 0;
-  static const int DeferredFlag = 1 << 1;
-
-  bool get isExport => flags & ExportFlag != 0;
-  bool get isImport => !isExport;
-  bool get isDeferred => flags & DeferredFlag != 0;
-
-  @override
-  void addAnnotation(Expression annotation) {
-    annotations.add(annotation..parent = this);
-  }
-
-  @override
-  R accept<R>(TreeVisitor<R> v) => v.visitLibraryDependency(this);
-
-  @override
-  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) =>
-      v.visitLibraryDependency(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(annotations, v);
-    visitList(combinators, v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    v.transformList(annotations, this);
-    v.transformList(combinators, this);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    v.transformExpressionList(annotations, this);
-    v.transformCombinatorList(combinators, this);
-  }
-
-  @override
-  String toString() {
-    return "LibraryDependency(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    if (isExport) {
-      printer.write('export ');
-    } else {
-      printer.write('import ');
-    }
-    if (isDeferred) {
-      printer.write('deferred ');
-    }
-    printer.writeLibraryReference(importedLibraryReference);
-    printer.write(';');
-  }
-}
-
-/// A part declaration in a library.
-///
-///     part <url>;
-///
-/// optionally with metadata.
-class LibraryPart extends TreeNode implements Annotatable {
-  @override
-  final List<Expression> annotations;
-
-  final String partUri;
-
-  LibraryPart(this.annotations, this.partUri) {
-    setParents(annotations, this);
-  }
-
-  @override
-  void addAnnotation(Expression annotation) {
-    annotations.add(annotation..parent = this);
-  }
-
-  @override
-  R accept<R>(TreeVisitor<R> v) => v.visitLibraryPart(this);
-
-  @override
-  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitLibraryPart(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(annotations, v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    v.transformList(annotations, this);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    v.transformExpressionList(annotations, this);
-  }
-
-  @override
-  String toString() {
-    return "LibraryPart(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    // TODO(johnniwinther): Implement this.
-  }
-}
-
-/// A `show` or `hide` clause for an import or export.
-class Combinator extends TreeNode {
-  bool isShow;
-
-  final List<String> names;
-
-  Combinator(this.isShow, this.names);
-  Combinator.show(this.names) : isShow = true;
-  Combinator.hide(this.names) : isShow = false;
-
-  bool get isHide => !isShow;
-
-  @override
-  R accept<R>(TreeVisitor<R> v) => v.visitCombinator(this);
-
-  @override
-  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitCombinator(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {}
-
-  @override
-  void transformChildren(Transformer v) {}
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {}
-
-  @override
-  String toString() {
-    return "Combinator(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    // TODO(johnniwinther): Implement this.
-  }
-}
-
-/// Declaration of a type alias.
-class Typedef extends NamedNode
-    implements FileUriNode, Annotatable, GenericDeclaration {
-  /// The URI of the source file that contains the declaration of this typedef.
-  @override
-  Uri fileUri;
-
-  @override
-  List<Expression> annotations = const <Expression>[];
-
-  String name;
-
-  @override
-  final List<TypeParameter> typeParameters;
-
-  // TODO(johnniwinther): Make this non-nullable.
-  DartType? type;
-
-  Typedef(this.name, this.type,
-      {Reference? reference,
-      required this.fileUri,
-      List<TypeParameter>? typeParameters,
-      List<TypeParameter>? typeParametersOfFunctionType,
-      List<VariableDeclaration>? positionalParameters,
-      List<VariableDeclaration>? namedParameters})
-      : this.typeParameters = typeParameters ?? <TypeParameter>[],
-        super(reference) {
-    setParents(this.typeParameters, this);
-  }
-
-  @override
-  void bindCanonicalNames(CanonicalName parent) {
-    parent.getChildFromTypedef(this).bindTo(reference);
-  }
-
-  Library get enclosingLibrary => parent as Library;
-
-  @override
-  R accept<R>(TreeVisitor<R> v) => v.visitTypedef(this);
-
-  @override
-  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitTypedef(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(annotations, v);
-    visitList(typeParameters, v);
-    type?.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    v.transformList(annotations, this);
-    v.transformList(typeParameters, this);
-    if (type != null) {
-      type = v.visitDartType(type!);
-    }
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    v.transformExpressionList(annotations, this);
-    v.transformTypeParameterList(typeParameters, this);
-    if (type != null) {
-      DartType newType = v.visitDartType(type!, dummyDartType);
-      if (identical(newType, dummyDartType)) {
-        type = null;
-      } else {
-        type = newType;
-      }
-    }
-  }
-
-  @override
-  void addAnnotation(Expression node) {
-    if (annotations.isEmpty) {
-      annotations = <Expression>[];
-    }
-    annotations.add(node);
-    node.parent = this;
-  }
-
-  @override
-  Location? _getLocationInEnclosingFile(int offset) {
-    return _getLocationInComponent(enclosingComponent, fileUri, offset,
-        viaForErrorMessage: "Typedef '$name'");
-  }
-
-  @override
-  String toString() {
-    return "Typedef(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeTypedefName(reference);
-  }
-}
-
-/// List-wrapper that marks the parent-class as dirty if the list is modified.
-///
-/// The idea being, that for non-dirty classes (classes just loaded from dill)
-/// the canonical names has already been calculated, and recalculating them is
-/// not needed. If, however, we change anything, recalculation of the canonical
-/// names can be needed.
-class DirtifyingList<E> extends ListBase<E> {
-  final Class dirtifyClass;
-  final List<E> wrapped;
-
-  DirtifyingList(this.dirtifyClass, this.wrapped);
-
-  @override
-  int get length {
-    return wrapped.length;
-  }
-
-  @override
-  void set length(int length) {
-    dirtifyClass.dirty = true;
-    wrapped.length = length;
-  }
-
-  @override
-  E operator [](int index) {
-    return wrapped[index];
-  }
-
-  @override
-  void operator []=(int index, E value) {
-    dirtifyClass.dirty = true;
-    wrapped[index] = value;
-  }
-}
-
-/// Declaration that can introduce [TypeParameter]s.
-sealed class GenericDeclaration implements TreeNode {
-  /// The type parameters introduced by this declaration.
-  List<TypeParameter> get typeParameters;
-}
-
-/// Functions that can introduce [TypeParameter]s.
-sealed class GenericFunction implements GenericDeclaration {
-  /// The [FunctionNode] that holds the introduced [typeParameters].
-  FunctionNode get function;
-}
-
-/// Common interface for [Class] and [ExtensionTypeDeclaration].
-sealed class TypeDeclaration
-    implements Annotatable, FileUriNode, GenericDeclaration {
-  /// The name of the declaration.
-  ///
-  /// This must be unique within the library.
-  String get name;
-}
-
-/// Declaration of a regular class or a mixin application.
-///
-/// Mixin applications may not contain fields or procedures, as they implicitly
-/// use those from its mixed-in type.  However, the IR does not enforce this
-/// rule directly, as doing so can obstruct transformations.  It is possible to
-/// transform a mixin application to become a regular class, and vice versa.
-class Class extends NamedNode implements TypeDeclaration {
-  /// Start offset of the class in the source file it comes from.
-  ///
-  /// Note that this includes annotations if any.
-  ///
-  /// Valid values are from 0 and up, or -1 ([TreeNode.noOffset]) if the file
-  /// start offset is not available (this is the default if none is specifically
-  /// set).
-  int startFileOffset = TreeNode.noOffset;
-
-  /// End offset in the source file it comes from. Valid values are from 0 and
-  /// up, or -1 ([TreeNode.noOffset]) if the file end offset is not available
-  /// (this is the default if none is specifically set).
-  int fileEndOffset = TreeNode.noOffset;
-
-  @override
-  List<int>? get fileOffsetsIfMultiple =>
-      [fileOffset, startFileOffset, fileEndOffset];
-
-  /// List of metadata annotations on the class.
-  ///
-  /// This defaults to an immutable empty list. Use [addAnnotation] to add
-  /// annotations if needed.
-  @override
-  List<Expression> annotations = const <Expression>[];
-
-  /// Name of the class.
-  ///
-  /// Must be non-null and must be unique within the library.
-  ///
-  /// The name may contain characters that are not valid in a Dart identifier,
-  /// in particular, the symbol '&' is used in class names generated for mixin
-  /// applications.
-  @override
-  String name;
-
-  // Must match serialized bit positions.
-  static const int FlagAbstract = 1 << 0;
-  static const int FlagEnum = 1 << 1;
-  static const int FlagAnonymousMixin = 1 << 2;
-  static const int FlagEliminatedMixin = 1 << 3;
-  static const int FlagMixinDeclaration = 1 << 4;
-  static const int FlagHasConstConstructor = 1 << 5;
-  static const int FlagMacro = 1 << 6;
-  static const int FlagSealed = 1 << 7;
-  static const int FlagMixinClass = 1 << 8;
-  static const int FlagBase = 1 << 9;
-  static const int FlagInterface = 1 << 10;
-  static const int FlagFinal = 1 << 11;
-
-  int flags = 0;
-
-  bool get isAbstract => flags & FlagAbstract != 0;
-
-  void set isAbstract(bool value) {
-    flags = value ? (flags | FlagAbstract) : (flags & ~FlagAbstract);
-  }
-
-  /// Whether this class is an enum.
-  bool get isEnum => flags & FlagEnum != 0;
-
-  void set isEnum(bool value) {
-    flags = value ? (flags | FlagEnum) : (flags & ~FlagEnum);
-  }
-
-  /// Whether this class is a macro class.
-  bool get isMacro => flags & FlagMacro != 0;
-
-  void set isMacro(bool value) {
-    flags = value ? (flags | FlagMacro) : (flags & ~FlagMacro);
-  }
-
-  /// Whether this class is a sealed class.
-  bool get isSealed => flags & FlagSealed != 0;
-
-  void set isSealed(bool value) {
-    flags = value ? (flags | FlagSealed) : (flags & ~FlagSealed);
-  }
-
-  /// Whether this class is a base class.
-  bool get isBase => flags & FlagBase != 0;
-
-  void set isBase(bool value) {
-    flags = value ? (flags | FlagBase) : (flags & ~FlagBase);
-  }
-
-  /// Whether this class is an interface class.
-  bool get isInterface => flags & FlagInterface != 0;
-
-  void set isInterface(bool value) {
-    flags = value ? (flags | FlagInterface) : (flags & ~FlagInterface);
-  }
-
-  /// Whether this class is a final class.
-  bool get isFinal => flags & FlagFinal != 0;
-
-  void set isFinal(bool value) {
-    flags = value ? (flags | FlagFinal) : (flags & ~FlagFinal);
-  }
-
-  /// Whether this class is a synthetic implementation created for each
-  /// mixed-in class. For example the following code:
-  /// class Z extends A with B, C, D {}
-  /// class A {}
-  /// class B {}
-  /// class C {}
-  /// class D {}
-  /// ...creates:
-  /// abstract class _Z&A&B extends A mixedIn B {}
-  /// abstract class _Z&A&B&C extends A&B mixedIn C {}
-  /// abstract class _Z&A&B&C&D extends A&B&C mixedIn D {}
-  /// class Z extends _Z&A&B&C&D {}
-  /// All X&Y classes are marked as synthetic.
-  bool get isAnonymousMixin => flags & FlagAnonymousMixin != 0;
-
-  void set isAnonymousMixin(bool value) {
-    flags =
-        value ? (flags | FlagAnonymousMixin) : (flags & ~FlagAnonymousMixin);
-  }
-
-  /// Whether this class was transformed from a mixin application.
-  /// In such case, its mixed-in type was pulled into the end of implemented
-  /// types list.
-  bool get isEliminatedMixin => flags & FlagEliminatedMixin != 0;
-
-  void set isEliminatedMixin(bool value) {
-    flags =
-        value ? (flags | FlagEliminatedMixin) : (flags & ~FlagEliminatedMixin);
-  }
-
-  /// Whether this class is a mixin class.
-  ///
-  /// The `mixin` modifier was added to the class declaration which allows the
-  /// class to be used as a mixin. The class can be mixed in by other classes
-  /// outside of its library. Otherwise, classes are not able to be used as a
-  /// mixin outside of its library from version 3.0 and later.
-  bool get isMixinClass => flags & FlagMixinClass != 0;
-
-  void set isMixinClass(bool value) {
-    flags = value ? (flags | FlagMixinClass) : (flags & ~FlagMixinClass);
-  }
-
-  /// True if this class was a mixin declaration in Dart.
-  ///
-  /// Mixins are declared in Dart with the `mixin` keyword.  They are compiled
-  /// to Kernel classes.
-  bool get isMixinDeclaration => flags & FlagMixinDeclaration != 0;
-
-  void set isMixinDeclaration(bool value) {
-    flags = value
-        ? (flags | FlagMixinDeclaration)
-        : (flags & ~FlagMixinDeclaration);
-  }
-
-  /// True if this class declares one or more constant constructors.
-  bool get hasConstConstructor => flags & FlagHasConstConstructor != 0;
-
-  void set hasConstConstructor(bool value) {
-    flags = value
-        ? (flags | FlagHasConstConstructor)
-        : (flags & ~FlagHasConstConstructor);
-  }
-
-  /// If this class is a mixin declaration, this list contains the types from
-  /// the `on` clause. Otherwise the list is empty.
-  List<Supertype> get onClause => _onClause ??= _computeOnClause();
-
-  List<Supertype> _computeOnClause() {
-    List<Supertype> constraints = <Supertype>[];
-
-    // Not a mixin declaration.
-    if (!isMixinDeclaration) return constraints;
-
-    // Otherwise we have a left-linear binary tree (subtrees are supertype and
-    // mixedInType) of constraints, where all the interior nodes are anonymous
-    // mixin applications.
-    Supertype? current = supertype;
-    while (current != null && current.classNode.isAnonymousMixin) {
-      Class currentClass = current.classNode;
-      assert(currentClass.implementedTypes.length == 2);
-      Substitution substitution = Substitution.fromSupertype(current);
-      constraints.add(
-          substitution.substituteSupertype(currentClass.implementedTypes[1]));
-      current =
-          substitution.substituteSupertype(currentClass.implementedTypes[0]);
-    }
-    return constraints..add(current!);
-  }
-
-  /// The URI of the source file this class was loaded from.
-  @override
-  Uri fileUri;
-
-  @override
-  final List<TypeParameter> typeParameters;
-
-  /// The immediate super type, or `null` if this is the root class.
-  Supertype? supertype;
-
-  /// The mixed-in type if this is a mixin application, otherwise `null`.
-  Supertype? mixedInType;
-
-  /// The types from the `implements` clause.
-  List<Supertype> implementedTypes;
-
-  List<Supertype>? _onClause;
-
-  /// Internal. Should *ONLY* be used from within kernel.
-  ///
-  /// If non-null, the function that will have to be called to fill-out the
-  /// content of this class. Note that this should not be called directly
-  /// though.
-  void Function()? lazyBuilder;
-
-  /// Makes sure the class is loaded, i.e. the fields, procedures etc have been
-  /// loaded from the dill. Generally, one should not need to call this as it is
-  /// done automatically when accessing the lists.
-  void ensureLoaded() {
-    void Function()? lazyBuilderLocal = lazyBuilder;
-    if (lazyBuilderLocal != null) {
-      lazyBuilder = null;
-      lazyBuilderLocal();
-    }
-  }
-
-  List<Field> _fieldsInternal;
-  DirtifyingList<Field>? _fieldsView;
-
-  /// Fields declared in the class.
-  ///
-  /// For mixin applications this should be empty.
-  List<Field> get fields {
-    ensureLoaded();
-    // If already dirty the caller just might as well add stuff directly too.
-    if (dirty) return _fieldsInternal;
-    return _fieldsView ??= new DirtifyingList(this, _fieldsInternal);
-  }
-
-  /// Internal. Should *ONLY* be used from within kernel.
-  ///
-  /// Used for adding fields when reading the dill file.
-  void set fieldsInternal(List<Field> fields) {
-    _fieldsInternal = fields;
-    _fieldsView = null;
-  }
-
-  List<Constructor> _constructorsInternal;
-  DirtifyingList<Constructor>? _constructorsView;
-
-  /// Constructors declared in the class.
-  List<Constructor> get constructors {
-    ensureLoaded();
-    // If already dirty the caller just might as well add stuff directly too.
-    if (dirty) return _constructorsInternal;
-    return _constructorsView ??=
-        new DirtifyingList(this, _constructorsInternal);
-  }
-
-  /// Internal. Should *ONLY* be used from within kernel.
-  ///
-  /// Used for adding constructors when reading the dill file.
-  void set constructorsInternal(List<Constructor> constructors) {
-    _constructorsInternal = constructors;
-    _constructorsView = null;
-  }
-
-  List<Procedure> _proceduresInternal;
-  DirtifyingList<Procedure>? _proceduresView;
-
-  /// Procedures declared in the class.
-  ///
-  /// For mixin applications this should only contain forwarding stubs.
-  List<Procedure> get procedures {
-    ensureLoaded();
-    // If already dirty the caller just might as well add stuff directly too.
-    if (dirty) return _proceduresInternal;
-    return _proceduresView ??= new DirtifyingList(this, _proceduresInternal);
-  }
-
-  /// Internal. Should *ONLY* be used from within kernel.
-  ///
-  /// Used for adding procedures when reading the dill file.
-  void set proceduresInternal(List<Procedure> procedures) {
-    _proceduresInternal = procedures;
-    _proceduresView = null;
-  }
-
-  Class(
-      {required this.name,
-      bool isAbstract = false,
-      bool isAnonymousMixin = false,
-      this.supertype,
-      this.mixedInType,
-      List<TypeParameter>? typeParameters,
-      List<Supertype>? implementedTypes,
-      List<Constructor>? constructors,
-      List<Procedure>? procedures,
-      List<Field>? fields,
-      required this.fileUri,
-      Reference? reference})
-      : this.typeParameters = typeParameters ?? <TypeParameter>[],
-        this.implementedTypes = implementedTypes ?? <Supertype>[],
-        this._fieldsInternal = fields ?? <Field>[],
-        this._constructorsInternal = constructors ?? <Constructor>[],
-        this._proceduresInternal = procedures ?? <Procedure>[],
-        super(reference) {
-    setParents(this.typeParameters, this);
-    setParents(this._constructorsInternal, this);
-    setParents(this._proceduresInternal, this);
-    setParents(this._fieldsInternal, this);
-    this.isAbstract = isAbstract;
-    this.isAnonymousMixin = isAnonymousMixin;
-  }
-
-  @override
-  CanonicalName bindCanonicalNames(CanonicalName parent) {
-    return parent.getChild(name)..bindTo(reference);
-  }
-
-  /// Computes the canonical name for this class and all its members.
-  void ensureCanonicalNames(CanonicalName parent) {
-    CanonicalName canonicalName = bindCanonicalNames(parent);
-    if (!dirty) return;
-    for (int i = 0; i < fields.length; ++i) {
-      fields[i].bindCanonicalNames(canonicalName);
-    }
-    for (int i = 0; i < procedures.length; ++i) {
-      procedures[i].bindCanonicalNames(canonicalName);
-    }
-    for (int i = 0; i < constructors.length; ++i) {
-      constructors[i].bindCanonicalNames(canonicalName);
-    }
-    dirty = false;
-  }
-
-  /// This is an advanced feature. Use of this method should be coordinated
-  /// with the kernel team.
-  ///
-  /// See [Component.relink] for a comprehensive description.
-  ///
-  /// Makes sure all references in named nodes in this class points to said
-  /// named node.
-  void relink() {
-    this.reference.node = this;
-    for (int i = 0; i < fields.length; ++i) {
-      Field member = fields[i];
-      member._relinkNode();
-    }
-    for (int i = 0; i < procedures.length; ++i) {
-      Procedure member = procedures[i];
-      member._relinkNode();
-    }
-    for (int i = 0; i < constructors.length; ++i) {
-      Constructor member = constructors[i];
-      member._relinkNode();
-    }
-    dirty = false;
-  }
-
-  /// The immediate super class, or `null` if this is the root class.
-  Class? get superclass => supertype?.classNode;
-
-  /// The mixed-in class if this is a mixin application, otherwise `null`.
-  ///
-  /// Note that this may itself be a mixin application.  Use [mixin] to get the
-  /// class that has the fields and procedures.
-  Class? get mixedInClass => mixedInType?.classNode;
-
-  /// The class that declares the field and procedures of this class.
-  Class get mixin => mixedInClass?.mixin ?? this;
-
-  bool get isMixinApplication => mixedInType != null;
-
-  String get demangledName {
-    if (isAnonymousMixin) return nameAsMixinApplication;
-    assert(!name.contains('&'));
-    return name;
-  }
-
-  String get nameAsMixinApplication {
-    assert(isAnonymousMixin);
-    return demangleMixinApplicationName(name);
-  }
-
-  String get nameAsMixinApplicationSubclass {
-    assert(isAnonymousMixin);
-    return demangleMixinApplicationSubclassName(name);
-  }
-
-  /// Members declared in this class.
-  ///
-  /// This getter is for convenience, not efficiency.  Consider manually
-  /// iterating the members to speed up code in production.
-  Iterable<Member> get members => <Iterable<Member>>[
-        fields,
-        constructors,
-        procedures,
-      ].expand((x) => x);
-
-  void forEachMember(void action(Member element)) {
-    fields.forEach(action);
-    constructors.forEach(action);
-    procedures.forEach(action);
-  }
-
-  /// The immediately extended, mixed-in, and implemented types.
-  ///
-  /// This getter is for convenience, not efficiency.  Consider manually
-  /// iterating the super types to speed up code in production.
-  Iterable<Supertype> get supers => <Iterable<Supertype>>[
-        supertype == null ? const [] : [supertype!],
-        mixedInType == null ? const [] : [mixedInType!],
-        implementedTypes
-      ].expand((x) => x);
-
-  /// The library containing this class.
-  Library get enclosingLibrary => parent as Library;
-
-  /// Internal. Should *ONLY* be used from within kernel.
-  ///
-  /// If true we have to compute canonical names for all children of this class.
-  /// if false we can skip it.
-  bool dirty = true;
-
-  /// Adds a constructor to this class.
-  void addConstructor(Constructor constructor) {
-    dirty = true;
-    constructor.parent = this;
-    _constructorsInternal.add(constructor);
-  }
-
-  /// Adds a procedure to this class.
-  void addProcedure(Procedure procedure) {
-    dirty = true;
-    procedure.parent = this;
-    _proceduresInternal.add(procedure);
-  }
-
-  /// Adds a field to this class.
-  void addField(Field field) {
-    dirty = true;
-    field.parent = this;
-    _fieldsInternal.add(field);
-  }
-
-  @override
-  void addAnnotation(Expression node) {
-    if (annotations.isEmpty) {
-      annotations = <Expression>[];
-    }
-    annotations.add(node);
-    node.parent = this;
-  }
-
-  @override
-  R accept<R>(TreeVisitor<R> v) => v.visitClass(this);
-
-  @override
-  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitClass(this, arg);
-
-  R acceptReference<R>(Visitor<R> v) => v.visitClassReference(this);
-
-  Supertype get asRawSupertype {
-    return new Supertype(this,
-        new List<DartType>.filled(typeParameters.length, const DynamicType()));
-  }
-
-  Supertype get asThisSupertype {
-    return new Supertype(
-        this, getAsTypeArguments(typeParameters, this.enclosingLibrary));
-  }
-
-  /// Returns the type of `this` for the class using [coreTypes] for caching.
-  InterfaceType getThisType(CoreTypes coreTypes, Nullability nullability) {
-    return coreTypes.thisInterfaceType(this, nullability);
-  }
-
-  @override
-  String toString() => 'Class(${toStringInternal()})';
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeClassName(reference);
-  }
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(annotations, v);
-    visitList(typeParameters, v);
-    supertype?.accept(v);
-    mixedInType?.accept(v);
-    visitList(implementedTypes, v);
-    visitList(constructors, v);
-    visitList(procedures, v);
-    visitList(fields, v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    v.transformList(annotations, this);
-    v.transformList(typeParameters, this);
-    if (supertype != null) {
-      supertype = v.visitSupertype(supertype!);
-    }
-    if (mixedInType != null) {
-      mixedInType = v.visitSupertype(mixedInType!);
-    }
-    v.transformSupertypeList(implementedTypes);
-    v.transformList(constructors, this);
-    v.transformList(procedures, this);
-    v.transformList(fields, this);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    v.transformExpressionList(annotations, this);
-    v.transformTypeParameterList(typeParameters, this);
-    if (supertype != null) {
-      Supertype newSupertype = v.visitSupertype(supertype!, dummySupertype);
-      if (identical(newSupertype, dummySupertype)) {
-        supertype = null;
-      } else {
-        supertype = newSupertype;
-      }
-    }
-    if (mixedInType != null) {
-      Supertype newMixedInType = v.visitSupertype(mixedInType!, dummySupertype);
-      if (identical(newMixedInType, dummySupertype)) {
-        mixedInType = null;
-      } else {
-        mixedInType = newMixedInType;
-      }
-    }
-    v.transformSupertypeList(implementedTypes);
-    v.transformConstructorList(constructors, this);
-    v.transformProcedureList(procedures, this);
-    v.transformFieldList(fields, this);
-  }
-
-  @override
-  Location? _getLocationInEnclosingFile(int offset) {
-    return _getLocationInComponent(enclosingComponent, fileUri, offset,
-        viaForErrorMessage: "Class '$name'");
-  }
-}
-
-/// Declaration of an extension.
-///
-/// The members are converted into top-level procedures and only accessible
-/// by reference in the [Extension] node.
-class Extension extends NamedNode
-    implements Annotatable, FileUriNode, GenericDeclaration {
-  /// Name of the extension.
-  ///
-  /// If unnamed, the extension will be given a synthesized name by the
-  /// front end.
-  String name;
-
-  /// The URI of the source file this class was loaded from.
-  @override
-  Uri fileUri;
-
-  /// Type parameters declared on the extension.
-  @override
-  final List<TypeParameter> typeParameters;
-
-  /// The type in the 'on clause' of the extension declaration.
-  ///
-  /// For instance A in:
-  ///
-  ///   class A {}
-  ///   extension B on A {}
-  ///
-  /// The 'on clause' appears also in the experimental feature 'extension
-  /// types' as a part of an extension type declaration, for example:
-  ///
-  ///   class A {}
-  ///   extension type B on A {}
-  late DartType onType;
-
-  /// The members declared by the extension.
-  ///
-  /// The members are converted into top-level members and only accessible
-  /// by reference through [ExtensionMemberDescriptor].
-  List<ExtensionMemberDescriptor> memberDescriptors;
-
-  @override
-  List<Expression> annotations = const <Expression>[];
-
-  // Must match serialized bit positions.
-  static const int FlagUnnamedExtension = 1 << 0;
-
-  int flags = 0;
-
-  @override
-  void addAnnotation(Expression node) {
-    if (annotations.isEmpty) {
-      annotations = <Expression>[];
-    }
-    annotations.add(node);
-    node.parent = this;
-  }
-
-  Extension(
-      {required this.name,
-      List<TypeParameter>? typeParameters,
-      DartType? onType,
-      List<ExtensionMemberDescriptor>? memberDescriptors,
-      required this.fileUri,
-      Reference? reference})
-      : this.typeParameters = typeParameters ?? <TypeParameter>[],
-        this.memberDescriptors =
-            memberDescriptors ?? <ExtensionMemberDescriptor>[],
-        super(reference) {
-    setParents(this.typeParameters, this);
-    if (onType != null) {
-      this.onType = onType;
-    }
-  }
-
-  @override
-  void bindCanonicalNames(CanonicalName parent) {
-    parent.getChild(name).bindTo(reference);
-  }
-
-  Library get enclosingLibrary => parent as Library;
-
-  bool get isUnnamedExtension {
-    return flags & FlagUnnamedExtension != 0;
-  }
-
-  void set isUnnamedExtension(bool value) {
-    flags = value
-        ? (flags | FlagUnnamedExtension)
-        : (flags & ~FlagUnnamedExtension);
-  }
-
-  @override
-  R accept<R>(TreeVisitor<R> v) => v.visitExtension(this);
-
-  @override
-  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitExtension(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(annotations, v);
-    visitList(typeParameters, v);
-    onType.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    v.transformList(annotations, this);
-    v.transformList(typeParameters, this);
-    onType = v.visitDartType(onType);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    v.transformExpressionList(annotations, this);
-    v.transformTypeParameterList(typeParameters, this);
-    onType = v.visitDartType(onType, cannotRemoveSentinel);
-  }
-
-  @override
-  Location? _getLocationInEnclosingFile(int offset) {
-    return _getLocationInComponent(enclosingComponent, fileUri, offset,
-        viaForErrorMessage: "Extension '$name'");
-  }
-
-  @override
-  String toString() {
-    return "Extension(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExtensionName(reference);
-  }
-}
-
-enum ExtensionMemberKind {
-  Field,
-  Method,
-  Getter,
-  Setter,
-  Operator,
-}
-
-/// Information about an member declaration in an extension.
-class ExtensionMemberDescriptor {
-  static const int FlagStatic = 1 << 0; // Must match serialized bit positions.
-
-  /// The name of the extension member.
-  ///
-  /// The name of the generated top-level member is mangled to ensure
-  /// uniqueness. This name is used to lookup an extension method in the
-  /// extension itself.
-  Name name;
-
-  /// [ExtensionMemberKind] kind of the original member.
-  ///
-  /// An extension method is converted into a regular top-level method. For
-  /// instance:
-  ///
-  ///     class A {
-  ///       var foo;
-  ///     }
-  ///     extension B on A {
-  ///       get bar => this.foo;
-  ///     }
-  ///
-  /// will be converted into
-  ///
-  ///     class A {}
-  ///     B|get#bar(A #this) => #this.foo;
-  ///
-  /// where `B|get#bar` is the synthesized name of the top-level method and
-  /// `#this` is the synthesized parameter that holds represents `this`.
-  ///
-  ExtensionMemberKind kind;
-
-  int flags = 0;
-
-  /// Reference to the top-level member created for the extension method.
-  final Reference memberReference;
-
-  /// Reference to the top-level member created for the extension member tear
-  /// off, if any.
-  final Reference? tearOffReference;
-
-  ExtensionMemberDescriptor(
-      {required this.name,
-      required this.kind,
-      bool isStatic = false,
-      required this.memberReference,
-      required this.tearOffReference}) {
-    this.isStatic = isStatic;
-  }
-
-  /// Return `true` if the extension method was declared as `static`.
-  bool get isStatic => flags & FlagStatic != 0;
-
-  void set isStatic(bool value) {
-    flags = value ? (flags | FlagStatic) : (flags & ~FlagStatic);
-  }
-
-  @override
-  String toString() {
-    return 'ExtensionMemberDescriptor($name,$kind,'
-        '${memberReference.toStringInternal()},isStatic=${isStatic})';
-  }
-}
-
-/// Declaration of an extension type.
-///
-/// The members are converted into top-level procedures and only accessible
-/// by reference in the [ExtensionTypeDeclaration] node.
-class ExtensionTypeDeclaration extends NamedNode implements TypeDeclaration {
-  /// Name of the extension type declaration.
-  @override
-  String name;
-
-  /// The URI of the source file this class was loaded from.
-  @override
-  Uri fileUri;
-
-  /// Type parameters declared on the extension.
-  @override
-  final List<TypeParameter> typeParameters;
-
-  /// The type in the underlying representation of the extension type
-  /// declaration.
-  ///
-  /// For instance A in the extension type declaration B:
-  ///
-  ///   class A {}
-  ///   extension type B(A it) {}
-  ///
-  late DartType declaredRepresentationType;
-
-  /// The name of the representation field.
-  ///
-  /// For instance 'it' in the extension type declaration B:
-  ///
-  ///   class A {}
-  ///   extension type B(A it) {}
-  ///
-  /// This name is used for accessing underlying representation from an
-  /// extension type. If the name starts with '_' is private wrt. the enclosing
-  /// library of the extension type declaration.
-  late String representationName;
-
-  /// Abstract procedures that are part of the extension type declaration
-  /// interface.
-  ///
-  /// This includes a getter for the representation field and member signatures
-  /// computed as the combined member signature of inherited non-extension type
-  /// members.
-  List<Procedure> _procedures;
-
-  /// The members declared by the extension type declaration.
-  ///
-  /// The members are converted into top-level members and only accessible
-  /// by reference through [ExtensionTypeMemberDescriptor].
-  List<ExtensionTypeMemberDescriptor> memberDescriptors;
-
-  @override
-  List<Expression> annotations = const <Expression>[];
-
-  List<TypeDeclarationType> implements;
-
-  int flags = 0;
-
-  @override
-  void addAnnotation(Expression node) {
-    if (annotations.isEmpty) {
-      annotations = <Expression>[];
-    }
-    annotations.add(node);
-    node.parent = this;
-  }
-
-  ExtensionTypeDeclaration(
-      {required this.name,
-      List<TypeParameter>? typeParameters,
-      DartType? declaredRepresentationType,
-      List<ExtensionTypeMemberDescriptor>? memberDescriptors,
-      List<TypeDeclarationType>? implements,
-      List<Procedure>? procedures,
-      required this.fileUri,
-      Reference? reference})
-      : this.typeParameters = typeParameters ?? <TypeParameter>[],
-        this.memberDescriptors =
-            memberDescriptors ?? <ExtensionTypeMemberDescriptor>[],
-        this.implements = implements ?? <TypeDeclarationType>[],
-        this._procedures = procedures ?? <Procedure>[],
-        super(reference) {
-    setParents(this.typeParameters, this);
-    setParents(this._procedures, this);
-    if (declaredRepresentationType != null) {
-      this.declaredRepresentationType = declaredRepresentationType;
-    }
-  }
-
-  @override
-  CanonicalName bindCanonicalNames(CanonicalName parent) {
-    return parent.getChild(name)..bindTo(reference);
-  }
-
-  /// Computes the canonical name for this extension type declarations and all
-  /// its members.
-  void ensureCanonicalNames(CanonicalName parent) {
-    CanonicalName canonicalName = bindCanonicalNames(parent);
-    for (int i = 0; i < procedures.length; ++i) {
-      procedures[i].bindCanonicalNames(canonicalName);
-    }
-  }
-
-  Library get enclosingLibrary => parent as Library;
-
-  void addProcedure(Procedure procedure) {
-    procedure.parent = this;
-    procedures.add(procedure);
-  }
-
-  List<Procedure> get procedures => _procedures;
-
-  /// Internal. Should *ONLY* be used from within kernel.
-  ///
-  /// Used for adding procedures when reading the dill file.
-  void set proceduresInternal(List<Procedure> procedures) {
-    _procedures = procedures;
-  }
-
-  /// This is an advanced feature. Use of this method should be coordinated
-  /// with the kernel team.
-  ///
-  /// See [Component.relink] for a comprehensive description.
-  ///
-  /// Makes sure all references in named nodes in this extension type
-  /// declaration points to said named node.
-  void relink() {
-    this.reference.node = this;
-    for (int i = 0; i < procedures.length; ++i) {
-      Procedure member = procedures[i];
-      member._relinkNode();
-    }
-  }
-
-  @override
-  R accept<R>(TreeVisitor<R> v) => v.visitExtensionTypeDeclaration(this);
-
-  @override
-  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) =>
-      v.visitExtensionTypeDeclaration(this, arg);
-
-  R acceptReference<R>(Visitor<R> v) =>
-      v.visitExtensionTypeDeclarationReference(this);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(annotations, v);
-    visitList(typeParameters, v);
-    declaredRepresentationType.accept(v);
-    visitList(procedures, v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    v.transformList(annotations, this);
-    v.transformList(typeParameters, this);
-    declaredRepresentationType = v.visitDartType(declaredRepresentationType);
-    v.transformList(procedures, this);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    v.transformExpressionList(annotations, this);
-    v.transformTypeParameterList(typeParameters, this);
-    declaredRepresentationType =
-        v.visitDartType(declaredRepresentationType, cannotRemoveSentinel);
-    v.transformProcedureList(procedures, this);
-  }
-
-  @override
-  Location? _getLocationInEnclosingFile(int offset) {
-    return _getLocationInComponent(enclosingComponent, fileUri, offset,
-        viaForErrorMessage: "Extension type '$name'");
-  }
-
-  @override
-  String toString() {
-    return "ExtensionTypeDeclaration(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExtensionTypeDeclarationName(reference);
-  }
-
-  /// Returns the inherent nullability of this extension type declaration.
-  ///
-  /// An extension type declaration is inherently non-nullable if it implements
-  /// a non-extension type or a non-nullable extension type declaration.
-  Nullability get inherentNullability {
-    for (DartType supertype in implements) {
-      if (supertype is! ExtensionType) {
-        // A supertype that is not an extension type has to be non-nullable and
-        // implement `Object` directly or indirectly.
-        return Nullability.nonNullable;
-      } else if (supertype.extensionTypeDeclaration.inherentNullability !=
-          Nullability.undetermined) {
-        // If an extension type is non-nullable, it implements `Object` directly
-        // or indirectly.
-        return Nullability.nonNullable;
-      }
-    }
-    // Direct or indirect implementation of `Objects` isn't found.
-    return Nullability.undetermined;
-  }
-}
-
-enum ExtensionTypeMemberKind {
-  Constructor,
-  Factory,
-  Field,
-  Method,
-  Getter,
-  Setter,
-  Operator,
-  RedirectingFactory,
-}
-
-/// Information about an member declaration in an extension type declaration.
-class ExtensionTypeMemberDescriptor {
-  static const int FlagStatic = 1 << 0; // Must match serialized bit positions.
-
-  /// The name of the extension type declaration member.
-  ///
-  /// The name of the generated top-level member is mangled to ensure
-  /// uniqueness. This name is used to lookup a member in the extension type
-  /// declaration itself.
-  Name name;
-
-  /// [ExtensionTypeMemberKind] kind of the original member.
-  ///
-  /// An extension type declaration member is converted into a regular top-level
-  /// method. For instance:
-  ///
-  ///     class A {
-  ///       var foo;
-  ///     }
-  ///     extension type B(A it) {
-  ///       get bar => this.foo;
-  ///     }
-  ///
-  /// will be converted into
-  ///
-  ///     class A {}
-  ///     B|get#bar(A #this) => #this.foo;
-  ///
-  /// where `B|get#bar` is the synthesized name of the top-level method and
-  /// `#this` is the synthesized parameter that holds represents `this`.
-  ///
-  ExtensionTypeMemberKind kind;
-
-  int flags = 0;
-
-  /// Reference to the top-level member created for the extension type
-  /// declaration member.
-  final Reference memberReference;
-
-  /// Reference to the top-level member created for the extension type
-  /// declaration member tear off, if any.
-  final Reference? tearOffReference;
-
-  ExtensionTypeMemberDescriptor(
-      {required this.name,
-      required this.kind,
-      bool isStatic = false,
-      required this.memberReference,
-      required this.tearOffReference}) {
-    this.isStatic = isStatic;
-  }
-
-  /// Return `true` if the extension type declaration member was declared as
-  /// `static`.
-  bool get isStatic => flags & FlagStatic != 0;
-
-  void set isStatic(bool value) {
-    flags = value ? (flags | FlagStatic) : (flags & ~FlagStatic);
-  }
-
-  @override
-  String toString() {
-    return 'ExtensionTypeMemberDescriptor($name,$kind,'
-        '${memberReference.toStringInternal()},isStatic=${isStatic},'
-        '${tearOffReference?.toStringInternal()})';
-  }
-}
-
-// ------------------------------------------------------------------------
-//                            MEMBERS
-// ------------------------------------------------------------------------
-
-sealed class Member extends NamedNode implements Annotatable, FileUriNode {
-  /// End offset in the source file it comes from.
-  ///
-  /// Valid values are from 0 and up, or -1 ([TreeNode.noOffset]) if the file
-  /// end offset is not available (this is the default if none is specifically
-  /// set).
-  int fileEndOffset = TreeNode.noOffset;
-
-  @override
-  List<int>? get fileOffsetsIfMultiple => [fileOffset, fileEndOffset];
-
-  /// List of metadata annotations on the member.
-  ///
-  /// This defaults to an immutable empty list. Use [addAnnotation] to add
-  /// annotations if needed.
-  @override
-  List<Expression> annotations = const <Expression>[];
-
-  Name name;
-
-  /// The URI of the source file this member was loaded from.
-  @override
-  Uri fileUri;
-
-  /// Flags summarizing the kinds of AST nodes contained in this member, for
-  /// speeding up transformations that only affect certain types of nodes.
-  ///
-  /// See [TransformerFlag] for the meaning of each bit.
-  ///
-  /// These should not be used for any purpose other than skipping certain
-  /// members if it can be determined that no work is needed in there.
-  ///
-  /// It is valid for these flags to be false positives in rare cases, so
-  /// transformers must tolerate the case where a flag is spuriously set.
-  ///
-  /// This value is not serialized; it is populated by the frontend and the
-  /// deserializer.
-  //
-  // TODO(asgerf): It might be worthwhile to put this on classes as well.
-  int transformerFlags = 0;
-
-  Member(this.name, this.fileUri, Reference? reference) : super(reference);
-
-  /// The enclosing [TypeDeclaration] if this member a class member or an
-  /// abstract extension type member.
-  TypeDeclaration? get enclosingTypeDeclaration =>
-      parent is TypeDeclaration ? parent as TypeDeclaration : null;
-
-  /// The enclosing [Class] if this member a class member.
-  ///
-  /// This includes both declared and inherited members, and both static and
-  /// instance members.
-  Class? get enclosingClass => parent is Class ? parent as Class : null;
-
-  /// The enclosing [ExtensionTypeDeclaration] if this member an abstract
-  /// extension type member.
-  ///
-  /// This includes abstract getters for representation fields and combined
-  /// member signatures from inherited non-extension type members.
-  ExtensionTypeDeclaration? get enclosingExtensionTypeDeclaration =>
-      parent is ExtensionTypeDeclaration
-          ? parent as ExtensionTypeDeclaration
-          : null;
-
-  Library get enclosingLibrary {
-    TreeNode? parent = this.parent;
-    if (parent is Class) {
-      return parent.enclosingLibrary;
-    } else if (parent is ExtensionTypeDeclaration) {
-      return parent.enclosingLibrary;
-    }
-    return parent as Library;
-  }
-
-  @override
-  R accept<R>(MemberVisitor<R> v);
-
-  @override
-  R accept1<R, A>(MemberVisitor1<R, A> v, A arg);
-
-  R acceptReference<R>(MemberReferenceVisitor<R> v);
-
-  /// Returns true if this is an abstract procedure.
-  bool get isAbstract => false;
-
-  /// Returns true if the member has the 'const' modifier.
-  bool get isConst;
-
-  /// True if this is a field or non-setter procedure.
-  ///
-  /// Note that operators and factories return `true`, even though there are
-  /// normally no calls to their getter.
-  bool get hasGetter;
-
-  /// True if this is a setter or a mutable field.
-  bool get hasSetter;
-
-  /// True if this is a non-static field or procedure.
-  bool get isInstanceMember;
-
-  /// True if the member has the `external` modifier, implying that the
-  /// implementation is provided by the backend, and is not necessarily written
-  /// in Dart.
-  ///
-  /// Members can have this modifier independently of whether the enclosing
-  /// library is external.
-  bool get isExternal;
-
-  /// If `true` this member is compiled from a member declared in an extension
-  /// declaration.
-  ///
-  /// For instance `field`, `method1` and `method2` in:
-  ///
-  ///     extension A on B {
-  ///       static var field;
-  ///       B method1() => this;
-  ///       static B method2() => new B();
-  ///     }
-  ///
-  bool get isExtensionMember;
-
-  /// If `true` this member is compiled from a member declared in an extension
-  /// type declaration.
-  ///
-  /// For instance `field`, `method1` and `method2` in:
-  ///
-  ///     extension type A(B it) {
-  ///       static var field;
-  ///       B method1() => this;
-  ///       static B method2() => new B();
-  ///     }
-  ///
-  bool get isExtensionTypeMember;
-
-  /// If `true` this procedure is not part of the interface but only part of the
-  /// class members.
-  ///
-  /// This is `true` for instance for augmented procedures and synthesized
-  /// fields added for the late lowering.
-  bool get isInternalImplementation => false;
-
-  /// The function signature and body of the procedure or constructor, or `null`
-  /// if this is a field.
-  FunctionNode? get function => null;
-
-  /// Returns a possibly synthesized name for this member, consistent with
-  /// the names used across all [toString] calls.
-  @override
-  String toString() => toStringInternal();
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeMemberName(reference);
-  }
-
-  @override
-  void addAnnotation(Expression node) {
-    if (annotations.isEmpty) {
-      annotations = <Expression>[];
-    }
-    annotations.add(node);
-    node.parent = this;
-  }
-
-  /// Returns the type of this member when accessed as a getter.
-  ///
-  /// For a field, this is the field type. For a getter, this is the return
-  /// type. For a method or constructor, this is the tear off type.
-  ///
-  /// For a setter, this is undefined. Currently, non-nullable `Never` is
-  /// returned.
-  // TODO(johnniwinther): Should we use `InvalidType` for the undefined cases?
-  DartType get getterType;
-
-  /// Returns the type of this member when access as a getter on a super class.
-  ///
-  /// This is in most cases the same as for [getterType].
-  ///
-  /// An exception is for forwarding semi stubs:
-  ///
-  ///    class Super {
-  ///      void method(num a) {}
-  ///    }
-  ///    class Class extends Super {
-  ///      void method(covariant int a);
-  ///    }
-  ///    class Subclass extends Class {
-  ///      void method(int a) {
-  ///        super.method; // Type `void Function(num)`.
-  ///        Class().method; // Type `void Function(int)`.
-  ///      }
-  ///    }
-  ///
-  /// Here, `Class.method` is turned into a forwarding semi stub
-  ///
-  ///     void method(covariant num a) => super.method(a);
-  ///
-  /// with [signatureType] `void Function(int)`. When `Class.method` is used
-  /// as the target of a super get, it has getter type `void Function(num)` and
-  /// as the target of an instance get, it has getter type `void Function(int)`.
-  DartType get superGetterType => getterType;
-
-  /// Returns the type of this member when accessed as a setter.
-  ///
-  /// For an assignable field, this is the field type. For a setter this is the
-  /// parameter type.
-  ///
-  /// For other members, including unassignable fields, this is undefined.
-  /// Currently, non-nullable `Never` is returned.
-  // TODO(johnniwinther): Should we use `InvalidType` for the undefined cases?
-  DartType get setterType;
-
-  /// Returns the type of this member when access as a setter on a super class.
-  ///
-  /// This is in most cases the same as for [setterType].
-  ///
-  /// An exception is for forwarding semi stubs:
-  ///
-  ///    class Super {
-  ///      void set setter(num a) {}
-  ///    }
-  ///    class Class extends Super {
-  ///      void set setter(covariant int a);
-  ///    }
-  ///    class Subclass extends Class {
-  ///      void set setter(int a) {
-  ///        super.setter = 0.5; // Valid.
-  ///        Class().setter = 0.5; // Invalid.
-  ///      }
-  ///    }
-  ///
-  /// Here, `Class.setter` is turned into a forwarding semi stub
-  ///
-  ///     void set setter(covariant num a) => super.setter = a;
-  ///
-  /// with [signatureType] `void Function(int)`. When `Class.setter` is used
-  /// as the target of a super set, it has setter type `num` and as the target
-  /// of an instance set, it has setter type `int`.
-  DartType get superSetterType => setterType;
-
-  bool get containsSuperCalls {
-    return transformerFlags & TransformerFlag.superCalls != 0;
-  }
-
-  /// If this member is a member signature, [memberSignatureOrigin] is one of
-  /// the non-member signature members from which it was created.
-  Member? get memberSignatureOrigin => null;
-}
-
-/// A field declaration.
-///
-/// The implied getter and setter for the field are not represented explicitly,
-/// but can be made explicit if needed.
-class Field extends Member {
-  DartType type; // Not null. Defaults to DynamicType.
-  int flags = 0;
-  Expression? initializer; // May be null.
-
-  /// Reference used for reading from this field.
-  ///
-  /// This should be used as the target in [StaticGet], [InstanceGet], and
-  /// [SuperPropertyGet].
-  final Reference getterReference;
-
-  /// Reference used for writing to this field.
-  ///
-  /// This should be used as the target in [StaticSet], [InstanceSet], and
-  /// [SuperPropertySet].
-  final Reference? setterReference;
-
-  @override
-  @Deprecated("Use the specific getterReference/setterReference instead")
-  Reference get reference => super.reference;
-
-  /// Reference used for initializing this field.
-  ///
-  /// This should be used as the target in [FieldInitializer] and as the key
-  /// in the field values of [InstanceConstant].
-  Reference get fieldReference => super.reference;
-
-  Field.mutable(Name name,
-      {this.type = const DynamicType(),
-      this.initializer,
-      bool isCovariantByDeclaration = false,
-      bool isFinal = false,
-      bool isStatic = false,
-      bool isLate = false,
-      int transformerFlags = 0,
-      required Uri fileUri,
-      Reference? fieldReference,
-      Reference? getterReference,
-      Reference? setterReference})
-      : this.getterReference = getterReference ?? new Reference(),
-        this.setterReference = setterReference ?? new Reference(),
-        super(name, fileUri, fieldReference) {
-    this.getterReference.node = this;
-    this.setterReference!.node = this;
-    initializer?.parent = this;
-    this.isCovariantByDeclaration = isCovariantByDeclaration;
-    this.isFinal = isFinal;
-    this.isStatic = isStatic;
-    this.isLate = isLate;
-    this.transformerFlags = transformerFlags;
-  }
-
-  Field.immutable(Name name,
-      {this.type = const DynamicType(),
-      this.initializer,
-      bool isCovariantByDeclaration = false,
-      bool isFinal = false,
-      bool isConst = false,
-      bool isStatic = false,
-      bool isLate = false,
-      int transformerFlags = 0,
-      required Uri fileUri,
-      Reference? fieldReference,
-      Reference? getterReference,
-      bool isEnumElement = false})
-      : this.getterReference = getterReference ?? new Reference(),
-        this.setterReference = null,
-        super(name, fileUri, fieldReference) {
-    this.getterReference.node = this;
-    initializer?.parent = this;
-    this.isCovariantByDeclaration = isCovariantByDeclaration;
-    this.isFinal = isFinal;
-    this.isConst = isConst;
-    this.isStatic = isStatic;
-    this.isLate = isLate;
-    this.isEnumElement = isEnumElement;
-    this.transformerFlags = transformerFlags;
-  }
-
-  @override
-  void bindCanonicalNames(CanonicalName parent) {
-    parent.getChildFromField(this).bindTo(fieldReference);
-    parent.getChildFromFieldGetter(this).bindTo(getterReference);
-    if (hasSetter) {
-      parent.getChildFromFieldSetter(this).bindTo(setterReference!);
-    }
-  }
-
-  @override
-  void _relinkNode() {
-    this.fieldReference.node = this;
-    this.getterReference.node = this;
-    if (hasSetter) {
-      this.setterReference!.node = this;
-    }
-  }
-
-  static const int FlagFinal = 1 << 0; // Must match serialized bit positions.
-  static const int FlagConst = 1 << 1;
-  static const int FlagStatic = 1 << 2;
-  static const int FlagCovariant = 1 << 3;
-  static const int FlagCovariantByClass = 1 << 4;
-  static const int FlagLate = 1 << 5;
-  static const int FlagExtensionMember = 1 << 6;
-  static const int FlagInternalImplementation = 1 << 7;
-  static const int FlagEnumElement = 1 << 8;
-  static const int FlagExtensionTypeMember = 1 << 9;
-
-  /// Whether the field is declared with the `covariant` keyword.
-  bool get isCovariantByDeclaration => flags & FlagCovariant != 0;
-
-  bool get isFinal => flags & FlagFinal != 0;
-
-  @override
-  bool get isConst => flags & FlagConst != 0;
-
-  bool get isStatic => flags & FlagStatic != 0;
-
-  @override
-  bool get isExtensionMember => flags & FlagExtensionMember != 0;
-
-  @override
-  bool get isExtensionTypeMember => flags & FlagExtensionTypeMember != 0;
-
-  /// Indicates whether the implicit setter associated with this field needs to
-  /// contain a runtime type check to deal with generic covariance.
-  ///
-  /// When `true`, runtime checks may need to be performed.
-  bool get isCovariantByClass => flags & FlagCovariantByClass != 0;
-
-  /// Whether the field is declared with the `late` keyword.
-  bool get isLate => flags & FlagLate != 0;
-
-  /// If `true` this field is not part of the interface but only part of the
-  /// class members.
-  ///
-  /// This is `true` for instance for synthesized fields added for the late
-  /// lowering.
-  @override
-  bool get isInternalImplementation => flags & FlagInternalImplementation != 0;
-
-  /// If `true` this field is an enum element.
-  ///
-  /// For instance
-  ///
-  ///    enum A {
-  ///      a, b;
-  ///      static const A c = A.a;
-  ///    }
-  ///
-  /// the fields `a` and `b` are enum elements whereas `c` is a regular field.
-  bool get isEnumElement => flags & FlagEnumElement != 0;
-
-  void set isCovariantByDeclaration(bool value) {
-    flags = value ? (flags | FlagCovariant) : (flags & ~FlagCovariant);
-  }
-
-  void set isFinal(bool value) {
-    flags = value ? (flags | FlagFinal) : (flags & ~FlagFinal);
-  }
-
-  void set isConst(bool value) {
-    flags = value ? (flags | FlagConst) : (flags & ~FlagConst);
-  }
-
-  void set isStatic(bool value) {
-    flags = value ? (flags | FlagStatic) : (flags & ~FlagStatic);
-  }
-
-  void set isExtensionMember(bool value) {
-    flags =
-        value ? (flags | FlagExtensionMember) : (flags & ~FlagExtensionMember);
-  }
-
-  void set isCovariantByClass(bool value) {
-    flags = value
-        ? (flags | FlagCovariantByClass)
-        : (flags & ~FlagCovariantByClass);
-  }
-
-  void set isLate(bool value) {
-    flags = value ? (flags | FlagLate) : (flags & ~FlagLate);
-  }
-
-  void set isInternalImplementation(bool value) {
-    flags = value
-        ? (flags | FlagInternalImplementation)
-        : (flags & ~FlagInternalImplementation);
-  }
-
-  void set isEnumElement(bool value) {
-    flags = value ? (flags | FlagEnumElement) : (flags & ~FlagEnumElement);
-  }
-
-  void set isExtensionTypeMember(bool value) {
-    flags = value
-        ? (flags | FlagExtensionTypeMember)
-        : (flags & ~FlagExtensionTypeMember);
-  }
-
-  @override
-  bool get isInstanceMember => !isStatic;
-
-  @override
-  bool get hasGetter => true;
-
-  @override
-  bool get hasSetter => setterReference != null;
-
-  @override
-  bool get isExternal => false;
-
-  @override
-  R accept<R>(MemberVisitor<R> v) => v.visitField(this);
-
-  @override
-  R accept1<R, A>(MemberVisitor1<R, A> v, A arg) => v.visitField(this, arg);
-
-  @override
-  R acceptReference<R>(MemberReferenceVisitor<R> v) =>
-      v.visitFieldReference(this);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(annotations, v);
-    type.accept(v);
-    name.accept(v);
-    initializer?.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    type = v.visitDartType(type);
-    v.transformList(annotations, this);
-    if (initializer != null) {
-      initializer = v.transform(initializer!);
-      initializer?.parent = this;
-    }
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    type = v.visitDartType(type, null);
-    v.transformExpressionList(annotations, this);
-    if (initializer != null) {
-      initializer = v.transformOrRemoveExpression(initializer!);
-      initializer?.parent = this;
-    }
-  }
-
-  @override
-  DartType get getterType => type;
-
-  @override
-  DartType get setterType => hasSetter ? type : const NeverType.nonNullable();
-
-  @override
-  Location? _getLocationInEnclosingFile(int offset) {
-    return _getLocationInComponent(enclosingComponent, fileUri, offset,
-        viaForErrorMessage: "Field '$name'");
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeMemberName(fieldReference);
-  }
-}
-
-/// A generative constructor, possibly redirecting.
-///
-/// Note that factory constructors are treated as [Procedure]s.
-///
-/// Constructors do not take type parameters.  Type arguments from a constructor
-/// invocation should be matched with the type parameters declared in the class.
-///
-/// For unnamed constructors, the name is an empty string (in a [Name]).
-class Constructor extends Member {
-  /// Start offset of the constructor in the source file it comes from.
-  ///
-  /// Note that this includes annotations if any.
-  ///
-  /// Valid values are from 0 and up, or -1 ([TreeNode.noOffset]) if the file
-  /// start offset is not available (this is the default if none is specifically
-  /// set).
-  int startFileOffset = TreeNode.noOffset;
-
-  @override
-  List<int>? get fileOffsetsIfMultiple =>
-      [fileOffset, startFileOffset, fileEndOffset];
-
-  int flags = 0;
-
-  @override
-  FunctionNode function;
-
-  List<Initializer> initializers;
-
-  Constructor(this.function,
-      {required Name name,
-      bool isConst = false,
-      bool isExternal = false,
-      bool isSynthetic = false,
-      List<Initializer>? initializers,
-      int transformerFlags = 0,
-      required Uri fileUri,
-      Reference? reference})
-      : this.initializers = initializers ?? <Initializer>[],
-        super(name, fileUri, reference) {
-    function.parent = this;
-    setParents(this.initializers, this);
-    this.isConst = isConst;
-    this.isExternal = isExternal;
-    this.isSynthetic = isSynthetic;
-    this.transformerFlags = transformerFlags;
-  }
-
-  @override
-  void bindCanonicalNames(CanonicalName parent) {
-    parent.getChildFromConstructor(this).bindTo(reference);
-  }
-
-  @override
-  Class get enclosingClass => parent as Class;
-
-  static const int FlagConst = 1 << 0; // Must match serialized bit positions.
-  static const int FlagExternal = 1 << 1;
-  static const int FlagSynthetic = 1 << 2;
-
-  @override
-  bool get isConst => flags & FlagConst != 0;
-
-  @override
-  bool get isExternal => flags & FlagExternal != 0;
-
-  /// True if this is a synthetic constructor inserted in a class that
-  /// does not otherwise declare any constructors.
-  bool get isSynthetic => flags & FlagSynthetic != 0;
-
-  void set isConst(bool value) {
-    flags = value ? (flags | FlagConst) : (flags & ~FlagConst);
-  }
-
-  void set isExternal(bool value) {
-    flags = value ? (flags | FlagExternal) : (flags & ~FlagExternal);
-  }
-
-  void set isSynthetic(bool value) {
-    flags = value ? (flags | FlagSynthetic) : (flags & ~FlagSynthetic);
-  }
-
-  @override
-  bool get isInstanceMember => false;
-
-  @override
-  bool get hasGetter => false;
-
-  @override
-  bool get hasSetter => false;
-
-  @override
-  bool get isExtensionMember => false;
-
-  @override
-  bool get isExtensionTypeMember => false;
-
-  @override
-  R accept<R>(MemberVisitor<R> v) => v.visitConstructor(this);
-
-  @override
-  R accept1<R, A>(MemberVisitor1<R, A> v, A arg) =>
-      v.visitConstructor(this, arg);
-
-  @override
-  R acceptReference<R>(MemberReferenceVisitor<R> v) =>
-      v.visitConstructorReference(this);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(annotations, v);
-    name.accept(v);
-    visitList(initializers, v);
-    function.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    v.transformList(annotations, this);
-    v.transformList(initializers, this);
-    function = v.transform(function);
-    function.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    v.transformExpressionList(annotations, this);
-    v.transformInitializerList(initializers, this);
-    function = v.transform(function);
-    function.parent = this;
-  }
-
-  // TODO(johnniwinther): Provide the tear off type here.
-  @override
-  DartType get getterType => const NeverType.nonNullable();
-
-  @override
-  DartType get setterType => const NeverType.nonNullable();
-
-  @override
-  Location? _getLocationInEnclosingFile(int offset) {
-    return _getLocationInComponent(enclosingComponent, fileUri, offset,
-        viaForErrorMessage: "Constructor '$name'");
-  }
-}
-
-/// Enum for the semantics of the `Procedure.stubTarget` property.
-enum ProcedureStubKind {
-  /// A regular procedure declared in source code.
-  ///
-  /// The stub target is `null`.
-  Regular,
-
-  /// An abstract procedure inserted to add `isCovariantByDeclaration` and
-  /// `isCovariantByClass` to parameters for a set of overridden members.
-  ///
-  /// The stub is inserted when not all of the overridden members agree on
-  /// the covariance flags. For instance:
-  ///
-  ///     class A<T> {
-  ///        void method1(num o) {}
-  ///        void method2(T o) {}
-  ///     }
-  ///     class B {
-  ///        void method1(covariant int o) {}
-  ///        void method2(int o) {}
-  ///     }
-  ///     class C implements A<int>, B {
-  ///        // Abstract forwarding stub needed because the parameter is
-  ///        // covariant in `B.method1` but not in `A.method1`.
-  ///        void method1(covariant num o);
-  ///        // Abstract forwarding stub needed because the parameter is a
-  ///        // generic covariant impl in `A.method2` but not in `B.method2`.
-  ///        void method2(/*generic-covariant-impl*/ int o);
-  ///     }
-  ///
-  /// The stub target is one of the overridden members.
-  AbstractForwardingStub,
-
-  /// A concrete procedure inserted to add `isCovariantByDeclaration` and
-  /// `isCovariantByClass` checks to parameters before calling the
-  /// overridden member in the superclass.
-  ///
-  /// The stub is inserted when not all of the overridden members agree on
-  /// the covariance flags and the overridden super class member does not
-  /// have the same covariance flags. For instance:
-  ///
-  ///     class A<T> {
-  ///        void method1(num o) {}
-  ///        void method2(T o) {}
-  ///     }
-  ///     class B {
-  ///        void method1(covariant int o) {}
-  ///        void method2(int o) {}
-  ///     }
-  ///     class C extends A<int> implements B {
-  ///        // Concrete forwarding stub needed because the parameter is
-  ///        // covariant in `B.method1` but not in `A.method1`.
-  ///        void method1(covariant num o) => super.method1(o);
-  ///        // No need for a concrete forwarding stub for `A.method2` because
-  ///        // it has the right covariance flags already.
-  ///     }
-  ///
-  /// The stub target is the called superclass member.
-  ConcreteForwardingStub,
-
-  /// A concrete procedure inserted to forward calls to `noSuchMethod` for
-  /// an inherited member that it does not implement.
-  ///
-  /// The stub is inserted when a class implements private members of another
-  /// library or declares/inherits a user-defined `noSuchMethod` method. For
-  /// instance:
-  ///
-  ///     // lib1:
-  ///     class A {
-  ///       void _privateMethod() {}
-  ///     }
-  ///     // lib2:
-  ///     class B implements A {
-  ///       // Forwarding stub inserted to forward calls to `A._privateMethod`.
-  ///       void _privateMethod() => noSuchMethod(#_privateMethod, ...);
-  ///     }
-  ///     class C {
-  ///       void method() {}
-  ///     }
-  ///     class D implements C {
-  ///       noSuchMethod(o) { ... }
-  ///       // Forwarding stub inserted to forward calls to `C.method`.
-  ///       void method() => noSuchMethod(#method, ...);
-  ///     }
-  ///
-  ///
-  /// The stub target is `null` if the procedure preexisted as an abstract
-  /// procedure. Otherwise the stub target is one of the inherited members.
-  NoSuchMethodForwarder,
-
-  /// An abstract procedure inserted to show the combined member signature type
-  /// of set of overridden members.
-  ///
-  /// The stub is inserted when an opt-in member is inherited into an opt-out
-  /// library or when NNBD_TOP_MERGE was used to compute the type of a merge
-  /// point in an opt-in library. For instance:
-  ///
-  ///     // lib1: opt-in
-  ///     class A {
-  ///       int? method1() => null;
-  ///       void method2(Object? o) {}
-  ///     }
-  ///     class B {
-  ///       dynamic method2(dynamic o);
-  ///     }
-  ///     class C implements A, B {
-  ///       // Member signature inserted for the NNBD_TOP_MERGE type of
-  ///       // `A.method2` and `B.method2`.
-  ///       Object? method2(Object? o);
-  ///     }
-  ///     // lib2: opt-out
-  ///     class D extends A {
-  ///       // Member signature inserted for the LEGACY_ERASURE type of
-  ///       // `A.method1` and `A.method2` with types `int* Function()`
-  ///       // and `void Function(Object*)`, respectively.
-  ///       int method1();
-  ///       void method2(Object o);
-  ///     }
-  ///
-  /// The stub target is one of the overridden members.
-  MemberSignature,
-
-  /// An abstract procedure inserted for the application of an abstract mixin
-  /// member.
-  ///
-  /// The stub is inserted when an abstract member is mixed into a mixin
-  /// application. For instance:
-  ///
-  ///     class Super {}
-  ///     abstract class Mixin {
-  ///        void method();
-  ///     }
-  ///     class Class = Super with Mixin
-  ///       // An abstract mixin stub for `A.method` is added to `Class`
-  ///       void method();
-  ///     ;
-  ///
-  /// This is added to ensure that interface targets are resolved consistently
-  /// in face of cloning. For instance, without the abstract mixin stub, this
-  /// call:
-  ///
-  ///     method(Class c) => c.method();
-  ///
-  /// would use `Mixin.method` as its target, but after loading from a VM .dill
-  /// (which clones all mixin members) the call would resolve to `Class.method`
-  /// instead. By adding the mixin stub to `Class`, all accesses both before
-  /// and after .dill will point to `Class.method`.
-  ///
-  /// The stub target is the mixin member.
-  AbstractMixinStub,
-
-  /// A concrete procedure inserted for the application of a concrete mixin
-  /// member. The implementation calls the mixin member via a super-call.
-  ///
-  /// The stub is inserted when a concrete member is mixed into a mixin
-  /// application. For instance:
-  ///
-  ///     class Super {}
-  ///     abstract class Mixin {
-  ///        void method() {}
-  ///     }
-  ///     class Class = Super with Mixin
-  ///       // A concrete mixin stub for `A.method` is added to `Class` which
-  ///       // calls `A.method`.
-  ///       void method() => super.method();
-  ///     ;
-  ///
-  /// This is added to ensure that super accesses are resolved correctly, even
-  /// in face of cloning. For instance, without the concrete mixin stub, this
-  /// super call:
-  ///
-  ///     class Subclass extends Class {
-  ///       method(Class c) => super.method();
-  ///     }
-  ///
-  /// would use `Mixin.method` as its target, which would need to be updated to
-  /// match the clone of the mixin member performed for instance by the VM. By
-  /// adding the concrete mixin stub to `Class`, all accesses both before and
-  /// after cloning will point to `Class.method`.
-  ///
-  /// The stub target is the called mixin member.
-  ConcreteMixinStub,
-
-  /// The representation field of an extension type declaration, encoded as
-  /// an abstract getter.
-  ///
-  /// The stub target is `null`.
-  RepresentationField,
-}
-
-/// A method, getter, setter, index-getter, index-setter, operator overloader,
-/// or factory.
-///
-/// Procedures can have the static, abstract, and/or external modifier, although
-/// only the static and external modifiers may be used together.
-///
-/// For non-static procedures the name is required for dynamic dispatch.
-/// For external procedures the name is required for identifying the external
-/// implementation.
-///
-/// For methods, getters, and setters the name is just as it was declared.
-/// For setters this does not include a trailing `=`.
-/// For index-getters/setters, this is `[]` and `[]=`.
-/// For operators, this is the token for the operator, e.g. `+` or `==`,
-/// except for the unary minus operator, whose name is `unary-`.
-class Procedure extends Member implements GenericFunction {
-  /// Start offset of the function in the source file it comes from.
-  ///
-  /// Note that this includes annotations if any.
-  ///
-  /// Valid values are from 0 and up, or -1 ([TreeNode.noOffset]) if the file
-  /// start offset is not available (this is the default if none is specifically
-  /// set).
-  int fileStartOffset = TreeNode.noOffset;
-
-  @override
-  List<int>? get fileOffsetsIfMultiple =>
-      [fileOffset, fileStartOffset, fileEndOffset];
-
-  final ProcedureKind kind;
-  int flags = 0;
-
-  @override
-  FunctionNode function;
-
-  ProcedureStubKind stubKind;
-  Reference? stubTargetReference;
-
-  /// The interface member signature type of this procedure.
-  ///
-  /// Normally this is derived from the parameter types and return type of
-  /// [function]. In rare cases, the interface member signature type is
-  /// different from the class member type, in which case the interface member
-  /// signature type is stored here.
-  ///
-  /// For instance
-  ///
-  ///   class Super {
-  ///     void method(num a) {}
-  ///   }
-  ///   class Class extends Super {
-  ///     void method(covariant int a);
-  ///   }
-  ///
-  /// Here the member `Class.method` is turned into a forwarding semi stub to
-  /// ensure that arguments passed to `Super.method` are checked as covariant.
-  /// Since `Super.method` allows `num` as argument, the inserted covariant
-  /// check must be against `num` and not `int`, and the parameter type of the
-  /// forwarding semi stub must be changed to `num`. Still, the interface of
-  /// `Class` requires that `Class.method` is `void Function(int)`, so for
-  /// this, it is stored explicitly as the [signatureType] on the procedure.
-  ///
-  /// When [signatureType] is null, you can compute the function type with
-  /// `function.computeFunctionType(Nullability.nonNullable)`. Alternatively,
-  /// you can use [computeSignatureOrFunctionType] that computes the interface
-  /// member signature type accounting for the possibility of [signatureType]
-  /// being null.
-  FunctionType? signatureType;
-
-  Procedure(Name name, ProcedureKind kind, FunctionNode function,
-      {bool isAbstract = false,
-      bool isStatic = false,
-      bool isExternal = false,
-      bool isConst = false,
-      bool isExtensionMember = false,
-      bool isExtensionTypeMember = false,
-      bool isSynthetic = false,
-      int transformerFlags = 0,
-      required Uri fileUri,
-      Reference? reference,
-      ProcedureStubKind stubKind = ProcedureStubKind.Regular,
-      Member? stubTarget})
-      : this._byReferenceRenamed(name, kind, function,
-            isAbstract: isAbstract,
-            isStatic: isStatic,
-            isExternal: isExternal,
-            isConst: isConst,
-            isExtensionMember: isExtensionMember,
-            isExtensionTypeMember: isExtensionTypeMember,
-            isSynthetic: isSynthetic,
-            transformerFlags: transformerFlags,
-            fileUri: fileUri,
-            reference: reference,
-            stubKind: stubKind,
-            stubTargetReference:
-                getMemberReferenceBasedOnProcedureKind(stubTarget, kind));
-
-  Procedure._byReferenceRenamed(Name name, this.kind, this.function,
-      {bool isAbstract = false,
-      bool isStatic = false,
-      bool isExternal = false,
-      bool isConst = false,
-      bool isExtensionMember = false,
-      bool isExtensionTypeMember = false,
-      bool isSynthetic = false,
-      int transformerFlags = 0,
-      required Uri fileUri,
-      Reference? reference,
-      this.stubKind = ProcedureStubKind.Regular,
-      this.stubTargetReference})
-      : super(name, fileUri, reference) {
-    function.parent = this;
-    this.isAbstract = isAbstract;
-    this.isStatic = isStatic;
-    this.isExternal = isExternal;
-    this.isConst = isConst;
-    this.isExtensionMember = isExtensionMember;
-    this.isExtensionTypeMember = isExtensionTypeMember;
-    this.isSynthetic = isSynthetic;
-    setTransformerFlagsWithoutLazyLoading(transformerFlags);
-    assert(!(isMemberSignature && stubTargetReference == null),
-        "No member signature origin for member signature $this.");
-    assert(
-        !(memberSignatureOrigin is Procedure &&
-            (memberSignatureOrigin as Procedure).isMemberSignature),
-        "Member signature origin cannot be a member signature "
-        "$memberSignatureOrigin for $this.");
-  }
-
-  @override
-  List<TypeParameter> get typeParameters => function.typeParameters;
-
-  // The function node's body might be lazily loaded, meaning that this value
-  // might not be set correctly yet. Make sure the body is loaded before
-  // returning anything.
-  @override
-  int get transformerFlags {
-    function.body;
-    return super.transformerFlags;
-  }
-
-  // The function node's body might be lazily loaded, meaning that this value
-  // might get overwritten later (when the body is read). To avoid that read the
-  // body now and only set the value afterwards.
-  @override
-  void set transformerFlags(int newValue) {
-    function.body;
-    super.transformerFlags = newValue;
-  }
-
-  // This function will set the transformer flags without loading the body.
-  // Used when reading the binary. For other cases one should probably use
-  // `transformerFlags = value;`.
-  void setTransformerFlagsWithoutLazyLoading(int newValue) {
-    super.transformerFlags = newValue;
-  }
-
-  @override
-  void bindCanonicalNames(CanonicalName parent) {
-    parent.getChildFromProcedure(this).bindTo(reference);
-  }
-
-  static const int FlagStatic = 1 << 0; // Must match serialized bit positions.
-  static const int FlagAbstract = 1 << 1;
-  static const int FlagExternal = 1 << 2;
-  static const int FlagConst = 1 << 3; // Only for external const factories.
-  static const int FlagExtensionMember = 1 << 4;
-  static const int FlagSynthetic = 1 << 5;
-  static const int FlagInternalImplementation = 1 << 6;
-  static const int FlagExtensionTypeMember = 1 << 7;
-  static const int FlagHasWeakTearoffReferencePragma = 1 << 8;
-
-  bool get isStatic => flags & FlagStatic != 0;
-
-  @override
-  bool get isAbstract => flags & FlagAbstract != 0;
-
-  @override
-  bool get isExternal => flags & FlagExternal != 0;
-
-  /// True if this has the `const` modifier.  This is only possible for external
-  /// constant factories, such as `String.fromEnvironment`.
-  @override
-  bool get isConst => flags & FlagConst != 0;
-
-  /// If set, this flag indicates that this function's implementation exists
-  /// solely for the purpose of type checking arguments and forwarding to
-  /// [concreteForwardingStubTarget].
-  ///
-  /// Note that just because this bit is set doesn't mean that the function was
-  /// not declared in the source; it's possible that this is a forwarding
-  /// semi-stub (see isForwardingSemiStub).  To determine whether this function
-  /// was present in the source, consult [isSyntheticForwarder].
-  bool get isForwardingStub =>
-      stubKind == ProcedureStubKind.AbstractForwardingStub ||
-      stubKind == ProcedureStubKind.ConcreteForwardingStub;
-
-  /// If set, this flag indicates that although this function is a forwarding
-  /// stub, it was present in the original source as an abstract method.
-  bool get isForwardingSemiStub => !isSynthetic && isForwardingStub;
-
-  /// If set, this method is a class member added to show the type of an
-  /// inherited member.
-  ///
-  /// This is used when the type of the inherited member cannot be computed
-  /// directly from the member(s) in the supertypes. For instance in case of
-  /// an nnbd opt-out class inheriting from an nnbd opt-in class; here all nnbd-
-  /// aware types are replaced with legacy types in the inherited signature.
-  bool get isMemberSignature => stubKind == ProcedureStubKind.MemberSignature;
-
-  // Indicates if this [Procedure] represents a redirecting factory constructor
-  // and doesn't have a runnable body.
-  bool get isRedirectingFactory {
-    return function.redirectingFactoryTarget != null;
-  }
-
-  /// If set, this flag indicates that this function was not present in the
-  /// source, and it exists solely for the purpose of type checking arguments
-  /// and forwarding to [concreteForwardingStubTarget].
-  bool get isSyntheticForwarder => isForwardingStub && !isForwardingSemiStub;
-  bool get isSynthetic => flags & FlagSynthetic != 0;
-
-  bool get isNoSuchMethodForwarder =>
-      stubKind == ProcedureStubKind.NoSuchMethodForwarder;
-
-  /// If `true` this procedure is not part of the interface but only part of the
-  /// class members.
-  ///
-  /// This is `true` for instance for augmented procedures.
-  @override
-  bool get isInternalImplementation => flags & FlagInternalImplementation != 0;
-
-  void set isInternalImplementation(bool value) {
-    flags = value
-        ? (flags | FlagInternalImplementation)
-        : (flags & ~FlagInternalImplementation);
-  }
-
-  @override
-  bool get isExtensionMember => flags & FlagExtensionMember != 0;
-
-  @override
-  bool get isExtensionTypeMember => flags & FlagExtensionTypeMember != 0;
-
-  void set isStatic(bool value) {
-    flags = value ? (flags | FlagStatic) : (flags & ~FlagStatic);
-  }
-
-  void set isAbstract(bool value) {
-    flags = value ? (flags | FlagAbstract) : (flags & ~FlagAbstract);
-  }
-
-  void set isExternal(bool value) {
-    flags = value ? (flags | FlagExternal) : (flags & ~FlagExternal);
-  }
-
-  void set isConst(bool value) {
-    flags = value ? (flags | FlagConst) : (flags & ~FlagConst);
-  }
-
-  void set isExtensionMember(bool value) {
-    flags =
-        value ? (flags | FlagExtensionMember) : (flags & ~FlagExtensionMember);
-  }
-
-  void set isExtensionTypeMember(bool value) {
-    flags = value
-        ? (flags | FlagExtensionTypeMember)
-        : (flags & ~FlagExtensionTypeMember);
-  }
-
-  void set isSynthetic(bool value) {
-    flags = value ? (flags | FlagSynthetic) : (flags & ~FlagSynthetic);
-  }
-
-  @override
-  bool get isInstanceMember => !isStatic;
-
-  bool get isGetter => kind == ProcedureKind.Getter;
-  bool get isSetter => kind == ProcedureKind.Setter;
-  bool get isAccessor => isGetter || isSetter;
-
-  @override
-  bool get hasGetter => kind != ProcedureKind.Setter;
-
-  @override
-  bool get hasSetter => kind == ProcedureKind.Setter;
-
-  bool get isFactory => kind == ProcedureKind.Factory;
-
-  Member? get concreteForwardingStubTarget =>
-      stubKind == ProcedureStubKind.ConcreteForwardingStub
-          ? stubTargetReference?.asMember
-          : null;
-
-  Member? get abstractForwardingStubTarget =>
-      stubKind == ProcedureStubKind.AbstractForwardingStub
-          ? stubTargetReference?.asMember
-          : null;
-
-  Member? get stubTarget => stubTargetReference?.asMember;
-
-  void set stubTarget(Member? target) {
-    stubTargetReference = getMemberReferenceBasedOnProcedureKind(target, kind);
-  }
-
-  @override
-  Member? get memberSignatureOrigin =>
-      stubKind == ProcedureStubKind.MemberSignature
-          ? stubTargetReference?.asMember
-          : null;
-
-  bool get hasWeakTearoffReferencePragma =>
-      flags & FlagHasWeakTearoffReferencePragma != 0;
-
-  void set hasWeakTearoffReferencePragma(bool value) {
-    flags = value
-        ? (flags | FlagHasWeakTearoffReferencePragma)
-        : (flags & ~FlagHasWeakTearoffReferencePragma);
-  }
-
-  /// Computes the interface member signature type of the procedure.
-  ///
-  /// In case [signatureType] is set, returns [signatureType]. Otherwise,
-  /// computes the function type of the function node.
-  FunctionType computeSignatureOrFunctionType() {
-    return signatureType ??
-        function.computeFunctionType(Nullability.nonNullable);
-  }
-
-  @override
-  R accept<R>(MemberVisitor<R> v) => v.visitProcedure(this);
-
-  @override
-  R accept1<R, A>(MemberVisitor1<R, A> v, A arg) => v.visitProcedure(this, arg);
-
-  @override
-  R acceptReference<R>(MemberReferenceVisitor<R> v) =>
-      v.visitProcedureReference(this);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(annotations, v);
-    name.accept(v);
-    function.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    v.transformList(annotations, this);
-    function = v.transform(function);
-    function.parent = this;
-    if (signatureType != null) {
-      signatureType = v.visitDartType(signatureType!) as FunctionType;
-    }
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    v.transformExpressionList(annotations, this);
-    function = v.transform(function);
-    function.parent = this;
-    if (signatureType != null) {
-      DartType newSignatureType =
-          v.visitDartType(signatureType!, dummyDartType);
-      if (identical(newSignatureType, dummyDartType)) {
-        signatureType = null;
-      } else {
-        signatureType = newSignatureType as FunctionType;
-      }
-    }
-  }
-
-  @override
-  DartType get getterType {
-    return isGetter
-        ? (signatureType?.returnType ?? function.returnType)
-        : (signatureType ??
-            function.computeFunctionType(enclosingLibrary.nonNullable));
-  }
-
-  @override
-  DartType get superGetterType {
-    return isGetter
-        ? function.returnType
-        : function.computeFunctionType(enclosingLibrary.nonNullable);
-  }
-
-  @override
-  DartType get setterType {
-    return isSetter
-        ? (signatureType?.positionalParameters[0] ??
-            function.positionalParameters[0].type)
-        : const NeverType.nonNullable();
-  }
-
-  @override
-  DartType get superSetterType {
-    return isSetter
-        ? function.positionalParameters[0].type
-        : const NeverType.nonNullable();
-  }
-
-  @override
-  Location? _getLocationInEnclosingFile(int offset) {
-    return _getLocationInComponent(enclosingComponent, fileUri, offset,
-        viaForErrorMessage: "Procedure '$name'");
-  }
-}
-
-enum ProcedureKind {
-  Method,
-  Getter,
-  Setter,
-  Operator,
-  Factory,
-}
-
-// ------------------------------------------------------------------------
-//                     CONSTRUCTOR INITIALIZERS
-// ------------------------------------------------------------------------
-
-/// Part of an initializer list in a constructor.
-sealed class Initializer extends TreeNode {
-  /// True if this is a synthetic constructor initializer.
-  @informative
-  bool isSynthetic = false;
-
-  @override
-  R accept<R>(InitializerVisitor<R> v);
-
-  @override
-  R accept1<R, A>(InitializerVisitor1<R, A> v, A arg);
-}
-
-abstract class AuxiliaryInitializer extends Initializer {
-  @override
-  R accept<R>(InitializerVisitor<R> v) => v.visitAuxiliaryInitializer(this);
-
-  @override
-  R accept1<R, A>(InitializerVisitor1<R, A> v, A arg) =>
-      v.visitAuxiliaryInitializer(this, arg);
-}
-
-/// An initializer with a compile-time error.
-///
-/// Should throw an exception at runtime.
-//
-// DESIGN TODO: The frontend should use this in a lot more cases to catch
-// invalid cases.
-class InvalidInitializer extends Initializer {
-  @override
-  R accept<R>(InitializerVisitor<R> v) => v.visitInvalidInitializer(this);
-
-  @override
-  R accept1<R, A>(InitializerVisitor1<R, A> v, A arg) =>
-      v.visitInvalidInitializer(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {}
-
-  @override
-  void transformChildren(Transformer v) {}
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {}
-
-  @override
-  String toString() {
-    return "InvalidInitializer(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    // TODO(johnniwinther): Implement this.
-  }
-}
-
-/// A field assignment `field = value` occurring in the initializer list of
-/// a constructor.
-///
-/// This node has nothing to do with declaration-site field initializers; those
-/// are [Expression]s stored in [Field.initializer].
-//
-// TODO: The frontend should check that all final fields are initialized
-//  exactly once, and that no fields are assigned twice in the initializer list.
-class FieldInitializer extends Initializer {
-  /// Reference to the field being initialized.  Not null.
-  Reference fieldReference;
-  Expression value;
-
-  FieldInitializer(Field field, Expression value)
-      : this.byReference(field.fieldReference, value);
-
-  FieldInitializer.byReference(this.fieldReference, this.value) {
-    value.parent = this;
-  }
-
-  Field get field => fieldReference.asField;
-
-  void set field(Field field) {
-    fieldReference = field.fieldReference;
-  }
-
-  @override
-  R accept<R>(InitializerVisitor<R> v) => v.visitFieldInitializer(this);
-
-  @override
-  R accept1<R, A>(InitializerVisitor1<R, A> v, A arg) =>
-      v.visitFieldInitializer(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    field.acceptReference(v);
-    value.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    value = v.transform(value);
-    value.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    value = v.transform(value);
-    value.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "FieldInitializer(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    // TODO(johnniwinther): Implement this.
-  }
-}
-
-/// A super call `super(x,y)` occurring in the initializer list of a
-/// constructor.
-///
-/// There are no type arguments on this call.
-//
-// TODO: The frontend should check that there is no more than one super call.
-//
-// DESIGN TODO: Consider if the frontend should insert type arguments derived
-// from the extends clause.
-class SuperInitializer extends Initializer {
-  /// Reference to the constructor being invoked in the super class. Not null.
-  Reference targetReference;
-  Arguments arguments;
-
-  SuperInitializer(Constructor target, Arguments arguments)
-      : this.byReference(
-            // Getter vs setter doesn't matter for constructors.
-            getNonNullableMemberReferenceGetter(target),
-            arguments);
-
-  SuperInitializer.byReference(this.targetReference, this.arguments) {
-    arguments.parent = this;
-  }
-
-  Constructor get target => targetReference.asConstructor;
-
-  void set target(Constructor target) {
-    // Getter vs setter doesn't matter for constructors.
-    targetReference = getNonNullableMemberReferenceGetter(target);
-  }
-
-  @override
-  R accept<R>(InitializerVisitor<R> v) => v.visitSuperInitializer(this);
-
-  @override
-  R accept1<R, A>(InitializerVisitor1<R, A> v, A arg) =>
-      v.visitSuperInitializer(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    target.acceptReference(v);
-    arguments.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "SuperInitializer(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('super');
-    if (target.name.text.isNotEmpty) {
-      printer.write('.');
-      printer.write(target.name.text);
-    }
-    printer.writeArguments(arguments, includeTypeArguments: false);
-  }
-}
-
-/// A redirecting call `this(x,y)` occurring in the initializer list of
-/// a constructor.
-//
-// TODO: The frontend should check that this is the only initializer and if the
-// constructor has a body or if there is a cycle in the initializer calls.
-class RedirectingInitializer extends Initializer {
-  /// Reference to the constructor being invoked in the same class. Not null.
-  Reference targetReference;
-  Arguments arguments;
-
-  RedirectingInitializer(Constructor target, Arguments arguments)
-      : this.byReference(
-            // Getter vs setter doesn't matter for constructors.
-            getNonNullableMemberReferenceGetter(target),
-            arguments);
-
-  RedirectingInitializer.byReference(this.targetReference, this.arguments) {
-    arguments.parent = this;
-  }
-
-  Constructor get target => targetReference.asConstructor;
-
-  void set target(Constructor target) {
-    // Getter vs setter doesn't matter for constructors.
-    targetReference = getNonNullableMemberReferenceGetter(target);
-  }
-
-  @override
-  R accept<R>(InitializerVisitor<R> v) => v.visitRedirectingInitializer(this);
-
-  @override
-  R accept1<R, A>(InitializerVisitor1<R, A> v, A arg) =>
-      v.visitRedirectingInitializer(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    target.acceptReference(v);
-    arguments.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "RedirectingInitializer(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('this');
-    if (target.name.text.isNotEmpty) {
-      printer.write('.');
-      printer.write(target.name.text);
-    }
-    printer.writeArguments(arguments, includeTypeArguments: false);
-  }
-}
-
-/// Binding of a temporary variable in the initializer list of a constructor.
-///
-/// The variable is in scope for the remainder of the initializer list, but is
-/// not in scope in the constructor body.
-class LocalInitializer extends Initializer {
-  VariableDeclaration variable;
-
-  LocalInitializer(this.variable) {
-    variable.parent = this;
-  }
-
-  @override
-  R accept<R>(InitializerVisitor<R> v) => v.visitLocalInitializer(this);
-
-  @override
-  R accept1<R, A>(InitializerVisitor1<R, A> v, A arg) =>
-      v.visitLocalInitializer(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    variable.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    variable = v.transform(variable);
-    variable.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    variable = v.transform(variable);
-    variable.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "LocalInitializer(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    // TODO(johnniwinther): Implement this.
-  }
-}
-
-class AssertInitializer extends Initializer {
-  AssertStatement statement;
-
-  AssertInitializer(this.statement) {
-    statement.parent = this;
-  }
-
-  @override
-  R accept<R>(InitializerVisitor<R> v) => v.visitAssertInitializer(this);
-
-  @override
-  R accept1<R, A>(InitializerVisitor1<R, A> v, A arg) =>
-      v.visitAssertInitializer(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    statement.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    statement = v.transform(statement);
-    statement.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    statement = v.transform(statement);
-    statement.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "AssertInitializer(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    statement.toTextInternal(printer);
-  }
-}
-
-// ------------------------------------------------------------------------
-//                            FUNCTIONS
-// ------------------------------------------------------------------------
-
-/// A function declares parameters and has a body.
-///
-/// This may occur in a procedure, constructor, function expression, or local
-/// function declaration.
-class FunctionNode extends TreeNode {
-  /// End offset in the source file it comes from. Valid values are from 0 and
-  /// up, or -1 ([TreeNode.noOffset]) if the file end offset is not available
-  /// (this is the default if none is specifically set).
-  int fileEndOffset = TreeNode.noOffset;
-
-  @override
-  List<int>? get fileOffsetsIfMultiple => [fileOffset, fileEndOffset];
-
-  /// Kernel async marker for the function.
-  ///
-  /// See also [dartAsyncMarker].
-  AsyncMarker asyncMarker;
-
-  /// Dart async marker for the function.
-  ///
-  /// See also [asyncMarker].
-  ///
-  /// A Kernel function can represent a Dart function with a different async
-  /// marker.
-  ///
-  /// For example, when async/await is translated away,
-  /// a Dart async function might be represented by a Kernel sync function.
-  AsyncMarker dartAsyncMarker;
-
-  List<TypeParameter> typeParameters;
-  int requiredParameterCount;
-  List<VariableDeclaration> positionalParameters;
-  List<VariableDeclaration> namedParameters;
-  DartType returnType; // Not null.
-  Statement? _body;
-
-  /// The emitted value of non-sync functions
-  ///
-  /// For `async` functions [emittedValueType] is the future value type, that
-  /// is, the returned element type. For instance
-  ///
-  ///     Future<Foo> method1() async => new Foo();
-  ///     FutureOr<Foo> method2() async => new Foo();
-  ///
-  /// here the return types are `Future<Foo>` and `FutureOr<Foo>` for `method1`
-  /// and `method2`, respectively, but the future value type is in both cases
-  /// `Foo`.
-  ///
-  /// For pre-nnbd libraries, this is set to `flatten(T)` of the return type
-  /// `T`, which can be seen as the pre-nnbd equivalent of the future value
-  /// type.
-  ///
-  /// For `sync*` functions [emittedValueType] is the type of the element of the
-  /// iterable returned by the function.
-  ///
-  /// For `async*` functions [emittedValueType] is the type of the element of
-  /// the stream returned by the function.
-  ///
-  /// For sync functions (those not marked with one of `async`, `sync*`, or
-  /// `async*`) the value of [emittedValueType] is null.
-  DartType? emittedValueType;
-
-  /// If the function is a redirecting factory constructor, this holds
-  /// the target and type arguments of the redirection.
-  RedirectingFactoryTarget? redirectingFactoryTarget;
-
-  void Function()? lazyBuilder;
-
-  void _buildLazy() {
-    void Function()? lazyBuilderLocal = lazyBuilder;
-    if (lazyBuilderLocal != null) {
-      lazyBuilder = null;
-      lazyBuilderLocal();
-    }
-  }
-
-  Statement? get body {
-    _buildLazy();
-    return _body;
-  }
-
-  void set body(Statement? body) {
-    _buildLazy();
-    _body = body;
-  }
-
-  FunctionNode(this._body,
-      {List<TypeParameter>? typeParameters,
-      List<VariableDeclaration>? positionalParameters,
-      List<VariableDeclaration>? namedParameters,
-      int? requiredParameterCount,
-      this.returnType = const DynamicType(),
-      this.asyncMarker = AsyncMarker.Sync,
-      AsyncMarker? dartAsyncMarker,
-      this.emittedValueType})
-      : this.positionalParameters =
-            positionalParameters ?? <VariableDeclaration>[],
-        this.requiredParameterCount =
-            requiredParameterCount ?? positionalParameters?.length ?? 0,
-        this.namedParameters = namedParameters ?? <VariableDeclaration>[],
-        this.typeParameters = typeParameters ?? <TypeParameter>[],
-        this.dartAsyncMarker = dartAsyncMarker ?? asyncMarker {
-    setParents(this.typeParameters, this);
-    setParents(this.positionalParameters, this);
-    setParents(this.namedParameters, this);
-    _body?.parent = this;
-  }
-
-  static DartType _getTypeOfVariable(VariableDeclaration node) => node.type;
-
-  static NamedType _getNamedTypeOfVariable(VariableDeclaration node,
-      [Substitution? substitution]) {
-    return new NamedType(
-        node.name!,
-        substitution != null
-            ? substitution.substituteType(node.type)
-            : node.type,
-        isRequired: node.isRequired);
-  }
-
-  /// Returns the function type of the node reusing its type parameters.
-  ///
-  /// This getter works similarly to [functionType], but reuses type parameters
-  /// of the function node (or the class enclosing it -- see the comment on
-  /// [functionType] about constructors of generic classes) in the result.  It
-  /// is useful in some contexts, especially when reasoning about the function
-  /// type of the enclosing generic function and in combination with
-  /// [FunctionType.withoutTypeParameters].
-  FunctionType computeThisFunctionType(Nullability nullability,
-      {bool reuseTypeParameters = false}) {
-    TreeNode? parent = this.parent;
-
-    List<StructuralParameter> structuralParameters;
-    List<TypeParameter> typeParametersToCopy = parent is Constructor
-        ? parent.enclosingClass.typeParameters
-        : typeParameters;
-    DartType returnType;
-    List<DartType> positionalParameters;
-    List<NamedType> namedParameters;
-    if (typeParametersToCopy.isEmpty || reuseTypeParameters) {
-      structuralParameters = const <StructuralParameter>[];
-      returnType = this.returnType;
-      List<VariableDeclaration> thisPositionals = this.positionalParameters;
-      positionalParameters = List.generate(thisPositionals.length,
-          (index) => _getTypeOfVariable(thisPositionals[index]),
-          growable: false);
-
-      List<VariableDeclaration> thisNamed = this.namedParameters;
-      if (thisNamed.isEmpty) {
-        namedParameters = const <NamedType>[];
-      } else {
-        namedParameters = List.generate(thisNamed.length,
-            (index) => _getNamedTypeOfVariable(thisNamed[index]),
-            growable: false);
-        namedParameters.sort();
-      }
-    } else {
-      // We need create a copy of the list of type parameters, otherwise
-      // transformations like erasure don't work.
-      FreshStructuralParametersFromTypeParameters freshStructuralParameters =
-          getFreshStructuralParametersFromTypeParameters(typeParametersToCopy);
-      structuralParameters = freshStructuralParameters.freshTypeParameters;
-      Substitution substitution = freshStructuralParameters.substitution;
-      returnType = substitution.substituteType(this.returnType);
-
-      List<VariableDeclaration> thisPositionals = this.positionalParameters;
-      positionalParameters = List.generate(
-          thisPositionals.length,
-          (index) => substitution
-              .substituteType(_getTypeOfVariable(thisPositionals[index])),
-          growable: false);
-      List<VariableDeclaration> thisNamed = this.namedParameters;
-      if (thisNamed.isEmpty) {
-        namedParameters = const <NamedType>[];
-      } else {
-        namedParameters = List.generate(thisNamed.length,
-            (index) => _getNamedTypeOfVariable(thisNamed[index], substitution),
-            growable: false);
-        namedParameters.sort();
-      }
-    }
-    // TODO(johnniwinther,cstefantsova): Cache the function type here and use
-    // [DartType.withDeclaredNullability] to handle the variants.
-    return new FunctionType(positionalParameters, returnType, nullability,
-        namedParameters: namedParameters,
-        typeParameters: structuralParameters,
-        requiredParameterCount: requiredParameterCount);
-  }
-
-  /// Returns the function type of the function node.
-  ///
-  /// If the function node describes a generic function, the resulting function
-  /// type will be generic.  If the function node describes a constructor of a
-  /// generic class, the resulting function type will be generic with its type
-  /// parameters constructed after those of the class.  In both cases, if the
-  /// resulting function type is generic, a fresh set of type parameters is used
-  /// in it.
-  // TODO(johnniwinther,cstefantsova): Merge it with [computeThisFunctionType].
-  FunctionType computeFunctionType(Nullability nullability) {
-    return computeThisFunctionType(nullability);
-  }
-
-  @override
-  R accept<R>(TreeVisitor<R> v) => v.visitFunctionNode(this);
-
-  @override
-  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) =>
-      v.visitFunctionNode(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(typeParameters, v);
-    visitList(positionalParameters, v);
-    visitList(namedParameters, v);
-    returnType.accept(v);
-    emittedValueType?.accept(v);
-    redirectingFactoryTarget?.target?.acceptReference(v);
-    if (redirectingFactoryTarget?.typeArguments != null) {
-      visitList(redirectingFactoryTarget!.typeArguments!, v);
-    }
-    body?.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    v.transformList(typeParameters, this);
-    v.transformList(positionalParameters, this);
-    v.transformList(namedParameters, this);
-    returnType = v.visitDartType(returnType);
-    if (emittedValueType != null) {
-      emittedValueType = v.visitDartType(emittedValueType!);
-    }
-    if (redirectingFactoryTarget?.typeArguments != null) {
-      v.transformDartTypeList(redirectingFactoryTarget!.typeArguments!);
-    }
-    if (body != null) {
-      body = v.transform(body!);
-      body?.parent = this;
-    }
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    v.transformTypeParameterList(typeParameters, this);
-    v.transformVariableDeclarationList(positionalParameters, this);
-    v.transformVariableDeclarationList(namedParameters, this);
-    returnType = v.visitDartType(returnType, cannotRemoveSentinel);
-    if (emittedValueType != null) {
-      emittedValueType =
-          v.visitDartType(emittedValueType!, cannotRemoveSentinel);
-    }
-    if (redirectingFactoryTarget?.typeArguments != null) {
-      v.transformDartTypeList(redirectingFactoryTarget!.typeArguments!);
-    }
-    if (body != null) {
-      body = v.transformOrRemoveStatement(body!);
-      body?.parent = this;
-    }
-  }
-
-  @override
-  String toString() {
-    return "FunctionNode(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    // TODO(johnniwinther): Implement this.
-  }
-}
-
-enum AsyncMarker {
-  // Do not change the order of these, the frontends depend on it.
-  Sync,
-  SyncStar,
-  Async,
-  AsyncStar,
-}
-
-/// The target constructor and passed type arguments of a redirecting factory,
-/// or if erroneous, the message for the error.
-class RedirectingFactoryTarget {
-  /// The reference to the target constructor if this is a valid redirecting
-  /// factory. `null` otherwise.
-  final Reference? targetReference;
-
-  /// The type arguments passed to the target constructor if this is a valid
-  /// redirecting factory. `null` otherwise.
-  final List<DartType>? typeArguments;
-
-  /// The message for the error, if this is an erroneous redirection. `null`
-  /// otherwise.
-  final String? errorMessage;
-
-  RedirectingFactoryTarget(Member target, List<DartType> typeArguments)
-      : this.byReference(target.reference, typeArguments);
-
-  RedirectingFactoryTarget.byReference(
-      Reference this.targetReference, List<DartType> this.typeArguments)
-      : errorMessage = null;
-
-  RedirectingFactoryTarget.error(String this.errorMessage)
-      : targetReference = null,
-        typeArguments = null;
-
-  /// The target constructor if this is a valid redirecting factory. `null`
-  /// otherwise.
-  Member? get target => targetReference?.asMember;
-
-  /// If `true`, this is an erroneous redirection.
-  bool get isError => errorMessage != null;
-
-  @override
-  String toString() => 'RedirectingFactoryTarget('
-      '${isError ? '$errorMessage' : '$target,$typeArguments'})';
-}
-
-// ------------------------------------------------------------------------
-//                                EXPRESSIONS
-// ------------------------------------------------------------------------
-
-sealed class Expression extends TreeNode {
-  /// Returns the static type of the expression.
-  ///
-  /// This calls `StaticTypeContext.getExpressionType` which calls
-  /// [getStaticTypeInternal] to compute the type of not already cached in
-  /// [context].
-  DartType getStaticType(StaticTypeContext context) {
-    return context.getExpressionType(this);
-  }
-
-  /// Computes the static type of this expression.
-  ///
-  /// This is called by `StaticTypeContext.getExpressionType` if the static
-  /// type of this expression is not already cached in [context].
-  DartType getStaticTypeInternal(StaticTypeContext context);
-
-  /// Returns the static type of the expression as an instantiation of
-  /// [superclass].
-  ///
-  /// Shouldn't be used on code compiled in legacy mode, as this method assumes
-  /// the IR is strongly typed.
-  ///
-  /// This method furthermore assumes that the type of the expression actually
-  /// is a subtype of (some instantiation of) the given [superclass].
-  /// If this is not the case, either an exception is thrown or the raw type of
-  /// [superclass] is returned.
-  InterfaceType getStaticTypeAsInstanceOf(
-      Class superclass, StaticTypeContext context) {
-    // This method assumes the program is correctly typed, so if the superclass
-    // is not generic, we can just return its raw type without computing the
-    // type of this expression.  It also ensures that all types are considered
-    // subtypes of Object (not just interface types), and function types are
-    // considered subtypes of Function.
-    if (superclass.typeParameters.isEmpty) {
-      return context.typeEnvironment.coreTypes
-          .rawType(superclass, context.nonNullable);
-    }
-    DartType type = getStaticType(context).nonTypeVariableBound;
-    if (type is NullType) {
-      return context.typeEnvironment.coreTypes
-          .bottomInterfaceType(superclass, context.nullable);
-    } else if (type is NeverType) {
-      return context.typeEnvironment.coreTypes
-          .bottomInterfaceType(superclass, type.nullability);
-    }
-    if (type is TypeDeclarationType) {
-      List<DartType>? upcastTypeArguments = context.typeEnvironment
-          .getTypeArgumentsAsInstanceOf(type, superclass);
-      if (upcastTypeArguments != null) {
-        return new InterfaceType(
-            superclass, type.nullability, upcastTypeArguments);
-      }
-    }
-
-    // The static type of this expression is not a subtype of [superclass]. The
-    // means that the static type of this expression is not the same as when
-    // the parent [PropertyGet] or [MethodInvocation] was created.
-    //
-    // For instance when cloning generic mixin methods, the substitution can
-    // render some of the code paths as dead code:
-    //
-    //     mixin M<T> {
-    //       int method(T t) => t is String ? t.length : 0;
-    //     }
-    //     class C with M<int> {}
-    //
-    // The mixin transformation will clone the `M.method` method into the
-    // unnamed mixin application for `Object&M<int>` as this:
-    //
-    //     int method(int t) => t is String ? t.length : 0;
-    //
-    // Now `t.length`, which was originally an access to `String.length` on a
-    // receiver of type `T & String`, is an access to `String.length` on `int`.
-    // When computing the static type of `t.length` we will try to compute the
-    // type of `int` as an instance of `String`, and we do not find it to be
-    // an instance of `String`.
-    //
-    // To resolve this case we compute the type of `t.length` to be the type
-    // as if accessed on an unknown subtype `String`.
-    return context.typeEnvironment.coreTypes
-        .rawType(superclass, context.nonNullable);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg);
-
-  int get precedence => astToText.Precedence.of(this);
-
-  @override
-  String toText(AstTextStrategy strategy) {
-    AstPrinter printer = new AstPrinter(strategy);
-    printer.writeExpression(this);
-    return printer.getText();
-  }
-}
-
-/// Abstract subclass of [Expression] that can be used to add [Expression]
-/// subclasses from outside `package:kernel`.
-abstract class AuxiliaryExpression extends Expression {
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitAuxiliaryExpression(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitAuxiliaryExpression(this, arg);
-}
-
-/// An expression containing compile-time errors.
-///
-/// Should throw a runtime error when evaluated.
-///
-/// The [fileOffset] of an [InvalidExpression] indicates the location in the
-/// tree where the expression occurs, rather than the location of the error.
-class InvalidExpression extends Expression {
-  // TODO(johnniwinther): Avoid using `null` as the empty string.
-  String? message;
-
-  /// The expression containing the error.
-  Expression? expression;
-
-  InvalidExpression(this.message, [this.expression]) {
-    expression?.parent = this;
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      const NeverType.nonNullable();
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitInvalidExpression(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitInvalidExpression(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    expression?.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    if (expression != null) {
-      expression = v.transform(expression!);
-      expression?.parent = this;
-    }
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    if (expression != null) {
-      expression = v.transformOrRemoveExpression(expression!);
-      expression?.parent = this;
-    }
-  }
-
-  @override
-  String toString() {
-    return "InvalidExpression(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('<invalid:');
-    printer.write(message ?? '');
-    if (expression != null) {
-      printer.write(', ');
-      printer.writeExpression(expression!);
-    }
-    printer.write('>');
-  }
-}
-
-/// Read a local variable, a local function, or a function parameter.
-class VariableGet extends Expression {
-  VariableDeclaration variable;
-  DartType? promotedType; // Null if not promoted.
-
-  VariableGet(this.variable, [this.promotedType]);
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    return promotedType ?? variable.type;
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitVariableGet(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitVariableGet(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    promotedType?.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    if (promotedType != null) {
-      promotedType = v.visitDartType(promotedType!);
-    }
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    if (promotedType != null) {
-      DartType newPromotedType = v.visitDartType(promotedType!, dummyDartType);
-      if (identical(newPromotedType, dummyDartType)) {
-        promotedType = null;
-      } else {
-        promotedType = newPromotedType;
-      }
-    }
-  }
-
-  @override
-  String toString() {
-    return "VariableGet(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write(printer.getVariableName(variable));
-    if (promotedType != null) {
-      printer.write('{');
-      printer.writeType(promotedType!);
-      printer.write('}');
-    }
-  }
-}
-
-/// Assign a local variable or function parameter.
-///
-/// Evaluates to the value of [value].
-class VariableSet extends Expression {
-  VariableDeclaration variable;
-  Expression value;
-
-  VariableSet(this.variable, this.value) {
-    value.parent = this;
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      value.getStaticType(context);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitVariableSet(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitVariableSet(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    value.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    value = v.transform(value);
-    value.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    value = v.transform(value);
-    value.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "VariableSet(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write(printer.getVariableName(variable));
-    printer.write(' = ');
-    printer.writeExpression(value);
-  }
-}
-
-class RecordIndexGet extends Expression {
-  Expression receiver;
-  RecordType receiverType;
-  final int index;
-
-  RecordIndexGet(this.receiver, this.receiverType, this.index)
-      : assert(0 <= index && index < receiverType.positional.length) {
-    receiver.parent = this;
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    assert(index < receiverType.positional.length);
-    return receiverType.positional[index];
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitRecordIndexGet(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitRecordIndexGet(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    receiver.accept(v);
-    receiverType.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    receiver = v.transform(receiver)..parent = this;
-    receiverType = v.visitDartType(receiverType) as RecordType;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    receiver = v.transform(receiver)..parent = this;
-    receiverType =
-        v.visitDartType(receiverType, cannotRemoveSentinel) as RecordType;
-  }
-
-  @override
-  String toString() {
-    return "RecordIndexGet(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExpression(receiver);
-    printer.write(".\$${index + 1}");
-  }
-}
-
-class RecordNameGet extends Expression {
-  Expression receiver;
-  RecordType receiverType;
-  final String name;
-
-  RecordNameGet(this.receiver, this.receiverType, this.name)
-      : assert(receiverType.named
-                .singleWhere((element) => element.name == name)
-                .name ==
-            name) {
-    receiver.parent = this;
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    DartType? result;
-    for (NamedType namedType in receiverType.named) {
-      if (namedType.name == name) {
-        result = namedType.type;
-        break;
-      }
-    }
-    assert(result != null);
-
-    return result!;
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitRecordNameGet(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitRecordNameGet(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    receiver.accept(v);
-    receiverType.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    receiver = v.transform(receiver)..parent = this;
-    receiverType = v.visitDartType(receiverType) as RecordType;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    receiver = v.transform(receiver)..parent = this;
-    receiverType =
-        v.visitDartType(receiverType, cannotRemoveSentinel) as RecordType;
-  }
-
-  @override
-  String toString() {
-    return "RecordNameGet(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExpression(receiver);
-    printer.write(".${name}");
-  }
-}
-
-enum DynamicAccessKind {
-  /// An access on a receiver of type dynamic.
-  ///
-  /// An access of this kind always results in a value of static type dynamic.
-  ///
-  /// Valid accesses to Object members on receivers of type dynamic are encoded
-  /// as an [InstanceInvocation] of kind [InstanceAccessKind.Object].
-  Dynamic,
-
-  /// An access on a receiver of type Never.
-  ///
-  /// An access of this kind always results in a value of static type Never.
-  ///
-  /// Valid accesses to Object members on receivers of type Never are also
-  /// encoded as [DynamicInvocation] of kind [DynamicAccessKind.Never] and _not_
-  /// as an [InstanceInvocation] of kind [InstanceAccessKind.Object].
-  Never,
-
-  /// An access on a receiver of an invalid type.
-  ///
-  /// An access of this kind always results in a value of an invalid static
-  /// type.
-  Invalid,
-
-  /// An access of an unresolved target.
-  ///
-  /// An access of this kind always results in a value of an invalid static
-  /// type.
-  Unresolved,
-}
-
-class DynamicGet extends Expression {
-  final DynamicAccessKind kind;
-  Expression receiver;
-  Name name;
-
-  DynamicGet(this.kind, this.receiver, this.name) {
-    receiver.parent = this;
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitDynamicGet(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitDynamicGet(this, arg);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    switch (kind) {
-      case DynamicAccessKind.Dynamic:
-        return const DynamicType();
-      case DynamicAccessKind.Never:
-        return const NeverType.nonNullable();
-      case DynamicAccessKind.Invalid:
-      case DynamicAccessKind.Unresolved:
-        return const InvalidType();
-    }
-  }
-
-  @override
-  void visitChildren(Visitor v) {
-    receiver.accept(v);
-    name.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    receiver = v.transform(receiver);
-    receiver.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    receiver = v.transform(receiver);
-    receiver.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "DynamicGet($kind,${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExpression(receiver,
-        minimumPrecedence: astToText.Precedence.PRIMARY);
-    printer.write('.');
-    printer.writeName(name);
-  }
-}
-
-/// A property read of an instance getter or field with a statically known
-/// interface target.
-class InstanceGet extends Expression {
-  final InstanceAccessKind kind;
-  Expression receiver;
-
-  // TODO(johnniwinther): Can we pull this from the [interfaceTarget] instead?
-  Name name;
-
-  /// The static type of result of the property read.
-  ///
-  /// This includes substituted type parameters from the static receiver type.
-  ///
-  /// For instance
-  ///
-  ///    class A<T> {
-  ///      T get t;
-  ///    }
-  ///    m(A<String> a) {
-  ///      a.t; // The result type is `String`.
-  ///    }
-  ///
-  DartType resultType;
-
-  Reference interfaceTargetReference;
-
-  InstanceGet(InstanceAccessKind kind, Expression receiver, Name name,
-      {required Member interfaceTarget, required DartType resultType})
-      : this.byReference(kind, receiver, name,
-            interfaceTargetReference:
-                getNonNullableMemberReferenceGetter(interfaceTarget),
-            resultType: resultType);
-
-  InstanceGet.byReference(this.kind, this.receiver, this.name,
-      {required this.interfaceTargetReference, required this.resultType}) {
-    receiver.parent = this;
-  }
-
-  Member get interfaceTarget => interfaceTargetReference.asMember;
-
-  void set interfaceTarget(Member member) {
-    interfaceTargetReference = getNonNullableMemberReferenceGetter(member);
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) => resultType;
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceGet(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitInstanceGet(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    receiver.accept(v);
-    interfaceTarget.acceptReference(v);
-    name.accept(v);
-    resultType.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    receiver = v.transform(receiver);
-    receiver.parent = this;
-    resultType = v.visitDartType(resultType);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    receiver = v.transform(receiver);
-    receiver.parent = this;
-    resultType = v.visitDartType(resultType, cannotRemoveSentinel);
-  }
-
-  @override
-  String toString() {
-    return "InstanceGet($kind,${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExpression(receiver,
-        minimumPrecedence: astToText.Precedence.PRIMARY);
-    printer.write('.');
-    printer.writeInterfaceMemberName(interfaceTargetReference, name);
-  }
-}
-
-/// A tear-off of the 'call' method on an expression whose static type is
-/// a function type or the type 'Function'.
-class FunctionTearOff extends Expression {
-  Expression receiver;
-
-  FunctionTearOff(this.receiver) {
-    receiver.parent = this;
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      receiver.getStaticType(context);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitFunctionTearOff(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitFunctionTearOff(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    receiver.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    receiver = v.transform(receiver);
-    receiver.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    receiver = v.transform(receiver);
-    receiver.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "FunctionTearOff(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExpression(receiver,
-        minimumPrecedence: astToText.Precedence.PRIMARY);
-    printer.write('.');
-    printer.writeName(Name.callName);
-  }
-}
-
-/// A tear-off of an instance method with a statically known interface target.
-class InstanceTearOff extends Expression {
-  final InstanceAccessKind kind;
-  Expression receiver;
-
-  // TODO(johnniwinther): Can we pull this from the [interfaceTarget] instead?
-  Name name;
-
-  /// The static type of result of the tear-off.
-  ///
-  /// This includes substituted type parameters from the static receiver type.
-  ///
-  /// For instance
-  ///
-  ///    class A<T, S> {
-  ///      T method<U>(S s, U u) { ... }
-  ///    }
-  ///    m(A<String, int> a) {
-  ///      a.method; // The result type is `String Function<U>(int, U)`.
-  ///    }
-  ///
-  DartType resultType;
-
-  Reference interfaceTargetReference;
-
-  InstanceTearOff(InstanceAccessKind kind, Expression receiver, Name name,
-      {required Procedure interfaceTarget, required DartType resultType})
-      : this.byReference(kind, receiver, name,
-            interfaceTargetReference:
-                getNonNullableMemberReferenceGetter(interfaceTarget),
-            resultType: resultType);
-
-  InstanceTearOff.byReference(this.kind, this.receiver, this.name,
-      {required this.interfaceTargetReference, required this.resultType}) {
-    receiver.parent = this;
-  }
-
-  Procedure get interfaceTarget => interfaceTargetReference.asProcedure;
-
-  void set interfaceTarget(Procedure procedure) {
-    interfaceTargetReference = getNonNullableMemberReferenceGetter(procedure);
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) => resultType;
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceTearOff(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitInstanceTearOff(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    receiver.accept(v);
-    interfaceTarget.acceptReference(v);
-    name.accept(v);
-    resultType.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    receiver = v.transform(receiver);
-    receiver.parent = this;
-    resultType = v.visitDartType(resultType);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    receiver = v.transform(receiver);
-    receiver.parent = this;
-    resultType = v.visitDartType(resultType, cannotRemoveSentinel);
-  }
-
-  @override
-  String toString() {
-    return "InstanceTearOff($kind, ${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExpression(receiver,
-        minimumPrecedence: astToText.Precedence.PRIMARY);
-    printer.write('.');
-    printer.writeInterfaceMemberName(interfaceTargetReference, name);
-  }
-}
-
-class DynamicSet extends Expression {
-  final DynamicAccessKind kind;
-  Expression receiver;
-  Name name;
-  Expression value;
-
-  DynamicSet(this.kind, this.receiver, this.name, this.value) {
-    receiver.parent = this;
-    value.parent = this;
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      value.getStaticType(context);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitDynamicSet(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitDynamicSet(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    receiver.accept(v);
-    name.accept(v);
-    value.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    receiver = v.transform(receiver);
-    receiver.parent = this;
-    value = v.transform(value);
-    value.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    receiver = v.transform(receiver);
-    receiver.parent = this;
-    value = v.transform(value);
-    value.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "DynamicSet($kind,${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExpression(receiver,
-        minimumPrecedence: astToText.Precedence.PRIMARY);
-    printer.write('.');
-    printer.writeName(name);
-    printer.write(' = ');
-    printer.writeExpression(value);
-  }
-}
-
-/// An property write of an instance setter or field with a statically known
-/// interface target.
-class InstanceSet extends Expression {
-  final InstanceAccessKind kind;
-  Expression receiver;
-
-  // TODO(johnniwinther): Can we pull this from the [interfaceTarget] instead?
-  Name name;
-  Expression value;
-
-  Reference interfaceTargetReference;
-
-  InstanceSet(
-      InstanceAccessKind kind, Expression receiver, Name name, Expression value,
-      {required Member interfaceTarget})
-      : this.byReference(kind, receiver, name, value,
-            interfaceTargetReference:
-                getNonNullableMemberReferenceSetter(interfaceTarget));
-
-  InstanceSet.byReference(this.kind, this.receiver, this.name, this.value,
-      {required this.interfaceTargetReference}) {
-    receiver.parent = this;
-    value.parent = this;
-  }
-
-  Member get interfaceTarget => interfaceTargetReference.asMember;
-
-  void set interfaceTarget(Member member) {
-    interfaceTargetReference = getNonNullableMemberReferenceSetter(member);
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      value.getStaticType(context);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceSet(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitInstanceSet(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    receiver.accept(v);
-    interfaceTarget.acceptReference(v);
-    name.accept(v);
-    value.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    receiver = v.transform(receiver);
-    receiver.parent = this;
-    value = v.transform(value);
-    value.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    receiver = v.transform(receiver);
-    receiver.parent = this;
-    value = v.transform(value);
-    value.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "InstanceSet(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExpression(receiver,
-        minimumPrecedence: astToText.Precedence.PRIMARY);
-    printer.write('.');
-    printer.writeInterfaceMemberName(interfaceTargetReference, name);
-    printer.write(' = ');
-    printer.writeExpression(value);
-  }
-}
-
-/// Expression of form `super.foo` occurring in a mixin declaration.
-///
-/// In this setting, the target is looked up on the types in the mixin 'on'
-/// clause and are therefore not necessary the runtime targets of the read. An
-/// [AbstractSuperPropertyGet] must be converted into a [SuperPropertyGet] to
-/// statically bind the target.
-///
-/// For instance
-///
-///    abstract class Interface {
-///      get getter;
-///    }
-///    mixin Mixin on Interface {
-///      get getter {
-///        // This is an [AbstractSuperPropertyGet] with interface target
-///        // `Interface.getter`.
-///        return super.getter;
-///      }
-///    }
-///    class Super implements Interface {
-///      // This is the target when `Mixin` is applied to `Class`.
-///      get getter => 42;
-///    }
-///    class Class extends Super with Mixin {}
-///
-/// This may invoke a getter, read a field, or tear off a method.
-class AbstractSuperPropertyGet extends Expression {
-  Name name;
-
-  Reference interfaceTargetReference;
-
-  AbstractSuperPropertyGet(Name name, Member interfaceTarget)
-      : this.byReference(
-            name, getNonNullableMemberReferenceGetter(interfaceTarget));
-
-  AbstractSuperPropertyGet.byReference(
-      this.name, this.interfaceTargetReference);
-
-  Member get interfaceTarget => interfaceTargetReference.asMember;
-
-  void set interfaceTarget(Member member) {
-    interfaceTargetReference = getNonNullableMemberReferenceGetter(member);
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    Class declaringClass = interfaceTarget.enclosingClass!;
-    if (declaringClass.typeParameters.isEmpty) {
-      return interfaceTarget.getterType;
-    }
-    List<DartType>? receiverArguments = context.typeEnvironment
-        .getTypeArgumentsAsInstanceOf(context.thisType!, declaringClass);
-    return Substitution.fromPairs(
-            declaringClass.typeParameters, receiverArguments!)
-        .substituteType(interfaceTarget.getterType);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitAbstractSuperPropertyGet(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitAbstractSuperPropertyGet(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    interfaceTarget.acceptReference(v);
-    name.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {}
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {}
-
-  @override
-  String toString() {
-    return "AbstractSuperPropertyGet(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('super.{abstract}');
-    printer.writeInterfaceMemberName(interfaceTargetReference, name);
-  }
-}
-
-/// Expression of form `super.field`.
-///
-/// This may invoke a getter, read a field, or tear off a method.
-class SuperPropertyGet extends Expression {
-  Name name;
-
-  Reference interfaceTargetReference;
-
-  SuperPropertyGet(Name name, Member interfaceTarget)
-      : this.byReference(
-            name, getNonNullableMemberReferenceGetter(interfaceTarget));
-
-  SuperPropertyGet.byReference(this.name, this.interfaceTargetReference);
-
-  Member get interfaceTarget => interfaceTargetReference.asMember;
-
-  void set interfaceTarget(Member member) {
-    interfaceTargetReference = getNonNullableMemberReferenceGetter(member);
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    Class declaringClass = interfaceTarget.enclosingClass!;
-    if (declaringClass.typeParameters.isEmpty) {
-      return interfaceTarget.getterType;
-    }
-    List<DartType>? receiverArguments = context.typeEnvironment
-        .getTypeArgumentsAsInstanceOf(context.thisType!, declaringClass);
-    return Substitution.fromPairs(
-            declaringClass.typeParameters, receiverArguments!)
-        .substituteType(interfaceTarget.getterType);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitSuperPropertyGet(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitSuperPropertyGet(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    interfaceTarget.acceptReference(v);
-    name.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {}
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {}
-
-  @override
-  String toString() {
-    return "SuperPropertyGet(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('super.');
-    printer.writeInterfaceMemberName(interfaceTargetReference, name);
-  }
-}
-
-/// Expression of form `super.foo = x` occurring in a mixin declaration.
-///
-/// In this setting, the target is looked up on the types in the mixin 'on'
-/// clause and are therefore not necessary the runtime targets of the
-/// assignment. An [AbstractSuperPropertySet] must be converted into a
-/// [SuperPropertySet] to statically bind the target.
-///
-/// For instance
-///
-///    abstract class Interface {
-///      void set setter(value);
-///    }
-///    mixin Mixin on Interface {
-///      void set setter(value) {
-///        // This is an [AbstractSuperPropertySet] with interface target
-///        // `Interface.setter`.
-///        super.setter = value;
-///      }
-///    }
-///    class Super implements Interface {
-///      // This is the target when `Mixin` is applied to `Class`.
-///      void set setter(value) {}
-///    }
-///    class Class extends Super with Mixin {}
-///
-/// This may invoke a setter or assign a field.
-class AbstractSuperPropertySet extends Expression {
-  Name name;
-  Expression value;
-
-  Reference interfaceTargetReference;
-
-  AbstractSuperPropertySet(Name name, Expression value, Member interfaceTarget)
-      : this.byReference(
-            name, value, getNonNullableMemberReferenceSetter(interfaceTarget));
-
-  AbstractSuperPropertySet.byReference(
-      this.name, this.value, this.interfaceTargetReference) {
-    value.parent = this;
-  }
-
-  Member get interfaceTarget => interfaceTargetReference.asMember;
-
-  void set interfaceTarget(Member member) {
-    interfaceTargetReference = getNonNullableMemberReferenceSetter(member);
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      value.getStaticType(context);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitAbstractSuperPropertySet(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitAbstractSuperPropertySet(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    interfaceTarget.acceptReference(v);
-    name.accept(v);
-    value.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    value = v.transform(value);
-    value.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    value = v.transform(value);
-    value.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "AbstractSuperPropertySet(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('super.{abstract}');
-    printer.writeInterfaceMemberName(interfaceTargetReference, name);
-    printer.write(' = ');
-    printer.writeExpression(value);
-  }
-}
-
-/// Expression of form `super.field = value`.
-///
-/// This may invoke a setter or assign a field.
-///
-/// Evaluates to the value of [value].
-class SuperPropertySet extends Expression {
-  Name name;
-  Expression value;
-
-  Reference interfaceTargetReference;
-
-  SuperPropertySet(Name name, Expression value, Member interfaceTarget)
-      : this.byReference(
-            name, value, getNonNullableMemberReferenceSetter(interfaceTarget));
-
-  SuperPropertySet.byReference(
-      this.name, this.value, this.interfaceTargetReference) {
-    value.parent = this;
-  }
-
-  Member get interfaceTarget => interfaceTargetReference.asMember;
-
-  void set interfaceTarget(Member member) {
-    interfaceTargetReference = getNonNullableMemberReferenceSetter(member);
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      value.getStaticType(context);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitSuperPropertySet(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitSuperPropertySet(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    interfaceTarget.acceptReference(v);
-    name.accept(v);
-    value.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    value = v.transform(value);
-    value.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    value = v.transform(value);
-    value.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "SuperPropertySet(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('super.');
-    printer.writeInterfaceMemberName(interfaceTargetReference, name);
-    printer.write(' = ');
-    printer.writeExpression(value);
-  }
-}
-
-/// Read a static field, call a static getter, or tear off a static method.
-class StaticGet extends Expression {
-  /// A static field, getter, or method (for tear-off).
-  Reference targetReference;
-
-  StaticGet(Member target)
-      : assert(target is Field || (target is Procedure && target.isGetter)),
-        this.targetReference = getNonNullableMemberReferenceGetter(target);
-
-  StaticGet.byReference(this.targetReference);
-
-  Member get target => targetReference.asMember;
-
-  void set target(Member target) {
-    targetReference = getNonNullableMemberReferenceGetter(target);
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      target.getterType;
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitStaticGet(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitStaticGet(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    target.acceptReference(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {}
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {}
-
-  @override
-  String toString() {
-    return "StaticGet(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeMemberName(targetReference);
-  }
-}
-
-/// Tear-off of a static method.
-class StaticTearOff extends Expression {
-  Reference targetReference;
-
-  StaticTearOff(Procedure target)
-      : assert(target.isStatic, "Unexpected static tear off target: $target"),
-        assert(target.kind == ProcedureKind.Method,
-            "Unexpected static tear off target: $target"),
-        this.targetReference = getNonNullableMemberReferenceGetter(target);
-
-  StaticTearOff.byReference(this.targetReference);
-
-  Procedure get target => targetReference.asProcedure;
-
-  void set target(Procedure target) {
-    targetReference = getNonNullableMemberReferenceGetter(target);
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      target.getterType;
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitStaticTearOff(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitStaticTearOff(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    target.acceptReference(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {}
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {}
-
-  @override
-  String toString() {
-    return "StaticTearOff(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeMemberName(targetReference);
-  }
-}
-
-/// Assign a static field or call a static setter.
-///
-/// Evaluates to the value of [value].
-class StaticSet extends Expression {
-  /// A mutable static field or a static setter.
-  Reference targetReference;
-  Expression value;
-
-  StaticSet(Member target, Expression value)
-      : this.byReference(getNonNullableMemberReferenceSetter(target), value);
-
-  StaticSet.byReference(this.targetReference, this.value) {
-    value.parent = this;
-  }
-
-  Member get target => targetReference.asMember;
-
-  void set target(Member target) {
-    targetReference = getNonNullableMemberReferenceSetter(target);
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      value.getStaticType(context);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitStaticSet(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitStaticSet(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    target.acceptReference(v);
-    value.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    value = v.transform(value);
-    value.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    value = v.transform(value);
-    value.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "StaticSet(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeMemberName(targetReference);
-    printer.write(' = ');
-    printer.writeExpression(value);
-  }
-}
-
-/// The arguments to a function call, divided into type arguments,
-/// positional arguments, and named arguments.
-class Arguments extends TreeNode {
-  final List<DartType> types;
-  final List<Expression> positional;
-  List<NamedExpression> named;
-
-  Arguments(this.positional,
-      {List<DartType>? types, List<NamedExpression>? named})
-      : this.types = types ?? <DartType>[],
-        this.named = named ?? <NamedExpression>[] {
-    setParents(this.positional, this);
-    setParents(this.named, this);
-  }
-
-  Arguments.empty()
-      : types = <DartType>[],
-        positional = <Expression>[],
-        named = <NamedExpression>[];
-
-  factory Arguments.forwarded(FunctionNode function, Library library) {
-    return new Arguments(
-        function.positionalParameters
-            .map<Expression>((p) => new VariableGet(p))
-            .toList(),
-        named: function.namedParameters
-            .map((p) => new NamedExpression(p.name!, new VariableGet(p)))
-            .toList(),
-        types: function.typeParameters
-            .map<DartType>((p) =>
-                new TypeParameterType.withDefaultNullabilityForLibrary(
-                    p, library))
-            .toList());
-  }
-
-  @override
-  R accept<R>(TreeVisitor<R> v) => v.visitArguments(this);
-
-  @override
-  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitArguments(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(types, v);
-    visitList(positional, v);
-    visitList(named, v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    v.transformDartTypeList(types);
-    v.transformList(positional, this);
-    v.transformList(named, this);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    v.transformDartTypeList(types);
-    v.transformExpressionList(positional, this);
-    v.transformNamedExpressionList(named, this);
-  }
-
-  @override
-  String toString() {
-    return "Arguments(${toStringInternal()})";
-  }
-
-  @override
-  String toText(AstTextStrategy strategy) {
-    AstPrinter printer = new AstPrinter(strategy);
-    printer.writeArguments(this);
-    return printer.getText();
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer, {bool includeTypeArguments = true}) {
-    if (includeTypeArguments) {
-      printer.writeTypeArguments(types);
-    }
-    printer.write('(');
-    for (int index = 0; index < positional.length; index++) {
-      if (index > 0) {
-        printer.write(', ');
-      }
-      printer.writeExpression(positional[index]);
-    }
-    if (named.isNotEmpty) {
-      if (positional.isNotEmpty) {
-        printer.write(', ');
-      }
-      for (int index = 0; index < named.length; index++) {
-        if (index > 0) {
-          printer.write(', ');
-        }
-        printer.writeNamedExpression(named[index]);
-      }
-    }
-    printer.write(')');
-  }
-}
-
-/// A named argument, `name: value`.
-class NamedExpression extends TreeNode {
-  String name;
-  Expression value;
-
-  NamedExpression(this.name, this.value) {
-    value.parent = this;
-  }
-
-  @override
-  R accept<R>(TreeVisitor<R> v) => v.visitNamedExpression(this);
-
-  @override
-  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) =>
-      v.visitNamedExpression(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    value.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    value = v.transform(value);
-    value.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    value = v.transform(value);
-    value.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "NamedExpression(${toStringInternal()})";
-  }
-
-  @override
-  String toText(AstTextStrategy strategy) {
-    AstPrinter printer = new AstPrinter(strategy);
-    toTextInternal(printer);
-    return printer.getText();
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write(name);
-    printer.write(': ');
-    printer.writeExpression(value);
-  }
-}
-
-/// Common super class for [DirectMethodInvocation], [MethodInvocation],
-/// [SuperMethodInvocation], [StaticInvocation], and [ConstructorInvocation].
-abstract class InvocationExpression extends Expression {
-  Arguments get arguments;
-
-  /// Name of the invoked method.
-  Name get name;
-}
-
-abstract class InstanceInvocationExpression extends InvocationExpression {
-  Expression get receiver;
-}
-
-class DynamicInvocation extends InstanceInvocationExpression {
-  // Must match serialized bit positions.
-  static const int FlagImplicitCall = 1 << 0;
-
-  final DynamicAccessKind kind;
-
-  @override
-  Expression receiver;
-
-  @override
-  Name name;
-
-  @override
-  Arguments arguments;
-
-  int flags = 0;
-
-  DynamicInvocation(this.kind, this.receiver, this.name, this.arguments) {
-    receiver.parent = this;
-    arguments.parent = this;
-  }
-
-  /// If `true` this is an implicit call to 'call'. For instance
-  ///
-  ///    method(dynamic d) {
-  ///      d(); // Implicit call.
-  ///      d.call(); // Explicit call.
-  ///
-  bool get isImplicitCall => flags & FlagImplicitCall != 0;
-
-  void set isImplicitCall(bool value) {
-    flags = value ? (flags | FlagImplicitCall) : (flags & ~FlagImplicitCall);
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    switch (kind) {
-      case DynamicAccessKind.Dynamic:
-        return const DynamicType();
-      case DynamicAccessKind.Never:
-        return const NeverType.nonNullable();
-      case DynamicAccessKind.Invalid:
-      case DynamicAccessKind.Unresolved:
-        return const InvalidType();
-    }
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitDynamicInvocation(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitDynamicInvocation(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    receiver.accept(v);
-    name.accept(v);
-    arguments.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    receiver = v.transform(receiver);
-    receiver.parent = this;
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    receiver = v.transform(receiver);
-    receiver.parent = this;
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "DynamicInvocation($kind,${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExpression(receiver,
-        minimumPrecedence: astToText.Precedence.PRIMARY);
-    if (!isImplicitCall) {
-      printer.write('.');
-      printer.writeName(name);
-    }
-    printer.writeArguments(arguments);
-  }
-}
-
-/// Access kind used by [InstanceInvocation], [InstanceGet], [InstanceSet],
-/// and [InstanceTearOff].
-enum InstanceAccessKind {
-  /// An access to a member on a static receiver type which is an interface
-  /// type.
-  ///
-  /// In null safe libraries the static receiver type is non-nullable.
-  ///
-  /// For instance:
-  ///
-  ///     class C { void method() {} }
-  ///     main() => new C().method();
-  ///
-  Instance,
-
-  /// An access to a member defined on Object on a static receiver type that
-  /// is either a non-interface type or a nullable type.
-  ///
-  /// For instance:
-  ///
-  ///     test1(String? s) => s.toString();
-  ///     test1(dynamic s) => s.hashCode;
-  ///
-  Object,
-
-  /// An access to a method on a static receiver type which is an interface
-  /// type which is inapplicable, that is, whose arguments don't match the
-  /// required parameter structure.
-  ///
-  /// This is an error case which is only used on expression nested within
-  /// [InvalidExpression]s.
-  ///
-  /// For instance:
-  ///
-  ///     class C { void method() {} }
-  ///     main() => new C().method(0); // Too many arguments.
-  ///
-  Inapplicable,
-
-  /// An access to a non-Object member on a static receiver type which is a
-  /// nullable interface type.
-  ///
-  /// This is an error case which is only used on expression nested within
-  /// [InvalidExpression]s.
-  ///
-  /// For instance:
-  ///
-  ///     class C { void method() {} }
-  ///     test(C? c) => c.method(0); // 'c' is nullable.
-  ///
-  Nullable,
-}
-
-/// An invocation of an instance method with a statically known interface
-/// target.
-class InstanceInvocation extends InstanceInvocationExpression {
-  // Must match serialized bit positions.
-  static const int FlagInvariant = 1 << 0;
-  static const int FlagBoundsSafe = 1 << 1;
-
-  final InstanceAccessKind kind;
-
-  @override
-  Expression receiver;
-
-  // TODO(johnniwinther): Can we pull this from the [interfaceTarget] instead?
-  @override
-  Name name;
-
-  @override
-  Arguments arguments;
-
-  int flags = 0;
-
-  /// The static type of the invocation.
-  ///
-  /// This includes substituted type parameters from the static receiver type
-  /// and generic type arguments.
-  ///
-  /// For instance
-  ///
-  ///    class A<T> {
-  ///      Map<T, S> map<S>(S s) { ... }
-  ///    }
-  ///    m(A<String> a) {
-  ///      a.map(0); // The function type is `Map<String, int> Function(int)`.
-  ///    }
-  ///
-  FunctionType functionType;
-
-  Reference interfaceTargetReference;
-
-  InstanceInvocation(InstanceAccessKind kind, Expression receiver, Name name,
-      Arguments arguments,
-      {required Procedure interfaceTarget, required FunctionType functionType})
-      : this.byReference(kind, receiver, name, arguments,
-            interfaceTargetReference:
-                getNonNullableMemberReferenceGetter(interfaceTarget),
-            functionType: functionType);
-
-  InstanceInvocation.byReference(
-      this.kind, this.receiver, this.name, this.arguments,
-      {required this.interfaceTargetReference, required this.functionType})
-      : assert(functionType.typeParameters.isEmpty) {
-    receiver.parent = this;
-    arguments.parent = this;
-  }
-
-  Procedure get interfaceTarget => interfaceTargetReference.asProcedure;
-
-  void set interfaceTarget(Procedure target) {
-    interfaceTargetReference = getNonNullableMemberReferenceGetter(target);
-  }
-
-  /// If `true`, this call is known to be safe wrt. parameter covariance checks.
-  ///
-  /// This is for instance the case in code patterns like this
-  ///
-  ///     List<int> list = <int>[];
-  ///     list.add(0);
-  ///
-  /// where the `list` variable is known to hold a value of the same type as
-  /// the static type. In contrast the would not be the case in code patterns
-  /// like this
-  ///
-  ///     List<num> list = <double>[];
-  ///     list.add(0); // Runtime error `int` is not a subtype of `double`.
-  ///
-  bool get isInvariant => flags & FlagInvariant != 0;
-
-  void set isInvariant(bool value) {
-    flags = value ? (flags | FlagInvariant) : (flags & ~FlagInvariant);
-  }
-
-  /// If `true`, this call is known to be safe wrt. parameter covariance checks.
-  ///
-  /// This is for instance the case in code patterns like this
-  ///
-  ///     List list = new List.filled(2, 0);
-  ///     list[1] = 42;
-  ///
-  /// where the `list` is known to have a sufficient length for the update
-  /// in `list[1] = 42`.
-  bool get isBoundsSafe => flags & FlagBoundsSafe != 0;
-
-  void set isBoundsSafe(bool value) {
-    flags = value ? (flags | FlagBoundsSafe) : (flags & ~FlagBoundsSafe);
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      functionType.returnType;
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceInvocation(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitInstanceInvocation(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    receiver.accept(v);
-    interfaceTarget.acceptReference(v);
-    name.accept(v);
-    arguments.accept(v);
-    functionType.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    receiver = v.transform(receiver);
-    receiver.parent = this;
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-    functionType = v.visitDartType(functionType) as FunctionType;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    receiver = v.transform(receiver);
-    receiver.parent = this;
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-    functionType =
-        v.visitDartType(functionType, cannotRemoveSentinel) as FunctionType;
-  }
-
-  @override
-  String toString() {
-    return "InstanceInvocation($kind, ${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExpression(receiver,
-        minimumPrecedence: astToText.Precedence.PRIMARY);
-    printer.write('.');
-    printer.writeInterfaceMemberName(interfaceTargetReference, name);
-    printer.writeArguments(arguments);
-  }
-}
-
-/// An invocation of an instance getter or field with a statically known
-/// interface target.
-///
-/// This is used only for web backend in order to support invocation of
-/// native properties as functions. This node will be removed when this
-/// invocation style is no longer supported.
-class InstanceGetterInvocation extends InstanceInvocationExpression {
-  // Must match serialized bit positions.
-  static const int FlagInvariant = 1 << 0;
-  static const int FlagBoundsSafe = 1 << 1;
-
-  final InstanceAccessKind kind;
-
-  @override
-  Expression receiver;
-
-  @override
-  Name name;
-
-  @override
-  Arguments arguments;
-
-  int flags = 0;
-
-  /// The static type of the invocation, or `dynamic` is of the type is unknown.
-  ///
-  /// This includes substituted type parameters from the static receiver type
-  /// and generic type arguments.
-  ///
-  /// For instance
-  ///
-  ///    class A<T> {
-  ///      Map<T, S> Function<S>(S) get map => ...
-  ///      dynamic get dyn => ...
-  ///    }
-  ///    m(A<String> a) {
-  ///      a.map(0); // The function type is `Map<String, int> Function(int)`.
-  ///      a.dyn(0); // The function type is `null`.
-  ///    }
-  ///
-  FunctionType? functionType;
-
-  Reference interfaceTargetReference;
-
-  InstanceGetterInvocation(InstanceAccessKind kind, Expression receiver,
-      Name name, Arguments arguments,
-      {required Member interfaceTarget, required FunctionType? functionType})
-      : this.byReference(kind, receiver, name, arguments,
-            interfaceTargetReference:
-                getNonNullableMemberReferenceGetter(interfaceTarget),
-            functionType: functionType);
-
-  InstanceGetterInvocation.byReference(
-      this.kind, this.receiver, this.name, this.arguments,
-      {required this.interfaceTargetReference, required this.functionType})
-      : assert(functionType == null || functionType.typeParameters.isEmpty) {
-    receiver.parent = this;
-    arguments.parent = this;
-  }
-
-  Member get interfaceTarget => interfaceTargetReference.asMember;
-
-  void set interfaceTarget(Member target) {
-    interfaceTargetReference = getNonNullableMemberReferenceGetter(target);
-  }
-
-  /// If `true`, this call is known to be safe wrt. parameter covariance checks.
-  ///
-  /// This is for instance the case in code patterns like this
-  ///
-  ///     List<int> list = <int>[];
-  ///     list.add(0);
-  ///
-  /// where the `list` variable is known to hold a value of the same type as
-  /// the static type. In contrast the would not be the case in code patterns
-  /// like this
-  ///
-  ///     List<num> list = <double>[];
-  ///     list.add(0); // Runtime error `int` is not a subtype of `double`.
-  ///
-  bool get isInvariant => flags & FlagInvariant != 0;
-
-  void set isInvariant(bool value) {
-    flags = value ? (flags | FlagInvariant) : (flags & ~FlagInvariant);
-  }
-
-  /// If `true`, this call is known to be safe wrt. parameter covariance checks.
-  ///
-  /// This is for instance the case in code patterns like this
-  ///
-  ///     List list = new List.filled(2, 0);
-  ///     list[1] = 42;
-  ///
-  /// where the `list` is known to have a sufficient length for the update
-  /// in `list[1] = 42`.
-  bool get isBoundsSafe => flags & FlagBoundsSafe != 0;
-
-  void set isBoundsSafe(bool value) {
-    flags = value ? (flags | FlagBoundsSafe) : (flags & ~FlagBoundsSafe);
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      functionType?.returnType ?? const DynamicType();
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceGetterInvocation(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitInstanceGetterInvocation(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    receiver.accept(v);
-    interfaceTarget.acceptReference(v);
-    name.accept(v);
-    arguments.accept(v);
-    functionType?.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    receiver = v.transform(receiver);
-    receiver.parent = this;
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-
-    if (functionType != null) {
-      functionType = v.visitDartType(functionType!) as FunctionType;
-    }
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    receiver = v.transform(receiver);
-    receiver.parent = this;
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-    if (functionType != null) {
-      functionType =
-          v.visitDartType(functionType!, cannotRemoveSentinel) as FunctionType;
-    }
-  }
-
-  @override
-  String toString() {
-    return "InstanceGetterInvocation($kind, ${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExpression(receiver,
-        minimumPrecedence: astToText.Precedence.PRIMARY);
-    printer.write('.');
-    printer.writeInterfaceMemberName(interfaceTargetReference, name);
-    printer.writeArguments(arguments);
-  }
-}
-
-/// Access kind used by [FunctionInvocation] and [FunctionTearOff].
-enum FunctionAccessKind {
-  /// An access to the 'call' method on an expression of static type `Function`.
-  ///
-  /// For instance
-  ///
-  ///     method(Function f) => f();
-  ///
-  Function,
-
-  /// An access to the 'call' method on an expression whose static type is a
-  /// function type.
-  ///
-  /// For instance
-  ///
-  ///     method(void Function() f) => f();
-  ///
-  FunctionType,
-
-  /// An access to the 'call' method on an expression whose static type is a
-  /// function type which is inapplicable, that is, whose arguments don't match
-  /// the required parameter structure.
-  ///
-  /// This is an error case which is only used on expression nested within
-  /// [InvalidExpression]s.
-  ///
-  /// For instance:
-  ///
-  ///     test(void Function() f) => f(0); // Too many arguments.
-  ///
-  Inapplicable,
-
-  /// An access to the 'call' method on an expression whose static type is a
-  /// nullable function type or `Function?`.
-  ///
-  /// This is an error case which is only used on expression nested within
-  /// [InvalidExpression]s.
-  ///
-  /// For instance:
-  ///
-  ///     test(void Function()? f) => f(); // 'f' is nullable.
-  ///
-  Nullable,
-}
-
-/// An invocation of the 'call' method on an expression whose static type is
-/// a function type or the type 'Function'.
-class FunctionInvocation extends InstanceInvocationExpression {
-  final FunctionAccessKind kind;
-
-  @override
-  Expression receiver;
-
-  @override
-  Arguments arguments;
-
-  /// The static type of the invocation.
-  ///
-  /// This is `null` if the static type of the receiver is not a function type
-  /// or is not bounded by a function type.
-  ///
-  /// For instance
-  ///
-  ///    m<T extends Function, S extends int Function()>(T t, S s, Function f) {
-  ///      X local<X>(X t) => t;
-  ///      t(); // The function type is `null`.
-  ///      s(); // The function type is `int Function()`.
-  ///      f(); // The function type is `null`.
-  ///      local(0); // The function type is `int Function(int)`.
-  ///    }
-  ///
-  FunctionType? functionType;
-
-  FunctionInvocation(this.kind, this.receiver, this.arguments,
-      {required this.functionType}) {
-    receiver.parent = this;
-    arguments.parent = this;
-  }
-
-  @override
-  Name get name => Name.callName;
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      functionType?.returnType ?? const DynamicType();
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitFunctionInvocation(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitFunctionInvocation(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    receiver.accept(v);
-    name.accept(v);
-    arguments.accept(v);
-    functionType?.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    receiver = v.transform(receiver);
-    receiver.parent = this;
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-    FunctionType? type = functionType;
-    if (type != null) {
-      functionType = v.visitDartType(type) as FunctionType;
-    }
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    receiver = v.transform(receiver);
-    receiver.parent = this;
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-    FunctionType? type = functionType;
-    if (type != null) {
-      functionType =
-          v.visitDartType(type, cannotRemoveSentinel) as FunctionType;
-    }
-  }
-
-  @override
-  String toString() {
-    return "FunctionInvocation(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExpression(receiver,
-        minimumPrecedence: astToText.Precedence.PRIMARY);
-    printer.writeArguments(arguments);
-  }
-}
-
-/// An invocation of a local function declaration.
-class LocalFunctionInvocation extends InvocationExpression {
-  /// The variable declaration for the function declaration.
-  VariableDeclaration variable;
-
-  @override
-  Arguments arguments;
-
-  /// The static type of the invocation.
-  ///
-  /// This might differ from the static type of [variable] for generic
-  /// functions.
-  ///
-  /// For instance
-  ///
-  ///    m() {
-  ///      T local<T>(T t) => t;
-  ///      local(0); // The static type is `int Function(int)`.
-  ///    }
-  ///
-  FunctionType functionType;
-
-  LocalFunctionInvocation(this.variable, this.arguments,
-      {required this.functionType}) {
-    arguments.parent = this;
-  }
-
-  /// The declaration for the invoked local function.
-  FunctionDeclaration get localFunction =>
-      variable.parent as FunctionDeclaration;
-
-  @override
-  Name get name => Name.callName;
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      functionType.returnType;
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitLocalFunctionInvocation(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitLocalFunctionInvocation(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    arguments.accept(v);
-    functionType.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-    functionType = v.visitDartType(functionType) as FunctionType;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-    functionType =
-        v.visitDartType(functionType, cannotRemoveSentinel) as FunctionType;
-  }
-
-  @override
-  String toString() {
-    return "LocalFunctionInvocation(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write(printer.getVariableName(variable));
-    printer.writeArguments(arguments);
-  }
-}
-
-/// Nullness test of an expression, that is `e == null`.
-///
-/// This is generated for code like `e1 == e2` where `e1` or `e2` is `null`.
-class EqualsNull extends Expression {
-  /// The expression tested for nullness.
-  Expression expression;
-
-  EqualsNull(this.expression) {
-    expression.parent = this;
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitEqualsNull(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitEqualsNull(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    expression.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    expression = v.transform(expression);
-    expression.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    expression = v.transform(expression);
-    expression.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "EqualsNull(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExpression(expression, minimumPrecedence: precedence);
-    printer.write(' == null');
-  }
-}
-
-/// A test of equality, that is `e1 == e2`.
-///
-/// This is generated for code like `e1 == e2` where neither `e1` nor `e2` is
-/// `null`.
-class EqualsCall extends Expression {
-  Expression left;
-  Expression right;
-
-  /// The static type of the invocation.
-  ///
-  /// This might differ from the static type of [Object.==] for covariant
-  /// parameters.
-  ///
-  /// For instance
-  ///
-  ///    class C<T> {
-  ///      bool operator(covariant C<T> other) { ... }
-  ///    }
-  ///    // The function type is `bool Function(C<num>)`.
-  ///    method(C<num> a, C<int> b) => a == b;
-  ///
-  FunctionType functionType;
-
-  Reference interfaceTargetReference;
-
-  EqualsCall(Expression left, Expression right,
-      {required FunctionType functionType, required Procedure interfaceTarget})
-      : this.byReference(left, right,
-            functionType: functionType,
-            interfaceTargetReference:
-                getNonNullableMemberReferenceGetter(interfaceTarget));
-
-  EqualsCall.byReference(this.left, this.right,
-      {required this.functionType, required this.interfaceTargetReference}) {
-    left.parent = this;
-    right.parent = this;
-  }
-
-  Procedure get interfaceTarget => interfaceTargetReference.asProcedure;
-
-  void set interfaceTarget(Procedure target) {
-    interfaceTargetReference = getNonNullableMemberReferenceGetter(target);
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    return functionType.returnType;
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitEqualsCall(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitEqualsCall(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    left.accept(v);
-    interfaceTarget.acceptReference(v);
-    right.accept(v);
-    functionType.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    left = v.transform(left);
-    left.parent = this;
-    right = v.transform(right);
-    right.parent = this;
-    functionType = v.visitDartType(functionType) as FunctionType;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    left = v.transform(left);
-    left.parent = this;
-    right = v.transform(right);
-    right.parent = this;
-    functionType =
-        v.visitDartType(functionType, cannotRemoveSentinel) as FunctionType;
-  }
-
-  @override
-  String toString() {
-    return "EqualsCall(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    int minimumPrecedence = precedence;
-    printer.writeExpression(left, minimumPrecedence: minimumPrecedence);
-    printer.write(' == ');
-    printer.writeExpression(right, minimumPrecedence: minimumPrecedence + 1);
-  }
-}
-
-/// Expression of form `super.foo(x)` occurring in a mixin declaration.
-///
-/// In this setting, the target is looked up on the types in the mixin 'on'
-/// clause and are therefore not necessary the runtime targets of the
-/// invocation. An [AbstractSuperMethodInvocation] must be converted into
-/// a [SuperMethodInvocation] to statically bind the target.
-///
-/// For instance
-///
-///    abstract class Interface {
-///      void method();
-///    }
-///    mixin Mixin on Interface {
-///      void method() {
-///        // This is an [AbstractSuperMethodInvocation] with interface target
-///        // `Interface.method`.
-///        super.method(); // This targets Super.method.
-///      }
-///    }
-///    class Super implements Interface {
-///      // This is the target when `Mixin` is applied to `Class`.
-///      void method() {}
-///    }
-///    class Class extends Super with Mixin {}
-///
-class AbstractSuperMethodInvocation extends InvocationExpression {
-  @override
-  Name name;
-
-  @override
-  Arguments arguments;
-
-  Reference interfaceTargetReference;
-
-  AbstractSuperMethodInvocation(
-      Name name, Arguments arguments, Procedure interfaceTarget)
-      : this.byReference(
-            name,
-            arguments,
-            // An invocation doesn't refer to the setter.
-            getNonNullableMemberReferenceGetter(interfaceTarget));
-
-  AbstractSuperMethodInvocation.byReference(
-      this.name, this.arguments, this.interfaceTargetReference) {
-    arguments.parent = this;
-  }
-
-  Procedure get interfaceTarget => interfaceTargetReference.asProcedure;
-
-  void set interfaceTarget(Procedure target) {
-    // An invocation doesn't refer to the setter.
-    interfaceTargetReference = getNonNullableMemberReferenceGetter(target);
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    Class superclass = interfaceTarget.enclosingClass!;
-    List<DartType>? receiverTypeArguments = context.typeEnvironment
-        .getTypeArgumentsAsInstanceOf(context.thisType!, superclass);
-    DartType returnType = Substitution.fromPairs(
-            superclass.typeParameters, receiverTypeArguments!)
-        .substituteType(interfaceTarget.function.returnType);
-    return Substitution.fromPairs(
-            interfaceTarget.function.typeParameters, arguments.types)
-        .substituteType(returnType);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) =>
-      v.visitAbstractSuperMethodInvocation(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitAbstractSuperMethodInvocation(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    interfaceTarget.acceptReference(v);
-    name.accept(v);
-    arguments.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "AbstractSuperMethodInvocation(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('super.{abstract}');
-    printer.writeInterfaceMemberName(interfaceTargetReference, name);
-    printer.writeArguments(arguments);
-  }
-}
-
-/// Expression of form `super.foo(x)`.
-///
-/// The provided arguments might not match the parameters of the target.
-class SuperMethodInvocation extends InvocationExpression {
-  @override
-  Name name;
-
-  @override
-  Arguments arguments;
-
-  Reference interfaceTargetReference;
-
-  SuperMethodInvocation(
-      Name name, Arguments arguments, Procedure interfaceTarget)
-      : this.byReference(
-            name,
-            arguments,
-            // An invocation doesn't refer to the setter.
-            getNonNullableMemberReferenceGetter(interfaceTarget));
-
-  SuperMethodInvocation.byReference(
-      this.name, this.arguments, this.interfaceTargetReference) {
-    arguments.parent = this;
-  }
-
-  Procedure get interfaceTarget => interfaceTargetReference.asProcedure;
-
-  void set interfaceTarget(Procedure target) {
-    // An invocation doesn't refer to the setter.
-    interfaceTargetReference = getNonNullableMemberReferenceGetter(target);
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    Class superclass = interfaceTarget.enclosingClass!;
-    List<DartType>? receiverTypeArguments = context.typeEnvironment
-        .getTypeArgumentsAsInstanceOf(context.thisType!, superclass);
-    DartType returnType = Substitution.fromPairs(
-            superclass.typeParameters, receiverTypeArguments!)
-        .substituteType(interfaceTarget.function.returnType);
-    return Substitution.fromPairs(
-            interfaceTarget.function.typeParameters, arguments.types)
-        .substituteType(returnType);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitSuperMethodInvocation(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitSuperMethodInvocation(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    interfaceTarget.acceptReference(v);
-    name.accept(v);
-    arguments.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "SuperMethodInvocation(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('super.');
-    printer.writeInterfaceMemberName(interfaceTargetReference, name);
-    printer.writeArguments(arguments);
-  }
-}
-
-/// Expression of form `foo(x)`, or `const foo(x)` if the target is an
-/// external constant factory.
-///
-/// The provided arguments might not match the parameters of the target.
-class StaticInvocation extends InvocationExpression {
-  Reference targetReference;
-
-  @override
-  Arguments arguments;
-
-  /// True if this is a constant call to an external constant factory.
-  bool isConst;
-
-  @override
-  Name get name => target.name;
-
-  StaticInvocation(Procedure target, Arguments arguments,
-      {bool isConst = false})
-      : this.byReference(
-            // An invocation doesn't refer to the setter.
-            getNonNullableMemberReferenceGetter(target),
-            arguments,
-            isConst: isConst);
-
-  StaticInvocation.byReference(this.targetReference, this.arguments,
-      {this.isConst = false}) {
-    arguments.parent = this;
-  }
-
-  Procedure get target => targetReference.asProcedure;
-
-  void set target(Procedure target) {
-    // An invocation doesn't refer to the setter.
-    targetReference = getNonNullableMemberReferenceGetter(target);
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    return Substitution.fromPairs(
-            target.function.typeParameters, arguments.types)
-        .substituteType(target.function.returnType);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitStaticInvocation(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitStaticInvocation(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    target.acceptReference(v);
-    arguments.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "StaticInvocation(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeMemberName(targetReference);
-    printer.writeArguments(arguments);
-  }
-}
-
-/// Expression of form `new Foo(x)` or `const Foo(x)`.
-///
-/// The provided arguments might not match the parameters of the target.
-//
-// DESIGN TODO: Should we pass type arguments in a separate field
-// `classTypeArguments`? They are quite different from type arguments to
-// generic functions.
-class ConstructorInvocation extends InvocationExpression {
-  Reference targetReference;
-
-  @override
-  Arguments arguments;
-
-  bool isConst;
-
-  @override
-  Name get name => target.name;
-
-  ConstructorInvocation(Constructor target, Arguments arguments,
-      {bool isConst = false})
-      : this.byReference(
-            // A constructor doesn't refer to the setter.
-            getNonNullableMemberReferenceGetter(target),
-            arguments,
-            isConst: isConst);
-
-  ConstructorInvocation.byReference(this.targetReference, this.arguments,
-      {this.isConst = false}) {
-    arguments.parent = this;
-  }
-
-  Constructor get target => targetReference.asConstructor;
-
-  void set target(Constructor target) {
-    // A constructor doesn't refer to the setter.
-    targetReference = getNonNullableMemberReferenceGetter(target);
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    return arguments.types.isEmpty
-        ? context.typeEnvironment.coreTypes
-            .rawType(target.enclosingClass, context.nonNullable)
-        : new InterfaceType(
-            target.enclosingClass, context.nonNullable, arguments.types);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitConstructorInvocation(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitConstructorInvocation(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    target.acceptReference(v);
-    arguments.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    arguments = v.transform(arguments);
-    arguments.parent = this;
-  }
-
-  // TODO(cstefantsova): Change the getter into a method that accepts a
-  // CoreTypes.
-  InterfaceType get constructedType {
-    Class enclosingClass = target.enclosingClass;
-    // TODO(cstefantsova): Get raw type from a CoreTypes object if arguments is
-    // empty.
-    return arguments.types.isEmpty
-        ? new InterfaceType(enclosingClass, target.enclosingLibrary.nonNullable,
-            const <DartType>[])
-        : new InterfaceType(enclosingClass, target.enclosingLibrary.nonNullable,
-            arguments.types);
-  }
-
-  @override
-  String toString() {
-    return "ConstructorInvocation(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    if (isConst) {
-      printer.write('const ');
-    } else {
-      printer.write('new ');
-    }
-    printer.writeClassName(target.enclosingClass.reference);
-    printer.writeTypeArguments(arguments.types);
-    if (target.name.text.isNotEmpty) {
-      printer.write('.');
-      printer.write(target.name.text);
-    }
-    printer.writeArguments(arguments, includeTypeArguments: false);
-  }
-}
-
-/// An explicit type instantiation of a generic function.
-class Instantiation extends Expression {
-  Expression expression;
-  final List<DartType> typeArguments;
-
-  Instantiation(this.expression, this.typeArguments) {
-    expression.parent = this;
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    DartType type = expression.getStaticType(context);
-    if (type is FunctionType) {
-      return FunctionTypeInstantiator.instantiate(type, typeArguments);
-    }
-    assert(type is InvalidType || type is NeverType,
-        "Unexpected operand type $type for $expression");
-    return type;
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitInstantiation(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitInstantiation(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    expression.accept(v);
-    visitList(typeArguments, v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    expression = v.transform(expression);
-    expression.parent = this;
-
-    v.transformDartTypeList(typeArguments);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    expression = v.transform(expression);
-    expression.parent = this;
-
-    v.transformDartTypeList(typeArguments);
-  }
-
-  @override
-  String toString() {
-    return "Instantiation(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExpression(expression);
-    printer.writeTypeArguments(typeArguments);
-  }
-}
-
-/// Expression of form `!x`.
-///
-/// The `is!` and `!=` operators are desugared into [Not] nodes with `is` and
-/// `==` expressions inside, respectively.
-class Not extends Expression {
-  Expression operand;
-
-  Not(this.operand) {
-    operand.parent = this;
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitNot(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) => v.visitNot(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    operand.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    operand = v.transform(operand);
-    operand.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    operand = v.transform(operand);
-    operand.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "Not(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('!');
-    printer.writeExpression(operand,
-        minimumPrecedence: astToText.Precedence.PREFIX);
-  }
-}
-
-enum LogicalExpressionOperator { AND, OR }
-
-String logicalExpressionOperatorToString(LogicalExpressionOperator operator) {
-  switch (operator) {
-    case LogicalExpressionOperator.AND:
-      return "&&";
-    case LogicalExpressionOperator.OR:
-      return "||";
-  }
-}
-
-/// Expression of form `x && y` or `x || y`
-class LogicalExpression extends Expression {
-  Expression left;
-  LogicalExpressionOperator operatorEnum; // AND (&&) or OR (||).
-  Expression right;
-
-  LogicalExpression(this.left, this.operatorEnum, this.right) {
-    left.parent = this;
-    right.parent = this;
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitLogicalExpression(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitLogicalExpression(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    left.accept(v);
-    right.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    left = v.transform(left);
-    left.parent = this;
-    right = v.transform(right);
-    right.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    left = v.transform(left);
-    left.parent = this;
-    right = v.transform(right);
-    right.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "LogicalExpression(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    int minimumPrecedence = precedence;
-    printer.writeExpression(left, minimumPrecedence: minimumPrecedence);
-    printer.write(' ${logicalExpressionOperatorToString(operatorEnum)} ');
-    printer.writeExpression(right, minimumPrecedence: minimumPrecedence + 1);
-  }
-}
-
-/// Expression of form `x ? y : z`.
-class ConditionalExpression extends Expression {
-  Expression condition;
-  Expression then;
-  Expression otherwise;
-
-  /// The static type of the expression.
-  DartType staticType;
-
-  ConditionalExpression(
-      this.condition, this.then, this.otherwise, this.staticType) {
-    condition.parent = this;
-    then.parent = this;
-    otherwise.parent = this;
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) => staticType;
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitConditionalExpression(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitConditionalExpression(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    condition.accept(v);
-    then.accept(v);
-    otherwise.accept(v);
-    staticType.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    condition = v.transform(condition);
-    condition.parent = this;
-    then = v.transform(then);
-    then.parent = this;
-    otherwise = v.transform(otherwise);
-    otherwise.parent = this;
-    staticType = v.visitDartType(staticType);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    condition = v.transform(condition);
-    condition.parent = this;
-    then = v.transform(then);
-    then.parent = this;
-    otherwise = v.transform(otherwise);
-    otherwise.parent = this;
-    staticType = v.visitDartType(staticType, cannotRemoveSentinel);
-  }
-
-  @override
-  String toString() {
-    return "ConditionalExpression(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExpression(condition,
-        minimumPrecedence: astToText.Precedence.LOGICAL_OR);
-    printer.write(' ?');
-    printer.write('{');
-    printer.writeType(staticType);
-    printer.write('}');
-    printer.write(' ');
-    printer.writeExpression(then);
-    printer.write(' : ');
-    printer.writeExpression(otherwise);
-  }
-}
-
-/// Convert expressions to strings and concatenate them.  Semantically, calls
-/// `toString` on every argument, checks that a string is returned, and returns
-/// the concatenation of all the strings.
-///
-/// If [expressions] is empty then an empty string is returned.
-///
-/// These arise from string interpolations and adjacent string literals.
-class StringConcatenation extends Expression {
-  final List<Expression> expressions;
-
-  StringConcatenation(this.expressions) {
-    setParents(expressions, this);
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      context.typeEnvironment.coreTypes.stringRawType(context.nonNullable);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitStringConcatenation(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitStringConcatenation(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(expressions, v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    v.transformList(expressions, this);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    v.transformExpressionList(expressions, this);
-  }
-
-  @override
-  String toString() {
-    return "StringConcatenation(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('"');
-    for (Expression part in expressions) {
-      if (part is StringLiteral) {
-        printer.write(escapeString(part.value));
-      } else {
-        printer.write(r'${');
-        printer.writeExpression(part);
-        printer.write('}');
-      }
-    }
-    printer.write('"');
-  }
-}
-
-/// Concatenate lists into a single list.
-///
-/// If [lists] is empty then an empty list is returned.
-///
-/// These arise from spread and control-flow elements in const list literals.
-/// They are only present before constant evaluation, or within unevaluated
-/// constants in constant expressions.
-class ListConcatenation extends Expression {
-  DartType typeArgument;
-  final List<Expression> lists;
-
-  ListConcatenation(this.lists, {this.typeArgument = const DynamicType()}) {
-    setParents(lists, this);
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    return context.typeEnvironment.listType(typeArgument, context.nonNullable);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitListConcatenation(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitListConcatenation(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    typeArgument.accept(v);
-    visitList(lists, v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    typeArgument = v.visitDartType(typeArgument);
-    v.transformList(lists, this);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    typeArgument = v.visitDartType(typeArgument, cannotRemoveSentinel);
-    v.transformExpressionList(lists, this);
-  }
-
-  @override
-  String toString() {
-    return "ListConcatenation(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    bool first = true;
-    for (Expression part in lists) {
-      if (!first) {
-        printer.write(' + ');
-      }
-      printer.writeExpression(part);
-      first = false;
-    }
-  }
-}
-
-/// Concatenate sets into a single set.
-///
-/// If [sets] is empty then an empty set is returned.
-///
-/// These arise from spread and control-flow elements in const set literals.
-/// They are only present before constant evaluation, or within unevaluated
-/// constants in constant expressions.
-///
-/// Duplicated values in or across the sets will result in a compile-time error
-/// during constant evaluation.
-class SetConcatenation extends Expression {
-  DartType typeArgument;
-  final List<Expression> sets;
-
-  SetConcatenation(this.sets, {this.typeArgument = const DynamicType()}) {
-    setParents(sets, this);
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    return context.typeEnvironment.setType(typeArgument, context.nonNullable);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitSetConcatenation(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitSetConcatenation(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    typeArgument.accept(v);
-    visitList(sets, v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    typeArgument = v.visitDartType(typeArgument);
-    v.transformList(sets, this);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    typeArgument = v.visitDartType(typeArgument, cannotRemoveSentinel);
-    v.transformExpressionList(sets, this);
-  }
-
-  @override
-  String toString() {
-    return "SetConcatenation(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    bool first = true;
-    for (Expression part in sets) {
-      if (!first) {
-        printer.write(' + ');
-      }
-      printer.writeExpression(part);
-      first = false;
-    }
-  }
-}
-
-/// Concatenate maps into a single map.
-///
-/// If [maps] is empty then an empty map is returned.
-///
-/// These arise from spread and control-flow elements in const map literals.
-/// They are only present before constant evaluation, or within unevaluated
-/// constants in constant expressions.
-///
-/// Duplicated keys in or across the maps will result in a compile-time error
-/// during constant evaluation.
-class MapConcatenation extends Expression {
-  DartType keyType;
-  DartType valueType;
-  final List<Expression> maps;
-
-  MapConcatenation(this.maps,
-      {this.keyType = const DynamicType(),
-      this.valueType = const DynamicType()}) {
-    setParents(maps, this);
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    return context.typeEnvironment
-        .mapType(keyType, valueType, context.nonNullable);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitMapConcatenation(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitMapConcatenation(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    keyType.accept(v);
-    valueType.accept(v);
-    visitList(maps, v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    keyType = v.visitDartType(keyType);
-    valueType = v.visitDartType(valueType);
-    v.transformList(maps, this);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    keyType = v.visitDartType(keyType, cannotRemoveSentinel);
-    valueType = v.visitDartType(valueType, cannotRemoveSentinel);
-    v.transformExpressionList(maps, this);
-  }
-
-  @override
-  String toString() {
-    return "MapConcatenation(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    bool first = true;
-    for (Expression part in maps) {
-      if (!first) {
-        printer.write(' + ');
-      }
-      printer.writeExpression(part);
-      first = false;
-    }
-  }
-}
-
-/// Create an instance directly from the field values.
-///
-/// These expressions arise from const constructor calls when one or more field
-/// initializing expressions, field initializers, assert initializers or unused
-/// arguments contain unevaluated expressions. They only ever occur within
-/// unevaluated constants in constant expressions.
-class InstanceCreation extends Expression {
-  final Reference classReference;
-  final List<DartType> typeArguments;
-  final Map<Reference, Expression> fieldValues;
-  final List<AssertStatement> asserts;
-  final List<Expression> unusedArguments;
-
-  InstanceCreation(this.classReference, this.typeArguments, this.fieldValues,
-      this.asserts, this.unusedArguments) {
-    setParents(fieldValues.values.toList(), this);
-    setParents(asserts, this);
-    setParents(unusedArguments, this);
-  }
-
-  Class get classNode => classReference.asClass;
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    return typeArguments.isEmpty
-        ? context.typeEnvironment.coreTypes
-            .rawType(classNode, context.nonNullable)
-        : new InterfaceType(classNode, context.nonNullable, typeArguments);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceCreation(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitInstanceCreation(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    classReference.asClass.acceptReference(v);
-    visitList(typeArguments, v);
-    for (final Reference reference in fieldValues.keys) {
-      reference.asField.acceptReference(v);
-    }
-    for (final Expression value in fieldValues.values) {
-      value.accept(v);
-    }
-    visitList(asserts, v);
-    visitList(unusedArguments, v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    fieldValues.forEach((Reference fieldRef, Expression value) {
-      Expression transformed = v.transform(value);
-      if (!identical(value, transformed)) {
-        fieldValues[fieldRef] = transformed;
-        transformed.parent = this;
-      }
-    });
-    v.transformList(asserts, this);
-    v.transformList(unusedArguments, this);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    fieldValues.forEach((Reference fieldRef, Expression value) {
-      Expression transformed = v.transform(value);
-      if (!identical(value, transformed)) {
-        fieldValues[fieldRef] = transformed;
-        transformed.parent = this;
-      }
-    });
-    v.transformList(asserts, this, dummyAssertStatement);
-    v.transformExpressionList(unusedArguments, this);
-  }
-
-  @override
-  String toString() {
-    return "InstanceCreation(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeClassName(classReference);
-    printer.writeTypeArguments(typeArguments);
-    printer.write('{');
-    bool first = true;
-    fieldValues.forEach((Reference fieldRef, Expression value) {
-      if (!first) {
-        printer.write(', ');
-      }
-      printer.writeName(fieldRef.asField.name);
-      printer.write(': ');
-      printer.writeExpression(value);
-      first = false;
-    });
-    for (AssertStatement assert_ in asserts) {
-      if (!first) {
-        printer.write(', ');
-      }
-      printer.write('assert(');
-      printer.writeExpression(assert_.condition);
-      if (assert_.message != null) {
-        printer.write(', ');
-        printer.writeExpression(assert_.message!);
-      }
-      printer.write(')');
-      first = false;
-    }
-    for (Expression unusedArgument in unusedArguments) {
-      if (!first) {
-        printer.write(', ');
-      }
-      printer.writeExpression(unusedArgument);
-      first = false;
-    }
-    printer.write('}');
-  }
-}
-
-/// A marker indicating that a subexpression originates in a different source
-/// file than the surrounding context.
-///
-/// These expressions arise from inlining of const variables during constant
-/// evaluation. They only ever occur within unevaluated constants in constant
-/// expressions.
-class FileUriExpression extends Expression implements FileUriNode {
-  /// The URI of the source file in which the subexpression is located.
-  /// Can be different from the file containing the [FileUriExpression].
-  @override
-  Uri fileUri;
-
-  Expression expression;
-
-  FileUriExpression(this.expression, this.fileUri) {
-    expression.parent = this;
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      expression.getStaticType(context);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitFileUriExpression(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitFileUriExpression(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    expression.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    expression = v.transform(expression)..parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    expression = v.transform(expression)..parent = this;
-  }
-
-  @override
-  Location? _getLocationInEnclosingFile(int offset) {
-    return _getLocationInComponent(enclosingComponent, fileUri, offset,
-        viaForErrorMessage: "File uri expression");
-  }
-
-  @override
-  String toString() {
-    return "FileUriExpression(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    if (printer.includeAuxiliaryProperties) {
-      printer.write('{');
-      printer.write(fileUri.toString());
-      printer.write('}');
-    }
-    printer.writeExpression(expression);
-  }
-}
-
-/// Expression of form `x is T`.
-class IsExpression extends Expression {
-  Expression operand;
-  DartType type;
-
-  IsExpression(this.operand, this.type) {
-    operand.parent = this;
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitIsExpression(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitIsExpression(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    operand.accept(v);
-    type.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    operand = v.transform(operand);
-    operand.parent = this;
-    type = v.visitDartType(type);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    operand = v.transform(operand);
-    operand.parent = this;
-    type = v.visitDartType(type, cannotRemoveSentinel);
-  }
-
-  @override
-  String toString() {
-    return "IsExpression(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExpression(operand,
-        minimumPrecedence: astToText.Precedence.BITWISE_OR);
-    printer.write(' is ');
-    printer.writeType(type);
-  }
-}
-
-/// Expression of form `x as T`.
-class AsExpression extends Expression {
-  int flags = 0;
-  Expression operand;
-  DartType type;
-
-  AsExpression(this.operand, this.type) {
-    operand.parent = this;
-  }
-
-  // Must match serialized bit positions.
-  static const int FlagTypeError = 1 << 0;
-  static const int FlagCovarianceCheck = 1 << 1;
-  static const int FlagForDynamic = 1 << 2;
-  static const int FlagUnchecked = 1 << 3;
-
-  /// If `true`, this test is an implicit down cast.
-  ///
-  /// If `true` a TypeError should be thrown. If `false` a CastError should be
-  /// thrown.
-  bool get isTypeError => flags & FlagTypeError != 0;
-
-  void set isTypeError(bool value) {
-    flags = value ? (flags | FlagTypeError) : (flags & ~FlagTypeError);
-  }
-
-  /// If `true`, this test is needed to ensure soundness of covariant type
-  /// variables using in contravariant positions.
-  ///
-  /// For instance
-  ///
-  ///    class Class<T> {
-  ///      void Function(T) field;
-  ///      Class(this.field);
-  ///    }
-  ///    main() {
-  ///      Class<num> c = new Class<int>((int i) {});
-  ///      void Function<num> field = c.field; // Check needed on `c.field`
-  ///      field(0.5);
-  ///    }
-  ///
-  /// Here a covariant check `c.field as void Function(num)` is needed because
-  /// the field could be (and indeed is) not a subtype of the static type of
-  /// the expression.
-  bool get isCovarianceCheck => flags & FlagCovarianceCheck != 0;
-
-  void set isCovarianceCheck(bool value) {
-    flags =
-        value ? (flags | FlagCovarianceCheck) : (flags & ~FlagCovarianceCheck);
-  }
-
-  /// If `true`, this is an implicit down cast from an expression of type
-  /// `dynamic`.
-  bool get isForDynamic => flags & FlagForDynamic != 0;
-
-  void set isForDynamic(bool value) {
-    flags = value ? (flags | FlagForDynamic) : (flags & ~FlagForDynamic);
-  }
-
-  /// If `true`, this test is added to show the known static type of the
-  /// expression and should not be performed at runtime.
-  ///
-  /// This is the case for instance for access to extension type representation
-  /// fields on an extension type, where this node shows that the static type
-  /// changes from the extension type of the declared representation type.
-  ///
-  /// This is also the case when a field access undergoes type promotion.
-  bool get isUnchecked => flags & FlagUnchecked != 0;
-
-  void set isUnchecked(bool value) {
-    flags = value ? (flags | FlagUnchecked) : (flags & ~FlagUnchecked);
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) => type;
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitAsExpression(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitAsExpression(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    operand.accept(v);
-    type.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    operand = v.transform(operand);
-    operand.parent = this;
-    type = v.visitDartType(type);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    operand = v.transform(operand);
-    operand.parent = this;
-    type = v.visitDartType(type, cannotRemoveSentinel);
-  }
-
-  @override
-  String toString() {
-    return "AsExpression(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExpression(operand,
-        minimumPrecedence: astToText.Precedence.BITWISE_OR);
-    printer.write(' as');
-    if (printer.includeAuxiliaryProperties) {
-      List<String> flags = <String>[];
-      if (isTypeError) {
-        flags.add('TypeError');
-      }
-      if (isCovarianceCheck) {
-        flags.add('CovarianceCheck');
-      }
-      if (isForDynamic) {
-        flags.add('ForDynamic');
-      }
-      if (flags.isNotEmpty) {
-        printer.write('{${flags.join(',')}}');
-      }
-    }
-    printer.write(' ');
-    printer.writeType(type);
-  }
-}
-
-/// Null check expression of form `x!`.
-///
-/// This expression was added as part of NNBD and is currently only created when
-/// the 'non-nullable' experimental feature is enabled.
-class NullCheck extends Expression {
-  Expression operand;
-
-  NullCheck(this.operand) {
-    operand.parent = this;
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    DartType operandType = operand.getStaticType(context);
-    return operandType is NullType
-        ? const NeverType.nonNullable()
-        : operandType.withDeclaredNullability(Nullability.nonNullable);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitNullCheck(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitNullCheck(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    operand.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    operand = v.transform(operand);
-    operand.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    operand = v.transform(operand);
-    operand.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "NullCheck(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExpression(operand,
-        minimumPrecedence: astToText.Precedence.POSTFIX);
-    printer.write('!');
-  }
-}
-
-/// An integer, double, boolean, string, or null constant.
-abstract class BasicLiteral extends Expression {
-  Object? get value;
-
-  @override
-  void visitChildren(Visitor v) {}
-
-  @override
-  void transformChildren(Transformer v) {}
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {}
-}
-
-class StringLiteral extends BasicLiteral {
-  @override
-  String value;
-
-  StringLiteral(this.value);
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      context.typeEnvironment.coreTypes.stringRawType(context.nonNullable);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitStringLiteral(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitStringLiteral(this, arg);
-
-  @override
-  String toString() {
-    return "StringLiteral(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('"');
-    printer.write(escapeString(value));
-    printer.write('"');
-  }
-}
-
-class IntLiteral extends BasicLiteral {
-  /// Note that this value holds a uint64 value.
-  /// E.g. "0x8000000000000000" will be saved as "-9223372036854775808" despite
-  /// technically (on some platforms, particularly JavaScript) being positive.
-  /// If the number is meant to be negative it will be wrapped in a "unary-".
-  @override
-  int value;
-
-  IntLiteral(this.value);
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      context.typeEnvironment.coreTypes.intRawType(context.nonNullable);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitIntLiteral(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitIntLiteral(this, arg);
-
-  @override
-  String toString() {
-    return "IntLiteral(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('$value');
-  }
-}
-
-class DoubleLiteral extends BasicLiteral {
-  @override
-  double value;
-
-  DoubleLiteral(this.value);
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      context.typeEnvironment.coreTypes.doubleRawType(context.nonNullable);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitDoubleLiteral(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitDoubleLiteral(this, arg);
-
-  @override
-  String toString() {
-    return "DoubleLiteral(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('$value');
-  }
-}
-
-class BoolLiteral extends BasicLiteral {
-  @override
-  bool value;
-
-  BoolLiteral(this.value);
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitBoolLiteral(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitBoolLiteral(this, arg);
-
-  @override
-  String toString() {
-    return "BoolLiteral(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('$value');
-  }
-}
-
-class NullLiteral extends BasicLiteral {
-  @override
-  Object? get value => null;
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) => const NullType();
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitNullLiteral(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitNullLiteral(this, arg);
-
-  @override
-  String toString() {
-    return "NullLiteral(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('null');
-  }
-}
-
-class SymbolLiteral extends Expression {
-  String value; // Everything strictly after the '#'.
-
-  SymbolLiteral(this.value);
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      context.typeEnvironment.coreTypes.symbolRawType(context.nonNullable);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitSymbolLiteral(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitSymbolLiteral(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {}
-
-  @override
-  void transformChildren(Transformer v) {}
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {}
-
-  @override
-  String toString() {
-    return "SymbolLiteral(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('#');
-    printer.write(value);
-  }
-}
-
-class TypeLiteral extends Expression {
-  DartType type;
-
-  TypeLiteral(this.type);
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      context.typeEnvironment.coreTypes.typeRawType(context.nonNullable);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitTypeLiteral(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitTypeLiteral(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    type.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    type = v.visitDartType(type);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    type = v.visitDartType(type, cannotRemoveSentinel);
-  }
-
-  @override
-  String toString() {
-    return "TypeLiteral(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeType(type);
-  }
-}
-
-class ThisExpression extends Expression {
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      context.thisType!;
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitThisExpression(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitThisExpression(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {}
-
-  @override
-  void transformChildren(Transformer v) {}
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {}
-
-  @override
-  String toString() {
-    return "ThisExpression(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('this');
-  }
-}
-
-class Rethrow extends Expression {
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      const NeverType.nonNullable();
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitRethrow(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitRethrow(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {}
-
-  @override
-  void transformChildren(Transformer v) {}
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {}
-
-  @override
-  String toString() {
-    return "Rethrow(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('rethrow');
-  }
-}
-
-class Throw extends Expression {
-  Expression expression;
-  int flags = 0;
-
-  Throw(this.expression) {
-    expression.parent = this;
-  }
-
-  // Must match serialized bit positions.
-  static const int FlagForErrorHandling = 1 << 0;
-
-  /// If `true`, this `throw` is *not* present in the source code but added
-  /// to ensure correctness and/or soundness of the generated code.
-  ///
-  /// This is used for instance in the lowering for handling duplicate writes
-  /// to a late final field or for pattern assignments that don't match.
-  bool get forErrorHandling => flags & FlagForErrorHandling != 0;
-
-  void set forErrorHandling(bool value) {
-    flags = value
-        ? (flags | FlagForErrorHandling)
-        : (flags & ~FlagForErrorHandling);
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      const NeverType.nonNullable();
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitThrow(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) => v.visitThrow(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    expression.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    expression = v.transform(expression);
-    expression.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    expression = v.transform(expression);
-    expression.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "Throw(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('throw ');
-    printer.writeExpression(expression);
-  }
-}
-
-class ListLiteral extends Expression {
-  bool isConst;
-  DartType typeArgument; // Not null, defaults to DynamicType.
-  final List<Expression> expressions;
-
-  ListLiteral(this.expressions,
-      {this.typeArgument = const DynamicType(), this.isConst = false}) {
-    setParents(expressions, this);
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    return context.typeEnvironment.listType(typeArgument, context.nonNullable);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitListLiteral(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitListLiteral(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    typeArgument.accept(v);
-    visitList(expressions, v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    typeArgument = v.visitDartType(typeArgument);
-    v.transformList(expressions, this);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    typeArgument = v.visitDartType(typeArgument, cannotRemoveSentinel);
-    v.transformExpressionList(expressions, this);
-  }
-
-  @override
-  String toString() {
-    return "ListLiteral(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    if (isConst) {
-      printer.write('const ');
-    }
-    printer.write('<');
-    printer.writeType(typeArgument);
-    printer.write('>[');
-    printer.writeExpressions(expressions);
-    printer.write(']');
-  }
-}
-
-class SetLiteral extends Expression {
-  bool isConst;
-  DartType typeArgument; // Not null, defaults to DynamicType.
-  final List<Expression> expressions;
-
-  SetLiteral(this.expressions,
-      {this.typeArgument = const DynamicType(), this.isConst = false}) {
-    setParents(expressions, this);
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    return context.typeEnvironment.setType(typeArgument, context.nonNullable);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitSetLiteral(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitSetLiteral(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    typeArgument.accept(v);
-    visitList(expressions, v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    typeArgument = v.visitDartType(typeArgument);
-    v.transformList(expressions, this);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    typeArgument = v.visitDartType(typeArgument, cannotRemoveSentinel);
-    v.transformExpressionList(expressions, this);
-  }
-
-  @override
-  String toString() {
-    return "SetLiteral(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    if (isConst) {
-      printer.write('const ');
-    }
-    printer.write('<');
-    printer.writeType(typeArgument);
-    printer.write('>{');
-    printer.writeExpressions(expressions);
-    printer.write('}');
-  }
-}
-
-class MapLiteral extends Expression {
-  bool isConst;
-  DartType keyType; // Not null, defaults to DynamicType.
-  DartType valueType; // Not null, defaults to DynamicType.
-  final List<MapLiteralEntry> entries;
-
-  MapLiteral(this.entries,
-      {this.keyType = const DynamicType(),
-      this.valueType = const DynamicType(),
-      this.isConst = false}) {
-    setParents(entries, this);
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    return context.typeEnvironment
-        .mapType(keyType, valueType, context.nonNullable);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitMapLiteral(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitMapLiteral(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    keyType.accept(v);
-    valueType.accept(v);
-    visitList(entries, v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    keyType = v.visitDartType(keyType);
-    valueType = v.visitDartType(valueType);
-    v.transformList(entries, this);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    keyType = v.visitDartType(keyType, cannotRemoveSentinel);
-    valueType = v.visitDartType(valueType, cannotRemoveSentinel);
-    v.transformMapEntryList(entries, this);
-  }
-
-  @override
-  String toString() {
-    return "MapLiteral(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    if (isConst) {
-      printer.write('const ');
-    }
-    printer.write('<');
-    printer.writeType(keyType);
-    printer.write(', ');
-    printer.writeType(valueType);
-    printer.write('>{');
-    for (int index = 0; index < entries.length; index++) {
-      if (index > 0) {
-        printer.write(', ');
-      }
-      printer.writeMapEntry(entries[index]);
-    }
-    printer.write('}');
-  }
-}
-
-class MapLiteralEntry extends TreeNode {
-  Expression key;
-  Expression value;
-
-  MapLiteralEntry(this.key, this.value) {
-    key.parent = this;
-    value.parent = this;
-  }
-
-  @override
-  R accept<R>(TreeVisitor<R> v) => v.visitMapLiteralEntry(this);
-
-  @override
-  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) =>
-      v.visitMapLiteralEntry(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    key.accept(v);
-    value.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    key = v.transform(key);
-    key.parent = this;
-    value = v.transform(value);
-    value.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    key = v.transform(key);
-    key.parent = this;
-    value = v.transform(value);
-    value.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "MapEntry(${toStringInternal()})";
-  }
-
-  @override
-  String toText(AstTextStrategy strategy) {
-    AstPrinter printer = new AstPrinter(strategy);
-    toTextInternal(printer);
-    return printer.getText();
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExpression(key);
-    printer.write(': ');
-    printer.writeExpression(value);
-  }
-}
-
-class RecordLiteral extends Expression {
-  bool isConst;
-  final List<Expression> positional;
-  final List<NamedExpression> named;
-  RecordType recordType;
-
-  RecordLiteral(this.positional, this.named, this.recordType,
-      {this.isConst = false})
-      : assert(positional.length == recordType.positional.length &&
-            named.length == recordType.named.length &&
-            recordType.named
-                .map((f) => f.name)
-                .toSet()
-                .containsAll(named.map((f) => f.name))),
-        assert(() {
-          // Assert that the named fields are sorted.
-          for (int i = 1; i < named.length; i++) {
-            if (named[i].name.compareTo(named[i - 1].name) < 0) {
-              return false;
-            }
-          }
-          return true;
-        }(),
-            "Named fields of a RecordLiterals aren't sorted lexicographically: "
-            "${named.map((f) => f.name).join(", ")}") {
-    setParents(positional, this);
-    setParents(named, this);
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    return recordType;
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitRecordLiteral(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitRecordLiteral(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(positional, v);
-    visitList(named, v);
-    recordType.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    v.transformList(positional, this);
-    v.transformList(named, this);
-    recordType = v.visitDartType(recordType) as RecordType;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    v.transformExpressionList(positional, this);
-    v.transformNamedExpressionList(named, this);
-    recordType =
-        v.visitDartType(recordType, cannotRemoveSentinel) as RecordType;
-  }
-
-  @override
-  String toString() {
-    return "RecordType(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    if (isConst) {
-      printer.write("const ");
-    }
-    printer.write("(");
-    for (int index = 0; index < positional.length; index++) {
-      if (index > 0) {
-        printer.write(", ");
-      }
-      printer.writeExpression(positional[index]);
-    }
-    if (named.isNotEmpty) {
-      if (positional.isNotEmpty) {
-        printer.write(", ");
-      }
-      for (int index = 0; index < named.length; index++) {
-        if (index > 0) {
-          printer.write(", ");
-        }
-        printer.writeNamedExpression(named[index]);
-      }
-    }
-    printer.write(")");
-  }
-}
-
-/// Expression of form `await x`.
-class AwaitExpression extends Expression {
-  Expression operand;
-
-  /// If non-null, the runtime should check whether the value of [operand] is a
-  /// subtype of [runtimeCheckType], and if _not_ so, wrap the value in a call
-  /// to the `Future.value()` constructor.
-  ///
-  /// For instance
-  ///
-  ///     FutureOr<Object> future1 = Future<Object?>.value();
-  ///     var x = await future1; // Check against `Future<Object>`.
-  ///
-  ///     Object object = Future<Object?>.value();
-  ///     var y = await object; // Check against `Future<Object>`.
-  ///
-  ///     Future<Object?> future2 = Future<Object?>.value();
-  ///     var z = await future2; // No check.
-  ///
-  /// This runtime checks is necessary to ensure that we don't evaluate the
-  /// await expression to `null` when the static type of the expression is
-  /// non-nullable.
-  ///
-  /// The [runtimeCheckType] is computed as `Future<T>` where `T = flatten(S)`
-  /// and `S` is the static type of [operand]. To avoid unnecessary runtime
-  /// checks, the [runtimeCheckType] is not set if the static type of the
-  /// [operand] is a subtype of `Future<T>`.
-  ///
-  /// See https://github.com/dart-lang/sdk/issues/49396 for further discussion
-  /// of which the check is needed.
-  DartType? runtimeCheckType;
-
-  AwaitExpression(this.operand) {
-    operand.parent = this;
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    return context.typeEnvironment.flatten(operand.getStaticType(context));
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitAwaitExpression(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitAwaitExpression(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    operand.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    operand = v.transform(operand);
-    operand.parent = this;
-    if (runtimeCheckType != null) {
-      runtimeCheckType = v.visitDartType(runtimeCheckType!);
-    }
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    operand = v.transform(operand);
-    operand.parent = this;
-    if (runtimeCheckType != null) {
-      runtimeCheckType = v.visitDartType(runtimeCheckType!, null);
-    }
-  }
-
-  @override
-  String toString() {
-    return "AwaitExpression(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('await ');
-    printer.writeExpression(operand);
-  }
-}
-
-/// Common super-interface for [FunctionExpression] and [FunctionDeclaration].
-abstract class LocalFunction implements GenericFunction {
-  @override
-  FunctionNode get function;
-}
-
-/// Expression of form `(x,y) => ...` or `(x,y) { ... }`
-///
-/// The arrow-body form `=> e` is desugared into `return e;`.
-class FunctionExpression extends Expression implements LocalFunction {
-  @override
-  FunctionNode function;
-
-  FunctionExpression(this.function) {
-    function.parent = this;
-  }
-
-  @override
-  List<TypeParameter> get typeParameters => function.typeParameters;
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    return function.computeFunctionType(context.nonNullable);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitFunctionExpression(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitFunctionExpression(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    function.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    function = v.transform(function);
-    function.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    function = v.transform(function);
-    function.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "FunctionExpression(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeFunctionNode(function, '');
-  }
-}
-
-class ConstantExpression extends Expression {
-  Constant constant;
-  DartType type;
-
-  ConstantExpression(this.constant, [this.type = const DynamicType()]);
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) => type;
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitConstantExpression(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitConstantExpression(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    constant.acceptReference(v);
-    type.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    constant = v.visitConstant(constant);
-    type = v.visitDartType(type);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    constant = v.visitConstant(constant, cannotRemoveSentinel);
-    type = v.visitDartType(type, cannotRemoveSentinel);
-  }
-
-  @override
-  String toString() {
-    return "ConstantExpression(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeConstant(constant);
-  }
-}
-
-class FileUriConstantExpression extends ConstantExpression
-    implements FileUriNode {
-  @override
-  Uri fileUri;
-
-  FileUriConstantExpression(Constant constant,
-      {DartType type = const DynamicType(), required this.fileUri})
-      : super(constant, type);
-
-  @override
-  Location? _getLocationInEnclosingFile(int offset) {
-    return _getLocationInComponent(enclosingComponent, fileUri, offset,
-        viaForErrorMessage: "File uri constant expression");
-  }
-}
-
-/// Synthetic expression of form `let v = x in y`
-class Let extends Expression {
-  VariableDeclaration variable; // Must have an initializer.
-  Expression body;
-
-  Let(this.variable, this.body) {
-    variable.parent = this;
-    body.parent = this;
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      body.getStaticType(context);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitLet(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) => v.visitLet(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    variable.accept(v);
-    body.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    variable = v.transform(variable);
-    variable.parent = this;
-    body = v.transform(body);
-    body.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    variable = v.transform(variable);
-    variable.parent = this;
-    body = v.transform(body);
-    body.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "Let(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('let ');
-    printer.writeVariableDeclaration(variable);
-    printer.write(' in ');
-    printer.writeExpression(body);
-  }
-}
-
-class BlockExpression extends Expression {
-  Block body;
-  Expression value;
-
-  BlockExpression(this.body, this.value) {
-    body.parent = this;
-    value.parent = this;
-  }
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) =>
-      value.getStaticType(context);
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitBlockExpression(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitBlockExpression(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    body.accept(v);
-    value.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    body = v.transform(body);
-    body.parent = this;
-    value = v.transform(value);
-    value.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    body = v.transform(body);
-    body.parent = this;
-    value = v.transform(value);
-    value.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "BlockExpression(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('block ');
-    printer.writeBlock(body.statements);
-    printer.write(' => ');
-    printer.writeExpression(value);
-  }
-}
-
-/// Attempt to load the library referred to by a deferred import.
-///
-/// This instruction is concerned with:
-/// - keeping track whether the deferred import is marked as 'loaded'
-/// - keeping track of whether the library code has already been downloaded
-/// - actually downloading and linking the library
-///
-/// Should return a future.  The value in this future will be the same value
-/// seen by callers of `loadLibrary` functions.
-///
-/// On backends that link the entire program eagerly, this instruction needs
-/// to mark the deferred import as 'loaded' and return a future.
-class LoadLibrary extends Expression {
-  /// Reference to a deferred import in the enclosing library.
-  LibraryDependency import;
-
-  LoadLibrary(this.import);
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    return context.typeEnvironment
-        .futureType(const DynamicType(), context.nonNullable);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitLoadLibrary(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitLoadLibrary(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {}
-
-  @override
-  void transformChildren(Transformer v) {}
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {}
-
-  @override
-  String toString() {
-    return "LoadLibrary(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write(import.name!);
-    printer.write('.loadLibrary()');
-  }
-}
-
-/// Checks that the given deferred import has been marked as 'loaded'.
-class CheckLibraryIsLoaded extends Expression {
-  /// Reference to a deferred import in the enclosing library.
-  LibraryDependency import;
-
-  CheckLibraryIsLoaded(this.import);
-
-  @override
-  DartType getStaticType(StaticTypeContext context) =>
-      getStaticTypeInternal(context);
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    return context.typeEnvironment.coreTypes.objectRawType(context.nonNullable);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitCheckLibraryIsLoaded(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitCheckLibraryIsLoaded(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {}
-
-  @override
-  void transformChildren(Transformer v) {}
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {}
-
-  @override
-  String toString() {
-    return "CheckLibraryIsLoaded(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write(import.name!);
-    printer.write('.checkLibraryIsLoaded()');
-  }
-}
-
-/// Tearing off a constructor of a class.
-class ConstructorTearOff extends Expression {
-  /// The reference to the constructor being torn off.
-  Reference targetReference;
-
-  ConstructorTearOff(Member target)
-      : assert(
-            target is Constructor || (target is Procedure && target.isFactory),
-            "Unexpected constructor tear off target: $target"),
-        this.targetReference = getNonNullableMemberReferenceGetter(target);
-
-  ConstructorTearOff.byReference(this.targetReference);
-
-  Member get target => targetReference.asMember;
-
-  FunctionNode get function => target.function!;
-
-  void set target(Member member) {
-    assert(member is Constructor ||
-        (member is Procedure && member.kind == ProcedureKind.Factory));
-    targetReference = getNonNullableMemberReferenceGetter(member);
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    return target.function!.computeFunctionType(Nullability.nonNullable);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitConstructorTearOff(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitConstructorTearOff(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    target.acceptReference(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {}
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {}
-
-  @override
-  String toString() {
-    return "ConstructorTearOff(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeMemberName(targetReference);
-  }
-}
-
-/// Tearing off a redirecting factory constructor of a class.
-class RedirectingFactoryTearOff extends Expression {
-  /// The reference to the redirecting factory constructor being torn off.
-  Reference targetReference;
-
-  RedirectingFactoryTearOff(Procedure target)
-      : assert(target.isRedirectingFactory),
-        this.targetReference = getNonNullableMemberReferenceGetter(target);
-
-  RedirectingFactoryTearOff.byReference(this.targetReference);
-
-  Procedure get target => targetReference.asProcedure;
-
-  void set target(Procedure target) {
-    targetReference = getNonNullableMemberReferenceGetter(target);
-  }
-
-  FunctionNode get function => target.function;
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    return target.function.computeFunctionType(Nullability.nonNullable);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitRedirectingFactoryTearOff(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitRedirectingFactoryTearOff(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    target.acceptReference(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {}
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {}
-
-  @override
-  String toString() {
-    return "RedirectingFactoryTearOff(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeMemberName(targetReference);
-  }
-}
-
-class TypedefTearOff extends Expression {
-  final List<StructuralParameter> structuralParameters;
-  Expression expression;
-  final List<DartType> typeArguments;
-
-  TypedefTearOff(
-      this.structuralParameters, this.expression, this.typeArguments) {
-    expression.parent = this;
-  }
-
-  @override
-  DartType getStaticTypeInternal(StaticTypeContext context) {
-    FreshStructuralParameters freshTypeParameters =
-        getFreshStructuralParameters(structuralParameters);
-    FunctionType type = expression.getStaticType(context) as FunctionType;
-    type = freshTypeParameters.substitute(
-            FunctionTypeInstantiator.instantiate(type, typeArguments))
-        as FunctionType;
-    return new FunctionType(
-        type.positionalParameters, type.returnType, type.declaredNullability,
-        namedParameters: type.namedParameters,
-        typeParameters: freshTypeParameters.freshTypeParameters,
-        requiredParameterCount: type.requiredParameterCount);
-  }
-
-  @override
-  R accept<R>(ExpressionVisitor<R> v) => v.visitTypedefTearOff(this);
-
-  @override
-  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
-      v.visitTypedefTearOff(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    expression.accept(v);
-    visitList(structuralParameters, v);
-    visitList(typeArguments, v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    expression = v.transform(expression);
-    expression.parent = this;
-    v.transformDartTypeList(typeArguments);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    expression = v.transform(expression);
-    expression.parent = this;
-    v.transformDartTypeList(typeArguments);
-  }
-
-  @override
-  String toString() {
-    return "TypedefTearOff(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeStructuralParameters(structuralParameters);
-    printer.write(".(");
-    printer.writeExpression(expression);
-    printer.writeTypeArguments(typeArguments);
-    printer.write(")");
-  }
-}
-
-// ------------------------------------------------------------------------
-//                              STATEMENTS
-// ------------------------------------------------------------------------
-
-sealed class Statement extends TreeNode {
-  @override
-  R accept<R>(StatementVisitor<R> v);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg);
-
-  @override
-  String toText(AstTextStrategy strategy) {
-    AstPrinter printer = new AstPrinter(strategy);
-    printer.writeStatement(this);
-    return printer.getText();
-  }
-}
-
-abstract class AuxiliaryStatement extends Statement {
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitAuxiliaryStatement(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
-      v.visitAuxiliaryStatement(this, arg);
-}
-
-class ExpressionStatement extends Statement {
-  Expression expression;
-
-  // TODO(johnniwinther): Fix this so set value is not lost. We include this
-  //   getter so offset is consistent before and after serialization.
-  //   ExpressionStatements are common so serializing the offset could
-  //   increase serialized size.
-  @override
-  int get fileOffset => expression.fileOffset;
-
-  ExpressionStatement(this.expression) {
-    expression.parent = this;
-  }
-
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitExpressionStatement(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
-      v.visitExpressionStatement(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    expression.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    expression = v.transform(expression);
-    expression.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    expression = v.transform(expression);
-    expression.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "ExpressionStatement(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeExpression(expression);
-    printer.write(';');
-  }
-}
-
-class Block extends Statement {
-  final List<Statement> statements;
-
-  /// End offset in the source file it comes from. Valid values are from 0 and
-  /// up, or -1 ([TreeNode.noOffset]) if the file end offset is not available
-  /// (this is the default if none is specifically set).
-  int fileEndOffset = TreeNode.noOffset;
-
-  @override
-  List<int>? get fileOffsetsIfMultiple => [fileOffset, fileEndOffset];
-
-  Block(this.statements) {
-    // Ensure statements is mutable.
-    assert(checkListIsMutable(statements, dummyStatement));
-    setParents(statements, this);
-  }
-
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitBlock(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) => v.visitBlock(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(statements, v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    v.transformList(statements, this);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    v.transformStatementList(statements, this);
-  }
-
-  void addStatement(Statement node) {
-    statements.add(node);
-    node.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "Block(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeBlock(statements);
-  }
-}
-
-/// A block that is only executed when asserts are enabled.
-///
-/// Sometimes arbitrary statements must be guarded by whether asserts are
-/// enabled.  For example, when a subexpression of an assert in async code is
-/// linearized and named, it can produce such a block of statements.
-class AssertBlock extends Statement {
-  final List<Statement> statements;
-
-  AssertBlock(this.statements) {
-    // Ensure statements is mutable.
-    assert(checkListIsMutable(statements, dummyStatement));
-    setParents(statements, this);
-  }
-
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitAssertBlock(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
-      v.visitAssertBlock(this, arg);
-
-  @override
-  void transformChildren(Transformer v) {
-    v.transformList(statements, this);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    v.transformStatementList(statements, this);
-  }
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(statements, v);
-  }
-
-  @override
-  String toString() {
-    return "AssertBlock(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('assert ');
-    printer.writeBlock(statements);
-  }
-}
-
-class EmptyStatement extends Statement {
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitEmptyStatement(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
-      v.visitEmptyStatement(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {}
-
-  @override
-  void transformChildren(Transformer v) {}
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {}
-
-  @override
-  String toString() {
-    return "EmptyStatement(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write(';');
-  }
-}
-
-class AssertStatement extends Statement {
-  Expression condition;
-  Expression? message; // May be null.
-
-  /// Character offset in the source where the assertion condition begins.
-  ///
-  /// This is an index into [Source.text].
-  int conditionStartOffset;
-
-  /// Character offset in the source where the assertion condition ends.
-  ///
-  /// This is an index into [Source.text].
-  int conditionEndOffset;
-
-  @override
-  List<int>? get fileOffsetsIfMultiple =>
-      [fileOffset, conditionStartOffset, conditionEndOffset];
-
-  AssertStatement(this.condition,
-      {this.message,
-      required this.conditionStartOffset,
-      required this.conditionEndOffset}) {
-    condition.parent = this;
-    message?.parent = this;
-  }
-
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitAssertStatement(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
-      v.visitAssertStatement(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    condition.accept(v);
-    message?.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    condition = v.transform(condition);
-    condition.parent = this;
-    if (message != null) {
-      message = v.transform(message!);
-      message?.parent = this;
-    }
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    condition = v.transform(condition);
-    condition.parent = this;
-    if (message != null) {
-      message = v.transformOrRemoveExpression(message!);
-      message?.parent = this;
-    }
-  }
-
-  @override
-  String toString() {
-    return "AssertStatement(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('assert(');
-    printer.writeExpression(condition);
-    if (message != null) {
-      printer.write(', ');
-      printer.writeExpression(message!);
-    }
-    printer.write(');');
-  }
-}
-
-/// A target of a [Break] statement.
-///
-/// The label itself has no name; breaks reference the statement directly.
-///
-/// The frontend does not generate labeled statements without uses.
-class LabeledStatement extends Statement {
-  late Statement body;
-
-  LabeledStatement(Statement? body) {
-    if (body != null) {
-      this.body = body..parent = this;
-    }
-  }
-
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitLabeledStatement(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
-      v.visitLabeledStatement(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    body.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    body = v.transform(body);
-    body.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    body = v.transform(body);
-    body.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "LabeledStatement(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write(printer.getLabelName(this));
-    printer.write(':');
-    printer.newLine();
-    printer.writeStatement(body);
-  }
-}
-
-/// Breaks out of an enclosing [LabeledStatement].
-///
-/// Both `break` and `continue` statements are translated into this node.
-///
-/// Example `break` desugaring:
-///
-///     while (x) {
-///       if (y) break;
-///       BODY
-///     }
-///
-///     ==>
-///
-///     L: while (x) {
-///       if (y) break L;
-///       BODY
-///     }
-///
-/// Example `continue` desugaring:
-///
-///     while (x) {
-///       if (y) continue;
-///       BODY
-///     }
-///
-///     ==>
-///
-///     while (x) {
-///       L: {
-///         if (y) break L;
-///         BODY
-///       }
-///     }
-///
-/// Note: Compiler-generated [LabeledStatement]s for [WhileStatement]s and
-/// [ForStatement]s are only generated when needed. If there isn't a `break` or
-/// `continue` in a loop, the kernel for the loop won't have a generated
-/// [LabeledStatement].
-class BreakStatement extends Statement {
-  LabeledStatement target;
-
-  BreakStatement(this.target);
-
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitBreakStatement(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
-      v.visitBreakStatement(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {}
-
-  @override
-  void transformChildren(Transformer v) {}
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {}
-
-  @override
-  String toString() {
-    return "BreakStatement(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('break ');
-    printer.write(printer.getLabelName(target));
-    printer.write(';');
-  }
-}
-
-/// Common interface for loop statements.
-abstract interface class LoopStatement implements Statement {
-  abstract Statement body;
-}
-
-class WhileStatement extends Statement implements LoopStatement {
-  Expression condition;
-
-  @override
-  Statement body;
-
-  WhileStatement(this.condition, this.body) {
-    condition.parent = this;
-    body.parent = this;
-  }
-
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitWhileStatement(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
-      v.visitWhileStatement(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    condition.accept(v);
-    body.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    condition = v.transform(condition);
-    condition.parent = this;
-    body = v.transform(body);
-    body.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    condition = v.transform(condition);
-    condition.parent = this;
-    body = v.transform(body);
-    body.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "WhileStatement(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('while (');
-    printer.writeExpression(condition);
-    printer.write(') ');
-    printer.writeStatement(body);
-  }
-}
-
-class DoStatement extends Statement implements LoopStatement {
-  @override
-  Statement body;
-
-  Expression condition;
-
-  DoStatement(this.body, this.condition) {
-    body.parent = this;
-    condition.parent = this;
-  }
-
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitDoStatement(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
-      v.visitDoStatement(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    body.accept(v);
-    condition.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    body = v.transform(body);
-    body.parent = this;
-    condition = v.transform(condition);
-    condition.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    body = v.transform(body);
-    body.parent = this;
-    condition = v.transform(condition);
-    condition.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "DoStatement(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('do ');
-    printer.writeStatement(body);
-    printer.write(' while (');
-    printer.writeExpression(condition);
-    printer.write(');');
-  }
-}
-
-class ForStatement extends Statement implements LoopStatement {
-  final List<VariableDeclaration> variables; // May be empty, but not null.
-  Expression? condition; // May be null.
-  final List<Expression> updates; // May be empty, but not null.
-
-  @override
-  Statement body;
-
-  ForStatement(this.variables, this.condition, this.updates, this.body) {
-    setParents(variables, this);
-    condition?.parent = this;
-    setParents(updates, this);
-    body.parent = this;
-  }
-
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitForStatement(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
-      v.visitForStatement(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(variables, v);
-    condition?.accept(v);
-    visitList(updates, v);
-    body.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    v.transformList(variables, this);
-    if (condition != null) {
-      condition = v.transform(condition!);
-      condition?.parent = this;
-    }
-    v.transformList(updates, this);
-    body = v.transform(body);
-    body.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    v.transformVariableDeclarationList(variables, this);
-    if (condition != null) {
-      condition = v.transformOrRemoveExpression(condition!);
-      condition?.parent = this;
-    }
-    v.transformExpressionList(updates, this);
-    body = v.transform(body);
-    body.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "ForStatement(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('for (');
-    for (int index = 0; index < variables.length; index++) {
-      if (index > 0) {
-        printer.write(', ');
-      }
-      printer.writeVariableDeclaration(variables[index],
-          includeModifiersAndType: index == 0);
-    }
-    printer.write('; ');
-    if (condition != null) {
-      printer.writeExpression(condition!);
-    }
-    printer.write('; ');
-    printer.writeExpressions(updates);
-    printer.write(') ');
-    printer.writeStatement(body);
-  }
-}
-
-class ForInStatement extends Statement implements LoopStatement {
-  /// Offset in the source file it comes from.
-  ///
-  /// Valid values are from 0 and up, or -1 ([TreeNode.noOffset]) if the file
-  /// offset is not available (this is the default if none is specifically set).
-  int bodyOffset = TreeNode.noOffset;
-
-  @override
-  List<int>? get fileOffsetsIfMultiple => [fileOffset, bodyOffset];
-
-  VariableDeclaration variable; // Has no initializer.
-  Expression iterable;
-
-  @override
-  Statement body;
-
-  bool isAsync; // True if this is an 'await for' loop.
-
-  ForInStatement(this.variable, this.iterable, this.body,
-      {this.isAsync = false}) {
-    variable.parent = this;
-    iterable.parent = this;
-    body.parent = this;
-  }
-
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitForInStatement(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
-      v.visitForInStatement(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    variable.accept(v);
-    iterable.accept(v);
-    body.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    variable = v.transform(variable);
-    variable.parent = this;
-    iterable = v.transform(iterable);
-    iterable.parent = this;
-    body = v.transform(body);
-    body.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    variable = v.transform(variable);
-    variable.parent = this;
-    iterable = v.transform(iterable);
-    iterable.parent = this;
-    body = v.transform(body);
-    body.parent = this;
-  }
-
-  /// Returns the type of the iterator in this for-in statement.
-  ///
-  /// This calls `StaticTypeContext.getForInIteratorType` which calls
-  /// [getStaticTypeInternal] to compute the type of not already cached in
-  /// [context].
-  DartType getIteratorType(StaticTypeContext context) =>
-      context.getForInIteratorType(this);
-
-  /// Computes the type of the iterator in this for-in statement.
-  ///
-  /// This is called by `StaticTypeContext.getForInIteratorType` if the iterator
-  /// type of this for-in statement is not already cached in [context].
-  DartType getIteratorTypeInternal(StaticTypeContext context) {
-    DartType? iteratorType;
-    if (isAsync) {
-      InterfaceType streamType = iterable.getStaticTypeAsInstanceOf(
-          context.typeEnvironment.coreTypes.streamClass, context);
-      iteratorType = new InterfaceType(
-          context.typeEnvironment.coreTypes.streamIteratorClass,
-          context.nonNullable,
-          streamType.typeArguments);
-    } else {
-      InterfaceType iterableType = iterable.getStaticTypeAsInstanceOf(
-          context.typeEnvironment.coreTypes.iterableClass, context);
-      Member? member = context.typeEnvironment.hierarchy
-          .getInterfaceMember(iterableType.classNode, new Name('iterator'));
-      if (member != null) {
-        iteratorType = Substitution.fromInterfaceType(iterableType)
-            .substituteType(member.getterType);
-      }
-    }
-    return iteratorType ?? const DynamicType();
-  }
-
-  /// Returns the type of the element in this for-in statement.
-  ///
-  /// This calls `StaticTypeContext.getForInElementType` which calls
-  /// [getStaticTypeInternal] to compute the type of not already cached in
-  /// [context].
-  DartType getElementType(StaticTypeContext context) =>
-      context.getForInElementType(this);
-
-  /// Computes the type of the element in this for-in statement.
-  ///
-  /// This is called by `StaticTypeContext.getForInElementType` if the element
-  /// type of this for-in statement is not already cached in [context].
-  DartType getElementTypeInternal(StaticTypeContext context) {
-    DartType iterableType =
-        iterable.getStaticType(context).nonTypeVariableBound;
-    // TODO(johnniwinther): Update this to use the type of
-    //  `iterable.iterator.current` if inference is updated accordingly.
-    while (iterableType is TypeParameterType) {
-      TypeParameterType typeParameterType = iterableType;
-      iterableType = typeParameterType.bound;
-    }
-    if (iterableType is NeverType) {
-      return iterableType;
-    }
-    if (iterableType is InvalidType) {
-      return iterableType;
-    }
-    if (iterableType is! TypeDeclarationType) {
-      // TODO(johnniwinther): Change this to an assert once the CFE correctly
-      // inserts casts for all invalid iterable types.
-      return const InvalidType();
-    }
-    if (isAsync) {
-      List<DartType> typeArguments = context.typeEnvironment
-          .getTypeArgumentsAsInstanceOf(
-              iterableType, context.typeEnvironment.coreTypes.streamClass)!;
-      return typeArguments.single;
-    } else {
-      List<DartType> typeArguments = context.typeEnvironment
-          .getTypeArgumentsAsInstanceOf(
-              iterableType, context.typeEnvironment.coreTypes.iterableClass)!;
-      return typeArguments.single;
-    }
-  }
-
-  @override
-  String toString() {
-    return "ForInStatement(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('for (');
-    printer.writeVariableDeclaration(variable);
-
-    printer.write(' in ');
-    printer.writeExpression(iterable);
-    printer.write(') ');
-    printer.writeStatement(body);
-  }
-}
-
-/// Statement of form `switch (e) { case x: ... }`.
-///
-/// Adjacent case clauses have been merged into a single [SwitchCase]. A runtime
-/// exception must be thrown if one [SwitchCase] falls through to another case.
-class SwitchStatement extends Statement {
-  Expression expression;
-  final List<SwitchCase> cases;
-
-  /// For switches without a default clause, whether all possible values are
-  /// covered by a switch case.  For switches with a default clause, always
-  /// `false`.
-  /// Initialized during type inference.
-  bool isExplicitlyExhaustive;
-
-  /// The static type of the [expression]
-  ///
-  /// This is set during inference.
-  DartType? expressionTypeInternal;
-
-  SwitchStatement(this.expression, this.cases,
-      {this.isExplicitlyExhaustive = false}) {
-    expression.parent = this;
-    setParents(cases, this);
-  }
-
-  /// The static type of the [expression]
-  ///
-  /// This is set during inference.
-  DartType get expressionType {
-    assert(expressionTypeInternal != null,
-        "Expression type hasn't been computed for $this.");
-    return expressionTypeInternal!;
-  }
-
-  void set expressionType(DartType value) {
-    expressionTypeInternal = value;
-  }
-
-  /// Whether the switch has a `default` case.
-  bool get hasDefault {
-    assert(cases.every((c) => c == cases.last || !c.isDefault));
-    return cases.isNotEmpty && cases.last.isDefault;
-  }
-
-  /// Whether the switch is guaranteed to hit one of the cases (including the
-  /// default case, if present).
-  bool get isExhaustive => isExplicitlyExhaustive || hasDefault;
-
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitSwitchStatement(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
-      v.visitSwitchStatement(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    expression.accept(v);
-    visitList(cases, v);
-    expressionTypeInternal?.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    expression = v.transform(expression);
-    expression.parent = this;
-    v.transformList(cases, this);
-    if (expressionTypeInternal != null) {
-      expressionTypeInternal = v.visitDartType(expressionTypeInternal!);
-    }
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    expression = v.transform(expression);
-    expression.parent = this;
-    v.transformSwitchCaseList(cases, this);
-    if (expressionTypeInternal != null) {
-      expressionTypeInternal =
-          v.visitDartType(expressionTypeInternal!, cannotRemoveSentinel);
-    }
-  }
-
-  @override
-  String toString() {
-    return "SwitchStatement(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('switch (');
-    printer.writeExpression(expression);
-    printer.write(') {');
-    printer.incIndentation();
-    for (SwitchCase switchCase in cases) {
-      printer.newLine();
-      printer.writeSwitchCase(switchCase);
-    }
-    printer.decIndentation();
-    printer.newLine();
-    printer.write('}');
-  }
-}
-
-/// A group of `case` clauses and/or a `default` clause.
-///
-/// This is a potential target of [ContinueSwitchStatement].
-class SwitchCase extends TreeNode {
-  final List<Expression> expressions;
-  final List<int> expressionOffsets;
-  late Statement body;
-  bool isDefault;
-
-  SwitchCase(this.expressions, this.expressionOffsets, Statement? body,
-      {this.isDefault = false}) {
-    setParents(expressions, this);
-    if (body != null) {
-      this.body = body..parent = this;
-    }
-  }
-
-  SwitchCase.defaultCase(Statement? body)
-      : isDefault = true,
-        expressions = <Expression>[],
-        expressionOffsets = <int>[] {
-    if (body != null) {
-      this.body = body..parent = this;
-    }
-  }
-
-  @override
-  List<int>? get fileOffsetsIfMultiple => [fileOffset, ...expressionOffsets];
-
-  @override
-  R accept<R>(TreeVisitor<R> v) => v.visitSwitchCase(this);
-
-  @override
-  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitSwitchCase(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(expressions, v);
-    body.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    v.transformList(expressions, this);
-    body = v.transform(body);
-    body.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    v.transformExpressionList(expressions, this);
-    body = v.transform(body);
-    body.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "SwitchCase(${toStringInternal()})";
-  }
-
-  @override
-  String toText(AstTextStrategy strategy) {
-    AstPrinter printer = new AstPrinter(strategy);
-    toTextInternal(printer);
-    return printer.getText();
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    for (int index = 0; index < expressions.length; index++) {
-      if (index > 0) {
-        printer.newLine();
-      }
-      printer.write('case ');
-      printer.writeExpression(expressions[index]);
-      printer.write(':');
-    }
-    if (isDefault) {
-      if (expressions.isNotEmpty) {
-        printer.newLine();
-      }
-      printer.write('default:');
-    }
-    printer.incIndentation();
-    Statement? block = body;
-    if (block is Block) {
-      for (Statement statement in block.statements) {
-        printer.newLine();
-        printer.writeStatement(statement);
-      }
-    } else {
-      printer.write(' ');
-      printer.writeStatement(body);
-    }
-    printer.decIndentation();
-  }
-}
-
-/// Jump to a case in an enclosing switch.
-class ContinueSwitchStatement extends Statement {
-  SwitchCase target;
-
-  ContinueSwitchStatement(this.target);
-
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitContinueSwitchStatement(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
-      v.visitContinueSwitchStatement(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {}
-
-  @override
-  void transformChildren(Transformer v) {}
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {}
-
-  @override
-  String toString() {
-    return "ContinueSwitchStatement(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('continue ');
-    printer.write(printer.getSwitchCaseName(target));
-    printer.write(';');
-  }
-}
-
-class IfStatement extends Statement {
-  Expression condition;
-  Statement then;
-  Statement? otherwise;
-
-  IfStatement(this.condition, this.then, this.otherwise) {
-    condition.parent = this;
-    then.parent = this;
-    otherwise?.parent = this;
-  }
-
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitIfStatement(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
-      v.visitIfStatement(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    condition.accept(v);
-    then.accept(v);
-    otherwise?.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    condition = v.transform(condition);
-    condition.parent = this;
-    then = v.transform(then);
-    then.parent = this;
-    if (otherwise != null) {
-      otherwise = v.transform(otherwise!);
-      otherwise?.parent = this;
-    }
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    condition = v.transform(condition);
-    condition.parent = this;
-    then = v.transform(then);
-    then.parent = this;
-    if (otherwise != null) {
-      otherwise = v.transformOrRemoveStatement(otherwise!);
-      otherwise?.parent = this;
-    }
-  }
-
-  @override
-  String toString() {
-    return "IfStatement(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('if (');
-    printer.writeExpression(condition);
-    printer.write(') ');
-    printer.writeStatement(then);
-    if (otherwise != null) {
-      printer.write(' else ');
-      printer.writeStatement(otherwise!);
-    }
-  }
-}
-
-class ReturnStatement extends Statement {
-  Expression? expression; // May be null.
-
-  ReturnStatement([this.expression]) {
-    expression?.parent = this;
-  }
-
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitReturnStatement(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
-      v.visitReturnStatement(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    expression?.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    if (expression != null) {
-      expression = v.transform(expression!);
-      expression?.parent = this;
-    }
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    if (expression != null) {
-      expression = v.transformOrRemoveExpression(expression!);
-      expression?.parent = this;
-    }
-  }
-
-  @override
-  String toString() {
-    return "ReturnStatement(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('return');
-    if (expression != null) {
-      printer.write(' ');
-      printer.writeExpression(expression!);
-    }
-    printer.write(';');
-  }
-}
-
-class TryCatch extends Statement {
-  Statement body;
-  List<Catch> catches;
-  bool isSynthetic;
-
-  TryCatch(this.body, this.catches, {this.isSynthetic = false}) {
-    body.parent = this;
-    setParents(catches, this);
-  }
-
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitTryCatch(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
-      v.visitTryCatch(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    body.accept(v);
-    visitList(catches, v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    body = v.transform(body);
-    body.parent = this;
-    v.transformList(catches, this);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    body = v.transform(body);
-    body.parent = this;
-    v.transformCatchList(catches, this);
-  }
-
-  @override
-  String toString() {
-    return "TryCatch(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('try ');
-    printer.writeStatement(body);
-    for (Catch catchClause in catches) {
-      printer.write(' ');
-      printer.writeCatch(catchClause);
-    }
-  }
-}
-
-class Catch extends TreeNode {
-  DartType guard; // Not null, defaults to dynamic.
-  VariableDeclaration? exception;
-  VariableDeclaration? stackTrace;
-  Statement body;
-
-  Catch(this.exception, this.body,
-      {this.guard = const DynamicType(), this.stackTrace}) {
-    exception?.parent = this;
-    stackTrace?.parent = this;
-    body.parent = this;
-  }
-
-  @override
-  R accept<R>(TreeVisitor<R> v) => v.visitCatch(this);
-
-  @override
-  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitCatch(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    guard.accept(v);
-    exception?.accept(v);
-    stackTrace?.accept(v);
-    body.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    guard = v.visitDartType(guard);
-    if (exception != null) {
-      exception = v.transform(exception!);
-      exception?.parent = this;
-    }
-    if (stackTrace != null) {
-      stackTrace = v.transform(stackTrace!);
-      stackTrace?.parent = this;
-    }
-    body = v.transform(body);
-    body.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    guard = v.visitDartType(guard, cannotRemoveSentinel);
-    if (exception != null) {
-      exception = v.transformOrRemoveVariableDeclaration(exception!);
-      exception?.parent = this;
-    }
-    if (stackTrace != null) {
-      stackTrace = v.transformOrRemoveVariableDeclaration(stackTrace!);
-      stackTrace?.parent = this;
-    }
-    body = v.transform(body);
-    body.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "Catch(${toStringInternal()})";
-  }
-
-  @override
-  String toText(AstTextStrategy strategy) {
-    AstPrinter printer = new AstPrinter(strategy);
-    toTextInternal(printer);
-    return printer.getText();
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    bool isImplicitType(DartType type) {
-      if (type is DynamicType) {
-        return true;
-      }
-      if (type is InterfaceType &&
-          type.classReference.node != null &&
-          type.classNode.name == 'Object') {
-        Uri uri = type.classNode.enclosingLibrary.importUri;
-        return uri.isScheme('dart') &&
-            uri.path == 'core' &&
-            type.nullability == Nullability.nonNullable;
-      }
-      return false;
-    }
-
-    if (exception != null) {
-      if (!isImplicitType(guard)) {
-        printer.write('on ');
-        printer.writeType(guard);
-        printer.write(' ');
-      }
-      printer.write('catch (');
-      printer.writeVariableDeclaration(exception!,
-          includeModifiersAndType: false);
-      if (stackTrace != null) {
-        printer.write(', ');
-        printer.writeVariableDeclaration(stackTrace!,
-            includeModifiersAndType: false);
-      }
-      printer.write(') ');
-    } else {
-      printer.write('on ');
-      printer.writeType(guard);
-      printer.write(' ');
-    }
-    printer.writeStatement(body);
-  }
-}
-
-class TryFinally extends Statement {
-  Statement body;
-  Statement finalizer;
-
-  TryFinally(this.body, this.finalizer) {
-    body.parent = this;
-    finalizer.parent = this;
-  }
-
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitTryFinally(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
-      v.visitTryFinally(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    body.accept(v);
-    finalizer.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    body = v.transform(body);
-    body.parent = this;
-    finalizer = v.transform(finalizer);
-    finalizer.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    body = v.transform(body);
-    body.parent = this;
-    finalizer = v.transform(finalizer);
-    finalizer.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "TryFinally(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    if (body is! TryCatch) {
-      // This is a `try {} catch (e) {} finally {}`. Avoid repeating `try`.
-      printer.write('try ');
-    }
-    printer.writeStatement(body);
-    printer.write(' finally ');
-    printer.writeStatement(finalizer);
-  }
-}
-
-/// Statement of form `yield x` or `yield* x`.
-class YieldStatement extends Statement {
-  Expression expression;
-  int flags = 0;
-
-  YieldStatement(this.expression, {bool isYieldStar = false}) {
-    expression.parent = this;
-    this.isYieldStar = isYieldStar;
-  }
-
-  static const int FlagYieldStar = 1 << 0;
-
-  bool get isYieldStar => flags & FlagYieldStar != 0;
-
-  void set isYieldStar(bool value) {
-    flags = value ? (flags | FlagYieldStar) : (flags & ~FlagYieldStar);
-  }
-
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitYieldStatement(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
-      v.visitYieldStatement(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    expression.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    expression = v.transform(expression);
-    expression.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    expression = v.transform(expression);
-    expression.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "YieldStatement(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('yield');
-    if (isYieldStar) {
-      printer.write('*');
-    }
-    printer.write(' ');
-    printer.writeExpression(expression);
-    printer.write(';');
-  }
-}
-
-/// Declaration of a local variable.
-///
-/// This may occur as a statement, but is also used in several non-statement
-/// contexts, such as in [ForStatement], [Catch], and [FunctionNode].
-///
-/// When this occurs as a statement, it must be a direct child of a [Block].
-//
-// DESIGN TODO: Should we remove the 'final' modifier from variables?
-class VariableDeclaration extends Statement implements Annotatable {
-  /// Offset of the equals sign in the source file it comes from.
-  ///
-  /// Valid values are from 0 and up, or -1 ([TreeNode.noOffset])
-  /// if the equals sign offset is not available (e.g. if not initialized)
-  /// (this is the default if none is specifically set).
-  int fileEqualsOffset = TreeNode.noOffset;
-
-  @override
-  List<int>? get fileOffsetsIfMultiple => [fileOffset, fileEqualsOffset];
-
-  /// List of metadata annotations on the variable declaration.
-  ///
-  /// This defaults to an immutable empty list. Use [addAnnotation] to add
-  /// annotations if needed.
-  @override
-  List<Expression> annotations = const <Expression>[];
-
-  /// The name of the variable or parameter as provided in the source code.
-  ///
-  /// If this variable is synthesized, for instance the variable of a [Let]
-  /// expression, the name can be `null`.
-  String? _name;
-  int flags = 0;
-  DartType type; // Not null, defaults to dynamic.
-
-  /// Offset of the declaration, set and used when writing the binary.
-  int binaryOffsetNoTag = -1;
-
-  /// For locals, this is the initial value.
-  /// For parameters, this is the default value.
-  ///
-  /// Should be null in other cases.
-  Expression? initializer; // May be null.
-
-  VariableDeclaration(this._name,
-      {this.initializer,
-      this.type = const DynamicType(),
-      int flags = -1,
-      bool isFinal = false,
-      bool isConst = false,
-      bool isInitializingFormal = false,
-      bool isCovariantByDeclaration = false,
-      bool isLate = false,
-      bool isRequired = false,
-      bool isLowered = false,
-      bool isSynthesized = false,
-      bool isHoisted = false,
-      bool hasDeclaredInitializer = false,
-      bool isWildcard = false}) {
-    initializer?.parent = this;
-    if (flags != -1) {
-      this.flags = flags;
-    } else {
-      this.isFinal = isFinal;
-      this.isConst = isConst;
-      this.isInitializingFormal = isInitializingFormal;
-      this.isCovariantByDeclaration = isCovariantByDeclaration;
-      this.isLate = isLate;
-      this.isRequired = isRequired;
-      this.isLowered = isLowered;
-      this.hasDeclaredInitializer = hasDeclaredInitializer;
-      this.isSynthesized = isSynthesized;
-      this.isHoisted = isHoisted;
-      this.isWildcard = isWildcard;
-    }
-    assert(_name != null || this.isSynthesized,
-        "Only synthesized variables can have no name.");
-  }
-
-  /// Creates a synthetic variable with the given expression as initializer.
-  VariableDeclaration.forValue(this.initializer,
-      {bool isFinal = true,
-      bool isConst = false,
-      bool isInitializingFormal = false,
-      bool isLate = false,
-      bool isRequired = false,
-      bool isLowered = false,
-      this.type = const DynamicType()}) {
-    initializer?.parent = this;
-    this.isFinal = isFinal;
-    this.isConst = isConst;
-    this.isInitializingFormal = isInitializingFormal;
-    this.isLate = isLate;
-    this.isRequired = isRequired;
-    this.isLowered = isLowered;
-    this.hasDeclaredInitializer = true;
-    this.isSynthesized = true;
-  }
-
-  /// The name of the variable as provided in the source code.
-  ///
-  /// The name of a variable can only be omitted if the variable is synthesized.
-  /// Otherwise, its name is as provided in the source code.
-  String? get name => _name;
-
-  void set name(String? value) {
-    assert(value != null || isSynthesized,
-        "Only synthesized variables can have no name.");
-    _name = value;
-  }
-
-  static const int FlagFinal = 1 << 0; // Must match serialized bit positions.
-  static const int FlagConst = 1 << 1;
-  static const int FlagHasDeclaredInitializer = 1 << 2;
-  static const int FlagInitializingFormal = 1 << 3;
-  static const int FlagCovariantByClass = 1 << 4;
-  static const int FlagLate = 1 << 5;
-  static const int FlagRequired = 1 << 6;
-  static const int FlagCovariantByDeclaration = 1 << 7;
-  static const int FlagLowered = 1 << 8;
-  static const int FlagSynthesized = 1 << 9;
-  static const int FlagHoisted = 1 << 10;
-  static const int FlagWildcard = 1 << 11;
-
-  bool get isFinal => flags & FlagFinal != 0;
-  bool get isConst => flags & FlagConst != 0;
-
-  /// Whether the parameter is declared with the `covariant` keyword.
-  bool get isCovariantByDeclaration => flags & FlagCovariantByDeclaration != 0;
-
-  /// Whether the variable is declared as an initializing formal parameter of
-  /// a constructor.
-  @informative
-  bool get isInitializingFormal => flags & FlagInitializingFormal != 0;
-
-  /// If this [VariableDeclaration] is a parameter of a method, indicates
-  /// whether the method implementation needs to contain a runtime type check to
-  /// deal with generic covariance.
-  ///
-  /// When `true`, runtime checks may need to be performed.
-  bool get isCovariantByClass => flags & FlagCovariantByClass != 0;
-
-  /// Whether the variable is declared with the `late` keyword.
-  ///
-  /// The `late` modifier is only supported on local variables and not on
-  /// parameters.
-  bool get isLate => flags & FlagLate != 0;
-
-  /// Whether the parameter is declared with the `required` keyword.
-  ///
-  /// The `required` modifier is only supported on named parameters and not on
-  /// positional parameters and local variables.
-  bool get isRequired => flags & FlagRequired != 0;
-
-  /// Whether the variable is part of a lowering.
-  ///
-  /// If a variable is part of a lowering its name may be synthesized so that it
-  /// doesn't reflect the name used in the source code and might not have a
-  /// one-to-one correspondence with the variable in the source.
-  ///
-  /// Lowering is used for instance of encoding of 'this' in extension instance
-  /// members and encoding of late locals.
-  bool get isLowered => flags & FlagLowered != 0;
-
-  /// Whether this variable is synthesized, that is, it is _not_ declared in
-  /// the source code.
-  ///
-  /// The name of a variable can only be omitted if the variable is synthesized.
-  /// Otherwise, its name is as provided in the source code.
-  bool get isSynthesized => flags & FlagSynthesized != 0;
-
-  /// Whether the declaration of this variable is has been moved to an earlier
-  /// source location.
-  ///
-  /// This is for instance the case for variables declared in a pattern, where
-  /// the lowering requires the variable to be declared before the expression
-  /// that performs that matching in which its initialization occurs.
-  bool get isHoisted => flags & FlagHoisted != 0;
-
-  /// Whether the variable has an initializer, either by declaration or copied
-  /// from an original declaration.
-  ///
-  /// Note that the variable might have a synthesized initializer expression,
-  /// so `hasDeclaredInitializer == false` doesn't imply `initializer == null`.
-  /// For instance, for duplicate variable names, an invalid expression is set
-  /// as the initializer of the second variable.
-  bool get hasDeclaredInitializer => flags & FlagHasDeclaredInitializer != 0;
-
-  /// Whether this variable is a wildcard variable.
-  ///
-  /// Wildcard variables have the name `_`.
-  bool get isWildcard => flags & FlagWildcard != 0;
-
-  /// Whether the variable is assignable.
-  ///
-  /// This is `true` if the variable is neither constant nor final, or if it
-  /// is late final without an initializer.
-  bool get isAssignable {
-    if (isConst) return false;
-    if (isFinal) {
-      if (isLate) return initializer == null;
-      return false;
-    }
-    return true;
-  }
-
-  void set isFinal(bool value) {
-    flags = value ? (flags | FlagFinal) : (flags & ~FlagFinal);
-  }
-
-  void set isConst(bool value) {
-    flags = value ? (flags | FlagConst) : (flags & ~FlagConst);
-  }
-
-  void set isCovariantByDeclaration(bool value) {
-    flags = value
-        ? (flags | FlagCovariantByDeclaration)
-        : (flags & ~FlagCovariantByDeclaration);
-  }
-
-  @informative
-  void set isInitializingFormal(bool value) {
-    flags = value
-        ? (flags | FlagInitializingFormal)
-        : (flags & ~FlagInitializingFormal);
-  }
-
-  void set isCovariantByClass(bool value) {
-    flags = value
-        ? (flags | FlagCovariantByClass)
-        : (flags & ~FlagCovariantByClass);
-  }
-
-  void set isLate(bool value) {
-    flags = value ? (flags | FlagLate) : (flags & ~FlagLate);
-  }
-
-  void set isRequired(bool value) {
-    flags = value ? (flags | FlagRequired) : (flags & ~FlagRequired);
-  }
-
-  void set isLowered(bool value) {
-    flags = value ? (flags | FlagLowered) : (flags & ~FlagLowered);
-  }
-
-  void set isSynthesized(bool value) {
-    assert(
-        value || _name != null, "Only synthesized variables can have no name.");
-    flags = value ? (flags | FlagSynthesized) : (flags & ~FlagSynthesized);
-  }
-
-  void set isHoisted(bool value) {
-    flags = value ? (flags | FlagHoisted) : (flags & ~FlagHoisted);
-  }
-
-  void set hasDeclaredInitializer(bool value) {
-    flags = value
-        ? (flags | FlagHasDeclaredInitializer)
-        : (flags & ~FlagHasDeclaredInitializer);
-  }
-
-  void set isWildcard(bool value) {
-    // TODO(kallentu): Change the name to be unique with other wildcard
-    // variables.
-    flags = value ? (flags | FlagWildcard) : (flags & ~FlagWildcard);
-  }
-
-  void clearAnnotations() {
-    annotations = const <Expression>[];
-  }
-
-  @override
-  void addAnnotation(Expression annotation) {
-    if (annotations.isEmpty) {
-      annotations = <Expression>[];
-    }
-    annotations.add(annotation..parent = this);
-  }
-
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitVariableDeclaration(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
-      v.visitVariableDeclaration(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(annotations, v);
-    type.accept(v);
-    initializer?.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    v.transformList(annotations, this);
-    type = v.visitDartType(type);
-    if (initializer != null) {
-      initializer = v.transform(initializer!);
-      initializer?.parent = this;
-    }
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    v.transformExpressionList(annotations, this);
-    type = v.visitDartType(type, cannotRemoveSentinel);
-    if (initializer != null) {
-      initializer = v.transformOrRemoveExpression(initializer!);
-      initializer?.parent = this;
-    }
-  }
-
-  /// Returns a possibly synthesized name for this variable, consistent with
-  /// the names used across all [toString] calls.
-  @override
-  String toString() {
-    return "VariableDeclaration(${toStringInternal()})";
-  }
-
-  @override
-  String toStringInternal() {
-    AstPrinter printer = new AstPrinter(defaultAstTextStrategy);
-    printer.writeVariableDeclaration(this, includeInitializer: false);
-    return printer.getText();
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeVariableDeclaration(this);
-    printer.write(';');
-  }
-}
-
-/// Declaration a local function.
-///
-/// The body of the function may use [variable] as its self-reference.
-class FunctionDeclaration extends Statement implements LocalFunction {
-  VariableDeclaration variable; // Is final and has no initializer.
-
-  @override
-  FunctionNode function;
-
-  FunctionDeclaration(this.variable, this.function) {
-    variable.parent = this;
-    function.parent = this;
-  }
-
-  @override
-  List<TypeParameter> get typeParameters => function.typeParameters;
-
-  @override
-  R accept<R>(StatementVisitor<R> v) => v.visitFunctionDeclaration(this);
-
-  @override
-  R accept1<R, A>(StatementVisitor1<R, A> v, A arg) =>
-      v.visitFunctionDeclaration(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    variable.accept(v);
-    function.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    variable = v.transform(variable);
-    variable.parent = this;
-    function = v.transform(function);
-    function.parent = this;
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    variable = v.transform(variable);
-    variable.parent = this;
-    function = v.transform(function);
-    function.parent = this;
-  }
-
-  @override
-  String toString() {
-    return "FunctionDeclaration(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeFunctionNode(function, printer.getVariableName(variable));
-    if (function.body is ReturnStatement) {
-      printer.write(';');
-    }
-  }
-}
-
-// ------------------------------------------------------------------------
-//                                NAMES
-// ------------------------------------------------------------------------
-
-/// A public name, or a private name qualified by a library.
-///
-/// Names are only used for expressions with dynamic dispatch, as all
-/// statically resolved references are represented in nameless form.
-///
-/// [Name]s are immutable and compare based on structural equality, and they
-/// are not AST nodes.
-///
-/// The [toString] method returns a human-readable string that includes the
-/// library name for private names; uniqueness is not guaranteed.
-abstract class Name extends Node {
-  @override
-  final int hashCode;
-
-  final String text;
-  Reference? get libraryReference;
-  Library? get library;
-  bool get isPrivate;
-
-  Name._internal(this.hashCode, this.text);
-
-  factory Name(String text, [Library? library]) =>
-      new Name.byReference(text, library?.reference);
-
-  factory Name.byReference(String text, Reference? libraryName) {
-    /// Use separate subclasses for the public and private case to save memory
-    /// for public names.
-    if (text.startsWith('_')) {
-      assert(libraryName != null);
-      return new _PrivateName(text, libraryName!);
-    } else {
-      return new _PublicName(text);
-    }
-  }
-
-  @override
-  bool operator ==(other) {
-    return other is Name && text == other.text && library == other.library;
-  }
-
-  @override
-  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?
-  }
-
-  /// Returns the textual representation of this node for use in debugging.
-  ///
-  /// Note that this adds some nodes to a static map to ensure consistent
-  /// naming, but that it thus also leaks memory.
-  @override
-  String leakingDebugToString() => astToText.debugNodeToString(this);
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeName(this);
-  }
-
-  /// The name of the `call` method on a function.
-  static final Name callName = new _PublicName('call');
-
-  /// The name of the `==` operator.
-  static final Name equalsName = new _PublicName('==');
-}
-
-class _PrivateName extends Name {
-  @override
-  final Reference libraryReference;
-
-  @override
-  bool get isPrivate => true;
-
-  _PrivateName(String text, Reference libraryReference)
-      : this.libraryReference = libraryReference,
-        super._internal(_computeHashCode(text, libraryReference), text);
-
-  @override
-  String toString() => toStringInternal();
-
-  @override
-  String toStringInternal() => '$library::$text';
-
-  @override
-  Library get library => libraryReference.asLibrary;
-
-  static int _computeHashCode(String name, Reference libraryReference) {
-    // TODO(cstefantsova): Factor in [libraryReference] in a non-deterministic
-    // way into the result.  Note, the previous code here was the following:
-    //     return 131 * name.hashCode + 17 *
-    //         libraryReference.asLibrary._libraryId;
-    return name.hashCode;
-  }
-}
-
-class _PublicName extends Name {
-  @override
-  Reference? get libraryReference => null;
-
-  @override
-  Library? get library => null;
-
-  @override
-  bool get isPrivate => false;
-
-  _PublicName(String text) : super._internal(text.hashCode, text);
-
-  @override
-  String toString() => toStringInternal();
-}
-
-// ------------------------------------------------------------------------
-//                             TYPES
-// ------------------------------------------------------------------------
-
-/// Represents nullability of a type.
-enum Nullability {
-  /// Non-legacy types not known to be nullable or non-nullable statically.
-  ///
-  /// An example of such type is type T in the example below.  Note that both
-  /// int and int? can be passed in for T, so an attempt to assign null to x is
-  /// a compile-time error as well as assigning x to y.
-  ///
-  ///   class A<T extends Object?> {
-  ///     foo(T x) {
-  ///       x = null;      // Compile-time error.
-  ///       Object y = x;  // Compile-time error.
-  ///     }
-  ///   }
-  undetermined,
-
-  /// Nullable types are marked with the '?' modifier.
-  ///
-  /// Null, dynamic, and void are nullable by default.
-  nullable,
-
-  /// Non-nullable types are types that aren't marked with the '?' modifier.
-  ///
-  /// Note that Null, dynamic, and void that are nullable by default.  Note also
-  /// that some types denoted by a type parameter without the '?' modifier can
-  /// be something else rather than non-nullable.
-  nonNullable,
-
-  /// Types in opt-out libraries are 'legacy' types.
-  ///
-  /// They are both subtypes and supertypes of the nullable and non-nullable
-  /// versions of the type.
-  legacy
-}
-
-/// A syntax-independent notion of a type.
-///
-/// [DartType]s are not AST nodes and may be shared between different parents.
-///
-/// [DartType] objects should be treated as unmodifiable objects, although
-/// immutability is not enforced for List fields, and [TypeParameter]s are
-/// cyclic structures that are constructed by mutation.
-///
-/// The `==` operator on [DartType]s compare based on type equality, not
-/// object identity.
-sealed class DartType extends Node implements SharedTypeStructure<DartType> {
-  const DartType();
-
-  @override
-  R accept<R>(DartTypeVisitor<R> v);
-
-  @override
-  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg);
-
-  @override
-  bool operator ==(Object other) => equals(other, null);
-
-  /// The nullability declared on the type.
-  ///
-  /// For example, the declared nullability of `FutureOr<int?>` is
-  /// [Nullability.nonNullable], the declared nullability of `dynamic` is
-  /// [Nullability.nullable], the declared nullability of `int*` is
-  /// [Nullability.legacy], the declared nullability of the promoted type `X &
-  /// int` where `X extends Object?`
-  /// is [Nullability.undetermined].
-  Nullability get declaredNullability;
-
-  /// The nullability of the type as the property to contain null.
-  ///
-  /// For example, nullability-as-property of FutureOr<int?> is
-  /// [Nullability.nullable], nullability-as-property of dynamic is
-  /// [Nullability.nullable], nullability-as-property of int* is
-  /// [Nullability.legacy], nullability-as-property of the promoted type `X &
-  /// int` where `X extends Object?`
-  /// is [Nullability.nonNullable].
-  Nullability get nullability;
-
-  @override
-  NullabilitySuffix get nullabilitySuffix {
-    if (isTypeWithoutNullabilityMarker(this)) {
-      return NullabilitySuffix.none;
-    } else if (isNullableTypeConstructorApplication(this)) {
-      return NullabilitySuffix.question;
-    } else {
-      assert(isLegacyTypeConstructorApplication(this));
-      return NullabilitySuffix.star;
-    }
-  }
-
-  /// If this is a typedef type, repeatedly unfolds its type definition until
-  /// the root term is not a typedef type, otherwise returns the type itself.
-  ///
-  /// Will never return a typedef type.
-  DartType get unalias => this;
-
-  /// Creates a copy of the type with the given [declaredNullability].
-  ///
-  /// Some types have fixed nullabilities, such as `dynamic`, `invalid-type`,
-  /// `void`, or `bottom`.
-  DartType withDeclaredNullability(Nullability declaredNullability);
-
-  /// Creates the type corresponding to this type without null, if possible.
-  ///
-  /// Note that not all types, for instance `dynamic`, have a corresponding
-  /// non-nullable type. For these, the type itself is returned.
-  ///
-  /// This corresponds to the `NonNull` function of the nnbd specification.
-  DartType toNonNull() => computeNonNull(this);
-
-  /// Checks if the type is potentially nullable.
-  ///
-  /// A type is potentially nullable if it's nullable or if its nullability is
-  /// undetermined at compile time.
-  bool get isPotentiallyNullable {
-    return nullability == Nullability.nullable ||
-        nullability == Nullability.undetermined;
-  }
-
-  /// Checks if the type is potentially non-nullable.
-  ///
-  /// A type is potentially non-nullable if it's non-nullable or if its
-  /// nullability is undetermined at compile time.
-  bool get isPotentiallyNonNullable {
-    return nullability == Nullability.nonNullable ||
-        nullability == Nullability.undetermined;
-  }
-
-  /// Returns the non-type variable bound of this type, taking nullability
-  /// into account.
-  ///
-  /// For instance in
-  ///
-  ///     method<T, S extends Class, U extends S?>()
-  ///
-  /// the non-type variable bound of `T` is `Object?`, for `S` it is `Class`,
-  /// and for `U` it is `Class?`.
-  DartType get nonTypeVariableBound;
-
-  /// Returns `true` if members *not* declared on `Object` can be accessed on
-  /// a receiver of this type.
-  bool get hasNonObjectMemberAccess;
-
-  /// Returns the type with all occurrences of [ExtensionType] replaced by their
-  /// representations, transitively. This is the type used at runtime to
-  /// represent this type.
-  ///
-  /// For instance, for these declarations
-  ///
-  ///    extension type ET1(int id) {}
-  ///    extension type ET2(ET1 id) {}
-  ///    extension type ET3<T>(T id) {}
-  ///
-  /// the extension type erasures for `ET1`, `ET2`, `ET3<ET2>` and `List<ET2>`
-  /// are `int`, `int`, `int`, `List<int>`, respectively.
-  DartType get extensionTypeErasure => computeExtensionTypeErasure(this);
-
-  /// Internal implementation of equality using [assumptions] to handle equality
-  /// of type parameters on function types coinductively.
-  bool equals(Object other, Assumptions? assumptions);
-
-  @override
-  String getDisplayString() => toText(const AstTextStrategy());
-
-  @override
-  bool isStructurallyEqualTo(SharedTypeStructure other) {
-    // TODO(cstefantsova): Use the actual algorithm for structural equality.
-    return this == other;
-  }
-
-  /// Returns a textual representation of the this type.
-  ///
-  /// If [verbose] is `true`, qualified names will include the library name/uri.
-  @override
-  String toText(AstTextStrategy strategy) {
-    AstPrinter printer = new AstPrinter(strategy);
-    printer.writeType(this);
-    return printer.getText();
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer);
-}
-
-/// A type which is an instantiation of a [TypeDeclaration].
-sealed class TypeDeclarationType extends DartType {
-  /// The [Reference] to the [TypeDeclaration] on which this
-  /// [TypeDeclarationType] is built.
-  Reference get typeDeclarationReference;
-
-  /// The type arguments used to instantiate this [TypeDeclarationType].
-  List<DartType> get typeArguments;
-
-  /// The [TypeDeclaration] on which this [TypeDeclarationType] is built.
-  TypeDeclaration get typeDeclaration =>
-      typeDeclarationReference.asTypeDeclaration;
-}
-
-abstract class AuxiliaryType extends DartType {
-  const AuxiliaryType();
-
-  @override
-  R accept<R>(DartTypeVisitor<R> v) => v.visitAuxiliaryType(this);
-
-  @override
-  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
-      v.visitAuxiliaryType(this, arg);
-}
-
-/// The type arising from invalid type annotations.
-///
-/// Can usually be treated as 'dynamic', but should occasionally be handled
-/// differently, e.g. `x is ERROR` should evaluate to false.
-class InvalidType extends DartType
-    implements SharedInvalidTypeStructure<DartType> {
-  @override
-  final int hashCode = 12345;
-
-  const InvalidType();
-
-  @override
-  R accept<R>(DartTypeVisitor<R> v) => v.visitInvalidType(this);
-
-  @override
-  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
-      v.visitInvalidType(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {}
-
-  @override
-  DartType get nonTypeVariableBound => this;
-
-  @override
-  bool get hasNonObjectMemberAccess => true;
-
-  @override
-  bool equals(Object other, Assumptions? assumptions) => other is InvalidType;
-
-  @override
-  Nullability get declaredNullability {
-    // TODO(johnniwinther,cstefantsova): Consider implementing
-    // invalidNullability.
-    return Nullability.nullable;
-  }
-
-  @override
-  Nullability get nullability {
-    // TODO(johnniwinther,cstefantsova): Consider implementing
-    // invalidNullability.
-    return Nullability.nullable;
-  }
-
-  @override
-  InvalidType withDeclaredNullability(Nullability declaredNullability) => this;
-
-  @override
-  String toString() {
-    return "InvalidType(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write("<invalid>");
-  }
-}
-
-class DynamicType extends DartType
-    implements SharedDynamicTypeStructure<DartType> {
-  @override
-  final int hashCode = 54321;
-
-  const DynamicType();
-
-  @override
-  R accept<R>(DartTypeVisitor<R> v) => v.visitDynamicType(this);
-
-  @override
-  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
-      v.visitDynamicType(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {}
-
-  @override
-  DartType get nonTypeVariableBound => this;
-
-  @override
-  bool get hasNonObjectMemberAccess => false;
-
-  @override
-  bool equals(Object other, Assumptions? assumptions) => other is DynamicType;
-
-  @override
-  Nullability get declaredNullability => Nullability.nullable;
-
-  @override
-  Nullability get nullability => Nullability.nullable;
-
-  @override
-  DynamicType withDeclaredNullability(Nullability declaredNullability) => this;
-
-  @override
-  String toString() {
-    return "DynamicType(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write("dynamic");
-  }
-}
-
-class VoidType extends DartType implements SharedVoidTypeStructure<DartType> {
-  @override
-  final int hashCode = 123121;
-
-  const VoidType();
-
-  @override
-  R accept<R>(DartTypeVisitor<R> v) => v.visitVoidType(this);
-
-  @override
-  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
-      v.visitVoidType(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {}
-
-  @override
-  DartType get nonTypeVariableBound => this;
-
-  @override
-  bool get hasNonObjectMemberAccess => false;
-
-  @override
-  bool equals(Object other, Assumptions? assumptions) => other is VoidType;
-
-  @override
-  Nullability get declaredNullability => Nullability.nullable;
-
-  @override
-  Nullability get nullability => Nullability.nullable;
-
-  @override
-  VoidType withDeclaredNullability(Nullability declaredNullability) => this;
-
-  @override
-  String toString() {
-    return "VoidType(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write("void");
-  }
-}
-
-class NeverType extends DartType {
-  @override
-  final Nullability declaredNullability;
-
-  const NeverType.nullable() : this.internal(Nullability.nullable);
-
-  const NeverType.nonNullable() : this.internal(Nullability.nonNullable);
-
-  const NeverType.legacy() : this.internal(Nullability.legacy);
-
-  const NeverType.internal(this.declaredNullability)
-      : assert(declaredNullability != Nullability.undetermined);
-
-  static NeverType fromNullability(Nullability nullability) {
-    switch (nullability) {
-      case Nullability.nullable:
-        return const NeverType.nullable();
-      case Nullability.nonNullable:
-        return const NeverType.nonNullable();
-      case Nullability.legacy:
-        return const NeverType.legacy();
-      case Nullability.undetermined:
-        throw new StateError("Unsupported nullability for 'NeverType': "
-            "'${nullability}'");
-    }
-  }
-
-  @override
-  Nullability get nullability => declaredNullability;
-
-  @override
-  DartType get nonTypeVariableBound => this;
-
-  @override
-  bool get hasNonObjectMemberAccess => switch (declaredNullability) {
-        Nullability.undetermined => false,
-        Nullability.nullable => false,
-        Nullability.nonNullable => true,
-        Nullability.legacy => true,
-      };
-
-  @override
-  int get hashCode {
-    return 485786 ^ ((0x33333333 >> nullability.index) ^ 0x33333333);
-  }
-
-  @override
-  R accept<R>(DartTypeVisitor<R> v) => v.visitNeverType(this);
-
-  @override
-  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
-      v.visitNeverType(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {}
-
-  @override
-  bool equals(Object other, Assumptions? assumptions) =>
-      other is NeverType && nullability == other.nullability;
-
-  @override
-  NeverType withDeclaredNullability(Nullability declaredNullability) {
-    return this.declaredNullability == declaredNullability
-        ? this
-        : NeverType.fromNullability(declaredNullability);
-  }
-
-  @override
-  String toString() {
-    return "NeverType(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write("Never");
-    printer.writeNullability(declaredNullability);
-  }
-}
-
-class NullType extends DartType {
-  @override
-  final int hashCode = 415324;
-
-  const NullType();
-
-  @override
-  R accept<R>(DartTypeVisitor<R> v) => v.visitNullType(this);
-
-  @override
-  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) {
-    return v.visitNullType(this, arg);
-  }
-
-  @override
-  void visitChildren(Visitor v) {}
-
-  @override
-  DartType get nonTypeVariableBound => this;
-
-  @override
-  bool get hasNonObjectMemberAccess => false;
-
-  @override
-  bool equals(Object other, Assumptions? assumptions) => other is NullType;
-
-  @override
-  Nullability get declaredNullability => Nullability.nullable;
-
-  @override
-  Nullability get nullability => Nullability.nullable;
-
-  @override
-  DartType withDeclaredNullability(Nullability nullability) => this;
-
-  @override
-  String toString() {
-    return "NullType(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write("Null");
-  }
-}
-
-class InterfaceType extends TypeDeclarationType {
-  final Reference classReference;
-
-  @override
-  final Nullability declaredNullability;
-
-  @override
-  final List<DartType> typeArguments;
-
-  /// The [typeArguments] list must not be modified after this call. If the
-  /// list is omitted, 'dynamic' type arguments are filled in.
-  InterfaceType(Class classNode, Nullability declaredNullability,
-      [List<DartType>? typeArguments])
-      : this.byReference(classNode.reference, declaredNullability,
-            typeArguments ?? _defaultTypeArguments(classNode));
-
-  InterfaceType.byReference(
-      this.classReference, this.declaredNullability, this.typeArguments);
-
-  @override
-  Reference get typeDeclarationReference => classReference;
-
-  Class get classNode => classReference.asClass;
-
-  @override
-  Nullability get nullability => declaredNullability;
-
-  @override
-  bool get hasNonObjectMemberAccess => switch (declaredNullability) {
-        Nullability.undetermined => false,
-        Nullability.nullable => false,
-        Nullability.nonNullable => true,
-        Nullability.legacy => true,
-      };
-
-  @override
-  DartType get nonTypeVariableBound => this;
-
-  static List<DartType> _defaultTypeArguments(Class classNode) {
-    if (classNode.typeParameters.length == 0) {
-      // Avoid allocating a list in this very common case.
-      return const <DartType>[];
-    } else {
-      return new List<DartType>.filled(
-          classNode.typeParameters.length, const DynamicType());
-    }
-  }
-
-  @override
-  R accept<R>(DartTypeVisitor<R> v) => v.visitInterfaceType(this);
-
-  @override
-  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
-      v.visitInterfaceType(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    classNode.acceptReference(v);
-    visitList(typeArguments, v);
-  }
-
-  @override
-  bool equals(Object other, Assumptions? assumptions) {
-    if (identical(this, other)) return true;
-    if (other is InterfaceType) {
-      if (nullability != other.nullability) return false;
-      if (classReference != other.classReference) return false;
-      if (typeArguments.length != other.typeArguments.length) return false;
-      for (int i = 0; i < typeArguments.length; ++i) {
-        if (!typeArguments[i].equals(other.typeArguments[i], assumptions)) {
-          return false;
-        }
-      }
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  @override
-  int get hashCode {
-    int hash = 0x3fffffff & classReference.hashCode;
-    for (int i = 0; i < typeArguments.length; ++i) {
-      hash = 0x3fffffff & (hash * 31 + (hash ^ typeArguments[i].hashCode));
-    }
-    int nullabilityHash = (0x33333333 >> nullability.index) ^ 0x33333333;
-    hash = 0x3fffffff & (hash * 31 + (hash ^ nullabilityHash));
-    return hash;
-  }
-
-  @override
-  InterfaceType withDeclaredNullability(Nullability declaredNullability) {
-    return declaredNullability == this.declaredNullability
-        ? this
-        : new InterfaceType.byReference(
-            classReference, declaredNullability, typeArguments);
-  }
-
-  @override
-  String toString() {
-    return "InterfaceType(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeClassName(classReference, forType: true);
-    printer.writeTypeArguments(typeArguments);
-    printer.writeNullability(declaredNullability);
-  }
-}
-
-/// A possibly generic function type.
-class FunctionType extends DartType
-    implements
-        SharedFunctionTypeStructure<DartType, StructuralParameter, NamedType> {
-  final List<StructuralParameter> typeParameters;
-  final int requiredParameterCount;
-  final List<DartType> positionalParameters;
-  final List<NamedType> namedParameters; // Must be sorted.
-
-  @override
-  final Nullability declaredNullability;
-
-  @override
-  final DartType returnType;
-
-  @override
-  late final int hashCode = _computeHashCode();
-
-  FunctionType(List<DartType> positionalParameters, this.returnType,
-      this.declaredNullability,
-      {this.namedParameters = const <NamedType>[],
-      this.typeParameters = const <StructuralParameter>[],
-      int? requiredParameterCount})
-      : this.positionalParameters = positionalParameters,
-        this.requiredParameterCount =
-            requiredParameterCount ?? positionalParameters.length;
-
-  @override
-  Nullability get nullability => declaredNullability;
-
-  @override
-  DartType get nonTypeVariableBound => this;
-
-  @override
-  bool get hasNonObjectMemberAccess => switch (declaredNullability) {
-        Nullability.undetermined => false,
-        Nullability.nullable => false,
-        Nullability.nonNullable => true,
-        Nullability.legacy => true,
-      };
-
-  @override
-  List<DartType> get positionalParameterTypes => positionalParameters;
-
-  @override
-  int get requiredPositionalParameterCount => requiredParameterCount;
-
-  @override
-  List<NamedType> get sortedNamedParameters => namedParameters;
-
-  @override
-  List<StructuralParameter> get typeFormals => typeParameters;
-
-  @override
-  R accept<R>(DartTypeVisitor<R> v) => v.visitFunctionType(this);
-
-  @override
-  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
-      v.visitFunctionType(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(typeParameters, v);
-    visitList(positionalParameters, v);
-    visitList(namedParameters, v);
-    returnType.accept(v);
-  }
-
-  @override
-  bool equals(Object other, Assumptions? assumptions) {
-    if (identical(this, other)) {
-      return true;
-    } else if (other is FunctionType) {
-      if (nullability != other.nullability) return false;
-      if (typeParameters.length != other.typeParameters.length ||
-          requiredParameterCount != other.requiredParameterCount ||
-          positionalParameters.length != other.positionalParameters.length ||
-          namedParameters.length != other.namedParameters.length) {
-        return false;
-      }
-      if (typeParameters.isNotEmpty) {
-        assumptions ??= new Assumptions();
-        for (int index = 0; index < typeParameters.length; index++) {
-          assumptions.assumeStructuralParameter(
-              typeParameters[index], other.typeParameters[index]);
-        }
-        for (int index = 0; index < typeParameters.length; index++) {
-          if (!typeParameters[index]
-              .bound
-              .equals(other.typeParameters[index].bound, assumptions)) {
-            return false;
-          }
-        }
-      }
-      if (!returnType.equals(other.returnType, assumptions)) {
-        return false;
-      }
-
-      for (int index = 0; index < positionalParameters.length; index++) {
-        if (!positionalParameters[index]
-            .equals(other.positionalParameters[index], assumptions)) {
-          return false;
-        }
-      }
-      for (int index = 0; index < namedParameters.length; index++) {
-        if (!namedParameters[index]
-            .equals(other.namedParameters[index], assumptions)) {
-          return false;
-        }
-      }
-      if (typeParameters.isNotEmpty) {
-        for (int index = 0; index < typeParameters.length; index++) {
-          assumptions!.forgetStructuralParameter(
-              typeParameters[index], other.typeParameters[index]);
-        }
-      }
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  /// Returns a variant of this function type that does not declare any type
-  /// parameters.
-  ///
-  /// Any uses of its type parameters become free variables in the returned
-  /// type.
-  FunctionType get withoutTypeParameters {
-    if (typeParameters.isEmpty) return this;
-    return new FunctionType(positionalParameters, returnType, nullability,
-        requiredParameterCount: requiredParameterCount,
-        namedParameters: namedParameters);
-  }
-
-  /// Looks up the type of the named parameter with the given name.
-  ///
-  /// Returns `null` if there is no named parameter with the given name.
-  DartType? getNamedParameter(String name) {
-    int lower = 0;
-    int upper = namedParameters.length - 1;
-    while (lower <= upper) {
-      int pivot = (lower + upper) ~/ 2;
-      NamedType namedParameter = namedParameters[pivot];
-      int comparison = name.compareTo(namedParameter.name);
-      if (comparison == 0) {
-        return namedParameter.type;
-      } else if (comparison < 0) {
-        upper = pivot - 1;
-      } else {
-        lower = pivot + 1;
-      }
-    }
-    return null;
-  }
-
-  int _computeHashCode() {
-    int hash = 1237;
-    hash = 0x3fffffff & (hash * 31 + requiredParameterCount);
-    for (int i = 0; i < typeParameters.length; ++i) {
-      StructuralParameter parameter = typeParameters[i];
-      hash = 0x3fffffff & (hash * 31 + parameter.bound.hashCode);
-    }
-    for (int i = 0; i < positionalParameters.length; ++i) {
-      hash = 0x3fffffff & (hash * 31 + positionalParameters[i].hashCode);
-    }
-    for (int i = 0; i < namedParameters.length; ++i) {
-      hash = 0x3fffffff & (hash * 31 + namedParameters[i].hashCode);
-    }
-    hash = 0x3fffffff & (hash * 31 + returnType.hashCode);
-    hash = 0x3fffffff & (hash * 31 + nullability.index);
-    return hash;
-  }
-
-  @override
-  FunctionType withDeclaredNullability(Nullability declaredNullability) {
-    if (declaredNullability == this.declaredNullability) return this;
-    return new FunctionType(
-        positionalParameters, returnType, declaredNullability,
-        namedParameters: namedParameters,
-        typeParameters: typeParameters,
-        requiredParameterCount: requiredParameterCount);
-  }
-
-  @override
-  String toString() {
-    return "FunctionType(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeType(returnType);
-    printer.write(" Function");
-    printer.writeStructuralParameters(typeParameters);
-    printer.write("(");
-    for (int i = 0; i < positionalParameters.length; i++) {
-      if (i > 0) {
-        printer.write(", ");
-      }
-      if (i == requiredParameterCount) {
-        printer.write("[");
-      }
-      printer.writeType(positionalParameters[i]);
-    }
-    if (requiredParameterCount < positionalParameters.length) {
-      printer.write("]");
-    }
-
-    if (namedParameters.isNotEmpty) {
-      if (positionalParameters.isNotEmpty) {
-        printer.write(", ");
-      }
-      printer.write("{");
-      for (int i = 0; i < namedParameters.length; i++) {
-        if (i > 0) {
-          printer.write(", ");
-        }
-        printer.writeNamedType(namedParameters[i]);
-      }
-      printer.write("}");
-    }
-    printer.write(")");
-    printer.writeNullability(declaredNullability);
-  }
-}
-
-/// A use of a [Typedef] as a type.
-///
-/// The underlying type can be extracted using [unalias].
-class TypedefType extends DartType {
-  @override
-  final Nullability declaredNullability;
-  final Reference typedefReference;
-  final List<DartType> typeArguments;
-
-  TypedefType(Typedef typedef, Nullability nullability,
-      [List<DartType>? typeArguments])
-      : this.byReference(typedef.reference, nullability,
-            typeArguments ?? const <DartType>[]);
-
-  TypedefType.byReference(
-      this.typedefReference, this.declaredNullability, this.typeArguments);
-
-  Typedef get typedefNode => typedefReference.asTypedef;
-
-  // TODO(cstefantsova): Replace with uniteNullabilities(declaredNullability,
-  // typedefNode.type.nullability).
-  @override
-  Nullability get nullability => declaredNullability;
-
-  @override
-  DartType get nonTypeVariableBound => unalias.nonTypeVariableBound;
-
-  @override
-  bool get hasNonObjectMemberAccess => unalias.hasNonObjectMemberAccess;
-
-  @override
-  R accept<R>(DartTypeVisitor<R> v) => v.visitTypedefType(this);
-
-  @override
-  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
-      v.visitTypedefType(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(typeArguments, v);
-    v.visitTypedefReference(typedefNode);
-  }
-
-  DartType get unaliasOnce {
-    DartType result =
-        Substitution.fromTypedefType(this).substituteType(typedefNode.type!);
-    return result.withDeclaredNullability(combineNullabilitiesForSubstitution(
-        inner: result.declaredNullability, outer: nullability));
-  }
-
-  @override
-  DartType get unalias {
-    return unaliasOnce.unalias;
-  }
-
-  @override
-  bool equals(Object other, Assumptions? assumptions) {
-    if (identical(this, other)) {
-      return true;
-    } else if (other is TypedefType) {
-      if (nullability != other.nullability) return false;
-      if (typedefReference != other.typedefReference ||
-          typeArguments.length != other.typeArguments.length) {
-        return false;
-      }
-      for (int i = 0; i < typeArguments.length; ++i) {
-        if (!typeArguments[i].equals(other.typeArguments[i], assumptions)) {
-          return false;
-        }
-      }
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  @override
-  int get hashCode {
-    int hash = 0x3fffffff & typedefNode.hashCode;
-    for (int i = 0; i < typeArguments.length; ++i) {
-      hash = 0x3fffffff & (hash * 31 + (hash ^ typeArguments[i].hashCode));
-    }
-    int nullabilityHash = (0x33333333 >> nullability.index) ^ 0x33333333;
-    hash = 0x3fffffff & (hash * 31 + (hash ^ nullabilityHash));
-    return hash;
-  }
-
-  @override
-  TypedefType withDeclaredNullability(Nullability declaredNullability) {
-    return declaredNullability == this.declaredNullability
-        ? this
-        : new TypedefType.byReference(
-            typedefReference, declaredNullability, typeArguments);
-  }
-
-  @override
-  String toString() {
-    return "TypedefType(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeTypedefName(typedefReference);
-    printer.writeTypeArguments(typeArguments);
-    printer.writeNullability(declaredNullability);
-  }
-}
-
-class FutureOrType extends DartType {
-  final DartType typeArgument;
-
-  @override
-  final Nullability declaredNullability;
-
-  FutureOrType(this.typeArgument, this.declaredNullability);
-
-  @override
-  Nullability get nullability {
-    return uniteNullabilities(typeArgument.nullability, declaredNullability);
-  }
-
-  @override
-  R accept<R>(DartTypeVisitor<R> v) => v.visitFutureOrType(this);
-
-  @override
-  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) {
-    return v.visitFutureOrType(this, arg);
-  }
-
-  @override
-  void visitChildren(Visitor v) {
-    typeArgument.accept(v);
-  }
-
-  @override
-  DartType get nonTypeVariableBound => this;
-
-  @override
-  bool get hasNonObjectMemberAccess => false;
-
-  @override
-  bool equals(Object other, Assumptions? assumptions) {
-    if (identical(this, other)) return true;
-    if (other is FutureOrType) {
-      if (declaredNullability != other.declaredNullability) return false;
-      if (!typeArgument.equals(other.typeArgument, assumptions)) {
-        return false;
-      }
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  @override
-  int get hashCode {
-    int hash = 0x12345678;
-    hash = 0x3fffffff & (hash * 31 + (hash ^ typeArgument.hashCode));
-    int nullabilityHash =
-        (0x33333333 >> declaredNullability.index) ^ 0x33333333;
-    hash = 0x3fffffff & (hash * 31 + (hash ^ nullabilityHash));
-    return hash;
-  }
-
-  @override
-  FutureOrType withDeclaredNullability(Nullability declaredNullability) {
-    return declaredNullability == this.declaredNullability
-        ? this
-        : new FutureOrType(typeArgument, declaredNullability);
-  }
-
-  @override
-  String toString() {
-    return "FutureOrType(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write("FutureOr<");
-    printer.writeType(typeArgument);
-    printer.write(">");
-    printer.writeNullability(declaredNullability);
-  }
-}
-
-class ExtensionType extends TypeDeclarationType {
-  final Reference extensionTypeDeclarationReference;
-
-  @override
-  final Nullability declaredNullability;
-
-  @override
-  final List<DartType> typeArguments;
-
-  ExtensionType(ExtensionTypeDeclaration extensionTypeDeclaration,
-      Nullability declaredNullability, [List<DartType>? typeArguments])
-      : this.byReference(
-            extensionTypeDeclaration.reference,
-            declaredNullability,
-            typeArguments ?? _defaultTypeArguments(extensionTypeDeclaration));
-
-  ExtensionType.byReference(this.extensionTypeDeclarationReference,
-      this.declaredNullability, this.typeArguments);
-
-  ExtensionTypeDeclaration get extensionTypeDeclaration =>
-      extensionTypeDeclarationReference.asExtensionTypeDeclaration;
-
-  @override
-  Reference get typeDeclarationReference => extensionTypeDeclarationReference;
-
-  /// Returns the type erasure of this extension type.
-  ///
-  /// This is the type used at runtime for this type, for instance in is-tests
-  /// and as-checks.
-  ///
-  /// The type erasure is the recursive replacement of extension types by their
-  /// type erasures in the declared representation type of
-  /// [extensionTypeDeclaration] instantiation with [typeArguments].
-  ///
-  /// For instance
-  ///
-  ///     extension type E1(int it) {}
-  ///     extension type E2<X>(X it) {}
-  ///     extension type E3<T>(E2<List<T>> it) {}
-  ///
-  /// the type erasure of `E1` is `int`, type erasure of `E2<num>` is `num` and
-  /// the type erasure of `E3<String>` is `List<String>`.
-  @override
-  DartType get extensionTypeErasure => _computeTypeErasure(
-      extensionTypeDeclarationReference, typeArguments, declaredNullability);
-
-  @override
-  Nullability get nullability {
-    return combineNullabilitiesForSubstitution(
-        inner: extensionTypeDeclaration.inherentNullability,
-        outer: declaredNullability);
-  }
-
-  @override
-  DartType get nonTypeVariableBound => this;
-
-  @override
-  bool get hasNonObjectMemberAccess => switch (declaredNullability) {
-        // Undetermined means that the extension type does not implement
-        // `Object` but is not explicitly marked as nullable.
-        Nullability.undetermined => true,
-        Nullability.nullable => false,
-        Nullability.nonNullable => true,
-        Nullability.legacy => true,
-      };
-
-  static List<DartType> _defaultTypeArguments(
-      ExtensionTypeDeclaration extensionTypeDeclaration) {
-    if (extensionTypeDeclaration.typeParameters.length == 0) {
-      // Avoid allocating a list in this very common case.
-      return const <DartType>[];
-    } else {
-      return new List<DartType>.filled(
-          extensionTypeDeclaration.typeParameters.length, const DynamicType());
-    }
-  }
-
-  static DartType _computeTypeErasure(
-      Reference extensionTypeDeclarationReference,
-      List<DartType> typeArguments,
-      Nullability declaredNullability) {
-    ExtensionTypeDeclaration extensionTypeDeclaration =
-        extensionTypeDeclarationReference.asExtensionTypeDeclaration;
-    DartType result = Substitution.fromPairs(
-            extensionTypeDeclaration.typeParameters, typeArguments)
-        .substituteType(extensionTypeDeclaration.declaredRepresentationType);
-    result = result.extensionTypeErasure;
-
-    // The nullability of the extension type affects the nullability of the type
-    // erasure only if it was [Nullability.nullable]. In all other cases, that
-    // is, [Nullability.nonNullable] or [Nullability.undetermined], it is
-    // unrelated to the nullability of the representation type and should be
-    // ignored.
-    Nullability erasureNullability;
-    if (declaredNullability == Nullability.nullable) {
-      erasureNullability = combineNullabilitiesForSubstitution(
-          inner: result.nullability, outer: declaredNullability);
-    } else {
-      erasureNullability = result.nullability;
-    }
-    result = result.withDeclaredNullability(erasureNullability);
-
-    return result;
-  }
-
-  @override
-  R accept<R>(DartTypeVisitor<R> v) {
-    return v.visitExtensionType(this);
-  }
-
-  @override
-  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) {
-    return v.visitExtensionType(this, arg);
-  }
-
-  @override
-  void visitChildren(Visitor v) {
-    extensionTypeDeclaration.acceptReference(v);
-    visitList(typeArguments, v);
-  }
-
-  @override
-  bool equals(Object other, Assumptions? assumptions) {
-    if (identical(this, other)) return true;
-    if (other is ExtensionType) {
-      if (nullability != other.nullability) return false;
-      if (extensionTypeDeclarationReference !=
-          other.extensionTypeDeclarationReference) {
-        return false;
-      }
-      if (typeArguments.length != other.typeArguments.length) return false;
-      for (int i = 0; i < typeArguments.length; ++i) {
-        if (!typeArguments[i].equals(other.typeArguments[i], assumptions)) {
-          return false;
-        }
-      }
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  @override
-  int get hashCode {
-    int hash = 0x3fffffff & extensionTypeDeclarationReference.hashCode;
-    for (int i = 0; i < typeArguments.length; ++i) {
-      hash = 0x3fffffff & (hash * 31 + (hash ^ typeArguments[i].hashCode));
-    }
-    int nullabilityHash = (0x33333333 >> nullability.index) ^ 0x33333333;
-    hash = 0x3fffffff & (hash * 31 + (hash ^ nullabilityHash));
-    return hash;
-  }
-
-  @override
-  ExtensionType withDeclaredNullability(Nullability declaredNullability) {
-    return declaredNullability == this.declaredNullability
-        ? this
-        : new ExtensionType.byReference(extensionTypeDeclarationReference,
-            declaredNullability, typeArguments);
-  }
-
-  @override
-  String toString() {
-    return "ExtensionType(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer
-        .writeExtensionTypeDeclarationName(extensionTypeDeclarationReference);
-    printer.writeTypeArguments(typeArguments);
-    printer.writeNullability(declaredNullability);
-  }
-}
-
-/// A named parameter in [FunctionType].
-class NamedType extends Node
-    implements
-        Comparable<NamedType>,
-        SharedNamedTypeStructure<DartType>,
-        SharedNamedFunctionParameterStructure<DartType> {
-  // Flag used for serialization if [isRequired].
-  static const int FlagRequiredNamedType = 1 << 0;
-
-  @override
-  final String name;
-  @override
-  final DartType type;
-  @override
-  final bool isRequired;
-
-  const NamedType(this.name, this.type, {this.isRequired = false});
-
-  @override
-  bool operator ==(Object other) => equals(other, null);
-
-  bool equals(Object other, Assumptions? assumptions) {
-    return other is NamedType &&
-        name == other.name &&
-        isRequired == other.isRequired &&
-        type.equals(other.type, assumptions);
-  }
-
-  @override
-  int get hashCode {
-    return name.hashCode * 31 + type.hashCode * 37 + isRequired.hashCode * 41;
-  }
-
-  @override
-  int compareTo(NamedType other) => name.compareTo(other.name);
-
-  @override
-  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);
-  }
-
-  @override
-  String toString() {
-    return "NamedType(${toStringInternal()})";
-  }
-
-  @override
-  String toText(AstTextStrategy strategy) {
-    AstPrinter printer = new AstPrinter(strategy);
-    printer.writeNamedType(this);
-    return printer.getText();
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    if (isRequired) {
-      printer.write("required ");
-    }
-    printer.write(name);
-    printer.write(': ');
-    printer.writeType(type);
-  }
-}
-
-class IntersectionType extends DartType {
-  final TypeParameterType left;
-  final DartType right;
-
-  IntersectionType(this.left, this.right) {
-    // TODO(cstefantsova): Also assert that [rhs] is a subtype of [lhs.bound].
-
-    Nullability leftNullability = left.nullability;
-    Nullability rightNullability = right.nullability;
-    assert(
-        (leftNullability == Nullability.nonNullable &&
-                rightNullability == Nullability.nonNullable) ||
-            (leftNullability == Nullability.nonNullable &&
-                rightNullability == Nullability.undetermined) ||
-            (leftNullability == Nullability.legacy &&
-                rightNullability == Nullability.legacy) ||
-            (leftNullability == Nullability.undetermined &&
-                rightNullability == Nullability.nonNullable) ||
-            (leftNullability == Nullability.undetermined &&
-                rightNullability == Nullability.nullable) ||
-            (leftNullability == Nullability.undetermined &&
-                rightNullability == Nullability.undetermined)
-            // These are observed in real situations:
-            ||
-            // pkg/front_end/test/id_tests/type_promotion_test
-            // replicated in nnbd_mixed/type_parameter_nullability
-            (leftNullability == Nullability.nullable &&
-                rightNullability == Nullability.nonNullable) ||
-            // pkg/front_end/test/fasta/types/kernel_type_parser_test
-            // pkg/front_end/test/fasta/incremental_hello_test
-            // pkg/front_end/test/fasta/types/fasta_types_test
-            // pkg/front_end/tool/fasta_perf_test
-            // nnbd/issue42089
-            // replicated in nnbd_mixed/type_parameter_nullability
-            (leftNullability == Nullability.nullable &&
-                rightNullability == Nullability.nullable) ||
-            // pkg/front_end/test/dill_round_trip_test
-            // pkg/front_end/test/compile_dart2js_with_no_sdk_test
-            // pkg/front_end/test/fasta/types/large_app_benchmark_test
-            // pkg/front_end/test/incremental_dart2js_test
-            // pkg/front_end/test/read_dill_from_binary_md_test
-            // pkg/front_end/test/static_types/static_type_test
-            // pkg/front_end/test/split_dill_test
-            // pkg/front_end/tool/incremental_perf_test
-            // pkg/vm/test/kernel_front_end_test
-            // general/promoted_null_aware_access
-            // inference/constructors_infer_from_arguments_factory
-            // inference/infer_types_on_loop_indices_for_each_loop
-            // inference/infer_types_on_loop_indices_for_each_loop_async
-            // replicated in nnbd_mixed/type_parameter_nullability
-            (leftNullability == Nullability.legacy &&
-                rightNullability == Nullability.nonNullable) ||
-            // pkg/front_end/test/fasta/incremental_hello_test
-            // pkg/front_end/tool/fasta_perf_test
-            // replicated in nnbd_mixed/type_parameter_nullability
-            (leftNullability == Nullability.nullable &&
-                rightNullability == Nullability.undetermined) ||
-            // These are only observed in tests and might be artifacts of the
-            // tests rather than real situations:
-            //
-            // pkg/front_end/test/fasta/types/kernel_type_parser_test
-            // pkg/front_end/test/fasta/types/fasta_types_test
-            (leftNullability == Nullability.legacy &&
-                rightNullability == Nullability.nullable) ||
-            // pkg/front_end/test/fasta/types/kernel_type_parser_test
-            // pkg/front_end/test/fasta/types/fasta_types_test
-            (leftNullability == Nullability.nonNullable &&
-                rightNullability == Nullability.nullable) ||
-            // pkg/front_end/test/fasta/types/kernel_type_parser_test
-            // pkg/front_end/test/fasta/types/fasta_types_test
-            (leftNullability == Nullability.undetermined &&
-                rightNullability == Nullability.legacy) ||
-            // pkg/kernel/test/clone_test
-            // The legacy nullability is due to RHS being InvalidType.
-            (leftNullability == Nullability.nonNullable &&
-                rightNullability == Nullability.legacy),
-        "Unexpected nullabilities for ${left} & ${right}: "
-        "leftNullability = ${leftNullability}, "
-        "rightNullability = ${rightNullability}.");
-  }
-
-  @override
-  DartType get nonTypeVariableBound {
-    DartType resolvedTypeParameterType = right.nonTypeVariableBound;
-    return resolvedTypeParameterType.withDeclaredNullability(
-        combineNullabilitiesForSubstitution(
-            inner: resolvedTypeParameterType.declaredNullability,
-            outer: declaredNullability));
-  }
-
-  @override
-  bool get hasNonObjectMemberAccess =>
-      nonTypeVariableBound.hasNonObjectMemberAccess;
-
-  @override
-  R accept<R>(DartTypeVisitor<R> v) => v.visitIntersectionType(this);
-
-  @override
-  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
-      v.visitIntersectionType(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    left.accept(v);
-    right.accept(v);
-  }
-
-  @override
-  bool equals(Object other, Assumptions? assumptions) {
-    if (identical(this, other)) {
-      return true;
-    } else if (other is IntersectionType) {
-      return left.equals(other.left, assumptions) &&
-          right.equals(other.right, assumptions);
-    } else {
-      return false;
-    }
-  }
-
-  @override
-  int get hashCode {
-    int nullabilityHash = (0x33333333 >> nullability.index) ^ 0x33333333;
-    int hash = nullabilityHash;
-    hash = 0x3fffffff & (hash * 31 + (hash ^ left.hashCode));
-    hash = 0x3fffffff & (hash * 31 + (hash ^ right.hashCode));
-    return hash;
-  }
-
-  /// Computes the nullability of [IntersectionType] from its parts.
-  ///
-  /// [nullability] is calculated from [left.nullability] and
-  /// [right.nullability].
-  ///
-  /// In the following program the nullability of `x` is
-  /// [Nullability.undetermined] because it's copied from that of `bar`. The
-  /// nullability of `y` is [Nullability.nonNullable] because its type is an
-  /// intersection type where the LHS is `T` and the RHS is the promoted type
-  /// `int`. The nullability of the type of `y` is computed from the
-  /// nullabilities of those two types.
-  ///
-  ///     class A<T extends Object?> {
-  ///       foo(T bar) {
-  ///         var x = bar;
-  ///         if (bar is int) {
-  ///           var y = bar;
-  ///         }
-  ///       }
-  ///     }
-  ///
-  /// The method combines the nullabilities of [left] and [right] to yield the
-  /// nullability of the intersection type.
-  @override
-  Nullability get nullability {
-    // Note that RHS is always a subtype of the bound of the type parameter.
-
-    // The code below implements the rule for the nullability of an
-    // intersection type as per the following table:
-    //
-    // | LHS \ RHS |  !  |  ?  |  *  |  %  |
-    // |-----------|-----|-----|-----|-----|
-    // |     !     |  !  |  +  | N/A |  !  |
-    // |     ?     | (!) | (?) | N/A | (%) |
-    // |     *     | (*) |  +  |  *  | N/A |
-    // |     %     |  !  |  %  |  +  |  %  |
-    //
-    // In the table, LHS corresponds to [lhsNullability] in the code below; RHS
-    // corresponds to [rhsNullability]; !, ?, *, and % correspond to
-    // nonNullable, nullable, legacy, and undetermined values of the
-    // Nullability enum.
-
-    Nullability lhsNullability = left.nullability;
-    Nullability rhsNullability = right.nullability;
-    assert(
-        (lhsNullability == Nullability.nonNullable &&
-                rhsNullability == Nullability.nonNullable) ||
-            (lhsNullability == Nullability.nonNullable &&
-                rhsNullability == Nullability.undetermined) ||
-            (lhsNullability == Nullability.legacy &&
-                rhsNullability == Nullability.legacy) ||
-            (lhsNullability == Nullability.undetermined &&
-                rhsNullability == Nullability.nonNullable) ||
-            (lhsNullability == Nullability.undetermined &&
-                rhsNullability == Nullability.nullable) ||
-            (lhsNullability == Nullability.undetermined &&
-                rhsNullability == Nullability.undetermined)
-            // Apparently these happens as well:
-            ||
-            // pkg/front_end/test/id_tests/type_promotion_test
-            (lhsNullability == Nullability.nullable &&
-                rhsNullability == Nullability.nonNullable) ||
-            // pkg/front_end/test/fasta/types/kernel_type_parser_test
-            // pkg/front_end/test/fasta/incremental_hello_test
-            // pkg/front_end/test/fasta/types/fasta_types_test
-            // pkg/front_end/tool/fasta_perf_test
-            // nnbd/issue42089
-            (lhsNullability == Nullability.nullable &&
-                rhsNullability == Nullability.nullable) ||
-            // pkg/front_end/test/dill_round_trip_test
-            // pkg/front_end/test/compile_dart2js_with_no_sdk_test
-            // pkg/front_end/test/fasta/types/large_app_benchmark_test
-            // pkg/front_end/test/incremental_dart2js_test
-            // pkg/front_end/test/read_dill_from_binary_md_test
-            // pkg/front_end/test/static_types/static_type_test
-            // pkg/front_end/test/split_dill_test
-            // pkg/front_end/tool/incremental_perf_test
-            // pkg/vm/test/kernel_front_end_test
-            // general/promoted_null_aware_access
-            // inference/constructors_infer_from_arguments_factory
-            // inference/infer_types_on_loop_indices_for_each_loop
-            // inference/infer_types_on_loop_indices_for_each_loop_async
-            (lhsNullability == Nullability.legacy &&
-                rhsNullability == Nullability.nonNullable) ||
-            // pkg/front_end/test/fasta/incremental_hello_test
-            // pkg/front_end/tool/fasta_perf_test
-            // pkg/front_end/test/fasta/incremental_hello_test
-            (lhsNullability == Nullability.nullable &&
-                rhsNullability == Nullability.undetermined) ||
-
-            // This is created but never observed.
-            // (lhsNullability == Nullability.legacy &&
-            //     rhsNullability == Nullability.nullable) ||
-
-            // pkg/front_end/test/fasta/types/kernel_type_parser_test
-            // pkg/front_end/test/fasta/types/fasta_types_test
-            (lhsNullability == Nullability.undetermined &&
-                rhsNullability == Nullability.legacy) ||
-            // pkg/front_end/test/fasta/types/kernel_type_parser_test
-            // pkg/front_end/test/fasta/types/fasta_types_test
-            (lhsNullability == Nullability.nonNullable &&
-                rhsNullability == Nullability.nullable),
-        "Unexpected nullabilities for: LHS nullability = $lhsNullability, "
-        "RHS nullability = ${rhsNullability}.");
-
-    // Whenever there's N/A in the table, it means that the corresponding
-    // combination of the LHS and RHS nullability is not possible when
-    // compiling from Dart source files, so we can define it to be whatever is
-    // faster and more convenient to implement.  The verifier should check that
-    // the cases marked as N/A never occur in the output of the CFE.
-    //
-    // The code below uses the following extension of the table function:
-    //
-    // | LHS \ RHS |  !  |  ?  |  *  |  %  |
-    // |-----------|-----|-----|-----|-----|
-    // |     !     |  !  |  !  |  !  |  !  |
-    // |     ?     | (!) | (?) |  *  | (%) |
-    // |     *     | (*) |  *  |  *  |  %  |
-    // |     %     |  !  |  %  |  %  |  %  |
-
-    if (lhsNullability == Nullability.nullable &&
-        rhsNullability == Nullability.nonNullable) {
-      return Nullability.nonNullable;
-    }
-
-    if (lhsNullability == Nullability.nullable &&
-        rhsNullability == Nullability.nullable) {
-      return Nullability.nullable;
-    }
-
-    if (lhsNullability == Nullability.legacy &&
-        rhsNullability == Nullability.nonNullable) {
-      return Nullability.legacy;
-    }
-
-    if (lhsNullability == Nullability.nullable &&
-        rhsNullability == Nullability.undetermined) {
-      return Nullability.undetermined;
-    }
-
-    // Intersection with a non-nullable type always yields a non-nullable type,
-    // as it's the most restrictive kind of types.
-    if (lhsNullability == Nullability.nonNullable ||
-        rhsNullability == Nullability.nonNullable) {
-      return Nullability.nonNullable;
-    }
-
-    // If the nullability of LHS is 'undetermined', the nullability of the
-    // intersection is also 'undetermined' if RHS is 'undetermined' or
-    // nullable.
-    //
-    // Consider the following example:
-    //
-    //     class A<X extends Object?, Y extends X> {
-    //       foo(X x) {
-    //         if (x is Y) {
-    //           x = null;     // Compile-time error.  Consider X = Y = int.
-    //           Object a = x; // Compile-time error.  Consider X = Y = int?.
-    //         }
-    //         if (x is int?) {
-    //           x = null;     // Compile-time error.  Consider X = int.
-    //           Object b = x; // Compile-time error.  Consider X = int?.
-    //         }
-    //       }
-    //     }
-    if (lhsNullability == Nullability.undetermined ||
-        rhsNullability == Nullability.undetermined) {
-      return Nullability.undetermined;
-    }
-
-    return Nullability.legacy;
-  }
-
-  @override
-  Nullability get declaredNullability => nullability;
-
-  @override
-  IntersectionType withDeclaredNullability(Nullability declaredNullability) {
-    if (left.declaredNullability == declaredNullability) {
-      return this;
-    }
-    TypeParameterType newLeft =
-        left.withDeclaredNullability(declaredNullability);
-    if (identical(newLeft, left)) {
-      return this;
-    }
-    return new IntersectionType(newLeft, right);
-  }
-
-  @override
-  String toString() {
-    return "IntersectionType(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('(');
-    printer.writeType(left);
-    printer.write(" & ");
-    printer.writeType(right);
-    printer.write(')');
-    printer.writeNullability(nullability);
-  }
-}
-
-/// Reference to a type variable.
-class TypeParameterType extends DartType {
-  /// The declared nullability of a type-parameter type.
-  @override
-  Nullability declaredNullability;
-
-  final TypeParameter parameter;
-
-  TypeParameterType(this.parameter, this.declaredNullability);
-
-  /// Creates a type-parameter type to be used in alpha-renaming.
-  ///
-  /// The constructed type object is supposed to be used as a value in a
-  /// substitution map created to perform an alpha-renaming from parameter
-  /// [from] to parameter [to] on a generic type.  The resulting type-parameter
-  /// type is an occurrence of [to] as a type, but the nullability property is
-  /// derived from the bound of [from].  It allows to assign the bound to [to]
-  /// after the desired alpha-renaming is performed, which is often the case.
-  TypeParameterType.forAlphaRenaming(TypeParameter from, TypeParameter to)
-      : this(to, computeNullabilityFromBound(from));
-
-  TypeParameterType.forAlphaRenamingFromStructuralParameters(
-      StructuralParameter from, TypeParameter to)
-      : this(to, StructuralParameterType.computeNullabilityFromBound(from));
-
-  /// Creates a type-parameter type with default nullability for the library.
-  ///
-  /// The nullability is computed as if the programmer omitted the modifier. It
-  /// means that in the opt-out libraries `Nullability.legacy` will be used, and
-  /// in opt-in libraries either `Nullability.nonNullable` or
-  /// `Nullability.undetermined` will be used, depending on the nullability of
-  /// the bound of [parameter].
-  TypeParameterType.withDefaultNullabilityForLibrary(
-      this.parameter, Library library)
-      : declaredNullability = computeNullabilityFromBound(parameter);
-
-  @override
-  DartType get nonTypeVariableBound {
-    DartType resolvedTypeParameterType = bound.nonTypeVariableBound;
-    return resolvedTypeParameterType.withDeclaredNullability(
-        combineNullabilitiesForSubstitution(
-            inner: resolvedTypeParameterType.declaredNullability,
-            outer: declaredNullability));
-  }
-
-  @override
-  bool get hasNonObjectMemberAccess =>
-      nonTypeVariableBound.hasNonObjectMemberAccess;
-
-  @override
-  R accept<R>(DartTypeVisitor<R> v) => v.visitTypeParameterType(this);
-
-  @override
-  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
-      v.visitTypeParameterType(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {}
-
-  @override
-  bool equals(Object other, Assumptions? assumptions) {
-    if (identical(this, other)) {
-      return true;
-    } else if (other is TypeParameterType) {
-      if (nullability != other.nullability) return false;
-      return parameter == other.parameter;
-    } else {
-      return false;
-    }
-  }
-
-  @override
-  int get hashCode {
-    int hash = parameter.hashCode;
-    int nullabilityHash = (0x33333333 >> nullability.index) ^ 0x33333333;
-    hash = 0x3fffffff & (hash * 31 + (hash ^ nullabilityHash));
-    return hash;
-  }
-
-  /// A quick access to the bound of the parameter.
-  DartType get bound => parameter.bound;
-
-  @override
-  Nullability get nullability => declaredNullability;
-
-  /// Gets a new [TypeParameterType] with given [declaredNullability].
-  @override
-  TypeParameterType withDeclaredNullability(Nullability declaredNullability) {
-    if (declaredNullability == this.declaredNullability) {
-      return this;
-    }
-    return new TypeParameterType(parameter, declaredNullability);
-  }
-
-  /// Gets the nullability of a type-parameter type based on the bound.
-  ///
-  /// This is a helper function to be used when the bound of the type parameter
-  /// is changing or is being set for the first time, and the update on some
-  /// type-parameter types is required.
-  static Nullability computeNullabilityFromBound(TypeParameter typeParameter) {
-    // If the bound is nullable or 'undetermined', both nullable and
-    // non-nullable types can be passed in for the type parameter, making the
-    // corresponding type parameter types 'undetermined.'  Otherwise, the
-    // nullability matches that of the bound.
-    DartType bound = typeParameter.bound;
-    if (identical(bound, TypeParameter.unsetBoundSentinel)) {
-      throw new StateError("Can't compute nullability from an absent bound.");
-    }
-
-    // If a type parameter's nullability depends on itself, it is deemed
-    // 'undetermined'. Currently, it's possible if the type parameter has a
-    // possibly nested FutureOr containing that type parameter.  If there are
-    // other ways for such a dependency to exist, they should be checked here.
-    bool nullabilityDependsOnItself = false;
-    {
-      DartType type = typeParameter.bound;
-      while (type is FutureOrType) {
-        type = type.typeArgument;
-      }
-      if (type is TypeParameterType && type.parameter == typeParameter) {
-        nullabilityDependsOnItself = true;
-      }
-    }
-    if (nullabilityDependsOnItself) {
-      return Nullability.undetermined;
-    }
-
-    Nullability boundNullability =
-        bound is InvalidType ? Nullability.undetermined : bound.nullability;
-    return boundNullability == Nullability.nullable ||
-            boundNullability == Nullability.undetermined
-        ? Nullability.undetermined
-        : boundNullability;
-  }
-
-  @override
-  String toString() {
-    return "TypeParameterType(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeTypeParameterName(parameter);
-    printer.writeNullability(declaredNullability);
-  }
-}
-
-/// Reference to a structural type variable declared by a [FunctionType]
-class StructuralParameterType extends DartType {
-  /// The declared nullability of the structural parameter type.
-  @override
-  Nullability declaredNullability;
-
-  final StructuralParameter parameter;
-
-  StructuralParameterType(this.parameter, this.declaredNullability);
-
-  /// Creates a structural parameter type to be used in alpha-renaming.
-  ///
-  /// The constructed type object is supposed to be used as a value in a
-  /// substitution map created to perform an alpha-renaming from the parameter
-  /// [from] to the parameter [to] on a generic type. The resulting structural
-  /// parameter type is an occurrence of [to] as a type, but the nullability
-  /// property is derived from the bound of [from].
-  ///
-  /// A typical use of this constructor is to create a [StructuralParameterType]
-  /// referring to [StructuralParameter] [from] that is not fully formed yet and
-  /// may miss a bound. In case of alpha renaming it is assumed that nothing but
-  /// the identity of the variables change, and the bound of the parameter being
-  /// replaced can be used to compute the nullability of the replacement.
-  StructuralParameterType.forAlphaRenaming(
-      StructuralParameter from, StructuralParameter to)
-      : this(to, computeNullabilityFromBound(from));
-
-  StructuralParameterType.forAlphaRenamingFromTypeParameters(
-      TypeParameter from, StructuralParameter to)
-      : this(to, TypeParameterType.computeNullabilityFromBound(from));
-
-  @override
-  DartType get nonTypeVariableBound {
-    DartType resolvedTypeParameterType = bound.nonTypeVariableBound;
-    return resolvedTypeParameterType.withDeclaredNullability(
-        combineNullabilitiesForSubstitution(
-            inner: resolvedTypeParameterType.nullability,
-            outer: declaredNullability));
-  }
-
-  @override
-  bool get hasNonObjectMemberAccess =>
-      nonTypeVariableBound.hasNonObjectMemberAccess;
-
-  @override
-  R accept<R>(DartTypeVisitor<R> v) => v.visitStructuralParameterType(this);
-
-  @override
-  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
-      v.visitStructuralParameterType(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {}
-
-  @override
-  bool operator ==(Object other) => equals(other, null);
-
-  @override
-  bool equals(Object other, Assumptions? assumptions) {
-    if (identical(this, other)) {
-      return true;
-    } else if (other is StructuralParameterType) {
-      if (nullability != other.nullability) return false;
-      if (parameter != other.parameter) {
-        // Function type parameters are also equal by assumption.
-        if (assumptions == null) {
-          return false;
-        }
-        if (!assumptions.isAssumedStructuralParameter(
-            parameter, other.parameter)) {
-          return false;
-        }
-      }
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  @override
-  int get hashCode {
-    int hash = 0;
-    int nullabilityHash = (0x33333333 >> nullability.index) ^ 0x33333333;
-    hash = 0x3fffffff & (hash * 31 + (hash ^ nullabilityHash));
-    return hash;
-  }
-
-  /// A quick access to the bound of the parameter.
-  DartType get bound => parameter.bound;
-
-  @override
-  Nullability get nullability => declaredNullability;
-
-  /// Gets a new [StructuralParameterType] with given [declaredNullability].
-  @override
-  StructuralParameterType withDeclaredNullability(
-      Nullability declaredNullability) {
-    if (declaredNullability == this.declaredNullability) {
-      return this;
-    }
-    return new StructuralParameterType(parameter, declaredNullability);
-  }
-
-  /// Gets the nullability of a structural parameter type based on the bound.
-  ///
-  /// This is a helper function to be used when the bound of the structural
-  /// parameter is changing or is being set for the first time, and the update
-  /// on some structural parameter types is required.
-  static Nullability computeNullabilityFromBound(
-      StructuralParameter structuralParameter) {
-    // If the bound is nullable or 'undetermined', both nullable and
-    // non-nullable types can be passed in for the type parameter, making the
-    // corresponding type parameter types 'undetermined.'  Otherwise, the
-    // nullability matches that of the bound.
-    DartType bound = structuralParameter.bound;
-    if (identical(bound, StructuralParameter.unsetBoundSentinel)) {
-      throw new StateError("Can't compute nullability from an absent bound.");
-    }
-
-    // If a type parameter's nullability depends on itself, it is deemed
-    // 'undetermined'. Currently, it's possible if the type parameter has a
-    // possibly nested FutureOr containing that type parameter.  If there are
-    // other ways for such a dependency to exist, they should be checked here.
-    bool nullabilityDependsOnItself = false;
-    {
-      DartType type = structuralParameter.bound;
-      while (type is FutureOrType) {
-        type = type.typeArgument;
-      }
-      if (type is StructuralParameterType &&
-          type.parameter == structuralParameter) {
-        nullabilityDependsOnItself = true;
-      }
-    }
-    if (nullabilityDependsOnItself) {
-      return Nullability.undetermined;
-    }
-
-    Nullability boundNullability =
-        bound is InvalidType ? Nullability.undetermined : bound.nullability;
-    return boundNullability == Nullability.nullable ||
-            boundNullability == Nullability.undetermined
-        ? Nullability.undetermined
-        : boundNullability;
-  }
-
-  @override
-  String toString() {
-    return "StructuralParameterType(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeStructuralParameterName(parameter);
-    printer.writeNullability(declaredNullability);
-  }
-}
-
-class RecordType extends DartType
-    implements SharedRecordTypeStructure<DartType> {
-  final List<DartType> positional;
-  final List<NamedType> named;
-
-  @override
-  final Nullability declaredNullability;
-
-  RecordType(this.positional, this.named, this.declaredNullability)
-      : /*TODO(johnniwinther): Enabled this assert:
-        assert(named.length == named.map((p) => p.name).toSet().length,
-            "Named field types must have unique names in a RecordType: "
-            "${named}"),*/
-        assert(() {
-          // Assert that the named field types are sorted.
-          for (int i = 1; i < named.length; i++) {
-            if (named[i].name.compareTo(named[i - 1].name) < 0) {
-              return false;
-            }
-          }
-          return true;
-        }(),
-            "Named field types aren't sorted lexicographically "
-            "in a RecordType: ${named}");
-
-  @override
-  List<SharedNamedTypeStructure<DartType>> get namedTypes => named;
-
-  @override
-  Nullability get nullability => declaredNullability;
-
-  @override
-  DartType get nonTypeVariableBound => this;
-
-  @override
-  bool get hasNonObjectMemberAccess => switch (declaredNullability) {
-        Nullability.undetermined => false,
-        Nullability.nullable => false,
-        Nullability.nonNullable => true,
-        Nullability.legacy => true,
-      };
-
-  @override
-  List<DartType> get positionalTypes => positional;
-
-  @override
-  R accept<R>(DartTypeVisitor<R> v) {
-    return v.visitRecordType(this);
-  }
-
-  @override
-  R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) {
-    return v.visitRecordType(this, arg);
-  }
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(positional, v);
-    visitList(named, v);
-  }
-
-  @override
-  bool equals(Object other, Assumptions? assumptions) {
-    if (identical(this, other)) {
-      return true;
-    } else if (other is RecordType) {
-      if (nullability != other.nullability) return false;
-      if (positional.length != other.positional.length) return false;
-      if (named.length != other.named.length) return false;
-      for (int index = 0; index < positional.length; index++) {
-        if (!positional[index].equals(other.positional[index], assumptions)) {
-          return false;
-        }
-      }
-      for (int index = 0; index < named.length; index++) {
-        if (!named[index].equals(other.named[index], assumptions)) {
-          return false;
-        }
-      }
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  @override
-  int get hashCode {
-    int hash = 1237;
-    for (int i = 0; i < positional.length; ++i) {
-      hash = 0x3fffffff & (hash * 31 + positional[i].hashCode);
-    }
-    for (int i = 0; i < named.length; ++i) {
-      hash = 0x3fffffff & (hash * 31 + named[i].hashCode);
-    }
-    hash = 0x3fffffff & (hash * 31 + nullability.index);
-    return hash;
-  }
-
-  @override
-  RecordType withDeclaredNullability(Nullability declaredNullability) {
-    return declaredNullability == this.declaredNullability
-        ? this
-        : new RecordType(this.positional, this.named, declaredNullability);
-  }
-
-  @override
-  String toString() {
-    return "RecordType(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write("(");
-    printer.writeTypes(positional);
-    if (named.isNotEmpty) {
-      if (positional.isNotEmpty) {
-        printer.write(", ");
-      }
-      printer.write("{");
-      for (int i = 0; i < named.length; i++) {
-        if (i > 0) {
-          printer.write(", ");
-        }
-        printer.writeType(named[i].type);
-        printer.write(' ');
-        printer.write(named[i].name);
-      }
-      printer.write("}");
-    }
-    printer.write(")");
-  }
-}
-
-/// Declaration of a type variable.
-///
-/// Type parameters declared in a [Class] or [FunctionNode] are part of the AST,
-/// have a parent pointer to its declaring class or function, and will be seen
-/// by tree visitors.
-///
-/// Type parameters declared by a [FunctionType] are orphans and have a `null`
-/// parent pointer.  [TypeParameter] objects should not be shared between
-/// different [FunctionType] objects.
-class TypeParameter extends TreeNode implements Annotatable {
-  int flags = 0;
-
-  /// List of metadata annotations on the type parameter.
-  ///
-  /// This defaults to an immutable empty list. Use [addAnnotation] to add
-  /// annotations if needed.
-  @override
-  List<Expression> annotations = const <Expression>[];
-
-  String? name; // Cosmetic name.
-
-  /// Sentinel value used for the [bound] that has not yet been computed. This
-  /// is needed to make the [bound] field non-nullable while supporting
-  /// recursive bounds.
-  static final DartType unsetBoundSentinel = new InvalidType();
-
-  /// The bound on the type variable.
-  ///
-  /// This is set to [unsetBoundSentinel] temporarily during IR construction.
-  /// This is set to the `Object?` for type parameters without an explicit
-  /// bound.
-  DartType bound;
-
-  /// Sentinel value used for the [defaultType] that has not yet been computed.
-  /// This is needed to make the [defaultType] field non-nullable while
-  /// supporting recursive bounds for which the default type need to be set
-  /// late.
-  static final DartType unsetDefaultTypeSentinel = new InvalidType();
-
-  /// The default value of the type variable. It is used to provide the
-  /// corresponding missing type argument in type annotations and as the
-  /// fall-back type value in type inference at compile time. At run time,
-  /// [defaultType] is used by the backends in place of the missing type
-  /// argument of a dynamic invocation of a generic function.
-  DartType defaultType;
-
-  /// Describes variance of the type parameter w.r.t. declaration on which it is
-  /// defined. For classes, if variance is not explicitly set, the type
-  /// parameter has legacy covariance defined by [isLegacyCovariant] which
-  /// on the lattice is equivalent to [Variance.covariant]. For typedefs, it's
-  /// the variance of the type parameters in the type term on the r.h.s. of the
-  /// typedef.
-  Variance? _variance;
-
-  Variance get variance => _variance ?? Variance.covariant;
-
-  void set variance(Variance? newVariance) => _variance = newVariance;
-
-  bool get isLegacyCovariant => _variance == null;
-
-  static const int legacyCovariantSerializationMarker = 4;
-
-  TypeParameter([this.name, DartType? bound, DartType? defaultType])
-      : bound = bound ?? unsetBoundSentinel,
-        defaultType = defaultType ?? unsetDefaultTypeSentinel;
-
-  // Must match serialized bit positions.
-  static const int FlagCovariantByClass = 1 << 0;
-
-  @Deprecated("Used TypeParameter.declaration instead.")
-  @override
-  TreeNode? get parent;
-
-  @Deprecated("Used TypeParameter.declaration instead.")
-  @override
-  void set parent(TreeNode? value);
-
-  // TODO(johnniwinther): Make this non-nullable.
-  GenericDeclaration? get declaration {
-    // TODO(johnniwinther): Store the declaration directly when [parent] is
-    // removed.
-    TreeNode? parent = super.parent;
-    if (parent is GenericDeclaration) {
-      return parent;
-    } else if (parent is FunctionNode) {
-      return parent.parent as GenericDeclaration;
-    }
-    assert(
-        parent == null,
-        "Unexpected type parameter parent node "
-        "${parent} (${parent.runtimeType}).");
-    return null;
-  }
-
-  void set declaration(GenericDeclaration? value) {
-    switch (value) {
-      case Typedef():
-      case Class():
-      case Extension():
-      case ExtensionTypeDeclaration():
-        super.parent = value;
-      case Procedure():
-        super.parent = value.function;
-      case LocalFunction():
-        super.parent = value.function;
-      case null:
-        super.parent = null;
-    }
-  }
-
-  /// If this [TypeParameter] is a type parameter of a generic method, indicates
-  /// whether the method implementation needs to contain a runtime type check to
-  /// deal with generic covariance.
-  ///
-  /// When `true`, runtime checks may need to be performed.
-  bool get isCovariantByClass => flags & FlagCovariantByClass != 0;
-
-  void set isCovariantByClass(bool value) {
-    flags = value
-        ? (flags | FlagCovariantByClass)
-        : (flags & ~FlagCovariantByClass);
-  }
-
-  @override
-  void addAnnotation(Expression annotation) {
-    if (annotations.isEmpty) {
-      annotations = <Expression>[];
-    }
-    annotations.add(annotation..parent = this);
-  }
-
-  @override
-  R accept<R>(TreeVisitor<R> v) => v.visitTypeParameter(this);
-
-  @override
-  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) =>
-      v.visitTypeParameter(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(annotations, v);
-    bound.accept(v);
-    defaultType.accept(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    v.transformList(annotations, this);
-    bound = v.visitDartType(bound);
-    defaultType = v.visitDartType(defaultType);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    v.transformExpressionList(annotations, this);
-    bound = v.visitDartType(bound, cannotRemoveSentinel);
-    defaultType = v.visitDartType(defaultType, cannotRemoveSentinel);
-  }
-
-  /// Returns a possibly synthesized name for this type parameter, consistent
-  /// with the names used across all [toString] calls.
-  @override
-  String toString() {
-    return "TypeParameter(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeTypeParameterName(this);
-  }
-}
-
-/// Declaration of a type variable by a [FunctionType]
-///
-/// [StructuralParameter] objects should not be shared between different
-/// [FunctionType] objects.
-class StructuralParameter extends Node
-    implements SharedTypeParameterStructure<DartType> {
-  int flags = 0;
-
-  String? name; // Cosmetic name.
-
-  static const int noOffset = -1;
-
-  /// Offset in the source file it comes from.
-  ///
-  /// Valid values are from 0 and up, or -1 ([noOffset]) if the file offset is
-  /// not available (this is the default if none is specifically set).
-  int fileOffset = noOffset;
-
-  Uri? uri;
-
-  /// Sentinel value used for the [bound] that has not yet been computed.
-  ///
-  /// This is needed to make the [bound] field non-nullable while supporting
-  /// recursive bounds.
-  static final DartType unsetBoundSentinel = new InvalidType();
-
-  /// The bound on the type variable.
-  ///
-  /// This is set to [unsetBoundSentinel] temporarily during IR construction.
-  /// This is set to the `Object?` for type parameters without an explicit
-  /// bound.
-  DartType bound;
-
-  /// Sentinel value used for the [defaultType] that has not yet been computed.
-  ///
-  /// This is needed to make the [defaultType] field non-nullable while
-  /// supporting recursive bounds for which the default type need to be set
-  /// late.
-  static final DartType unsetDefaultTypeSentinel = new InvalidType();
-
-  /// The default value of the type variable.
-  ///
-  /// It is used to provide the corresponding missing type argument in type
-  /// annotations and as the fall-back type value in type inference at compile
-  /// time. At run time, [defaultType] is used by the backends in place of the
-  /// missing type argument of a dynamic invocation of a generic function.
-  DartType defaultType;
-
-  /// Variance of type parameter w.r.t. declaration on which it is defined.
-  Variance? _variance;
-
-  @override
-  String get displayName => name ?? '<unknown>';
-
-  Variance get variance => _variance ?? Variance.covariant;
-
-  void set variance(Variance? newVariance) => _variance = newVariance;
-
-  bool get isLegacyCovariant => _variance == null;
-
-  static const int legacyCovariantSerializationMarker = 4;
-
-  StructuralParameter([this.name, DartType? bound, DartType? defaultType])
-      : bound = bound ?? unsetBoundSentinel,
-        defaultType = defaultType ?? unsetDefaultTypeSentinel;
-
-  @override
-  R accept<R>(Visitor<R> v) => v.visitStructuralParameter(this);
-
-  @override
-  R accept1<R, A>(Visitor1<R, A> v, A arg) =>
-      v.visitStructuralParameter(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    bound.accept(v);
-    defaultType.accept(v);
-  }
-
-  /// Returns a possibly synthesized name for this type parameter
-  ///
-  /// Consistent with the names used across all [toString] calls.
-  @override
-  String toString() {
-    return "StructuralParameter(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeStructuralParameterName(this);
-  }
-}
-
-class Supertype extends Node {
-  Reference className;
-  final List<DartType> typeArguments;
-
-  Supertype(Class classNode, List<DartType> typeArguments)
-      : this.byReference(classNode.reference, typeArguments);
-
-  Supertype.byReference(this.className, this.typeArguments);
-
-  Class get classNode => className.asClass;
-
-  @override
-  R accept<R>(Visitor<R> v) => v.visitSupertype(this);
-
-  @override
-  R accept1<R, A>(Visitor1<R, A> v, A arg) => v.visitSupertype(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    classNode.acceptReference(v);
-    visitList(typeArguments, v);
-  }
-
-  InterfaceType get asInterfaceType {
-    return new InterfaceType(
-        classNode, classNode.enclosingLibrary.nonNullable, typeArguments);
-  }
-
-  @override
-  bool operator ==(Object other) {
-    if (identical(this, other)) return true;
-    if (other is Supertype) {
-      if (className != other.className) return false;
-      if (typeArguments.length != other.typeArguments.length) return false;
-      for (int i = 0; i < typeArguments.length; ++i) {
-        if (typeArguments[i] != other.typeArguments[i]) return false;
-      }
-      return true;
-    } else {
-      return false;
-    }
-  }
-
-  @override
-  int get hashCode {
-    int hash = 0x3fffffff & className.hashCode;
-    for (int i = 0; i < typeArguments.length; ++i) {
-      hash = 0x3fffffff & (hash * 31 + (hash ^ typeArguments[i].hashCode));
-    }
-    return hash;
-  }
-
-  @override
-  String toString() {
-    return "Supertype(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeClassName(className, forType: true);
-    printer.writeTypeArguments(typeArguments);
-  }
-}
-
-// ------------------------------------------------------------------------
-//                             CONSTANTS
-// ------------------------------------------------------------------------
-
-sealed class Constant extends Node {
-  /// Calls the `visit*ConstantReference()` method on visitor [v] for all
-  /// constants referenced in this constant.
-  ///
-  /// (Note that a constant can be seen as a DAG (directed acyclic graph) and
-  ///  not a tree!)
-  @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>(ConstantReferenceVisitor<R> v);
-
-  /// Calls the `visit*ConstantReference()` method on the visitor [v].
-  R acceptReference1<R, A>(ConstantReferenceVisitor1<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.
-  DartType getType(StaticTypeContext context);
-}
-
-abstract class AuxiliaryConstant extends Constant {
-  @override
-  R accept<R>(ConstantVisitor<R> v) => v.visitAuxiliaryConstant(this);
-
-  @override
-  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
-      v.visitAuxiliaryConstant(this, arg);
-
-  @override
-  R acceptReference<R>(ConstantReferenceVisitor<R> v) =>
-      v.visitAuxiliaryConstantReference(this);
-
-  @override
-  R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) =>
-      v.visitAuxiliaryConstantReference(this, arg);
-}
-
-sealed class PrimitiveConstant<T> extends Constant {
-  final T value;
-
-  PrimitiveConstant(this.value);
-
-  @override
-  int get hashCode => value.hashCode;
-
-  @override
-  bool operator ==(Object other) =>
-      other is PrimitiveConstant<T> && other.value == value;
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('$value');
-  }
-}
-
-class NullConstant extends PrimitiveConstant<Null> {
-  NullConstant() : super(null);
-
-  @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>(ConstantReferenceVisitor<R> v) =>
-      v.visitNullConstantReference(this);
-
-  @override
-  R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) =>
-      v.visitNullConstantReference(this, arg);
-
-  @override
-  DartType getType(StaticTypeContext context) => const NullType();
-
-  @override
-  String toString() => 'NullConstant(${toStringInternal()})';
-}
-
-class BoolConstant extends PrimitiveConstant<bool> {
-  BoolConstant(bool value) : super(value);
-
-  @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>(ConstantReferenceVisitor<R> v) =>
-      v.visitBoolConstantReference(this);
-
-  @override
-  R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) =>
-      v.visitBoolConstantReference(this, arg);
-
-  @override
-  DartType getType(StaticTypeContext context) =>
-      context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
-
-  @override
-  String toString() => 'BoolConstant(${toStringInternal()})';
-}
-
-/// An integer constant on a non-JS target.
-class IntConstant extends PrimitiveConstant<int> {
-  IntConstant(int value) : super(value);
-
-  @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>(ConstantReferenceVisitor<R> v) =>
-      v.visitIntConstantReference(this);
-
-  @override
-  R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) =>
-      v.visitIntConstantReference(this, arg);
-
-  @override
-  DartType getType(StaticTypeContext context) =>
-      context.typeEnvironment.coreTypes.intRawType(context.nonNullable);
-
-  @override
-  String toString() => 'IntConstant(${toStringInternal()})';
-}
-
-/// A double constant on a non-JS target or any numeric constant on a JS target.
-class DoubleConstant extends PrimitiveConstant<double> {
-  DoubleConstant(double value) : super(value);
-
-  @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>(ConstantReferenceVisitor<R> v) =>
-      v.visitDoubleConstantReference(this);
-
-  @override
-  R acceptReference1<R, A>(ConstantReferenceVisitor1<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);
-
-  @override
-  String toString() => 'DoubleConstant(${toStringInternal()})';
-}
-
-class StringConstant extends PrimitiveConstant<String> {
-  StringConstant(String value) : super(value);
-
-  @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>(ConstantReferenceVisitor<R> v) =>
-      v.visitStringConstantReference(this);
-
-  @override
-  R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) =>
-      v.visitStringConstantReference(this, arg);
-
-  @override
-  DartType getType(StaticTypeContext context) =>
-      context.typeEnvironment.coreTypes.stringRawType(context.nonNullable);
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('"');
-    printer.write(escapeString(value));
-    printer.write('"');
-  }
-
-  @override
-  String toString() => 'StringConstant(${toStringInternal()})';
-}
-
-class SymbolConstant extends Constant {
-  final String name;
-  final Reference? libraryReference;
-
-  SymbolConstant(this.name, this.libraryReference);
-
-  @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>(ConstantReferenceVisitor<R> v) =>
-      v.visitSymbolConstantReference(this);
-
-  @override
-  R acceptReference1<R, A>(ConstantReferenceVisitor1<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);
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('#');
-    if (printer.includeAuxiliaryProperties && libraryReference != null) {
-      printer.write(libraryNameToString(libraryReference!.asLibrary));
-      printer.write('::');
-    }
-    printer.write(name);
-  }
-}
-
-class MapConstant extends Constant {
-  final DartType keyType;
-  final DartType valueType;
-  final List<ConstantMapEntry> entries;
-
-  MapConstant(this.keyType, this.valueType, this.entries);
-
-  @override
-  void visitChildren(Visitor v) {
-    keyType.accept(v);
-    valueType.accept(v);
-    for (final ConstantMapEntry entry in entries) {
-      entry.key.acceptReference(v);
-      entry.value.acceptReference(v);
-    }
-  }
-
-  @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>(ConstantReferenceVisitor<R> v) =>
-      v.visitMapConstantReference(this);
-
-  @override
-  R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) =>
-      v.visitMapConstantReference(this, arg);
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('const <');
-    printer.writeType(keyType);
-    printer.write(', ');
-    printer.writeType(valueType);
-    printer.write('>{');
-    for (int i = 0; i < entries.length; i++) {
-      if (i > 0) {
-        printer.write(', ');
-      }
-      printer.writeConstantMapEntry(entries[i]);
-    }
-    printer.write('}');
-  }
-
-  @override
-  String toString() => 'MapConstant(${toStringInternal()})';
-
-  @override
-  late final int hashCode = _Hash.combine2Finish(
-      keyType.hashCode, valueType.hashCode, _Hash.combineListHash(entries));
-
-  @override
-  bool operator ==(Object other) =>
-      identical(this, other) ||
-      (other is MapConstant &&
-          other.keyType == keyType &&
-          other.valueType == valueType &&
-          listEquals(other.entries, entries));
-
-  @override
-  DartType getType(StaticTypeContext context) =>
-      context.typeEnvironment.mapType(keyType, valueType, context.nonNullable);
-}
-
-class ConstantMapEntry {
-  final Constant key;
-  final Constant value;
-  ConstantMapEntry(this.key, this.value);
-
-  @override
-  String toString() => 'ConstantMapEntry(${toStringInternal()})';
-
-  @override
-  int get hashCode => _Hash.hash2(key, value);
-
-  @override
-  bool operator ==(Object other) =>
-      other is ConstantMapEntry && other.key == key && other.value == value;
-
-  String toStringInternal() => toText(defaultAstTextStrategy);
-
-  String toText(AstTextStrategy strategy) {
-    AstPrinter printer = new AstPrinter(strategy);
-    printer.writeConstantMapEntry(this);
-    return printer.getText();
-  }
-
-  void toTextInternal(AstPrinter printer) {
-    printer.writeConstant(key);
-    printer.write(': ');
-    printer.writeConstant(value);
-  }
-}
-
-class ListConstant extends Constant {
-  final DartType typeArgument;
-  final List<Constant> entries;
-
-  ListConstant(this.typeArgument, this.entries);
-
-  @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>(ConstantReferenceVisitor<R> v) =>
-      v.visitListConstantReference(this);
-
-  @override
-  R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) =>
-      v.visitListConstantReference(this, arg);
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('const <');
-    printer.writeType(typeArgument);
-    printer.write('>[');
-    for (int i = 0; i < entries.length; i++) {
-      if (i > 0) {
-        printer.write(', ');
-      }
-      printer.writeConstant(entries[i]);
-    }
-    printer.write(']');
-  }
-
-  @override
-  String toString() => 'ListConstant(${toStringInternal()})';
-
-  @override
-  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);
-}
-
-class SetConstant extends Constant {
-  final DartType typeArgument;
-  final List<Constant> entries;
-
-  SetConstant(this.typeArgument, this.entries);
-
-  @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>(ConstantReferenceVisitor<R> v) =>
-      v.visitSetConstantReference(this);
-
-  @override
-  R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) =>
-      v.visitSetConstantReference(this, arg);
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('const <');
-    printer.writeType(typeArgument);
-    printer.write('>{');
-    for (int i = 0; i < entries.length; i++) {
-      if (i > 0) {
-        printer.write(', ');
-      }
-      printer.writeConstant(entries[i]);
-    }
-    printer.write('}');
-  }
-
-  @override
-  String toString() => 'SetConstant(${toStringInternal()})';
-
-  @override
-  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);
-}
-
-class RecordConstant extends Constant {
-  /// Positional field values.
-  final List<Constant> positional;
-
-  /// Named field values, sorted by name.
-  final Map<String, Constant> named;
-
-  /// The runtime type of the constant.
-  ///
-  /// [recordType] is computed from the individual types of the record fields
-  /// and reflects runtime type of the record constant, as opposed to the
-  /// static type of the expression that defined the constant.
-  ///
-  /// The following program shows the distinction between the static and the
-  /// runtime types of the constant. The static type of the first record in the
-  /// invocation of `identical` is `(E, String)`, the static type of the second
-  /// — `(int, String)`. The runtime type of both constants is `(int, String)`,
-  /// and the assertion condition should be satisfied.
-  ///
-  ///   extension type const E(Object? it) {}
-  ///
-  ///   main() {
-  ///     const bool check = identical(const (E(1), "foo"), const (1, "foo"));
-  ///     assert(check);
-  ///   }
-  final RecordType recordType;
-
-  RecordConstant(this.positional, this.named, this.recordType)
-      : assert(positional.length == recordType.positional.length &&
-            named.length == recordType.named.length &&
-            recordType.named
-                .map((f) => f.name)
-                .toSet()
-                .containsAll(named.keys)),
-        assert(() {
-          // Assert that the named fields are sorted.
-          String? previous;
-          for (String name in named.keys) {
-            if (previous != null && name.compareTo(previous) < 0) {
-              return false;
-            }
-            previous = name;
-          }
-          return true;
-        }(),
-            "Named fields of a RecordConstant aren't sorted lexicographically: "
-            "${named.keys.join(", ")}");
-
-  RecordConstant.fromTypeContext(
-      this.positional, this.named, StaticTypeContext staticTypeContext)
-      : recordType = new RecordType([
-          for (Constant constant in positional)
-            constant.getType(staticTypeContext)
-        ], [
-          for (var MapEntry(key: name, value: constant) in named.entries)
-            new NamedType(name, constant.getType(staticTypeContext))
-        ], staticTypeContext.nonNullable);
-
-  @override
-  void visitChildren(Visitor v) {
-    recordType.accept(v);
-    for (final Constant entry in positional) {
-      entry.acceptReference(v);
-    }
-    for (final Constant entry in named.values) {
-      entry.acceptReference(v);
-    }
-  }
-
-  @override
-  R accept<R>(ConstantVisitor<R> v) => v.visitRecordConstant(this);
-
-  @override
-  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
-      v.visitRecordConstant(this, arg);
-
-  @override
-  R acceptReference<R>(ConstantReferenceVisitor<R> v) =>
-      v.visitRecordConstantReference(this);
-
-  @override
-  R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) =>
-      v.visitRecordConstantReference(this, arg);
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write("const (");
-    String comma = '';
-    for (Constant entry in positional) {
-      printer.write(comma);
-      printer.writeConstant(entry);
-      comma = ', ';
-    }
-    if (named.isNotEmpty) {
-      printer.write(comma);
-      comma = '';
-      printer.write("{");
-      for (MapEntry<String, Constant> entry in named.entries) {
-        printer.write(comma);
-        printer.write(entry.key);
-        printer.write(": ");
-        printer.writeConstant(entry.value);
-        comma = ', ';
-      }
-      printer.write("}");
-    }
-    printer.write(")");
-  }
-
-  @override
-  String toString() => "RecordConstant(${toStringInternal()})";
-
-  @override
-  late final int hashCode =
-      _Hash.combineMapHashUnordered(named, _Hash.combineListHash(positional));
-
-  @override
-  bool operator ==(Object other) =>
-      identical(this, other) ||
-      (other is RecordConstant &&
-          listEquals(other.positional, positional) &&
-          mapEquals(other.named, named));
-
-  @override
-  DartType getType(StaticTypeContext context) => recordType;
-}
-
-class InstanceConstant extends Constant {
-  final Reference classReference;
-  final List<DartType> typeArguments;
-  final Map<Reference, Constant> fieldValues;
-
-  InstanceConstant(this.classReference, this.typeArguments, this.fieldValues);
-
-  Class get classNode => classReference.asClass;
-
-  @override
-  void visitChildren(Visitor v) {
-    classReference.asClass.acceptReference(v);
-    visitList(typeArguments, v);
-    for (final Reference reference in fieldValues.keys) {
-      reference.asField.acceptReference(v);
-    }
-    for (final Constant constant in fieldValues.values) {
-      constant.acceptReference(v);
-    }
-  }
-
-  @override
-  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>(ConstantReferenceVisitor<R> v) =>
-      v.visitInstanceConstantReference(this);
-
-  @override
-  R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) =>
-      v.visitInstanceConstantReference(this, arg);
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('const ');
-    printer.writeClassName(classReference);
-    printer.writeTypeArguments(typeArguments);
-    printer.write('{');
-    String comma = '';
-    fieldValues.forEach((Reference fieldRef, Constant constant) {
-      printer.write(comma);
-      printer.writeMemberName(fieldRef);
-      printer.write(': ');
-      printer.writeConstant(constant);
-      comma = ', ';
-    });
-    printer.write('}');
-  }
-
-  @override
-  String toString() => 'InstanceConstant(${toStringInternal()})';
-
-  @override
-  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 &&
-            other.classReference == classReference &&
-            listEquals(other.typeArguments, typeArguments) &&
-            mapEquals(other.fieldValues, fieldValues));
-  }
-
-  @override
-  DartType getType(StaticTypeContext context) =>
-      new InterfaceType(classNode, context.nonNullable, typeArguments);
-}
-
-class InstantiationConstant extends Constant {
-  final Constant tearOffConstant;
-  final List<DartType> types;
-
-  InstantiationConstant(this.tearOffConstant, this.types);
-
-  @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>(ConstantReferenceVisitor<R> v) =>
-      v.visitInstantiationConstantReference(this);
-
-  @override
-  R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) =>
-      v.visitInstantiationConstantReference(this, arg);
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeConstant(tearOffConstant);
-    printer.writeTypeArguments(types);
-  }
-
-  @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;
-    return FunctionTypeInstantiator.instantiate(type, types);
-  }
-}
-
-abstract class TearOffConstant implements Constant {
-  Reference get targetReference;
-  Member get target;
-  FunctionNode get function;
-}
-
-class StaticTearOffConstant extends Constant implements TearOffConstant {
-  @override
-  final Reference targetReference;
-
-  StaticTearOffConstant(Procedure target)
-      : assert(target.isStatic),
-        assert(target.kind == ProcedureKind.Method,
-            "Unexpected static tear off target: $target"),
-        targetReference = target.reference;
-
-  StaticTearOffConstant.byReference(this.targetReference);
-
-  @override
-  Procedure get target => targetReference.asProcedure;
-
-  @override
-  FunctionNode get function => target.function;
-
-  @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>(ConstantReferenceVisitor<R> v) =>
-      v.visitStaticTearOffConstantReference(this);
-
-  @override
-  R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) =>
-      v.visitStaticTearOffConstantReference(this, arg);
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeMemberName(targetReference);
-  }
-
-  @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);
-  }
-}
-
-class ConstructorTearOffConstant extends Constant implements TearOffConstant {
-  @override
-  final Reference targetReference;
-
-  ConstructorTearOffConstant(Member target)
-      : assert(
-            target is Constructor || (target is Procedure && target.isFactory),
-            "Unexpected constructor tear off target: $target"),
-        this.targetReference = getNonNullableMemberReferenceGetter(target);
-
-  ConstructorTearOffConstant.byReference(this.targetReference);
-
-  @override
-  Member get target => targetReference.asMember;
-
-  @override
-  FunctionNode get function => target.function!;
-
-  @override
-  void visitChildren(Visitor v) {
-    target.acceptReference(v);
-  }
-
-  @override
-  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>(ConstantReferenceVisitor<R> v) =>
-      v.visitConstructorTearOffConstantReference(this);
-
-  @override
-  R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) =>
-      v.visitConstructorTearOffConstantReference(this, arg);
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeMemberName(targetReference);
-  }
-
-  @override
-  String toString() => 'ConstructorTearOffConstant(${toStringInternal()})';
-
-  @override
-  int get hashCode => targetReference.hashCode;
-
-  @override
-  bool operator ==(Object other) {
-    return other is ConstructorTearOffConstant &&
-        other.targetReference == targetReference;
-  }
-
-  @override
-  FunctionType getType(StaticTypeContext context) {
-    return function.computeFunctionType(context.nonNullable);
-  }
-}
-
-class RedirectingFactoryTearOffConstant extends Constant
-    implements TearOffConstant {
-  @override
-  final Reference targetReference;
-
-  RedirectingFactoryTearOffConstant(Procedure target)
-      : assert(target.isRedirectingFactory),
-        this.targetReference = getNonNullableMemberReferenceGetter(target);
-
-  RedirectingFactoryTearOffConstant.byReference(this.targetReference);
-
-  @override
-  Procedure get target => targetReference.asProcedure;
-
-  @override
-  FunctionNode get function => target.function;
-
-  @override
-  void visitChildren(Visitor v) {
-    target.acceptReference(v);
-  }
-
-  @override
-  R accept<R>(ConstantVisitor<R> v) =>
-      v.visitRedirectingFactoryTearOffConstant(this);
-
-  @override
-  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
-      v.visitRedirectingFactoryTearOffConstant(this, arg);
-
-  @override
-  R acceptReference<R>(ConstantReferenceVisitor<R> v) =>
-      v.visitRedirectingFactoryTearOffConstantReference(this);
-
-  @override
-  R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) =>
-      v.visitRedirectingFactoryTearOffConstantReference(this, arg);
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeMemberName(targetReference);
-  }
-
-  @override
-  String toString() =>
-      'RedirectingFactoryTearOffConstant(${toStringInternal()})';
-
-  @override
-  int get hashCode => targetReference.hashCode;
-
-  @override
-  bool operator ==(Object other) {
-    return other is RedirectingFactoryTearOffConstant &&
-        other.targetReference == targetReference;
-  }
-
-  @override
-  FunctionType getType(StaticTypeContext context) {
-    return function.computeFunctionType(context.nonNullable);
-  }
-}
-
-class TypedefTearOffConstant extends Constant {
-  final List<StructuralParameter> parameters;
-  final TearOffConstant tearOffConstant;
-  final List<DartType> types;
-
-  @override
-  late final int hashCode = _computeHashCode();
-
-  TypedefTearOffConstant(this.parameters, this.tearOffConstant, this.types);
-
-  @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>(ConstantReferenceVisitor<R> v) =>
-      v.visitTypedefTearOffConstantReference(this);
-
-  @override
-  R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) =>
-      v.visitTypedefTearOffConstantReference(this, arg);
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeStructuralParameters(parameters);
-    printer.writeConstant(tearOffConstant);
-    printer.writeTypeArguments(types);
-  }
-
-  @override
-  String toString() => 'TypedefTearOffConstant(${toStringInternal()})';
-
-  @override
-  bool operator ==(Object other) {
-    if (other is! TypedefTearOffConstant) return false;
-    if (other.tearOffConstant != tearOffConstant) return false;
-    if (other.parameters.length != parameters.length) return false;
-    if (parameters.isNotEmpty) {
-      Assumptions assumptions = new Assumptions();
-      for (int index = 0; index < parameters.length; index++) {
-        assumptions.assumeStructuralParameter(
-            parameters[index], other.parameters[index]);
-      }
-      for (int index = 0; index < parameters.length; index++) {
-        if (!parameters[index]
-            .bound
-            .equals(other.parameters[index].bound, assumptions)) {
-          return false;
-        }
-      }
-      for (int i = 0; i < types.length; ++i) {
-        if (!types[i].equals(other.types[i], assumptions)) {
-          return false;
-        }
-      }
-    }
-    return true;
-  }
-
-  int _computeHashCode() {
-    int hash = 1237;
-    for (int i = 0; i < parameters.length; ++i) {
-      StructuralParameter parameter = parameters[i];
-      hash = 0x3fffffff & (hash * 31 + parameter.bound.hashCode);
-    }
-    for (int i = 0; i < types.length; ++i) {
-      hash = 0x3fffffff & (hash * 31 + types[i].hashCode);
-    }
-    hash = 0x3fffffff & (hash * 31 + tearOffConstant.hashCode);
-    return hash;
-  }
-
-  @override
-  DartType getType(StaticTypeContext context) {
-    FunctionType type = tearOffConstant.getType(context) as FunctionType;
-    FreshStructuralParameters freshStructuralParameters =
-        getFreshStructuralParameters(parameters);
-    type = freshStructuralParameters.substitute(
-        FunctionTypeInstantiator.instantiate(type, types)) as FunctionType;
-    return new FunctionType(
-        type.positionalParameters, type.returnType, type.declaredNullability,
-        namedParameters: type.namedParameters,
-        typeParameters: freshStructuralParameters.freshTypeParameters,
-        requiredParameterCount: type.requiredParameterCount);
-  }
-}
-
-class TypeLiteralConstant extends Constant {
-  final DartType type;
-
-  TypeLiteralConstant(this.type);
-
-  @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>(ConstantReferenceVisitor<R> v) =>
-      v.visitTypeLiteralConstantReference(this);
-
-  @override
-  R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) =>
-      v.visitTypeLiteralConstantReference(this, arg);
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.writeType(type);
-  }
-
-  @override
-  String toString() => 'TypeLiteralConstant(${toStringInternal()})';
-
-  @override
-  int get hashCode => type.hashCode;
-
-  @override
-  bool operator ==(Object other) {
-    return other is TypeLiteralConstant && other.type == type;
-  }
-
-  @override
-  DartType getType(StaticTypeContext context) =>
-      context.typeEnvironment.coreTypes.typeRawType(context.nonNullable);
-}
-
-class UnevaluatedConstant extends Constant {
-  final Expression expression;
-
-  UnevaluatedConstant(this.expression) {
-    expression.parent = null;
-  }
-
-  @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>(ConstantReferenceVisitor<R> v) =>
-      v.visitUnevaluatedConstantReference(this);
-
-  @override
-  R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) =>
-      v.visitUnevaluatedConstantReference(this, arg);
-
-  @override
-  DartType getType(StaticTypeContext context) =>
-      expression.getStaticType(context);
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    printer.write('unevaluated{');
-    printer.writeExpression(expression);
-    printer.write('}');
-  }
-
-  @override
-  String toString() {
-    return "UnevaluatedConstant(${toStringInternal()})";
-  }
-
-  @override
-  int get hashCode => expression.hashCode;
-
-  @override
-  bool operator ==(Object other) {
-    return other is UnevaluatedConstant && other.expression == expression;
-  }
-}
-
-// ------------------------------------------------------------------------
-//                                COMPONENT
-// ------------------------------------------------------------------------
-
-/// A way to bundle up libraries in a component.
-class Component extends TreeNode {
-  final CanonicalName root;
-
-  /// Problems in this [Component] encoded as json objects.
-  ///
-  /// Note that this field can be null, and by convention should be null if the
-  /// list is empty.
-  List<String>? problemsAsJson;
-
-  final List<Library> libraries;
-
-  /// Map from a source file URI to a line-starts table and source code.
-  /// Given a source file URI and a offset in that file one can translate
-  /// it to a line:column position in that file.
-  final Map<Uri, Source> uriToSource;
-
-  /// Mapping between string tags and [MetadataRepository] corresponding to
-  /// those tags.
-  final Map<String, MetadataRepository<dynamic>> metadata =
-      <String, MetadataRepository<dynamic>>{};
-
-  /// Reference to the main method in one of the libraries.
-  Reference? _mainMethodName;
-  Reference? get mainMethodName => _mainMethodName;
-  NonNullableByDefaultCompiledMode? _mode;
-  NonNullableByDefaultCompiledMode get mode {
-    return _mode ?? NonNullableByDefaultCompiledMode.Strong;
-  }
-
-  NonNullableByDefaultCompiledMode? get modeRaw => _mode;
-
-  Component(
-      {CanonicalName? nameRoot,
-      List<Library>? libraries,
-      Map<Uri, Source>? uriToSource,
-      NonNullableByDefaultCompiledMode? mode})
-      : root = nameRoot ?? new CanonicalName.root(),
-        libraries = libraries ?? <Library>[],
-        uriToSource = uriToSource ?? <Uri, Source>{},
-        _mode = mode {
-    adoptChildren();
-  }
-
-  void adoptChildren() {
-    for (int i = 0; i < libraries.length; ++i) {
-      // The libraries are owned by this component, and so are their canonical
-      // names if they exist.
-      Library library = libraries[i];
-      library.parent = this;
-      CanonicalName? name = library.reference.canonicalName;
-      if (name != null && name.parent != root) {
-        root.adoptChild(name);
-      }
-    }
-  }
-
-  void computeCanonicalNames() {
-    for (int i = 0; i < libraries.length; ++i) {
-      computeCanonicalNamesForLibrary(libraries[i]);
-    }
-  }
-
-  /// This is an advanced feature. Use of this method should be coordinated
-  /// with the kernel team.
-  ///
-  /// Makes sure all references in named nodes in this component points to said
-  /// named node.
-  ///
-  /// The use case is advanced incremental compilation, where we want to rebuild
-  /// a single library and make all other libraries use the new library and the
-  /// content therein *while* having the option to go back to pointing (be
-  /// "linked") to the old library if the delta is rejected.
-  ///
-  /// Please note that calling this is a potentially dangerous thing to do,
-  /// and that stuff *can* go wrong, and you could end up in a situation where
-  /// you point to several versions of "the same" library. Examples:
-  ///  * If you only relink part (e.g. a class) if your component you can wind
-  ///    up in an unfortunate situation where if the library (say libA) contains
-  ///    class 'B' and class 'C', you only replace 'B' (with one in library
-  ///    'libAPrime'), everything pointing to 'B' via parent pointers talks
-  ///    about 'libAPrime', whereas everything pointing to 'C' would still
-  ///    ultimately point to 'libA'.
-  ///  * If you relink to a library that doesn't have exactly the same members
-  ///    as the one you're "linking from" you can wind up in an unfortunate
-  ///    situation, e.g. if the thing you relink two is missing a static method,
-  ///    any links to that static method will still point to the old static
-  ///    method and thus (via parent pointers) to the old library.
-  ///  * (probably more).
-  void relink() {
-    for (int i = 0; i < libraries.length; ++i) {
-      libraries[i].relink();
-    }
-  }
-
-  void computeCanonicalNamesForLibrary(Library library) {
-    library.ensureCanonicalNames(root);
-  }
-
-  void unbindCanonicalNames() {
-    // TODO(jensj): Get rid of this.
-    for (int i = 0; i < libraries.length; i++) {
-      Library lib = libraries[i];
-      for (int j = 0; j < lib.classes.length; j++) {
-        Class c = lib.classes[j];
-        c.dirty = true;
-      }
-    }
-    root.unbindAll();
-  }
-
-  Procedure? get mainMethod => mainMethodName?.asProcedure;
-
-  void setMainMethodAndMode(Reference? main, bool overwriteMainIfSet,
-      NonNullableByDefaultCompiledMode mode) {
-    if (_mainMethodName == null || overwriteMainIfSet) {
-      _mainMethodName = main;
-    }
-    _mode = mode;
-  }
-
-  @override
-  R accept<R>(TreeVisitor<R> v) => v.visitComponent(this);
-
-  @override
-  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitComponent(this, arg);
-
-  @override
-  void visitChildren(Visitor v) {
-    visitList(libraries, v);
-    mainMethod?.acceptReference(v);
-  }
-
-  @override
-  void transformChildren(Transformer v) {
-    v.transformList(libraries, this);
-  }
-
-  @override
-  void transformOrRemoveChildren(RemovingTransformer v) {
-    v.transformLibraryList(libraries, this);
-  }
-
-  @override
-  Component get enclosingComponent => this;
-
-  /// Translates an offset to line and column numbers in the given file.
-  Location? getLocation(Uri file, int offset, {String? viaForErrorMessage}) {
-    return uriToSource[file]
-        ?.getLocation(file, offset, viaForErrorMessage: viaForErrorMessage);
-  }
-
-  /// Translates line and column numbers to an offset in the given file.
-  ///
-  /// Returns offset of the line and column in the file, or -1 if the
-  /// source is not available or has no lines.
-  /// Throws [RangeError] if line or calculated offset are out of range.
-  int getOffset(Uri file, int line, int column) {
-    return uriToSource[file]?.getOffset(line, column) ?? -1;
-  }
-
-  void addMetadataRepository(MetadataRepository repository) {
-    metadata[repository.tag] = repository;
-  }
-
-  @override
-  String toString() {
-    return "Component(${toStringInternal()})";
-  }
-
-  @override
-  void toTextInternal(AstPrinter printer) {
-    // TODO(johnniwinther): Implement this.
-  }
-
-  @override
-  String leakingDebugToString() => astToText.debugComponentToString(this);
-}
-
-/// A tuple with file, line, and column number, for displaying human-readable
-/// locations.
-class Location {
-  final Uri file;
-  final int line; // 1-based.
-  final int column; // 1-based.
-
-  Location(this.file, this.line, this.column);
-
-  @override
-  String toString() => '$file:$line:$column';
-}
-
-abstract class MetadataRepository<T> {
-  /// Unique string tag associated with this repository.
-  String get tag;
-
-  /// Mutable mapping between nodes and their metadata.
-  Map<Node, T> get mapping;
-
-  /// Write [metadata] object corresponding to the given [Node] into
-  /// the given [BinarySink].
-  ///
-  /// Metadata is serialized immediately before serializing [node],
-  /// so implementation of this method can use serialization context of
-  /// [node]'s parents (such as declared type parameters and variables).
-  /// In order to use scope declared by the [node] itself, implementation of
-  /// this method can use [BinarySink.enterScope] and [BinarySink.leaveScope]
-  /// methods.
-  ///
-  /// [metadata] must be an object owned by this repository.
-  void writeToBinary(T metadata, Node node, BinarySink sink);
-
-  /// Construct a metadata object from its binary payload read from the
-  /// given [BinarySource].
-  ///
-  /// Metadata is deserialized immediately after deserializing [node],
-  /// so it can use deserialization context of [node]'s parents.
-  /// In order to use scope declared by the [node] itself, implementation of
-  /// this method can use [BinarySource.enterScope] and
-  /// [BinarySource.leaveScope] methods.
-  T readFromBinary(Node node, BinarySource source);
-
-  /// Method to check whether a node can have metadata attached to it
-  /// or referenced from the metadata payload.
-  ///
-  /// Currently due to binary format specifics Catch and MapEntry nodes
-  /// can't have metadata attached to them. Also, metadata is not saved on
-  /// Block nodes inside BlockExpressions.
-  static bool isSupported(Node node) {
-    return !(node is MapLiteralEntry ||
-        node is Catch ||
-        (node is Block && node.parent is BlockExpression));
-  }
-}
-
-abstract class BinarySink {
-  void writeByte(int byte);
-  void writeUInt32(int value);
-  void writeUInt30(int value);
-
-  /// Write List<Byte> into the sink.
-  void writeByteList(List<int> bytes);
-
-  void writeNullAllowedCanonicalNameReference(Reference? reference);
-  void writeStringReference(String str);
-  void writeDartType(DartType type);
-  void writeConstantReference(Constant constant);
-}
-
-abstract class BinarySource {
-  int readByte();
-  int readUInt30();
-  int readUint32();
-
-  /// Read List<Byte> from the source.
-  List<int> readByteList();
-
-  CanonicalName? readNullableCanonicalNameReference();
-  String readStringReference();
-  DartType readDartType();
-  Constant readConstantReference();
-}
-
-// ------------------------------------------------------------------------
-//                             INTERNAL FUNCTIONS
-// ------------------------------------------------------------------------
-
-void setParents(List<TreeNode> nodes, TreeNode parent) {
-  for (int i = 0; i < nodes.length; ++i) {
-    nodes[i].parent = parent;
-  }
-}
-
-void visitList(List<Node> nodes, Visitor visitor) {
-  for (int i = 0; i < nodes.length; ++i) {
-    nodes[i].accept(visitor);
-  }
-}
-
-void visitIterable(Iterable<Node> nodes, Visitor visitor) {
-  for (Node node in nodes) {
-    node.accept(visitor);
-  }
-}
-
-class _ChildReplacer extends Transformer {
-  final TreeNode child;
-  final TreeNode replacement;
-
-  _ChildReplacer(this.child, this.replacement);
-
-  @override
-  TreeNode defaultTreeNode(TreeNode node) {
-    if (node == child) {
-      return replacement;
-    } else {
-      return node;
-    }
-  }
-}
-
-class Source {
-  static final Uint8List _emptySource = new Uint8List(0);
-  final List<int>? lineStarts;
-
-  /// A UTF8 encoding of the original source file.
-  final Uint8List source;
-
-  final Uri? importUri;
-
-  final Uri? fileUri;
-
-  Set<Reference>? constantCoverageConstructors;
-
-  String? cachedText;
-
-  Source(this.lineStarts, this.source, this.importUri, this.fileUri);
-
-  Source.emptySource(this.lineStarts, this.importUri, this.fileUri)
-      : source = _emptySource;
-
-  /// Return the text corresponding to [line] which is a 1-based line
-  /// number. The returned line contains no line separators.
-  String? getTextLine(int line) {
-    List<int>? lineStarts = this.lineStarts;
-    if (source.isEmpty || lineStarts == null || lineStarts.isEmpty) {
-      return null;
-    }
-    RangeError.checkValueInInterval(line, 1, lineStarts.length, 'line');
-
-    String cachedText = text;
-    // -1 as line numbers start at 1.
-    int index = line - 1;
-    if (index + 1 == lineStarts.length) {
-      // Last line.
-      return cachedText.substring(lineStarts[index]);
-    } else if (index < lineStarts.length) {
-      // We subtract 1 from the next line for two reasons:
-      // 1. If the file isn't terminated by a newline, that index is invalid.
-      // 2. To remove the newline at the end of the line.
-      int endOfLine = lineStarts[index + 1] - 1;
-      if (endOfLine > index && cachedText[endOfLine - 1] == "\r") {
-        --endOfLine; // Windows line endings.
-      }
-      return cachedText.substring(lineStarts[index], endOfLine);
-    }
-    // This shouldn't happen: should have been caught by the range check above.
-    throw "Internal error";
-  }
-
-  String get text => cachedText ??= utf8.decode(source, allowMalformed: true);
-
-  /// Translates an offset to 1-based line and column numbers in the given file.
-  Location getLocation(Uri file, int offset, {String? viaForErrorMessage}) {
-    List<int>? lineStarts = this.lineStarts;
-    if (lineStarts == null || lineStarts.isEmpty) {
-      return new Location(file, TreeNode.noOffset, TreeNode.noOffset);
-    }
-    if (viaForErrorMessage != null) {
-      RangeError.checkValueInInterval(
-          offset,
-          0,
-          lineStarts.last,
-          'offset',
-          'Asked for out-of-bounds offset for uri "$file" '
-              'via $viaForErrorMessage');
-    } else {
-      RangeError.checkValueInInterval(offset, 0, lineStarts.last, 'offset',
-          'Asked for out-of-bounds offset for uri "$file"');
-    }
-    int low = 0, high = lineStarts.length - 1;
-    while (low < high) {
-      int mid = high - ((high - low) >> 1); // Get middle, rounding up.
-      int pivot = lineStarts[mid];
-      if (pivot <= offset) {
-        low = mid;
-      } else {
-        high = mid - 1;
-      }
-    }
-    int lineIndex = low;
-    int lineStart = lineStarts[lineIndex];
-    int lineNumber = 1 + lineIndex;
-    int columnNumber = 1 + offset - lineStart;
-    return new Location(file, lineNumber, columnNumber);
-  }
-
-  /// Translates 1-based line and column numbers to an offset in the given file
-  ///
-  /// Returns offset of the line and column in the file, or -1 if the source
-  /// has no lines.
-  /// Throws [RangeError] if line or calculated offset are out of range.
-  int getOffset(int line, int column) {
-    List<int>? lineStarts = this.lineStarts;
-    if (lineStarts == null || lineStarts.isEmpty) {
-      return -1;
-    }
-    RangeError.checkValueInInterval(line, 1, lineStarts.length, 'line');
-    int offset = lineStarts[line - 1] + column - 1;
-    RangeError.checkValueInInterval(offset, 0, lineStarts.last, 'offset');
-    return offset;
-  }
-}
-
-/// Returns the [Reference] object for the given member based on the
-/// ProcedureKind.
-///
-/// Returns `null` if the member is `null`.
-Reference? getMemberReferenceBasedOnProcedureKind(
-    Member? member, ProcedureKind kind) {
-  if (member == null) return null;
-  if (member is Field) {
-    if (kind == ProcedureKind.Setter) return member.setterReference!;
-    return member.getterReference;
-  }
-  return member.reference;
-}
-
-/// Returns the (getter) [Reference] object for the given member.
-///
-/// Returns `null` if the member is `null`.
-/// TODO(jensj): Should it be called NotSetter instead of Getter?
-Reference? getMemberReferenceGetter(Member? member) {
-  if (member == null) return null;
-  return getNonNullableMemberReferenceGetter(member);
-}
-
-Reference getNonNullableMemberReferenceGetter(Member member) {
-  if (member is Field) return member.getterReference;
-  return member.reference;
-}
-
-Reference getNonNullableMemberReferenceSetter(Member member) {
-  if (member is Field) return member.setterReference!;
-  return member.reference;
-}
-
-/// Murmur-inspired hashing, with a fall-back to Jenkins-inspired hashing when
-/// compiled to JavaScript.
-///
-/// A hash function should be constructed of several [combine] calls followed by
-/// a [finish] call.
-class _Hash {
-  static const int M = 0x9ddfea08eb382000 + 0xd69;
-  static const bool intIs64Bit = (1 << 63) != 0;
-
-  /// Primitive hash combining step.
-  static int combine(int value, int hash) {
-    if (intIs64Bit) {
-      value *= M;
-      value ^= _shru(value, 47);
-      value *= M;
-      hash ^= value;
-      hash *= M;
-    } else {
-      // Fall back to Jenkins-inspired hashing on JavaScript platforms.
-      hash = 0x1fffffff & (hash + value);
-      hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
-      hash = hash ^ (hash >> 6);
-    }
-    return hash;
-  }
-
-  /// Primitive hash finalization step.
-  static int finish(int hash) {
-    if (intIs64Bit) {
-      hash ^= _shru(hash, 44);
-      hash *= M;
-      hash ^= _shru(hash, 41);
-    } else {
-      // Fall back to Jenkins-inspired hashing on JavaScript platforms.
-      hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
-      hash = hash ^ (hash >> 11);
-      hash = 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
-    }
-    return hash;
-  }
-
-  static int combineFinish(int value, int hash) {
-    return finish(combine(value, hash));
-  }
-
-  static int combine2(int value1, int value2, int hash) {
-    return combine(value2, combine(value1, hash));
-  }
-
-  static int combine2Finish(int value1, int value2, int hash) {
-    return finish(combine2(value1, value2, hash));
-  }
-
-  static int hash2(Object object1, Object? object2) {
-    return combine2Finish(object2.hashCode, object2.hashCode, 0);
-  }
-
-  static int combineListHash(List<Object> list, [int hash = 1]) {
-    for (Object item in list) {
-      hash = _Hash.combine(item.hashCode, hash);
-    }
-    return hash;
-  }
-
-  static int combineList(List<int> hashes, int hash) {
-    for (int item in hashes) {
-      hash = combine(item, hash);
-    }
-    return hash;
-  }
-
-  static int combineMapHashUnordered(Map? map, [int hash = 2]) {
-    if (map == null || map.isEmpty) return hash;
-    List<int> entryHashes = List.filled(
-        map.length,
-        // `-1` is used as a dummy default value.
-        -1);
-    int i = 0;
-    for (MapEntry entry in map.entries) {
-      entryHashes[i++] = combine(entry.key.hashCode, entry.value.hashCode);
-    }
-    entryHashes.sort();
-    return combineList(entryHashes, hash);
-  }
-
-  // TODO(sra): Replace with '>>>'.
-  static int _shru(int v, int n) {
-    assert(n >= 1);
-    assert(intIs64Bit);
-    return ((v >> 1) & (0x7fffFFFFffffF000 + 0xFFF)) >> (n - 1);
-  }
-}
-
-int listHashCode(List<Object> list) {
-  return _Hash.finish(_Hash.combineListHash(list));
-}
-
-bool listEquals(List a, List b) {
-  if (a.length != b.length) return false;
-  for (int i = 0; i < a.length; i++) {
-    if (a[i] != b[i]) return false;
-  }
-  return true;
-}
-
-bool mapEquals(Map a, Map b) {
-  if (a.length != b.length) return false;
-  for (final Object key in a.keys) {
-    if (!b.containsKey(key) || a[key] != b[key]) return false;
-  }
-  return true;
-}
-
-/// Annotation describing information which is not part of Dart semantics; in
-/// other words, if this information (or any information it refers to) changes,
-/// static analysis and runtime behavior of the library are unaffected.
-const Null informative = null;
-
-Location? _getLocationInComponent(Component? component, Uri fileUri, int offset,
-    {required String viaForErrorMessage}) {
-  if (component != null) {
-    return component.getLocation(fileUri, offset,
-        viaForErrorMessage: viaForErrorMessage);
-  } else {
-    return new Location(fileUri, TreeNode.noOffset, TreeNode.noOffset);
-  }
-}
-
-/// Convert the synthetic name of an implicit mixin application class
-/// into a name suitable for user-faced strings.
-///
-/// For example, when compiling "class A extends S with M1, M2", the
-/// two synthetic classes will be named "_A&S&M1" and "_A&S&M1&M2".
-/// This function will return "S with M1" and "S with M1, M2", respectively.
-String demangleMixinApplicationName(String name) {
-  List<String> nameParts = name.split('&');
-  if (nameParts.length < 2 || name == "&") return name;
-  String demangledName = nameParts[1];
-  for (int i = 2; i < nameParts.length; i++) {
-    demangledName += (i == 2 ? " with " : ", ") + nameParts[i];
-  }
-  return demangledName;
-}
-
-/// Extract from the synthetic name of an implicit mixin application class
-/// the name of the final subclass of the mixin application.
-///
-/// For example, when compiling "class A extends S with M1, M2", the
-/// two synthetic classes will be named "_A&S&M1" and "_A&S&M1&M2".
-/// This function will return "A" for both classes.
-String demangleMixinApplicationSubclassName(String name) {
-  List<String> nameParts = name.split('&');
-  if (nameParts.length < 2) return name;
-  assert(nameParts[0].startsWith('_'));
-  return nameParts[0].substring(1);
-}
-
-/// Computes a list of [typeParameters] taken as types.
-List<DartType> getAsTypeArguments(
-    List<TypeParameter> typeParameters, Library library) {
-  if (typeParameters.isEmpty) return const <DartType>[];
-  return new List<DartType>.generate(
-      typeParameters.length,
-      (int i) => new TypeParameterType.withDefaultNullabilityForLibrary(
-          typeParameters[i], library),
-      growable: false);
-}
-
-class Version extends Object {
-  final int major;
-  final int minor;
-
-  const Version(this.major, this.minor);
-
-  bool operator <(Version other) {
-    if (major < other.major) return true;
-    if (major > other.major) return false;
-
-    // Major is the same.
-    if (minor < other.minor) return true;
-    return false;
-  }
-
-  bool operator <=(Version other) {
-    if (major < other.major) return true;
-    if (major > other.major) return false;
-
-    // Major is the same.
-    if (minor <= other.minor) return true;
-    return false;
-  }
-
-  bool operator >(Version other) {
-    if (major > other.major) return true;
-    if (major < other.major) return false;
-
-    // Major is the same.
-    if (minor > other.minor) return true;
-    return false;
-  }
-
-  bool operator >=(Version other) {
-    if (major > other.major) return true;
-    if (major < other.major) return false;
-
-    // Major is the same.
-    if (minor >= other.minor) return true;
-    return false;
-  }
-
-  /// Returns this language version as a 'major.minor' text.
-  String toText() => '${major}.${minor}';
-
-  @override
-  int get hashCode {
-    return major.hashCode * 13 + minor.hashCode * 17;
-  }
-
-  @override
-  bool operator ==(Object other) {
-    if (identical(this, other)) return true;
-    return other is Version && major == other.major && minor == other.minor;
-  }
-
-  @override
-  String toString() {
-    return "Version(major=$major, minor=$minor)";
-  }
-}
-
-/// Almost const <NamedExpression>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<NamedExpression> emptyListOfNamedExpression =
-    List.filled(0, dummyNamedExpression, growable: false);
-
-/// Almost const <VariableDeclaration>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<VariableDeclaration> emptyListOfVariableDeclaration =
-    List.filled(0, dummyVariableDeclaration, growable: false);
-
-/// Almost const <Combinator>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<Combinator> emptyListOfCombinator =
-    List.filled(0, dummyCombinator, growable: false);
-
-/// Almost const <Expression>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<Expression> emptyListOfExpression =
-    List.filled(0, dummyExpression, growable: false);
-
-/// Almost const <AssertStatement>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<AssertStatement> emptyListOfAssertStatement =
-    List.filled(0, dummyAssertStatement, growable: false);
-
-/// Almost const <SwitchCase>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<SwitchCase> emptyListOfSwitchCase =
-    List.filled(0, dummySwitchCase, growable: false);
-
-/// Almost const <SwitchExpressionCase>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<SwitchExpressionCase> emptyListOfSwitchExpressionCase =
-    List.filled(0, dummySwitchExpressionCase, growable: false);
-
-/// Almost const <PatternSwitchCase>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<PatternSwitchCase> emptyListOfPatternSwitchCase =
-    List.filled(0, dummyPatternSwitchCase, growable: false);
-
-/// Almost const <Catch>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<Catch> emptyListOfCatch =
-    List.filled(0, dummyCatch, growable: false);
-
-/// Almost const <Supertype>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<Supertype> emptyListOfSupertype =
-    List.filled(0, dummySupertype, growable: false);
-
-/// Almost const <DartType>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<DartType> emptyListOfDartType =
-    List.filled(0, dummyDartType, growable: false);
-
-/// Almost const <NamedType>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<NamedType> emptyListOfNamedType =
-    List.filled(0, dummyNamedType, growable: false);
-
-/// Almost const <TypeParameter>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<TypeParameter> emptyListOfTypeParameter =
-    List.filled(0, dummyTypeParameter, growable: false);
-
-/// Almost const <StructuralParameter>[], but not const in an attempt to
-/// avoid polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<StructuralParameter> emptyListOfStructuralParameter =
-    List.filled(0, dummyStructuralParameter, growable: false);
-
-/// Almost const <Constant>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<Constant> emptyListOfConstant =
-    List.filled(0, dummyConstant, growable: false);
-
-/// Almost const <String>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<String> emptyListOfString = List.filled(0, '', growable: false);
-
-/// Almost const <Typedef>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<Typedef> emptyListOfTypedef =
-    List.filled(0, dummyTypedef, growable: false);
-
-/// Almost const <Extension>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<Extension> emptyListOfExtension =
-    List.filled(0, dummyExtension, growable: false);
-
-/// Almost const <ExtensionTypeDeclaration>[], but not const in an attempt to
-/// avoid polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<ExtensionTypeDeclaration> emptyListOfExtensionTypeDeclaration =
-    List.filled(0, dummyExtensionTypeDeclaration, growable: false);
-
-/// Almost const <Field>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<Field> emptyListOfField =
-    List.filled(0, dummyField, growable: false);
-
-/// Almost const <LibraryPart>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<LibraryPart> emptyListOfLibraryPart =
-    List.filled(0, dummyLibraryPart, growable: false);
-
-/// Almost const <LibraryDependency>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<LibraryDependency> emptyListOfLibraryDependency =
-    List.filled(0, dummyLibraryDependency, growable: false);
-
-/// Almost const <Procedure>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<Procedure> emptyListOfProcedure =
-    List.filled(0, dummyProcedure, growable: false);
-
-/// Almost const <MapLiteralEntry>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<MapLiteralEntry> emptyListOfMapLiteralEntry =
-    List.filled(0, dummyMapLiteralEntry, growable: false);
-
-/// Almost const <Class>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<Class> emptyListOfClass =
-    List.filled(0, dummyClass, growable: false);
-
-/// Almost const <ExtensionMemberDescriptor>[], but not const in an attempt to
-/// avoid polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<ExtensionMemberDescriptor> emptyListOfExtensionMemberDescriptor =
-    List.filled(0, dummyExtensionMemberDescriptor, growable: false);
-
-/// Almost const <ExtensionTypeMemberDescriptor>[], but not const in an attempt
-/// to avoid polymorphism. See
-/// https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<ExtensionTypeMemberDescriptor>
-    emptyListOfExtensionTypeMemberDescriptor =
-    List.filled(0, dummyExtensionTypeMemberDescriptor, growable: false);
-
-/// Almost const <TypeDeclarationType>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<TypeDeclarationType> emptyListOfTypeDeclarationType =
-    List.filled(0, dummyExtensionType, growable: false);
-
-/// Almost const <Constructor>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<Constructor> emptyListOfConstructor =
-    List.filled(0, dummyConstructor, growable: false);
-
-/// Almost const <Initializer>[], but not const in an attempt to avoid
-/// polymorphism. See https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<Initializer> emptyListOfInitializer =
-    List.filled(0, dummyInitializer, growable: false);
-
-/// Non-nullable [DartType] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final DartType dummyDartType = new DynamicType();
-
-/// Non-nullable [Supertype] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final Supertype dummySupertype = new Supertype(dummyClass, const []);
-
-/// Non-nullable [NamedType] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final NamedType dummyNamedType =
-    new NamedType('', dummyDartType, isRequired: false);
-
-/// Non-nullable [Uri] dummy value.
-final Uri dummyUri = new Uri(scheme: 'dummy');
-
-/// Non-nullable [Name] dummy value.
-final Name dummyName = new _PublicName('');
-
-/// Non-nullable [Reference] dummy value.
-final Reference dummyReference = new Reference();
-
-/// Non-nullable [Component] dummy value.
-///
-/// This can be used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final Component dummyComponent = new Component();
-
-/// Non-nullable [Library] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final Library dummyLibrary = new Library(dummyUri, fileUri: dummyUri);
-
-/// Non-nullable [LibraryDependency] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final LibraryDependency dummyLibraryDependency =
-    new LibraryDependency.import(dummyLibrary);
-
-/// Non-nullable [Combinator] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final Combinator dummyCombinator = new Combinator(false, const []);
-
-/// Non-nullable [LibraryPart] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final LibraryPart dummyLibraryPart = new LibraryPart(const [], '');
-
-/// Non-nullable [Class] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final Class dummyClass = new Class(name: '', fileUri: dummyUri);
-
-/// Non-nullable [Constructor] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final Constructor dummyConstructor =
-    new Constructor(dummyFunctionNode, name: dummyName, fileUri: dummyUri);
-
-/// Non-nullable [Extension] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final Extension dummyExtension = new Extension(name: '', fileUri: dummyUri);
-
-/// Non-nullable [ExtensionMemberDescriptor] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final ExtensionMemberDescriptor dummyExtensionMemberDescriptor =
-    new ExtensionMemberDescriptor(
-        name: dummyName,
-        kind: ExtensionMemberKind.Getter,
-        memberReference: dummyReference,
-        tearOffReference: null);
-
-/// Non-nullable [ExtensionTypeDeclaration] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final ExtensionTypeDeclaration dummyExtensionTypeDeclaration =
-    new ExtensionTypeDeclaration(name: '', fileUri: dummyUri);
-
-/// Non-nullable [ExtensionTypeMemberDescriptor] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final ExtensionTypeMemberDescriptor dummyExtensionTypeMemberDescriptor =
-    new ExtensionTypeMemberDescriptor(
-        name: dummyName,
-        kind: ExtensionTypeMemberKind.Getter,
-        memberReference: dummyReference,
-        tearOffReference: null);
-
-/// Non-nullable [ExtensionType] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final ExtensionType dummyExtensionType =
-    new ExtensionType(dummyExtensionTypeDeclaration, Nullability.nonNullable);
-
-/// Non-nullable [Member] dummy value.
-///
-/// This can be used for instance as a dummy initial value for the
-/// `List.filled` constructor.
-final Member dummyMember = new Field.mutable(dummyName, fileUri: dummyUri);
-
-/// Non-nullable [Procedure] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final Procedure dummyProcedure = new Procedure(
-    dummyName, ProcedureKind.Method, dummyFunctionNode,
-    fileUri: dummyUri);
-
-/// Non-nullable [Field] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final Field dummyField = new Field.mutable(dummyName, fileUri: dummyUri);
-
-/// Non-nullable [Typedef] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final Typedef dummyTypedef = new Typedef('', null, fileUri: dummyUri);
-
-/// Non-nullable [Initializer] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final Initializer dummyInitializer = new InvalidInitializer();
-
-/// Non-nullable [FunctionNode] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final FunctionNode dummyFunctionNode = new FunctionNode(null);
-
-/// Non-nullable [Statement] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final Statement dummyStatement = new EmptyStatement();
-
-/// Non-nullable [Expression] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final Expression dummyExpression = new NullLiteral();
-
-/// Non-nullable [NamedExpression] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final NamedExpression dummyNamedExpression =
-    new NamedExpression('', dummyExpression);
-
-/// Almost const <Pattern>[], but not const in an attempt to avoid
-/// polymorphism. See
-/// https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<Pattern> emptyListOfPattern =
-    List.filled(0, dummyPattern, growable: false);
-
-/// Almost const <NamedPattern>[], but not const in an attempt to avoid
-/// polymorphism. See
-/// https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<NamedPattern> emptyListOfNamedPattern =
-    List.filled(0, dummyNamedPattern, growable: false);
-
-/// Almost const <MapPatternEntry>[], but not const in an attempt to avoid
-/// polymorphism. See
-/// https://dart-review.googlesource.com/c/sdk/+/185828.
-final List<MapPatternEntry> emptyListOfMapPatternEntry =
-    List.filled(0, dummyMapPatternEntry, growable: false);
-
-/// Non-nullable [VariableDeclaration] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final VariableDeclaration dummyVariableDeclaration =
-    new VariableDeclaration(null, isSynthesized: true);
-
-/// Non-nullable [TypeParameter] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final TypeParameter dummyTypeParameter = new TypeParameter();
-
-/// Non-nullable [StructuralParameter] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final StructuralParameter dummyStructuralParameter = new StructuralParameter();
-
-/// Non-nullable [MapLiteralEntry] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final MapLiteralEntry dummyMapLiteralEntry =
-    new MapLiteralEntry(dummyExpression, dummyExpression);
-
-/// Non-nullable [Arguments] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final Arguments dummyArguments = new Arguments(const []);
-
-/// Non-nullable [AssertStatement] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final AssertStatement dummyAssertStatement = new AssertStatement(
-    dummyExpression,
-    conditionStartOffset: TreeNode.noOffset,
-    conditionEndOffset: TreeNode.noOffset);
-
-/// Non-nullable [SwitchCase] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final SwitchCase dummySwitchCase = new SwitchCase.defaultCase(dummyStatement);
-
-/// Non-nullable [Catch] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final Catch dummyCatch = new Catch(null, dummyStatement);
-
-/// Non-nullable [Constant] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final Constant dummyConstant = new NullConstant();
-
-/// Non-nullable [LabeledStatement] dummy value.
-///
-/// This is used as the removal sentinel in [RemovingTransformer] and can be
-/// used for instance as a dummy initial value for the `List.filled`
-/// constructor.
-final LabeledStatement dummyLabeledStatement = new LabeledStatement(null);
-
-/// Of the dummy nodes, some are tree nodes. `TreeNode`s has a parent pointer
-/// and that can be set when the dummy is used. This means that we can leak
-/// through them. This list will (at least as a stopgap) allow us to null-out
-/// the parent pointer when/if needed.
-///
-/// This should manually be kept up to date.
-final List<TreeNode> dummyTreeNodes = [
-  dummyComponent,
-  dummyLibrary,
-  dummyLibraryDependency,
-  dummyCombinator,
-  dummyLibraryPart,
-  dummyClass,
-  dummyConstructor,
-  dummyExtension,
-  dummyMember,
-  dummyProcedure,
-  dummyField,
-  dummyTypedef,
-  dummyInitializer,
-  dummyFunctionNode,
-  dummyStatement,
-  dummyExpression,
-  dummyNamedExpression,
-  dummyVariableDeclaration,
-  dummyTypeParameter,
-  dummyMapLiteralEntry,
-  dummyArguments,
-  dummyAssertStatement,
-  dummySwitchCase,
-  dummyCatch,
-  dummyLabeledStatement,
-];
-
-void clearDummyTreeNodesParentPointer() {
-  for (TreeNode treeNode in dummyTreeNodes) {
-    treeNode.parent = null;
-  }
-}
-
-/// Sentinel value used to signal that a node cannot be removed through the
-/// [RemovingTransformer].
-const Null cannotRemoveSentinel = null;
-
-/// Helper that can be used in asserts to check that [list] is mutable by
-/// adding and removing [dummyElement].
-bool checkListIsMutable<E>(List<E> list, E dummyElement) {
-  list
-    ..add(dummyElement)
-    ..removeLast();
-  return true;
-}
+part 'src/ast/statements.dart';
+part 'src/ast/typedefs.dart';
+part 'src/ast/types.dart';
diff --git a/pkg/kernel/lib/src/ast/components.dart b/pkg/kernel/lib/src/ast/components.dart
new file mode 100644
index 0000000..bc0932f
--- /dev/null
+++ b/pkg/kernel/lib/src/ast/components.dart
@@ -0,0 +1,347 @@
+// Copyright (c) 2024, 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 '../../ast.dart';
+
+// ------------------------------------------------------------------------
+//                                COMPONENT
+// ------------------------------------------------------------------------
+
+/// A way to bundle up libraries in a component.
+class Component extends TreeNode {
+  final CanonicalName root;
+
+  /// Problems in this [Component] encoded as json objects.
+  ///
+  /// Note that this field can be null, and by convention should be null if the
+  /// list is empty.
+  List<String>? problemsAsJson;
+
+  final List<Library> libraries;
+
+  /// Map from a source file URI to a line-starts table and source code.
+  /// Given a source file URI and a offset in that file one can translate
+  /// it to a line:column position in that file.
+  final Map<Uri, Source> uriToSource;
+
+  /// Mapping between string tags and [MetadataRepository] corresponding to
+  /// those tags.
+  final Map<String, MetadataRepository<dynamic>> metadata =
+      <String, MetadataRepository<dynamic>>{};
+
+  /// Reference to the main method in one of the libraries.
+  Reference? _mainMethodName;
+  Reference? get mainMethodName => _mainMethodName;
+  NonNullableByDefaultCompiledMode? _mode;
+  NonNullableByDefaultCompiledMode get mode {
+    return _mode ?? NonNullableByDefaultCompiledMode.Strong;
+  }
+
+  NonNullableByDefaultCompiledMode? get modeRaw => _mode;
+
+  Component(
+      {CanonicalName? nameRoot,
+      List<Library>? libraries,
+      Map<Uri, Source>? uriToSource,
+      NonNullableByDefaultCompiledMode? mode})
+      : root = nameRoot ?? new CanonicalName.root(),
+        libraries = libraries ?? <Library>[],
+        uriToSource = uriToSource ?? <Uri, Source>{},
+        _mode = mode {
+    adoptChildren();
+  }
+
+  void adoptChildren() {
+    for (int i = 0; i < libraries.length; ++i) {
+      // The libraries are owned by this component, and so are their canonical
+      // names if they exist.
+      Library library = libraries[i];
+      library.parent = this;
+      CanonicalName? name = library.reference.canonicalName;
+      if (name != null && name.parent != root) {
+        root.adoptChild(name);
+      }
+    }
+  }
+
+  void computeCanonicalNames() {
+    for (int i = 0; i < libraries.length; ++i) {
+      computeCanonicalNamesForLibrary(libraries[i]);
+    }
+  }
+
+  /// This is an advanced feature. Use of this method should be coordinated
+  /// with the kernel team.
+  ///
+  /// Makes sure all references in named nodes in this component points to said
+  /// named node.
+  ///
+  /// The use case is advanced incremental compilation, where we want to rebuild
+  /// a single library and make all other libraries use the new library and the
+  /// content therein *while* having the option to go back to pointing (be
+  /// "linked") to the old library if the delta is rejected.
+  ///
+  /// Please note that calling this is a potentially dangerous thing to do,
+  /// and that stuff *can* go wrong, and you could end up in a situation where
+  /// you point to several versions of "the same" library. Examples:
+  ///  * If you only relink part (e.g. a class) if your component you can wind
+  ///    up in an unfortunate situation where if the library (say libA) contains
+  ///    class 'B' and class 'C', you only replace 'B' (with one in library
+  ///    'libAPrime'), everything pointing to 'B' via parent pointers talks
+  ///    about 'libAPrime', whereas everything pointing to 'C' would still
+  ///    ultimately point to 'libA'.
+  ///  * If you relink to a library that doesn't have exactly the same members
+  ///    as the one you're "linking from" you can wind up in an unfortunate
+  ///    situation, e.g. if the thing you relink two is missing a static method,
+  ///    any links to that static method will still point to the old static
+  ///    method and thus (via parent pointers) to the old library.
+  ///  * (probably more).
+  void relink() {
+    for (int i = 0; i < libraries.length; ++i) {
+      libraries[i].relink();
+    }
+  }
+
+  void computeCanonicalNamesForLibrary(Library library) {
+    library.ensureCanonicalNames(root);
+  }
+
+  void unbindCanonicalNames() {
+    // TODO(jensj): Get rid of this.
+    for (int i = 0; i < libraries.length; i++) {
+      Library lib = libraries[i];
+      for (int j = 0; j < lib.classes.length; j++) {
+        Class c = lib.classes[j];
+        c.dirty = true;
+      }
+    }
+    root.unbindAll();
+  }
+
+  Procedure? get mainMethod => mainMethodName?.asProcedure;
+
+  void setMainMethodAndMode(Reference? main, bool overwriteMainIfSet,
+      NonNullableByDefaultCompiledMode mode) {
+    if (_mainMethodName == null || overwriteMainIfSet) {
+      _mainMethodName = main;
+    }
+    _mode = mode;
+  }
+
+  @override
+  R accept<R>(TreeVisitor<R> v) => v.visitComponent(this);
+
+  @override
+  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitComponent(this, arg);
+
+  @override
+  void visitChildren(Visitor v) {
+    visitList(libraries, v);
+    mainMethod?.acceptReference(v);
+  }
+
+  @override
+  void transformChildren(Transformer v) {
+    v.transformList(libraries, this);
+  }
+
+  @override
+  void transformOrRemoveChildren(RemovingTransformer v) {
+    v.transformLibraryList(libraries, this);
+  }
+
+  @override
+  Component get enclosingComponent => this;
+
+  /// Translates an offset to line and column numbers in the given file.
+  Location? getLocation(Uri file, int offset, {String? viaForErrorMessage}) {
+    return uriToSource[file]
+        ?.getLocation(file, offset, viaForErrorMessage: viaForErrorMessage);
+  }
+
+  /// Translates line and column numbers to an offset in the given file.
+  ///
+  /// Returns offset of the line and column in the file, or -1 if the
+  /// source is not available or has no lines.
+  /// Throws [RangeError] if line or calculated offset are out of range.
+  int getOffset(Uri file, int line, int column) {
+    return uriToSource[file]?.getOffset(line, column) ?? -1;
+  }
+
+  void addMetadataRepository(MetadataRepository repository) {
+    metadata[repository.tag] = repository;
+  }
+
+  @override
+  String toString() {
+    return "Component(${toStringInternal()})";
+  }
+
+  @override
+  void toTextInternal(AstPrinter printer) {
+    // TODO(johnniwinther): Implement this.
+  }
+
+  @override
+  String leakingDebugToString() => astToText.debugComponentToString(this);
+}
+
+/// A tuple with file, line, and column number, for displaying human-readable
+/// locations.
+class Location {
+  final Uri file;
+  final int line; // 1-based.
+  final int column; // 1-based.
+
+  Location(this.file, this.line, this.column);
+
+  @override
+  String toString() => '$file:$line:$column';
+}
+
+class Source {
+  static final Uint8List _emptySource = new Uint8List(0);
+  final List<int>? lineStarts;
+
+  /// A UTF8 encoding of the original source file.
+  final Uint8List source;
+
+  final Uri? importUri;
+
+  final Uri? fileUri;
+
+  Set<Reference>? constantCoverageConstructors;
+
+  String? cachedText;
+
+  Source(this.lineStarts, this.source, this.importUri, this.fileUri);
+
+  Source.emptySource(this.lineStarts, this.importUri, this.fileUri)
+      : source = _emptySource;
+
+  /// Return the text corresponding to [line] which is a 1-based line
+  /// number. The returned line contains no line separators.
+  String? getTextLine(int line) {
+    List<int>? lineStarts = this.lineStarts;
+    if (source.isEmpty || lineStarts == null || lineStarts.isEmpty) {
+      return null;
+    }
+    RangeError.checkValueInInterval(line, 1, lineStarts.length, 'line');
+
+    String cachedText = text;
+    // -1 as line numbers start at 1.
+    int index = line - 1;
+    if (index + 1 == lineStarts.length) {
+      // Last line.
+      return cachedText.substring(lineStarts[index]);
+    } else if (index < lineStarts.length) {
+      // We subtract 1 from the next line for two reasons:
+      // 1. If the file isn't terminated by a newline, that index is invalid.
+      // 2. To remove the newline at the end of the line.
+      int endOfLine = lineStarts[index + 1] - 1;
+      if (endOfLine > index && cachedText[endOfLine - 1] == "\r") {
+        --endOfLine; // Windows line endings.
+      }
+      return cachedText.substring(lineStarts[index], endOfLine);
+    }
+    // This shouldn't happen: should have been caught by the range check above.
+    throw "Internal error";
+  }
+
+  String get text => cachedText ??= utf8.decode(source, allowMalformed: true);
+
+  /// Translates an offset to 1-based line and column numbers in the given file.
+  Location getLocation(Uri file, int offset, {String? viaForErrorMessage}) {
+    List<int>? lineStarts = this.lineStarts;
+    if (lineStarts == null || lineStarts.isEmpty) {
+      return new Location(file, TreeNode.noOffset, TreeNode.noOffset);
+    }
+    if (viaForErrorMessage != null) {
+      RangeError.checkValueInInterval(
+          offset,
+          0,
+          lineStarts.last,
+          'offset',
+          'Asked for out-of-bounds offset for uri "$file" '
+              'via $viaForErrorMessage');
+    } else {
+      RangeError.checkValueInInterval(offset, 0, lineStarts.last, 'offset',
+          'Asked for out-of-bounds offset for uri "$file"');
+    }
+    int low = 0, high = lineStarts.length - 1;
+    while (low < high) {
+      int mid = high - ((high - low) >> 1); // Get middle, rounding up.
+      int pivot = lineStarts[mid];
+      if (pivot <= offset) {
+        low = mid;
+      } else {
+        high = mid - 1;
+      }
+    }
+    int lineIndex = low;
+    int lineStart = lineStarts[lineIndex];
+    int lineNumber = 1 + lineIndex;
+    int columnNumber = 1 + offset - lineStart;
+    return new Location(file, lineNumber, columnNumber);
+  }
+
+  /// Translates 1-based line and column numbers to an offset in the given file
+  ///
+  /// Returns offset of the line and column in the file, or -1 if the source
+  /// has no lines.
+  /// Throws [RangeError] if line or calculated offset are out of range.
+  int getOffset(int line, int column) {
+    List<int>? lineStarts = this.lineStarts;
+    if (lineStarts == null || lineStarts.isEmpty) {
+      return -1;
+    }
+    RangeError.checkValueInInterval(line, 1, lineStarts.length, 'line');
+    int offset = lineStarts[line - 1] + column - 1;
+    RangeError.checkValueInInterval(offset, 0, lineStarts.last, 'offset');
+    return offset;
+  }
+}
+
+abstract class MetadataRepository<T> {
+  /// Unique string tag associated with this repository.
+  String get tag;
+
+  /// Mutable mapping between nodes and their metadata.
+  Map<Node, T> get mapping;
+
+  /// Write [metadata] object corresponding to the given [Node] into
+  /// the given [BinarySink].
+  ///
+  /// Metadata is serialized immediately before serializing [node],
+  /// so implementation of this method can use serialization context of
+  /// [node]'s parents (such as declared type parameters and variables).
+  /// In order to use scope declared by the [node] itself, implementation of
+  /// this method can use [BinarySink.enterScope] and [BinarySink.leaveScope]
+  /// methods.
+  ///
+  /// [metadata] must be an object owned by this repository.
+  void writeToBinary(T metadata, Node node, BinarySink sink);
+
+  /// Construct a metadata object from its binary payload read from the
+  /// given [BinarySource].
+  ///
+  /// Metadata is deserialized immediately after deserializing [node],
+  /// so it can use deserialization context of [node]'s parents.
+  /// In order to use scope declared by the [node] itself, implementation of
+  /// this method can use [BinarySource.enterScope] and
+  /// [BinarySource.leaveScope] methods.
+  T readFromBinary(Node node, BinarySource source);
+
+  /// Method to check whether a node can have metadata attached to it
+  /// or referenced from the metadata payload.
+  ///
+  /// Currently due to binary format specifics Catch and MapEntry nodes
+  /// can't have metadata attached to them. Also, metadata is not saved on
+  /// Block nodes inside BlockExpressions.
+  static bool isSupported(Node node) {
+    return !(node is MapLiteralEntry ||
+        node is Catch ||
+        (node is Block && node.parent is BlockExpression));
+  }
+}
diff --git a/pkg/kernel/lib/src/ast/constants.dart b/pkg/kernel/lib/src/ast/constants.dart
new file mode 100644
index 0000000..f53070a
--- /dev/null
+++ b/pkg/kernel/lib/src/ast/constants.dart
@@ -0,0 +1,1170 @@
+// Copyright (c) 2024, 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 '../../ast.dart';
+
+// ------------------------------------------------------------------------
+//                             CONSTANTS
+// ------------------------------------------------------------------------
+
+sealed class Constant extends Node {
+  /// Calls the `visit*ConstantReference()` method on visitor [v] for all
+  /// constants referenced in this constant.
+  ///
+  /// (Note that a constant can be seen as a DAG (directed acyclic graph) and
+  ///  not a tree!)
+  @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>(ConstantReferenceVisitor<R> v);
+
+  /// Calls the `visit*ConstantReference()` method on the visitor [v].
+  R acceptReference1<R, A>(ConstantReferenceVisitor1<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.
+  DartType getType(StaticTypeContext context);
+}
+
+abstract class AuxiliaryConstant extends Constant {
+  @override
+  R accept<R>(ConstantVisitor<R> v) => v.visitAuxiliaryConstant(this);
+
+  @override
+  R accept1<R, A>(ConstantVisitor1<R, A> v, A arg) =>
+      v.visitAuxiliaryConstant(this, arg);
+
+  @override
+  R acceptReference<R>(ConstantReferenceVisitor<R> v) =>
+      v.visitAuxiliaryConstantReference(this);
+
+  @override
+  R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) =>
+      v.visitAuxiliaryConstantReference(this, arg);
+}
+
+sealed class PrimitiveConstant<T> extends Constant {
+  final T value;
+
+  PrimitiveConstant(this.value);
+
+  @override
+  int get hashCode => value.hashCode;
+
+  @override
+  bool operator ==(Object other) =>
+      other is PrimitiveConstant<T> && other.value == value;
+
+  @override
+  void toTextInternal(AstPrinter printer) {
+    printer.write('$value');
+  }
+}
+
+class NullConstant extends PrimitiveConstant<Null> {
+  NullConstant() : super(null);
+
+  @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>(ConstantReferenceVisitor<R> v) =>
+      v.visitNullConstantReference(this);
+
+  @override
+  R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) =>
+      v.visitNullConstantReference(this, arg);
+
+  @override
+  DartType getType(StaticTypeContext context) => const NullType();
+
+  @override
+  String toString() => 'NullConstant(${toStringInternal()})';
+}
+
+class BoolConstant extends PrimitiveConstant<bool> {
+  BoolConstant(bool value) : super(value);
+
+  @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>(ConstantReferenceVisitor<R> v) =>
+      v.visitBoolConstantReference(this);
+
+  @override
+  R acceptReference1<R, A>(ConstantReferenceVisitor1<R, A> v, A arg) =>
+      v.visitBoolConstantReference(this, arg);
+
+  @override
+  DartType getType(StaticTypeContext context) =>
+      context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
+
+  @override
+  String toString() => 'BoolConstant(${toStringInternal()})';
+}
+
+/// An integer constant on a non-JS target.
+class IntConstant extends PrimitiveConstant<int> {
+  IntConstant(int value) : super(value);
+
+  @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>(ConstantReferenceVisitor<R> v) =>
+      v.visitIntConstantReference(this);
+
+  @override
+  R acceptReference1<R, A>(ConstantReferenceVisit