// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:collection';
import 'dart:math' as math;

import 'package:_fe_analyzer_shared/src/scanner/string_canonicalizer.dart';
import 'package:_fe_analyzer_shared/src/type_inference/type_analysis_result.dart';
import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/doc_comment.dart';
import 'package:analyzer/dart/ast/precedence.dart';
import 'package:analyzer/dart/ast/syntactic_entity.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/dart/element/scope.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/source/line_info.dart';
import 'package:analyzer/src/dart/ast/extensions.dart';
import 'package:analyzer/src/dart/ast/to_source_visitor.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type_schema.dart';
import 'package:analyzer/src/dart/resolver/body_inference_context.dart';
import 'package:analyzer/src/dart/resolver/typed_literal_resolver.dart';
import 'package:analyzer/src/fasta/token_utils.dart' as util show findPrevious;
import 'package:analyzer/src/generated/inference_log.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/utilities/extensions/element.dart';
import 'package:analyzer/src/utilities/extensions/object.dart';
import 'package:collection/collection.dart';
import 'package:meta/meta.dart';

/// Two or more string literals that are implicitly concatenated because of
/// being adjacent (separated only by whitespace).
///
/// For example
/// ```dart
/// 'Hello ' 'World'
/// ```
///
/// While the grammar only allows adjacent strings where all of the strings are
/// of the same kind (single line or multi-line), this class doesn't enforce
/// that restriction.
///
///    adjacentStrings ::=
///        [StringLiteral] [StringLiteral]+
abstract final class AdjacentStrings implements StringLiteral {
  /// The strings that are implicitly concatenated.
  NodeList<StringLiteral> get strings;
}

final class AdjacentStringsImpl extends StringLiteralImpl
    implements AdjacentStrings {
  final NodeListImpl<StringLiteralImpl> _strings = NodeListImpl._();

  /// Initializes a newly created list of adjacent strings.
  ///
  /// To be syntactically valid, the list of [strings] must contain at least two
  /// elements.
  AdjacentStringsImpl({
    required List<StringLiteralImpl> strings,
  }) {
    _strings._initialize(this, strings);
  }

  @override
  Token get beginToken => _strings.beginToken!;

  @override
  Token get endToken => _strings.endToken!;

  @override
  NodeListImpl<StringLiteralImpl> get strings => _strings;

  @override
  ChildEntities get _childEntities {
    return ChildEntities()..addNodeList('strings', strings);
  }

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitAdjacentStrings(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitAdjacentStrings(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _strings.accept(visitor);
  }

  @override
  void _appendStringValue(StringBuffer buffer) {
    int length = strings.length;
    for (int i = 0; i < length; i++) {
      strings[i]._appendStringValue(buffer);
    }
  }
}

/// An AST node that can be annotated with either a documentation comment, a
/// list of annotations (metadata), or both.
abstract final class AnnotatedNode implements AstNode {
  /// The documentation comment associated with this node, or `null` if this
  /// node doesn't have a documentation comment associated with it.
  Comment? get documentationComment;

  /// The first token following the comment and metadata.
  Token get firstTokenAfterCommentAndMetadata;

  /// The annotations associated with this node.
  ///
  /// If there are no annotations, then the returned list is empty.
  NodeList<Annotation> get metadata;

  /// A list containing the comment and annotations associated with this node,
  /// sorted in lexical order.
  ///
  /// If there are neither annotations nor a comment, then the returned list is
  /// empty.
  List<AstNode> get sortedCommentAndAnnotations;
}

sealed class AnnotatedNodeImpl extends AstNodeImpl with _AnnotatedNodeMixin {
  /// Initializes a newly created annotated node.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the node
  /// doesn't have the corresponding attribute.
  AnnotatedNodeImpl({
    required CommentImpl? comment,
    required List<AnnotationImpl>? metadata,
  }) {
    _initializeCommentAndAnnotations(comment, metadata);
  }

  @override
  Token get beginToken {
    if (_comment == null) {
      if (_metadata.isEmpty) {
        return firstTokenAfterCommentAndMetadata;
      }
      return _metadata.beginToken!;
    } else if (_metadata.isEmpty) {
      return _comment!.beginToken;
    }
    Token commentToken = _comment!.beginToken;
    Token metadataToken = _metadata.beginToken!;
    if (commentToken.offset < metadataToken.offset) {
      return commentToken;
    }
    return metadataToken;
  }

  @override
  ChildEntities get _childEntities {
    return ChildEntities()
      ..addNode('documentationComment', documentationComment)
      ..addNodeList('metadata', metadata);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _visitCommentAndAnnotations(visitor);
  }
}

/// An annotation that can be associated with a declaration.
///
/// For example
/// ```dart
/// @override
/// ```
///
/// or
/// ```dart
/// @Deprecated('1.3.2')
/// ```
///
///    metadata ::=
///        annotation*
///
///    annotation ::=
///        '@' metadatum
///
///    metadatum ::=
///        [Identifier]
///      | qualifiedName
///      | constructorDesignation argumentPart
abstract final class Annotation implements AstNode {
  /// The arguments to the constructor being invoked, or `null` if this
  /// annotation isn't the invocation of a constructor.
  ArgumentList? get arguments;

  /// The at sign (`@`) that introduces the annotation.
  Token get atSign;

  /// The name of the constructor being invoked, or `null` if this annotation
  /// isn't the invocation of a named constructor.
  SimpleIdentifier? get constructorName;

  /// The element associated with this annotation, or `null` if the AST
  /// structure hasn't been resolved or if this annotation couldn't be resolved.
  Element? get element;

  /// The element associated with this annotation.
  ///
  /// Returns `null` if the AST structure hasn't been resolved or if this
  /// annotation couldn't be resolved.
  @experimental
  Element2? get element2;

  /// The element annotation representing this annotation in the element model,
  /// or `null` if the AST hasn't been resolved.
  ElementAnnotation? get elementAnnotation;

  /// The name of either the class defining the constructor that is being
  /// invoked or the field that is being referenced.
  ///
  /// If a named constructor is being referenced, then the name of the
  /// constructor is available using [constructorName].
  Identifier get name;

  @override
  AstNode get parent;

  /// The period before the constructor name, or `null` if this annotation isn't
  /// the invocation of a named constructor.
  Token? get period;

  /// The type arguments to the constructor being invoked, or `null` if either
  /// this annotation isn't the invocation of a constructor or this annotation
  /// doesn't specify type arguments explicitly.
  ///
  /// Note that type arguments are only valid if [Feature.generic_metadata] is
  /// enabled.
  TypeArgumentList? get typeArguments;
}

final class AnnotationImpl extends AstNodeImpl implements Annotation {
  @override
  final Token atSign;

  IdentifierImpl _name;

  TypeArgumentListImpl? _typeArguments;

  @override
  final Token? period;

  SimpleIdentifierImpl? _constructorName;

  ArgumentListImpl? _arguments;

  Element? _element;

  @override
  ElementAnnotationImpl? elementAnnotation;

  /// Initializes a newly created annotation.
  ///
  /// Both the [period] and the [constructorName] can be `null` if the
  /// annotation isn't referencing a named constructor.
  ///
  /// The [arguments] can be `null` if the annotation isn't referencing a
  /// constructor.
  ///
  /// Note that type arguments are only valid if [Feature.generic_metadata] is
  /// enabled.
  AnnotationImpl({
    required this.atSign,
    required IdentifierImpl name,
    required TypeArgumentListImpl? typeArguments,
    required this.period,
    required SimpleIdentifierImpl? constructorName,
    required ArgumentListImpl? arguments,
  })  : _name = name,
        _typeArguments = typeArguments,
        _constructorName = constructorName,
        _arguments = arguments {
    _becomeParentOf(_name);
    _becomeParentOf(_typeArguments);
    _becomeParentOf(_constructorName);
    _becomeParentOf(_arguments);
  }

  @override
  ArgumentListImpl? get arguments => _arguments;

  set arguments(ArgumentListImpl? arguments) {
    _arguments = _becomeParentOf(arguments);
  }

  @override
  Token get beginToken => atSign;

  @override
  SimpleIdentifierImpl? get constructorName => _constructorName;

  set constructorName(SimpleIdentifierImpl? name) {
    _constructorName = _becomeParentOf(name);
  }

  @override
  Element? get element {
    if (_element case var element?) {
      return element;
    } else if (_constructorName == null) {
      return _name.staticElement;
    }
    return null;
  }

  set element(Element? element) {
    _element = element;
  }

  @experimental
  @override
  Element2? get element2 {
    var element = this.element;
    if (element case Fragment fragment) {
      return fragment.element;
    } else if (element case Element2 element) {
      return element;
    }
    return null;
  }

  @override
  Token get endToken {
    if (arguments case var arguments?) {
      return arguments.endToken;
    } else if (constructorName case var constructorName?) {
      return constructorName.endToken;
    }
    return _name.endToken;
  }

  @override
  IdentifierImpl get name => _name;

  set name(IdentifierImpl name) {
    _name = _becomeParentOf(name)!;
  }

  @override
  AstNode get parent => super.parent!;

  @override
  TypeArgumentListImpl? get typeArguments => _typeArguments;

  set typeArguments(TypeArgumentListImpl? typeArguments) {
    _typeArguments = _becomeParentOf(typeArguments);
  }

  @override
  ChildEntities get _childEntities {
    return ChildEntities()
      ..addToken('atSign', atSign)
      ..addNode('name', name)
      ..addNode('typeArguments', typeArguments)
      ..addToken('period', period)
      ..addNode('constructorName', constructorName)
      ..addNode('arguments', arguments);
  }

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitAnnotation(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _name.accept(visitor);
    _typeArguments?.accept(visitor);
    _constructorName?.accept(visitor);
    _arguments?.accept(visitor);
  }
}

/// A list of arguments in the invocation of an executable element (that is, a
/// function, method, or constructor).
///
///    argumentList ::=
///        '(' arguments? ')'
///
///    arguments ::=
///        [NamedExpression] (',' [NamedExpression])*
///      | [Expression] (',' [Expression])* (',' [NamedExpression])*
abstract final class ArgumentList implements AstNode {
  /// The expressions producing the values of the arguments.
  ///
  /// If there are no arguments the list will be empty.
  ///
  /// Although the language requires that positional arguments appear before
  /// named arguments unless the [Feature.named_arguments_anywhere] is enabled,
  /// this class allows them to be intermixed.
  NodeList<Expression> get arguments;

  /// The left parenthesis.
  Token get leftParenthesis;

  /// The right parenthesis.
  Token get rightParenthesis;
}

final class ArgumentListImpl extends AstNodeImpl implements ArgumentList {
  @override
  final Token leftParenthesis;

  final NodeListImpl<ExpressionImpl> _arguments = NodeListImpl._();

  @override
  final Token rightParenthesis;

  /// A list containing the elements representing the parameters corresponding
  /// to each of the arguments in this list, or `null` if the AST hasn't been
  /// resolved or if the function or method being invoked couldn't be
  /// determined based on static type information.
  ///
  /// The list must be the same length as the number of arguments, but can
  /// contain `null` entries if a given argument doesn't correspond to a formal
  /// parameter.
  List<ParameterElement?>? _correspondingStaticParameters;

  /// Initializes a newly created list of arguments.
  ArgumentListImpl({
    required this.leftParenthesis,
    required List<ExpressionImpl> arguments,
    required this.rightParenthesis,
  }) {
    _arguments._initialize(this, arguments);
  }

  @override
  NodeListImpl<ExpressionImpl> get arguments => _arguments;

  @override
  Token get beginToken => leftParenthesis;

  List<ParameterElement?>? get correspondingStaticParameters =>
      _correspondingStaticParameters;

  set correspondingStaticParameters(List<ParameterElement?>? parameters) {
    if (parameters != null && parameters.length != _arguments.length) {
      throw ArgumentError(
          "Expected ${_arguments.length} parameters, not ${parameters.length}");
    }
    _correspondingStaticParameters = parameters;
  }

  @override
  Token get endToken => rightParenthesis;

  @override
  // TODO(paulberry): Add commas.
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('leftParenthesis', leftParenthesis)
    ..addNodeList('arguments', arguments)
    ..addToken('rightParenthesis', rightParenthesis);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitArgumentList(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _arguments.accept(visitor);
  }

  /// Returns the parameter element representing the parameter to which the
  /// value of the given expression is bound, or `null` if any of the following
  /// are not true
  /// - the given [expression] is a child of this list
  /// - the AST structure is resolved
  /// - the function being invoked is known based on static type information
  /// - the expression corresponds to one of the parameters of the function
  ///   being invoked
  ParameterElement? _getStaticParameterElementFor(Expression expression) {
    if (_correspondingStaticParameters == null ||
        _correspondingStaticParameters!.length != _arguments.length) {
      // Either the AST structure hasn't been resolved, the invocation of which
      // this list is a part couldn't be resolved, or the argument list was
      // modified after the parameters were set.
      return null;
    }
    int index = _arguments.indexOf(expression);
    if (index < 0) {
      // The expression isn't a child of this node.
      return null;
    }
    return _correspondingStaticParameters![index];
  }
}

/// An as expression.
///
///    asExpression ::=
///        [Expression] 'as' [TypeAnnotation]
abstract final class AsExpression implements Expression {
  /// The `as` operator.
  Token get asOperator;

  /// The expression used to compute the value being cast.
  Expression get expression;

  /// The type being cast to.
  TypeAnnotation get type;
}

final class AsExpressionImpl extends ExpressionImpl implements AsExpression {
  ExpressionImpl _expression;

  @override
  final Token asOperator;

  TypeAnnotationImpl _type;

  /// Initializes a newly created as expression.
  AsExpressionImpl({
    required ExpressionImpl expression,
    required this.asOperator,
    required TypeAnnotationImpl type,
  })  : _expression = expression,
        _type = type {
    _becomeParentOf(_expression);
    _becomeParentOf(_type);
  }

  @override
  Token get beginToken => _expression.beginToken;

  @override
  Token get endToken => _type.endToken;

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  Precedence get precedence => Precedence.relational;

  @override
  TypeAnnotationImpl get type => _type;

  set type(TypeAnnotationImpl type) {
    _type = _becomeParentOf(type);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('expression', expression)
    ..addToken('asOperator', asOperator)
    ..addNode('type', type);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitAsExpression(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitAsExpression(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _expression.accept(visitor);
    _type.accept(visitor);
  }
}

/// An assert in the initializer list of a constructor.
///
///    assertInitializer ::=
///        'assert' '(' [Expression] (',' [Expression])? ')'
abstract final class AssertInitializer
    implements Assertion, ConstructorInitializer {}

final class AssertInitializerImpl extends ConstructorInitializerImpl
    implements AssertInitializer {
  @override
  final Token assertKeyword;

  @override
  final Token leftParenthesis;

  ExpressionImpl _condition;

  @override
  final Token? comma;

  ExpressionImpl? _message;

  @override
  final Token rightParenthesis;

  /// Initializes a newly created assert initializer.
  AssertInitializerImpl({
    required this.assertKeyword,
    required this.leftParenthesis,
    required ExpressionImpl condition,
    required this.comma,
    required ExpressionImpl? message,
    required this.rightParenthesis,
  })  : _condition = condition,
        _message = message {
    _becomeParentOf(_condition);
    _becomeParentOf(_message);
  }

  @override
  Token get beginToken => assertKeyword;

  @override
  ExpressionImpl get condition => _condition;

  set condition(ExpressionImpl condition) {
    _condition = _becomeParentOf(condition);
  }

  @override
  Token get endToken => rightParenthesis;

  @override
  ExpressionImpl? get message => _message;

  set message(ExpressionImpl? expression) {
    _message = _becomeParentOf(expression);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('assertKeyword', assertKeyword)
    ..addToken('leftParenthesis', leftParenthesis)
    ..addNode('condition', condition)
    ..addToken('comma', comma)
    ..addNode('message', message)
    ..addToken('rightParenthesis', rightParenthesis);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitAssertInitializer(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _condition.accept(visitor);
    message?.accept(visitor);
  }
}

/// An assertion, either in a block or in the initializer list of a constructor.
abstract final class Assertion implements AstNode {
  /// The token representing the `assert` keyword.
  Token get assertKeyword;

  /// The comma between the [condition] and the [message], or `null` if no
  /// message was supplied.
  Token? get comma;

  /// The condition that is being asserted to be `true`.
  Expression get condition;

  /// The left parenthesis.
  Token get leftParenthesis;

  /// The message to report if the assertion fails, or `null` if no message was
  /// supplied.
  Expression? get message;

  /// The right parenthesis.
  Token get rightParenthesis;
}

/// An assert statement.
///
///    assertStatement ::=
///        'assert' '(' [Expression] (',' [Expression])? ')' ';'
abstract final class AssertStatement implements Assertion, Statement {
  /// The semicolon terminating the statement.
  Token get semicolon;
}

final class AssertStatementImpl extends StatementImpl
    implements AssertStatement {
  @override
  final Token assertKeyword;

  @override
  final Token leftParenthesis;

  ExpressionImpl _condition;

  @override
  final Token? comma;

  ExpressionImpl? _message;

  @override
  final Token rightParenthesis;

  @override
  final Token semicolon;

  /// Initializes a newly created assert statement.
  AssertStatementImpl({
    required this.assertKeyword,
    required this.leftParenthesis,
    required ExpressionImpl condition,
    required this.comma,
    required ExpressionImpl? message,
    required this.rightParenthesis,
    required this.semicolon,
  })  : _condition = condition,
        _message = message {
    _becomeParentOf(_condition);
    _becomeParentOf(_message);
  }

  @override
  Token get beginToken => assertKeyword;

  @override
  ExpressionImpl get condition => _condition;

  set condition(ExpressionImpl condition) {
    _condition = _becomeParentOf(condition);
  }

  @override
  Token get endToken => semicolon;

  @override
  ExpressionImpl? get message => _message;

  set message(ExpressionImpl? expression) {
    _message = _becomeParentOf(expression as ExpressionImpl);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('assertKeyword', assertKeyword)
    ..addToken('leftParenthesis', leftParenthesis)
    ..addNode('condition', condition)
    ..addToken('comma', comma)
    ..addNode('message', message)
    ..addToken('rightParenthesis', rightParenthesis)
    ..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitAssertStatement(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _condition.accept(visitor);
    message?.accept(visitor);
  }
}

/// A variable pattern in [PatternAssignment].
///
///    variablePattern ::= identifier
abstract final class AssignedVariablePattern implements VariablePattern {
  /// The element referenced by this pattern, or `null` if either [name] doesn't
  /// resolve to an element or the AST structure hasn't been resolved.
  ///
  /// In valid code this is either a [LocalVariableElement] or a
  /// [ParameterElement].
  Element? get element;

  /// The element referenced by this pattern.
  ///
  /// Returns `null` if either [name] doesn't resolve to an element or the AST
  /// structure hasn't been resolved.
  ///
  /// In valid code this is either a [LocalVariableElement2] or a
  /// [FormalParameterElement].
  @experimental
  Element2? get element2;
}

final class AssignedVariablePatternImpl extends VariablePatternImpl
    implements AssignedVariablePattern {
  @override
  Element? element;

  AssignedVariablePatternImpl({
    required super.name,
  });

  @override
  Token get beginToken => name;

  @experimental
  @override
  Element2? get element2 {
    return element.asElement2;
  }

  @override
  Token get endToken => name;

  @override
  PatternPrecedence get precedence => PatternPrecedence.primary;

  @override
  ChildEntities get _childEntities => ChildEntities()..addToken('name', name);

  @override
  E? accept<E>(AstVisitor<E> visitor) {
    return visitor.visitAssignedVariablePattern(this);
  }

  @override
  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
    var element = this.element;
    if (element is PromotableElement) {
      return resolverVisitor
          .analyzeAssignedVariablePatternSchema(element)
          .unwrapTypeSchemaView();
    }
    return resolverVisitor.operations.unknownType.unwrapTypeSchemaView();
  }

  @override
  PatternResult<DartType> resolvePattern(
    ResolverVisitor resolverVisitor,
    SharedMatchContext context,
  ) {
    return resolverVisitor.resolveAssignedVariablePattern(
      node: this,
      context: context,
    );
  }

  @override
  void visitChildren(AstVisitor visitor) {}
}

/// An assignment expression.
///
///    assignmentExpression ::=
///        [Expression] operator [Expression]
abstract final class AssignmentExpression
    implements
        NullShortableExpression,
        MethodReferenceExpression,
        CompoundAssignmentExpression {
  /// The expression used to compute the left hand side.
  Expression get leftHandSide;

  /// The assignment operator being applied.
  Token get operator;

  /// The expression used to compute the right-hand side.
  Expression get rightHandSide;
}

final class AssignmentExpressionImpl extends ExpressionImpl
    with NullShortableExpressionImpl, CompoundAssignmentExpressionImpl
    implements AssignmentExpression {
  ExpressionImpl _leftHandSide;

  @override
  final Token operator;

  ExpressionImpl _rightHandSide;

  @override
  MethodElement? staticElement;

  /// Initializes a newly created assignment expression.
  AssignmentExpressionImpl({
    required ExpressionImpl leftHandSide,
    required this.operator,
    required ExpressionImpl rightHandSide,
  })  : _leftHandSide = leftHandSide,
        _rightHandSide = rightHandSide {
    _becomeParentOf(_leftHandSide);
    _becomeParentOf(_rightHandSide);
  }

  @override
  Token get beginToken => _leftHandSide.beginToken;

  @experimental
  @override
  MethodElement2? get element => (staticElement as MethodFragment?)?.element;

  @override
  Token get endToken => _rightHandSide.endToken;

  @override
  ExpressionImpl get leftHandSide => _leftHandSide;

  set leftHandSide(ExpressionImpl expression) {
    _leftHandSide = _becomeParentOf(expression);
  }

  @override
  Precedence get precedence => Precedence.assignment;

  @override
  ExpressionImpl get rightHandSide => _rightHandSide;

  set rightHandSide(ExpressionImpl expression) {
    _rightHandSide = _becomeParentOf(expression);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('leftHandSide', leftHandSide)
    ..addToken('operator', operator)
    ..addNode('rightHandSide', rightHandSide);

  @override
  AstNode? get _nullShortingExtensionCandidate => parent;

  /// The parameter element representing the parameter to which the value of the
  /// right operand is bound, or `null` if the AST structure is not resolved or
  /// the function being invoked is not known based on static type information.
  ParameterElement? get _staticParameterElementForRightHandSide {
    Element? executableElement;
    if (operator.type != TokenType.EQ) {
      executableElement = staticElement;
    } else {
      executableElement = writeElement;
    }

    if (executableElement is ExecutableElement) {
      List<ParameterElement> parameters = executableElement.parameters;
      if (parameters.isEmpty) {
        return null;
      }
      if (operator.type == TokenType.EQ && leftHandSide is IndexExpression) {
        return parameters.length == 2 ? parameters[1] : null;
      }
      return parameters[0];
    }

    return null;
  }

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitAssignmentExpression(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitAssignmentExpression(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _leftHandSide.accept(visitor);
    _rightHandSide.accept(visitor);
  }

  @override
  bool _extendsNullShorting(Expression descendant) =>
      identical(descendant, _leftHandSide);
}

/// A node in the AST structure for a Dart program.
abstract final class AstNode implements SyntacticEntity {
  /// A comparator that can be used to sort AST nodes in lexical order.
  ///
  /// In other words, `compare` returns a negative value if the offset of the
  /// first node is less than the offset of the second node, zero (0) if the
  /// nodes have the same offset, and a positive value if the offset of the
  /// first node is greater than the offset of the second node.
  static Comparator<AstNode> LEXICAL_ORDER =
      (AstNode first, AstNode second) => first.offset - second.offset;

  /// The first token included in this node's source range.
  Token get beginToken;

  /// An iterator that can be used to iterate through all the entities (either
  /// AST nodes or tokens) that make up the contents of this node, including doc
  /// comments but excluding other comments.
  Iterable<SyntacticEntity> get childEntities;

  /// The offset of the character immediately following the last character of
  /// this node's source range.
  ///
  /// This is equivalent to `node.offset + node.length`. For a compilation unit
  /// this is equal to the length of the unit's source. For synthetic nodes this
  /// is equivalent to the node's offset (because the length is zero (`0`) by
  /// definition).
  @override
  int get end;

  /// The last token included in this node's source range.
  Token get endToken;

  /// Whether this node is a synthetic node.
  ///
  /// A synthetic node is a node that was introduced by the parser in order to
  /// recover from an error in the code. Synthetic nodes always have a length
  /// of zero (`0`).
  bool get isSynthetic;

  @override
  int get length;

  @override
  int get offset;

  /// Returns this node's parent node, or `null` if this node is the root of an
  /// AST structure.
  ///
  /// Note that the relationship between an AST node and its parent node may
  /// change over the lifetime of a node.
  AstNode? get parent;

  /// The node at the root of this node's AST structure.
  ///
  /// Note that this method's performance is linear with respect to the depth
  /// of the node in the AST structure (O(depth)).
  AstNode get root;

  /// Use the given [visitor] to visit this node.
  ///
  /// Returns the value returned by the visitor as a result of visiting this
  /// node.
  E? accept<E>(AstVisitor<E> visitor);

  /// Returns the token before [target], or `null` if it can't be found.
  Token? findPrevious(Token target);

  /// Returns either this node or the most immediate ancestor of this node for
  /// which the [predicate] returns `true`, or `null` if there's no such node.
  E? thisOrAncestorMatching<E extends AstNode>(
    bool Function(AstNode) predicate,
  );

  /// Returns either this node or the most immediate ancestor of this node that
  /// has the given type, or `null` if there's no such node.
  E? thisOrAncestorOfType<E extends AstNode>();

  /// Returns a textual description of this node in a form approximating valid
  /// source.
  ///
  /// The returned string isn't valid source code primarily in the case where
  /// the node itself isn't well-formed.
  ///
  /// Clients should never depend on the returned value being valid code, nor
  /// being consistent from one version of the package to the next. As a result,
  /// clients should never display the returned string to users.
  String toSource();

  /// Returns a textual description of this node.
  ///
  /// The returned string is intended to be useful only for debugging.
  ///
  /// Clients should never depend on the returned value being useful for any
  /// purpose, nor being consistent from one version of the package to the next.
  /// As a result, clients should never display the returned string to users.
  @override
  String toString();

  /// Use the given [visitor] to visit all of the children of this node.
  ///
  /// The children are visited in lexical order.
  void visitChildren(AstVisitor visitor);
}

sealed class AstNodeImpl implements AstNode {
  AstNode? _parent;

  @override
  Iterable<SyntacticEntity> get childEntities =>
      _childEntities.syntacticEntities;

  @override
  int get end => offset + length;

  @override
  bool get isSynthetic => false;

  @override
  int get length {
    var beginToken = this.beginToken;
    var endToken = this.endToken;
    return endToken.offset + endToken.length - beginToken.offset;
  }

  /// The properties (tokens and nodes) of this node, with names, in the order
  /// in which these entities should normally appear, not necessarily in the
  /// order they really are (because of recovery).
  Iterable<ChildEntity> get namedChildEntities => _childEntities.entities;

  @override
  int get offset {
    var beginToken = this.beginToken;
    return beginToken.offset;
  }

  @override
  AstNode? get parent => _parent;

  @override
  AstNode get root {
    AstNode root = this;
    var rootParent = parent;
    while (rootParent != null) {
      root = rootParent;
      rootParent = root.parent;
    }
    return root;
  }

  ChildEntities get _childEntities => ChildEntities();

  void detachFromParent() {
    _parent = null;
  }

  @override
  Token? findPrevious(Token target) =>
      util.findPrevious(beginToken, target) ?? parent?.findPrevious(target);

  @override
  E? thisOrAncestorMatching<E extends AstNode>(
    bool Function(AstNode) predicate,
  ) {
    AstNode? node = this;
    while (node != null && !predicate(node)) {
      node = node.parent;
    }
    return node as E?;
  }

  @override
  E? thisOrAncestorOfType<E extends AstNode>() {
    AstNode? node = this;
    while (node != null && node is! E) {
      node = node.parent;
    }
    return node as E?;
  }

  @override
  String toSource() {
    StringBuffer buffer = StringBuffer();
    accept(ToSourceVisitor(buffer));
    return buffer.toString();
  }

  @override
  String toString() => toSource();

  /// Returns the [child] node after making this node the parent of the [child]
  /// node.
  T _becomeParentOf<T extends AstNodeImpl?>(T child) {
    child?._parent = this;
    return child;
  }
}

/// Mixin for any [AstNodeImpl] that can potentially introduce a new scope.
base mixin AstNodeWithNameScopeMixin on AstNodeImpl {
  /// The [Scope] that was used while resolving `this`, or `null` if resolution
  /// has not been performed yet.
  Scope? nameScope;
}

/// An object that can be used to visit an AST structure.
///
/// Clients may not extend, implement or mix-in this class. There are classes
/// that implement this interface that provide useful default behaviors in
/// `package:analyzer/dart/ast/visitor.dart`. A couple of the most useful
/// include
/// - SimpleAstVisitor which implements every visit method by doing nothing,
/// - RecursiveAstVisitor which causes every node in a structure to be visited,
///   and
/// - ThrowingAstVisitor which implements every visit method by throwing an
///   exception.
abstract class AstVisitor<R> {
  R? visitAdjacentStrings(AdjacentStrings node);

  R? visitAnnotation(Annotation node);

  R? visitArgumentList(ArgumentList node);

  R? visitAsExpression(AsExpression node);

  R? visitAssertInitializer(AssertInitializer node);

  R? visitAssertStatement(AssertStatement assertStatement);

  R? visitAssignedVariablePattern(AssignedVariablePattern node);

  R? visitAssignmentExpression(AssignmentExpression node);

  R? visitAugmentedExpression(AugmentedExpression node);

  R? visitAugmentedInvocation(AugmentedInvocation node);

  R? visitAwaitExpression(AwaitExpression node);

  R? visitBinaryExpression(BinaryExpression node);

  R? visitBlock(Block node);

  R? visitBlockFunctionBody(BlockFunctionBody node);

  R? visitBooleanLiteral(BooleanLiteral node);

  R? visitBreakStatement(BreakStatement node);

  R? visitCascadeExpression(CascadeExpression node);

  R? visitCaseClause(CaseClause node);

  R? visitCastPattern(CastPattern node);

  R? visitCatchClause(CatchClause node);

  R? visitCatchClauseParameter(CatchClauseParameter node);

  R? visitClassDeclaration(ClassDeclaration node);

  R? visitClassTypeAlias(ClassTypeAlias node);

  R? visitComment(Comment node);

  R? visitCommentReference(CommentReference node);

  R? visitCompilationUnit(CompilationUnit node);

  R? visitConditionalExpression(ConditionalExpression node);

  R? visitConfiguration(Configuration node);

  R? visitConstantPattern(ConstantPattern node);

  R? visitConstructorDeclaration(ConstructorDeclaration node);

  R? visitConstructorFieldInitializer(ConstructorFieldInitializer node);

  R? visitConstructorName(ConstructorName node);

  R? visitConstructorReference(ConstructorReference node);

  R? visitConstructorSelector(ConstructorSelector node);

  R? visitContinueStatement(ContinueStatement node);

  R? visitDeclaredIdentifier(DeclaredIdentifier node);

  R? visitDeclaredVariablePattern(DeclaredVariablePattern node);

  R? visitDefaultFormalParameter(DefaultFormalParameter node);

  R? visitDoStatement(DoStatement node);

  R? visitDottedName(DottedName node);

  R? visitDoubleLiteral(DoubleLiteral node);

  R? visitEmptyFunctionBody(EmptyFunctionBody node);

  R? visitEmptyStatement(EmptyStatement node);

  R? visitEnumConstantArguments(EnumConstantArguments node);

  R? visitEnumConstantDeclaration(EnumConstantDeclaration node);

  R? visitEnumDeclaration(EnumDeclaration node);

  R? visitExportDirective(ExportDirective node);

  R? visitExpressionFunctionBody(ExpressionFunctionBody node);

  R? visitExpressionStatement(ExpressionStatement node);

  R? visitExtendsClause(ExtendsClause node);

  R? visitExtensionDeclaration(ExtensionDeclaration node);

  R? visitExtensionOnClause(ExtensionOnClause node);

  R? visitExtensionOverride(ExtensionOverride node);

  R? visitExtensionTypeDeclaration(ExtensionTypeDeclaration node);

  R? visitFieldDeclaration(FieldDeclaration node);

  R? visitFieldFormalParameter(FieldFormalParameter node);

  R? visitForEachPartsWithDeclaration(ForEachPartsWithDeclaration node);

  R? visitForEachPartsWithIdentifier(ForEachPartsWithIdentifier node);

  R? visitForEachPartsWithPattern(ForEachPartsWithPattern node);

  R? visitForElement(ForElement node);

  R? visitFormalParameterList(FormalParameterList node);

  R? visitForPartsWithDeclarations(ForPartsWithDeclarations node);

  R? visitForPartsWithExpression(ForPartsWithExpression node);

  R? visitForPartsWithPattern(ForPartsWithPattern node);

  R? visitForStatement(ForStatement node);

  R? visitFunctionDeclaration(FunctionDeclaration node);

  R? visitFunctionDeclarationStatement(FunctionDeclarationStatement node);

  R? visitFunctionExpression(FunctionExpression node);

  R? visitFunctionExpressionInvocation(FunctionExpressionInvocation node);

  R? visitFunctionReference(FunctionReference node);

  R? visitFunctionTypeAlias(FunctionTypeAlias functionTypeAlias);

  R? visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node);

  R? visitGenericFunctionType(GenericFunctionType node);

  R? visitGenericTypeAlias(GenericTypeAlias node);

  R? visitGuardedPattern(GuardedPattern node);

  R? visitHideCombinator(HideCombinator node);

  R? visitIfElement(IfElement node);

  R? visitIfStatement(IfStatement node);

  R? visitImplementsClause(ImplementsClause node);

  R? visitImplicitCallReference(ImplicitCallReference node);

  R? visitImportDirective(ImportDirective node);

  R? visitImportPrefixReference(ImportPrefixReference node);

  R? visitIndexExpression(IndexExpression node);

  R? visitInstanceCreationExpression(InstanceCreationExpression node);

  R? visitIntegerLiteral(IntegerLiteral node);

  R? visitInterpolationExpression(InterpolationExpression node);

  R? visitInterpolationString(InterpolationString node);

  R? visitIsExpression(IsExpression node);

  R? visitLabel(Label node);

  R? visitLabeledStatement(LabeledStatement node);

  R? visitLibraryDirective(LibraryDirective node);

  R? visitLibraryIdentifier(LibraryIdentifier node);

  R? visitListLiteral(ListLiteral node);

  R? visitListPattern(ListPattern node);

  R? visitLogicalAndPattern(LogicalAndPattern node);

  R? visitLogicalOrPattern(LogicalOrPattern node);

  R? visitMapLiteralEntry(MapLiteralEntry node);

  R? visitMapPattern(MapPattern node);

  R? visitMapPatternEntry(MapPatternEntry node);

  R? visitMethodDeclaration(MethodDeclaration node);

  R? visitMethodInvocation(MethodInvocation node);

  R? visitMixinDeclaration(MixinDeclaration node);

  R? visitMixinOnClause(MixinOnClause node);

  R? visitNamedExpression(NamedExpression node);

  R? visitNamedType(NamedType node);

  R? visitNativeClause(NativeClause node);

  R? visitNativeFunctionBody(NativeFunctionBody node);

  R? visitNullAssertPattern(NullAssertPattern node);

  R? visitNullAwareElement(NullAwareElement node);

  R? visitNullCheckPattern(NullCheckPattern node);

  R? visitNullLiteral(NullLiteral node);

  R? visitObjectPattern(ObjectPattern node);

  R? visitParenthesizedExpression(ParenthesizedExpression node);

  R? visitParenthesizedPattern(ParenthesizedPattern node);

  R? visitPartDirective(PartDirective node);

  R? visitPartOfDirective(PartOfDirective node);

  R? visitPatternAssignment(PatternAssignment node);

  R? visitPatternField(PatternField node);

  R? visitPatternFieldName(PatternFieldName node);

  R? visitPatternVariableDeclaration(PatternVariableDeclaration node);

  R? visitPatternVariableDeclarationStatement(
      PatternVariableDeclarationStatement node);

  R? visitPostfixExpression(PostfixExpression node);

  R? visitPrefixedIdentifier(PrefixedIdentifier node);

  R? visitPrefixExpression(PrefixExpression node);

  R? visitPropertyAccess(PropertyAccess node);

  R? visitRecordLiteral(RecordLiteral node);

  R? visitRecordPattern(RecordPattern node);

  R? visitRecordTypeAnnotation(RecordTypeAnnotation node);

  R? visitRecordTypeAnnotationNamedField(RecordTypeAnnotationNamedField node);

  R? visitRecordTypeAnnotationNamedFields(RecordTypeAnnotationNamedFields node);

  R? visitRecordTypeAnnotationPositionalField(
      RecordTypeAnnotationPositionalField node);

  R? visitRedirectingConstructorInvocation(
      RedirectingConstructorInvocation node);

  R? visitRelationalPattern(RelationalPattern node);

  R? visitRepresentationConstructorName(RepresentationConstructorName node);

  R? visitRepresentationDeclaration(RepresentationDeclaration node);

  R? visitRestPatternElement(RestPatternElement node);

  R? visitRethrowExpression(RethrowExpression node);

  R? visitReturnStatement(ReturnStatement node);

  R? visitScriptTag(ScriptTag node);

  R? visitSetOrMapLiteral(SetOrMapLiteral node);

  R? visitShowCombinator(ShowCombinator node);

  R? visitSimpleFormalParameter(SimpleFormalParameter node);

  R? visitSimpleIdentifier(SimpleIdentifier node);

  R? visitSimpleStringLiteral(SimpleStringLiteral node);

  R? visitSpreadElement(SpreadElement node);

  R? visitStringInterpolation(StringInterpolation node);

  R? visitSuperConstructorInvocation(SuperConstructorInvocation node);

  R? visitSuperExpression(SuperExpression node);

  R? visitSuperFormalParameter(SuperFormalParameter node);

  R? visitSwitchCase(SwitchCase node);

  R? visitSwitchDefault(SwitchDefault node);

  R? visitSwitchExpression(SwitchExpression node);

  R? visitSwitchExpressionCase(SwitchExpressionCase node);

  R? visitSwitchPatternCase(SwitchPatternCase node);

  R? visitSwitchStatement(SwitchStatement node);

  R? visitSymbolLiteral(SymbolLiteral node);

  R? visitThisExpression(ThisExpression node);

  R? visitThrowExpression(ThrowExpression node);

  R? visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node);

  R? visitTryStatement(TryStatement node);

  R? visitTypeArgumentList(TypeArgumentList node);

  R? visitTypeLiteral(TypeLiteral node);

  R? visitTypeParameter(TypeParameter node);

  R? visitTypeParameterList(TypeParameterList node);

  R? visitVariableDeclaration(VariableDeclaration node);

  R? visitVariableDeclarationList(VariableDeclarationList node);

  R? visitVariableDeclarationStatement(VariableDeclarationStatement node);

  R? visitWhenClause(WhenClause node);

  R? visitWhileStatement(WhileStatement node);

  R? visitWildcardPattern(WildcardPattern node);

  R? visitWithClause(WithClause node);

  R? visitYieldStatement(YieldStatement node);
}

/// The augmented expression.
///
/// It is created only inside an augmentation.
/// The exact meaning depends on what is augmented, and where it is used.
///
/// Augmenting getters: `augmented` invokes the getter and evaluates to the
/// return value.
/// The [element] is the augmented getter.
/// The [staticType] is the return type of the getter.
///
/// Augmenting setters: `augmented` must be followed by an `=`, and will
/// directly invoke the augmented setter.
/// The [element] is the augmented setter.
/// The [staticType] is meaningless, and set to `null`.
///
/// Augmenting fields: `augmented` can only be used in an initializer
/// expression, and refers to the original field's initializer expression.
/// The [element] is the augmented field.
/// The [staticType] is the type of the field.
///
/// Augmenting binary operators: `augmented` must be the LHS, and followed by
/// the argument, e.g. `augmented + 1`.
/// The [element] is the augmented [MethodElement].
/// The [staticType] is the type of `this`.
///
/// Augmenting index operators: `augmented` must be the index target,
/// e.g. `augmented[0]`.
/// The [element] is the augmented [MethodElement].
/// The [staticType] is the type of `this`.
///
/// Augmenting prefix operators: `augmented` must be the target, e.g.
/// `~augmented`.
/// The [element] is the augmented [MethodElement].
/// The [staticType] is the type of `this`.
abstract final class AugmentedExpression implements Expression {
  /// The 'augmented' keyword.
  Token get augmentedKeyword;

  /// The referenced augmented element: getter, setter, variable.
  Element? get element;

  /// The referenced augmented element: getter, setter, variable.
  // TODO(brianwilkerson): Consider resolving this to a fragment rather than an
  //  element. In this case I think that's closer to the right semantics.
  @experimental
  Element2? get element2;
}

final class AugmentedExpressionImpl extends ExpressionImpl
    implements AugmentedExpression {
  @override
  final Token augmentedKeyword;

  @override
  Element? element;

  AugmentedExpressionImpl({
    required this.augmentedKeyword,
  });

  @override
  Token get beginToken => augmentedKeyword;

  @experimental
  @override
  Element2? get element2 => (element as Fragment?)?.element;

  @override
  Token get endToken => augmentedKeyword;

  @override
  bool get isAssignable => true;

  @override
  Precedence get precedence => Precedence.primary;

  @override
  ChildEntities get _childEntities =>
      ChildEntities()..addToken('augmentedKeyword', augmentedKeyword);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitAugmentedExpression(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitAugmentedExpression(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    // There are no children to visit.
  }
}

/// Invocation of the augmented function, constructor, or method.
///
///    augmentedInvocation ::=
///        'augmented' [TypeArgumentList]? [ArgumentList]
abstract final class AugmentedInvocation implements Expression {
  /// The list of value arguments.
  ArgumentList get arguments;

  /// The 'augmented' keyword.
  Token get augmentedKeyword;

  /// The referenced augmented element: function, constructor, or method.
  ExecutableElement? get element;

  /// The referenced augmented element: function, constructor, or method.
  ///
  /// Returns `null` if the AST structure hasn't been resolved or if this
  /// fragment is the first fragment in the chain.
  // TODO(brianwilkerson): Consider resolving this to a fragment rather than an
  //  element. In this case I think that's closer to the right semantics.
  @experimental
  ExecutableElement2? get element2;

  /// The list of type arguments.
  ///
  /// In valid code cannot be provided for augmented constructor invocation.
  TypeArgumentList? get typeArguments;
}

final class AugmentedInvocationImpl extends ExpressionImpl
    implements AugmentedInvocation {
  @override
  final Token augmentedKeyword;

  @override
  ExecutableElement? element;

  @override
  final TypeArgumentListImpl? typeArguments;

  @override
  final ArgumentListImpl arguments;

  AugmentedInvocationImpl({
    required this.augmentedKeyword,
    required this.typeArguments,
    required this.arguments,
  }) {
    _becomeParentOf(typeArguments);
    _becomeParentOf(arguments);
  }

  @override
  Token get beginToken => augmentedKeyword;

  @experimental
  @override
  ExecutableElement2? get element2 => (element as ExecutableFragment?)?.element;

  @override
  Token get endToken => arguments.endToken;

  @override
  Precedence get precedence => Precedence.postfix;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('augmentedKeyword', augmentedKeyword)
    ..addNode('typeArguments', typeArguments)
    ..addNode('arguments', arguments);

  @override
  E? accept<E>(AstVisitor<E> visitor) {
    return visitor.visitAugmentedInvocation(this);
  }

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitAugmentedInvocation(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    typeArguments?.accept(visitor);
    arguments.accept(visitor);
  }
}

/// An await expression.
///
///    awaitExpression ::=
///        'await' [Expression]
abstract final class AwaitExpression implements Expression {
  /// The `await` keyword.
  Token get awaitKeyword;

  /// The expression whose value is being waited on.
  Expression get expression;
}

final class AwaitExpressionImpl extends ExpressionImpl
    implements AwaitExpression {
  @override
  final Token awaitKeyword;

  ExpressionImpl _expression;

  /// Initializes a newly created await expression.
  AwaitExpressionImpl({
    required this.awaitKeyword,
    required ExpressionImpl expression,
  }) : _expression = expression {
    _becomeParentOf(_expression);
  }

  @override
  Token get beginToken {
    return awaitKeyword;
  }

  @override
  Token get endToken => _expression.endToken;

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  Precedence get precedence => Precedence.prefix;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('awaitKeyword', awaitKeyword)
    ..addNode('expression', expression);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitAwaitExpression(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitAwaitExpression(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _expression.accept(visitor);
  }
}

/// A binary (infix) expression.
///
///    binaryExpression ::=
///        [Expression] [Token] [Expression]
abstract final class BinaryExpression
    implements Expression, MethodReferenceExpression {
  /// The expression used to compute the left operand.
  Expression get leftOperand;

  /// The binary operator being applied.
  Token get operator;

  /// The expression used to compute the right operand.
  Expression get rightOperand;

  /// The function type of the invocation, or `null` if the AST structure hasn't
  /// been resolved or if the invocation couldn't be resolved.
  FunctionType? get staticInvokeType;
}

final class BinaryExpressionImpl extends ExpressionImpl
    implements BinaryExpression {
  ExpressionImpl _leftOperand;

  @override
  final Token operator;

  ExpressionImpl _rightOperand;

  @override
  MethodElement? staticElement;

  @override
  FunctionType? staticInvokeType;

  /// Initializes a newly created binary expression.
  BinaryExpressionImpl({
    required ExpressionImpl leftOperand,
    required this.operator,
    required ExpressionImpl rightOperand,
  })  : _leftOperand = leftOperand,
        _rightOperand = rightOperand {
    _becomeParentOf(leftOperand);
    _becomeParentOf(rightOperand);
  }

  @override
  Token get beginToken => _leftOperand.beginToken;

  @experimental
  @override
  MethodElement2? get element => staticElement?.asElement2 as MethodElement2?;

  @override
  Token get endToken => _rightOperand.endToken;

  @override
  ExpressionImpl get leftOperand => _leftOperand;

  set leftOperand(ExpressionImpl expression) {
    _leftOperand = _becomeParentOf(expression);
  }

  @override
  Precedence get precedence => Precedence.forTokenType(operator.type);

  @override
  ExpressionImpl get rightOperand => _rightOperand;

  set rightOperand(ExpressionImpl expression) {
    _rightOperand = _becomeParentOf(expression);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('leftOperand', leftOperand)
    ..addToken('operator', operator)
    ..addNode('rightOperand', rightOperand);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitBinaryExpression(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitBinaryExpression(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _leftOperand.accept(visitor);
    _rightOperand.accept(visitor);
  }
}

/// A sequence of statements.
///
///    block ::=
///        '{' statement* '}'
abstract final class Block implements Statement {
  /// The left curly bracket.
  Token get leftBracket;

  /// The right curly bracket.
  Token get rightBracket;

  /// The statements contained in the block.
  NodeList<Statement> get statements;
}

/// A function body that consists of a block of statements.
///
///    blockFunctionBody ::=
///        ('async' | 'async' '*' | 'sync' '*')? [Block]
abstract final class BlockFunctionBody implements FunctionBody {
  /// The block representing the body of the function.
  Block get block;
}

final class BlockFunctionBodyImpl extends FunctionBodyImpl
    implements BlockFunctionBody {
  @override
  final Token? keyword;

  @override
  final Token? star;

  BlockImpl _block;

  /// Initializes a newly created function body consisting of a block of
  /// statements.
  ///
  /// The [keyword] can be `null` if there's no keyword specified for the block.
  ///
  /// The [star] can be `null` if there's no star following the keyword (and
  /// must be `null` if there's no keyword).
  BlockFunctionBodyImpl({
    required this.keyword,
    required this.star,
    required BlockImpl block,
  }) : _block = block {
    _becomeParentOf(_block);
  }

  @override
  Token get beginToken {
    if (keyword case var keyword?) {
      return keyword;
    }
    return _block.beginToken;
  }

  @override
  BlockImpl get block => _block;

  set block(BlockImpl block) {
    _block = _becomeParentOf(block);
  }

  @override
  Token get endToken => _block.endToken;

  @override
  bool get isAsynchronous => keyword?.lexeme == Keyword.ASYNC.lexeme;

  @override
  bool get isGenerator => star != null;

  @override
  bool get isSynchronous => keyword?.lexeme != Keyword.ASYNC.lexeme;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('keyword', keyword)
    ..addToken('star', star)
    ..addNode('block', block);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitBlockFunctionBody(this);

  @override
  DartType resolve(ResolverVisitor resolver, DartType? imposedType) =>
      resolver.visitBlockFunctionBody(this, imposedType: imposedType);

  @override
  void visitChildren(AstVisitor visitor) {
    _block.accept(visitor);
  }
}

final class BlockImpl extends StatementImpl
    with AstNodeWithNameScopeMixin
    implements Block {
  @override
  final Token leftBracket;

  final NodeListImpl<StatementImpl> _statements = NodeListImpl._();

  @override
  final Token rightBracket;

  /// Initializes a newly created block of code.
  BlockImpl({
    required this.leftBracket,
    required List<StatementImpl> statements,
    required this.rightBracket,
  }) {
    _statements._initialize(this, statements);
  }

  @override
  Token get beginToken => leftBracket;

  @override
  Token get endToken => rightBracket;

  @override
  NodeListImpl<StatementImpl> get statements => _statements;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('leftBracket', leftBracket)
    ..addNodeList('statements', statements)
    ..addToken('rightBracket', rightBracket);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitBlock(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _statements.accept(visitor);
  }
}

/// A boolean literal expression.
///
///    booleanLiteral ::=
///        'false' | 'true'
abstract final class BooleanLiteral implements Literal {
  /// The token representing the literal.
  Token get literal;

  /// The value of the literal.
  bool get value;
}

final class BooleanLiteralImpl extends LiteralImpl implements BooleanLiteral {
  @override
  final Token literal;

  @override
  final bool value;

  /// Initializes a newly created boolean literal.
  BooleanLiteralImpl({
    required this.literal,
    required this.value,
  });

  @override
  Token get beginToken => literal;

  @override
  Token get endToken => literal;

  @override
  bool get isSynthetic => literal.isSynthetic;

  @override
  ChildEntities get _childEntities =>
      ChildEntities()..addToken('literal', literal);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitBooleanLiteral(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitBooleanLiteral(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    // There are no children to visit.
  }
}

/// A break statement.
///
///    breakStatement ::=
///        'break' [SimpleIdentifier]? ';'
abstract final class BreakStatement implements Statement {
  /// The token representing the `break` keyword.
  Token get breakKeyword;

  /// The label associated with the statement, or `null` if there's no label.
  SimpleIdentifier? get label;

  /// The semicolon terminating the statement.
  Token get semicolon;

  /// The node from which this break statement is breaking, or `null` if the AST
  /// hasn't yet been resolved or if the target couldn't be resolved.
  ///
  /// This is either a [Statement] (in the case of breaking out of a loop), a
  /// [SwitchMember] (in the case of a labeled break statement whose label
  /// matches a label on a switch case in an enclosing switch statement).
  ///
  /// Note that if the source code has errors, the target might be invalid.
  /// For example, if the break statement is trying to break to a switch case
  /// the target will be the switch case even though breaking to a switch case
  /// isn't valid.
  AstNode? get target;
}

final class BreakStatementImpl extends StatementImpl implements BreakStatement {
  @override
  final Token breakKeyword;

  SimpleIdentifierImpl? _label;

  @override
  final Token semicolon;

  @override
  AstNode? target;

  /// Initializes a newly created break statement.
  ///
  /// The [label] can be `null` if there's no label associated with the
  /// statement.
  BreakStatementImpl({
    required this.breakKeyword,
    required SimpleIdentifierImpl? label,
    required this.semicolon,
  }) : _label = label {
    _becomeParentOf(_label);
  }

  @override
  Token get beginToken => breakKeyword;

  @override
  Token get endToken => semicolon;

  @override
  SimpleIdentifierImpl? get label => _label;

  set label(SimpleIdentifierImpl? identifier) {
    _label = _becomeParentOf(identifier);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('breakKeyword', breakKeyword)
    ..addNode('label', label)
    ..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitBreakStatement(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _label?.accept(visitor);
  }
}

/// A sequence of cascaded expressions: expressions that share a common target.
///
/// There are three kinds of expressions that can be used in a cascade
/// expression: [IndexExpression], [MethodInvocation] and [PropertyAccess].
///
///    cascadeExpression ::=
///        [Expression] cascadeSection*
///
///    cascadeSection ::=
///        ('..' | '?..') (cascadeSelector arguments*)
///        (assignableSelector arguments*)*
///        (assignmentOperator expressionWithoutCascade)?
///
///    cascadeSelector ::=
///        '[ ' expression '] '
///      | identifier
abstract final class CascadeExpression
    implements Expression, NullShortableExpression {
  /// The cascade sections sharing the common target.
  NodeList<Expression> get cascadeSections;

  /// Whether this cascade is null aware (as opposed to non-null).
  bool get isNullAware;

  /// The target of the cascade sections.
  Expression get target;
}

final class CascadeExpressionImpl extends ExpressionImpl
    with NullShortableExpressionImpl
    implements CascadeExpression {
  ExpressionImpl _target;

  final NodeListImpl<ExpressionImpl> _cascadeSections = NodeListImpl._();

  /// Initializes a newly created cascade expression.
  ///
  /// The list of [cascadeSections] must contain at least one element.
  CascadeExpressionImpl({
    required ExpressionImpl target,
    required List<ExpressionImpl> cascadeSections,
  }) : _target = target {
    _becomeParentOf(_target);
    _cascadeSections._initialize(this, cascadeSections);
  }

  @override
  Token get beginToken => _target.beginToken;

  @override
  NodeListImpl<ExpressionImpl> get cascadeSections => _cascadeSections;

  @override
  Token get endToken => _cascadeSections.endToken!;

  @override
  bool get isNullAware {
    return target.endToken.next!.type == TokenType.QUESTION_PERIOD_PERIOD;
  }

  @override
  Precedence get precedence => Precedence.cascade;

  @override
  ExpressionImpl get target => _target;

  set target(ExpressionImpl target) {
    _target = _becomeParentOf(target);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('target', target)
    ..addNodeList('cascadeSections', cascadeSections);

  @override
  AstNode? get _nullShortingExtensionCandidate => null;

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitCascadeExpression(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitCascadeExpression(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _target.accept(visitor);
    _cascadeSections.accept(visitor);
  }

  @override
  bool _extendsNullShorting(Expression descendant) {
    return _cascadeSections.contains(descendant);
  }
}

/// The `case` clause that can optionally appear in an `if` statement.
///
///    caseClause ::=
///        'case' [GuardedPattern]
abstract final class CaseClause implements AstNode {
  /// The token representing the `case` keyword.
  Token get caseKeyword;

  /// The pattern controlling whether the statements are executed.
  GuardedPattern get guardedPattern;
}

final class CaseClauseImpl extends AstNodeImpl implements CaseClause {
  @override
  final Token caseKeyword;

  @override
  final GuardedPatternImpl guardedPattern;

  CaseClauseImpl({
    required this.caseKeyword,
    required this.guardedPattern,
  }) {
    _becomeParentOf(guardedPattern);
  }

  @override
  Token get beginToken => caseKeyword;

  @override
  Token get endToken => guardedPattern.endToken;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('caseKeyword', caseKeyword)
    ..addNode('guardedPattern', guardedPattern);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitCaseClause(this);

  @override
  void visitChildren(AstVisitor visitor) {
    guardedPattern.accept(visitor);
  }
}

sealed class CaseNodeImpl implements AstNode {
  GuardedPatternImpl get guardedPattern;
}

/// A cast pattern.
///
///    castPattern ::=
///        [DartPattern] 'as' [TypeAnnotation]
abstract final class CastPattern implements DartPattern {
  /// The `as` token.
  Token get asToken;

  /// The pattern used to match the value being cast.
  DartPattern get pattern;

  /// The type that the value being matched is cast to.
  TypeAnnotation get type;
}

final class CastPatternImpl extends DartPatternImpl implements CastPattern {
  @override
  final Token asToken;

  @override
  final DartPatternImpl pattern;

  @override
  final TypeAnnotationImpl type;

  CastPatternImpl({
    required this.pattern,
    required this.asToken,
    required this.type,
  }) {
    _becomeParentOf(pattern);
    _becomeParentOf(type);
  }

  @override
  Token get beginToken => pattern.beginToken;

  @override
  Token get endToken => type.endToken;

  @override
  PatternPrecedence get precedence => PatternPrecedence.postfix;

  @override
  VariablePatternImpl? get variablePattern => pattern.variablePattern;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addNode('pattern', pattern)
    ..addToken('asToken', asToken)
    ..addNode('type', type);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitCastPattern(this);

  @override
  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
    return resolverVisitor.analyzeCastPatternSchema().unwrapTypeSchemaView();
  }

  @override
  PatternResult<DartType> resolvePattern(
    ResolverVisitor resolverVisitor,
    SharedMatchContext context,
  ) {
    inferenceLogWriter?.enterPattern(this);
    type.accept(resolverVisitor);
    var requiredType = type.typeOrThrow;

    var analysisResult = resolverVisitor.analyzeCastPattern(
      context: context,
      pattern: this,
      innerPattern: pattern,
      requiredType: SharedTypeView(requiredType),
    );

    resolverVisitor.checkPatternNeverMatchesValueType(
      context: context,
      pattern: this,
      requiredType: requiredType,
      matchedValueType: analysisResult.matchedValueType.unwrapTypeView(),
    );
    inferenceLogWriter?.exitPattern(this);

    return analysisResult;
  }

  @override
  void visitChildren(AstVisitor visitor) {
    pattern.accept(visitor);
    type.accept(visitor);
  }
}

/// A catch clause within a try statement.
///
///    onPart ::=
///        catchPart [Block]
///      | 'on' type catchPart? [Block]
///
///    catchPart ::=
///        'catch' '(' [CatchClauseParameter] (',' [CatchClauseParameter])? ')'
abstract final class CatchClause implements AstNode {
  /// The body of the catch block.
  Block get body;

  /// The token representing the `catch` keyword, or `null` if there's no
  /// `catch` keyword.
  Token? get catchKeyword;

  /// The comma separating the exception parameter from the stack trace
  /// parameter, or `null` if there's no stack trace parameter.
  Token? get comma;

  /// The parameter whose value is the exception that was thrown, or `null` if
  /// there's no `catch` keyword.
  CatchClauseParameter? get exceptionParameter;

  /// The type of exceptions caught by this catch clause, or `null` if this
  /// catch clause catches every type of exception.
  TypeAnnotation? get exceptionType;

  /// The left parenthesis, or `null` if there's no `catch` keyword.
  Token? get leftParenthesis;

  /// The token representing the `on` keyword, or `null` if there's no `on`
  /// keyword.
  Token? get onKeyword;

  /// The right parenthesis, or `null` if there's no `catch` keyword.
  Token? get rightParenthesis;

  /// The parameter whose value is the stack trace associated with the
  /// exception, or `null` if there's no stack trace parameter.
  CatchClauseParameter? get stackTraceParameter;
}

final class CatchClauseImpl extends AstNodeImpl implements CatchClause {
  @override
  final Token? onKeyword;

  TypeAnnotationImpl? _exceptionType;

  @override
  final Token? catchKeyword;

  @override
  final Token? leftParenthesis;

  CatchClauseParameterImpl? _exceptionParameter;

  @override
  final Token? comma;

  CatchClauseParameterImpl? _stackTraceParameter;

  @override
  final Token? rightParenthesis;

  BlockImpl _body;

  /// Initializes a newly created catch clause.
  ///
  /// The [onKeyword] and [exceptionType] can be `null` if the clause is to
  /// catch all exceptions.
  ///
  /// The [comma] and [_stackTraceParameter] can be `null` if the stack trace
  /// parameter isn't defined.
  CatchClauseImpl({
    required this.onKeyword,
    required TypeAnnotationImpl? exceptionType,
    required this.catchKeyword,
    required this.leftParenthesis,
    required CatchClauseParameterImpl? exceptionParameter,
    required this.comma,
    required CatchClauseParameterImpl? stackTraceParameter,
    required this.rightParenthesis,
    required BlockImpl body,
  })  : assert(onKeyword != null || catchKeyword != null),
        _exceptionType = exceptionType,
        _exceptionParameter = exceptionParameter,
        _stackTraceParameter = stackTraceParameter,
        _body = body {
    _becomeParentOf(_exceptionType);
    _becomeParentOf(_exceptionParameter);
    _becomeParentOf(_stackTraceParameter);
    _becomeParentOf(_body);
  }

  @override
  Token get beginToken {
    if (onKeyword case var onKeyword?) {
      return onKeyword;
    }
    return catchKeyword!;
  }

  @override
  BlockImpl get body => _body;

  set body(BlockImpl block) {
    _body = _becomeParentOf(block);
  }

  @override
  Token get endToken => _body.endToken;

  @override
  CatchClauseParameterImpl? get exceptionParameter {
    return _exceptionParameter;
  }

  set exceptionParameter(CatchClauseParameterImpl? parameter) {
    _exceptionParameter = parameter;
    _becomeParentOf(parameter);
  }

  @override
  TypeAnnotationImpl? get exceptionType => _exceptionType;

  set exceptionType(TypeAnnotationImpl? exceptionType) {
    _exceptionType = _becomeParentOf(exceptionType);
  }

  @override
  CatchClauseParameterImpl? get stackTraceParameter {
    return _stackTraceParameter;
  }

  set stackTraceParameter(CatchClauseParameterImpl? parameter) {
    _stackTraceParameter = parameter;
    _becomeParentOf(parameter);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('onKeyword', onKeyword)
    ..addNode('exceptionType', exceptionType)
    ..addToken('catchKeyword', catchKeyword)
    ..addToken('leftParenthesis', leftParenthesis)
    ..addNode('exceptionParameter', exceptionParameter)
    ..addToken('comma', comma)
    ..addNode('stackTraceParameter', stackTraceParameter)
    ..addToken('rightParenthesis', rightParenthesis)
    ..addNode('body', body);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitCatchClause(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _exceptionType?.accept(visitor);
    _exceptionParameter?.accept(visitor);
    _stackTraceParameter?.accept(visitor);
    _body.accept(visitor);
  }
}

/// An 'exception' or 'stackTrace' parameter in [CatchClause].
abstract final class CatchClauseParameter extends AstNode {
  /// The declared element, or `null` if the AST hasn't been resolved.
  LocalVariableElement? get declaredElement;

  /// The declared element.
  ///
  /// Returns `null` if the AST hasn't been resolved.
  @experimental
  LocalVariableElement2? get declaredElement2;

  /// The name of the parameter.
  Token get name;
}

final class CatchClauseParameterImpl extends AstNodeImpl
    implements CatchClauseParameter {
  @override
  final Token name;

  @override
  LocalVariableElementImpl? declaredElement;

  CatchClauseParameterImpl({
    required this.name,
  });

  @override
  Token get beginToken => name;

  @experimental
  @override
  LocalVariableElement2? get declaredElement2 {
    return declaredElement.asElement2 as LocalVariableElementImpl2?;
  }

  @override
  Token get endToken => name;

  @override
  ChildEntities get _childEntities =>
      super._childEntities..addToken('name', name);

  @override
  E? accept<E>(AstVisitor<E> visitor) {
    return visitor.visitCatchClauseParameter(this);
  }

  @override
  void visitChildren(AstVisitor visitor) {}
}

/// A helper class to allow iteration of child entities of an AST node.
class ChildEntities {
  /// The list of child entities to be iterated over.
  final List<ChildEntity> entities = [];

  List<SyntacticEntity> get syntacticEntities {
    var result = <SyntacticEntity>[];
    for (var entity in entities) {
      var entityValue = entity.value;
      if (entityValue is SyntacticEntity) {
        result.add(entityValue);
      } else if (entityValue is List<Object>) {
        for (var element in entityValue) {
          if (element is SyntacticEntity) {
            result.add(element);
          }
        }
      }
    }

    var needsSorting = false;
    int? lastOffset;
    for (var entity in result) {
      if (lastOffset != null && lastOffset > entity.offset) {
        needsSorting = true;
        break;
      }
      lastOffset = entity.offset;
    }

    if (needsSorting) {
      result.sort((a, b) => a.offset - b.offset);
    }

    return result;
  }

  void addAll(ChildEntities other) {
    entities.addAll(other.entities);
  }

  void addNode(String name, AstNode? value) {
    if (value != null) {
      entities.add(
        ChildEntity(name, value),
      );
    }
  }

  void addNodeList(String name, List<AstNode> value) {
    entities.add(
      ChildEntity(name, value),
    );
  }

  void addToken(String name, Token? value) {
    if (value != null) {
      entities.add(
        ChildEntity(name, value),
      );
    }
  }

  void addTokenList(String name, List<Token> value) {
    entities.add(
      ChildEntity(name, value),
    );
  }
}

/// A named child of an [AstNode], usually a token, node, or a list of nodes.
class ChildEntity {
  final String name;
  final Object value;

  ChildEntity(this.name, this.value);
}

/// The declaration of a class.
///
///    classDeclaration ::=
///        classModifiers 'class' name [TypeParameterList]?
///        [ExtendsClause]? [WithClause]? [ImplementsClause]?
///        '{' [ClassMember]* '}'
///
///    classModifiers ::= 'sealed'
///      | 'abstract'? ('base' | 'interface' | 'final')?
///      | 'abstract'? 'base'? 'mixin'
abstract final class ClassDeclaration
    implements NamedCompilationUnitMember, FragmentDeclaration {
  /// The `abstract` keyword, or `null` if the keyword was absent.
  Token? get abstractKeyword;

  /// The `augment` keyword, or `null` if the keyword was absent.
  @experimental
  Token? get augmentKeyword;

  /// The `base` keyword, or `null` if the keyword was absent.
  Token? get baseKeyword;

  /// The token representing the `class` keyword.
  Token get classKeyword;

  @override
  ClassElement? get declaredElement;

  @experimental
  @override
  ClassFragment? get declaredFragment;

  /// The `extends` clause for this class, or `null` if the class doesn't extend
  /// any other class.
  ExtendsClause? get extendsClause;

  /// The `final` keyword, or `null` if the keyword was absent.
  Token? get finalKeyword;

  /// The `implements` clause for the class, or `null` if the class doesn't
  /// implement any interfaces.
  ImplementsClause? get implementsClause;

  /// The `interface` keyword, or `null` if the keyword was absent.
  Token? get interfaceKeyword;

  /// The left curly bracket.
  Token get leftBracket;

  /// The `macro` keyword, or `null` if the keyword was absent.
  @experimental
  Token? get macroKeyword;

  /// The members defined by the class.
  NodeList<ClassMember> get members;

  /// The `mixin` keyword, or `null` if the keyword was absent.
  Token? get mixinKeyword;

  /// The native clause for this class, or `null` if the class doesn't have a
  /// native clause.
  NativeClause? get nativeClause;

  /// The right curly bracket.
  Token get rightBracket;

  /// The `sealed` keyword, or `null` if the keyword was absent.
  Token? get sealedKeyword;

  /// The type parameters for the class, or `null` if the class doesn't have any
  /// type parameters.
  TypeParameterList? get typeParameters;

  /// The `with` clause for the class, or `null` if the class doesn't have a
  /// `with` clause.
  WithClause? get withClause;
}

final class ClassDeclarationImpl extends NamedCompilationUnitMemberImpl
    with AstNodeWithNameScopeMixin
    implements ClassDeclaration {
  @override
  final Token? augmentKeyword;

  @override
  final Token? abstractKeyword;

  @override
  final Token? macroKeyword;

  @override
  final Token? sealedKeyword;

  @override
  final Token? baseKeyword;

  @override
  final Token? interfaceKeyword;

  @override
  final Token? finalKeyword;

  @override
  final Token? mixinKeyword;

  @override
  final Token classKeyword;

  @override
  TypeParameterListImpl? typeParameters;

  @override
  ExtendsClauseImpl? extendsClause;

  @override
  WithClauseImpl? withClause;

  @override
  ImplementsClauseImpl? implementsClause;

  @override
  final NativeClauseImpl? nativeClause;

  @override
  final Token leftBracket;

  @override
  final NodeListImpl<ClassMemberImpl> members = NodeListImpl._();

  @override
  final Token rightBracket;

  @override
  ClassElementImpl? declaredElement;

  ClassDeclarationImpl({
    required super.comment,
    required super.metadata,
    required this.augmentKeyword,
    required this.abstractKeyword,
    required this.macroKeyword,
    required this.sealedKeyword,
    required this.baseKeyword,
    required this.interfaceKeyword,
    required this.finalKeyword,
    required this.mixinKeyword,
    required this.classKeyword,
    required super.name,
    required this.typeParameters,
    required this.extendsClause,
    required this.withClause,
    required this.implementsClause,
    required this.nativeClause,
    required this.leftBracket,
    required List<ClassMemberImpl> members,
    required this.rightBracket,
  }) {
    _becomeParentOf(typeParameters);
    _becomeParentOf(extendsClause);
    _becomeParentOf(withClause);
    _becomeParentOf(implementsClause);
    _becomeParentOf(nativeClause);
    this.members._initialize(this, members);
  }

  @experimental
  @override
  ClassFragment? get declaredFragment => declaredElement as ClassFragment;

  @override
  Token get endToken => rightBracket;

  @override
  Token get firstTokenAfterCommentAndMetadata {
    return abstractKeyword ??
        macroKeyword ??
        sealedKeyword ??
        baseKeyword ??
        interfaceKeyword ??
        finalKeyword ??
        augmentKeyword ??
        mixinKeyword ??
        classKeyword;
  }

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('abstractKeyword', abstractKeyword)
    ..addToken('macroKeyword', macroKeyword)
    ..addToken('sealedKeyword', sealedKeyword)
    ..addToken('baseKeyword', baseKeyword)
    ..addToken('interfaceKeyword', interfaceKeyword)
    ..addToken('finalKeyword', finalKeyword)
    ..addToken('augmentKeyword', augmentKeyword)
    ..addToken('mixinKeyword', mixinKeyword)
    ..addToken('classKeyword', classKeyword)
    ..addToken('name', name)
    ..addNode('typeParameters', typeParameters)
    ..addNode('extendsClause', extendsClause)
    ..addNode('withClause', withClause)
    ..addNode('implementsClause', implementsClause)
    ..addToken('leftBracket', leftBracket)
    ..addNodeList('members', members)
    ..addToken('rightBracket', rightBracket);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitClassDeclaration(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    typeParameters?.accept(visitor);
    extendsClause?.accept(visitor);
    withClause?.accept(visitor);
    implementsClause?.accept(visitor);
    nativeClause?.accept(visitor);
    members.accept(visitor);
  }
}

/// A node that declares a name within the scope of a class, enum, extension,
/// extension type, or mixin declaration.
sealed class ClassMember implements Declaration {}

sealed class ClassMemberImpl extends DeclarationImpl implements ClassMember {
  /// Initializes a newly created member of a class.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the member
  /// doesn't have the corresponding attribute.
  ClassMemberImpl({
    required super.comment,
    required super.metadata,
  });
}

/// A class type alias.
///
///    classTypeAlias ::=
///        classModifiers 'class' [SimpleIdentifier] [TypeParameterList]? '='
///        mixinApplication
///
///    classModifiers ::= 'sealed'
///      | 'abstract'? ('base' | 'interface' | 'final')?
///      | 'abstract'? 'base'? 'mixin'
///
///    mixinApplication ::=
///        [NamedType] [WithClause] [ImplementsClause]? ';'
abstract final class ClassTypeAlias implements TypeAlias, FragmentDeclaration {
  /// The token for the `abstract` keyword, or `null` if this isn't defining an
  /// abstract class.
  Token? get abstractKeyword;

  /// The `base` keyword, or `null` if the keyword was absent.
  Token? get baseKeyword;

  @override
  ClassElement? get declaredElement;

  @experimental
  @override
  ClassFragment? get declaredFragment;

  /// The token for the '=' separating the name from the definition.
  Token get equals;

  /// The `final` keyword, or `null` if the keyword was absent.
  Token? get finalKeyword;

  /// The implements clause for this class, or `null` if there's no implements
  /// clause.
  ImplementsClause? get implementsClause;

  /// The `interface` keyword, or `null` if the keyword was absent.
  Token? get interfaceKeyword;

  /// The `mixin` keyword, or `null` if the keyword was absent.
  Token? get mixinKeyword;

  /// The `sealed` keyword, or `null` if the keyword was absent.
  Token? get sealedKeyword;

  /// The name of the superclass of the class being declared.
  NamedType get superclass;

  /// The type parameters for the class, or `null` if the class doesn't have any
  /// type parameters.
  TypeParameterList? get typeParameters;

  /// The with clause for this class.
  WithClause get withClause;
}

final class ClassTypeAliasImpl extends TypeAliasImpl implements ClassTypeAlias {
  TypeParameterListImpl? _typeParameters;

  @override
  final Token equals;

  @override
  final Token? abstractKeyword;

  /// The token for the `macro` keyword, or `null` if this isn't defining a
  /// macro class.
// TODO(brianwilkerson): Move this comment to the getter when it's added to
  //  the public API.
  final Token? macroKeyword;

  @override
  final Token? sealedKeyword;

  @override
  final Token? baseKeyword;

  @override
  final Token? interfaceKeyword;

  @override
  final Token? finalKeyword;

  @override
  final Token? mixinKeyword;

  NamedTypeImpl _superclass;

  WithClauseImpl _withClause;

  ImplementsClauseImpl? _implementsClause;

  @override
  ClassElementImpl? declaredElement;

  /// Initializes a newly created class type alias.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the class
  /// type alias doesn't have the corresponding attribute.
  ///
  /// The [typeParameters] can be `null` if the class doesn't have any type
  /// parameters.
  ///
  /// The [abstractKeyword] can be `null` if the class isn't abstract.
  ///
  /// The [implementsClause] can be `null` if the class doesn't implement any
  /// interfaces.
  ClassTypeAliasImpl({
    required super.comment,
    required super.metadata,
    required super.typedefKeyword,
    required super.name,
    required TypeParameterListImpl? typeParameters,
    required this.equals,
    required this.abstractKeyword,
    required this.macroKeyword,
    required this.sealedKeyword,
    required this.baseKeyword,
    required this.interfaceKeyword,
    required this.finalKeyword,
    required super.augmentKeyword,
    required this.mixinKeyword,
    required NamedTypeImpl superclass,
    required WithClauseImpl withClause,
    required ImplementsClauseImpl? implementsClause,
    required super.semicolon,
  })  : _typeParameters = typeParameters,
        _superclass = superclass,
        _withClause = withClause,
        _implementsClause = implementsClause {
    _becomeParentOf(_typeParameters);
    _becomeParentOf(_superclass);
    _becomeParentOf(_withClause);
    _becomeParentOf(_implementsClause);
  }

  @experimental
  @override
  ClassFragment? get declaredFragment => declaredElement as ClassFragment?;

  @override
  Token get firstTokenAfterCommentAndMetadata {
    return abstractKeyword ??
        macroKeyword ??
        sealedKeyword ??
        baseKeyword ??
        interfaceKeyword ??
        finalKeyword ??
        augmentKeyword ??
        mixinKeyword ??
        typedefKeyword;
  }

  @override
  ImplementsClauseImpl? get implementsClause => _implementsClause;

  set implementsClause(ImplementsClauseImpl? implementsClause) {
    _implementsClause = _becomeParentOf(implementsClause);
  }

  @override
  NamedTypeImpl get superclass => _superclass;

  set superclass(NamedTypeImpl superclass) {
    _superclass = _becomeParentOf(superclass);
  }

  @override
  TypeParameterListImpl? get typeParameters => _typeParameters;

  set typeParameters(TypeParameterListImpl? typeParameters) {
    _typeParameters = _becomeParentOf(typeParameters as TypeParameterListImpl);
  }

  @override
  WithClauseImpl get withClause => _withClause;

  set withClause(WithClauseImpl withClause) {
    _withClause = _becomeParentOf(withClause);
  }

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('typedefKeyword', typedefKeyword)
    ..addToken('name', name)
    ..addNode('typeParameters', typeParameters)
    ..addToken('equals', equals)
    ..addToken('abstractKeyword', abstractKeyword)
    ..addToken('macroKeyword', macroKeyword)
    ..addToken('sealedKeyword', sealedKeyword)
    ..addToken('baseKeyword', baseKeyword)
    ..addToken('interfaceKeyword', interfaceKeyword)
    ..addToken('finalKeyword', finalKeyword)
    ..addToken('augmentKeyword', augmentKeyword)
    ..addToken('mixinKeyword', mixinKeyword)
    ..addNode('superclass', superclass)
    ..addNode('withClause', withClause)
    ..addNode('implementsClause', implementsClause)
    ..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitClassTypeAlias(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _typeParameters?.accept(visitor);
    _superclass.accept(visitor);
    _withClause.accept(visitor);
    _implementsClause?.accept(visitor);
  }
}

sealed class CollectionElement implements AstNode {}

sealed class CollectionElementImpl extends AstNodeImpl
    implements CollectionElement {
  /// Dispatches this collection element to the [resolver], with the given
  /// [context] information.
  void resolveElement(
      ResolverVisitor resolver, CollectionLiteralContext? context);
}

/// A combinator associated with an import or export directive.
///
///    combinator ::=
///        [HideCombinator]
///      | [ShowCombinator]
sealed class Combinator implements AstNode {
  /// The `hide` or `show` keyword specifying what kind of processing is to be
  /// done on the names.
  Token get keyword;
}

sealed class CombinatorImpl extends AstNodeImpl implements Combinator {
  @override
  final Token keyword;

  /// Initializes a newly created combinator.
  CombinatorImpl({
    required this.keyword,
  });

  @override
  Token get beginToken => keyword;
}

/// A comment within the source code.
///
///    comment ::=
///        endOfLineComment
///      | blockComment
///      | documentationComment
///
///    endOfLineComment ::=
///        '//' (CHARACTER - EOL)* EOL
///
///    blockComment ::=
///        '/ *' CHARACTER* '&#42;/'
///
///    documentationComment ::=
///        '/ **' (CHARACTER | [CommentReference])* '&#42;/'
///      | ('///' (CHARACTER - EOL)* EOL)+
abstract final class Comment implements AstNode {
  /// The markdown code blocks (both fenced and indented) contained in this
  /// comment.
  @experimental
  List<MdCodeBlock> get codeBlocks;

  @experimental
  List<DocDirective> get docDirectives;

  @experimental
  List<DocImport> get docImports;

  /// Whether this comment has a line beginning with '@nodoc', indicating its
  /// contents aren't intended for publishing.
  @experimental
  bool get hasNodoc;

  /// The references embedded within the documentation comment.
  ///
  /// If there are no references in the comment then the list will be empty.
  NodeList<CommentReference> get references;

  /// The tokens representing the comment.
  List<Token> get tokens;
}

final class CommentImpl extends AstNodeImpl
    with AstNodeWithNameScopeMixin
    implements Comment {
  @override
  final List<Token> tokens;

  final NodeListImpl<CommentReferenceImpl> _references = NodeListImpl._();

  @override
  final List<MdCodeBlock> codeBlocks;

  @override
  final List<DocImport> docImports;

  @override
  final List<DocDirective> docDirectives;

  @override
  final bool hasNodoc;

  /// Initializes a newly created comment.
  ///
  /// The list of [tokens] must contain at least one token.
  ///
  /// The [type] is the type of the comment.
  ///
  /// The list of [references] can be empty if the comment doesn't contain any
  /// embedded references.
  CommentImpl({
    required this.tokens,
    required List<CommentReferenceImpl> references,
    required this.codeBlocks,
    required this.docImports,
    required this.docDirectives,
    required this.hasNodoc,
  }) {
    _references._initialize(this, references);
  }

  @override
  Token get beginToken => tokens[0];

  @override
  Token get endToken => tokens[tokens.length - 1];

  @override
  NodeListImpl<CommentReferenceImpl> get references => _references;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNodeList('references', references)
    ..addTokenList('tokens', tokens);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitComment(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _references.accept(visitor);
  }
}

/// An interface for an [Expression] which can make up a [CommentReference].
///
///    commentReferableExpression ::=
///        [ConstructorReference]
///      | [FunctionReference]
///      | [PrefixedIdentifier]
///      | [PropertyAccess]
///      | [SimpleIdentifier]
///      | [TypeLiteral]
///
/// This interface should align closely with dartdoc's notion of
/// comment-referable expressions at:
/// https://github.com/dart-lang/dartdoc/blob/master/lib/src/comment_references/parser.dart
abstract final class CommentReferableExpression implements Expression {}

sealed class CommentReferableExpressionImpl extends ExpressionImpl
    implements CommentReferableExpression {}

/// A reference to a Dart element that is found within a documentation comment.
///
///    commentReference ::=
///        '[' 'new'? [CommentReferableExpression] ']'
abstract final class CommentReference implements AstNode {
  /// The comment-referable expression being referenced.
  CommentReferableExpression get expression;

  /// The token representing the `new` keyword, or `null` if there was no `new`
  /// keyword.
  Token? get newKeyword;
}

final class CommentReferenceImpl extends AstNodeImpl
    implements CommentReference {
  @override
  final Token? newKeyword;

  CommentReferableExpressionImpl _expression;

  @override
  final bool isSynthetic;

  /// Initializes a newly created reference to a Dart element.
  ///
  /// The [newKeyword] can be `null` if the reference isn't to a constructor.
  CommentReferenceImpl({
    required this.newKeyword,
    required CommentReferableExpressionImpl expression,
    required this.isSynthetic,
  }) : _expression = expression {
    _becomeParentOf(_expression);
  }

  @override
  Token get beginToken => newKeyword ?? _expression.beginToken;

  @override
  Token get endToken => _expression.endToken;

  @override
  CommentReferableExpressionImpl get expression => _expression;

  set expression(CommentReferableExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('newKeyword', newKeyword)
    ..addNode('expression', expression);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitCommentReference(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _expression.accept(visitor);
  }
}

/// A compilation unit.
///
/// While the grammar restricts the order of the directives and declarations
/// within a compilation unit, this class doesn't enforce those restrictions.
/// In particular, the children of a compilation unit are visited in lexical
/// order even if lexical order doesn't conform to the restrictions of the
/// grammar.
///
///    compilationUnit ::=
///        directives declarations
///
///    directives ::=
///        [ScriptTag]? [LibraryDirective]? namespaceDirective* [PartDirective]*
///      | [PartOfDirective]
///
///    namespaceDirective ::=
///        [ImportDirective]
///      | [ExportDirective]
///
///    declarations ::=
///        [CompilationUnitMember]*
abstract final class CompilationUnit implements AstNode {
  /// The first (non-EOF) token in the token stream that was parsed to form this
  /// compilation unit.
  @override
  Token get beginToken;

  /// The declarations contained in this compilation unit.
  NodeList<CompilationUnitMember> get declarations;

  /// The element associated with this compilation unit, or `null` if the AST
  /// structure hasn't been resolved.
  CompilationUnitElement? get declaredElement;

  /// The fragment associated with this compilation unit.
  ///
  /// Returns `null` if the AST structure hasn't been resolved.
  @experimental
  LibraryFragment? get declaredFragment;

  /// The directives contained in this compilation unit.
  NodeList<Directive> get directives;

  /// The last token in the token stream that was parsed to form this
  /// compilation unit.
  ///
  /// This token should always have a type of [TokenType.EOF].
  @override
  Token get endToken;

  /// The set of features available to this compilation unit.
  ///
  /// Determined by some combination of the `package_config.json` file, the
  /// enclosing package's SDK version constraint, and/or the presence of a
  /// `@dart` directive in a comment at the top of the file.
  FeatureSet get featureSet;

  /// The language version override specified for this compilation unit using a
  /// token like '// @dart = 2.7', or `null` if no override is specified.
  LanguageVersionToken? get languageVersionToken;

  /// The line information for this compilation unit.
  LineInfo get lineInfo;

  /// The script tag at the beginning of the compilation unit, or `null` if
  /// there's no script tag in this compilation unit.
  ScriptTag? get scriptTag;

  /// A list containing all of the directives and declarations in this
  /// compilation unit, sorted in lexical order.
  List<AstNode> get sortedDirectivesAndDeclarations;
}

final class CompilationUnitImpl extends AstNodeImpl
    with AstNodeWithNameScopeMixin
    implements CompilationUnit {
  @override
  Token beginToken;

  ScriptTagImpl? _scriptTag;

  final NodeListImpl<DirectiveImpl> _directives = NodeListImpl._();

  final NodeListImpl<CompilationUnitMemberImpl> _declarations =
      NodeListImpl._();

  @override
  final Token endToken;

  @override
  CompilationUnitElementImpl? declaredElement;

  @override
  final LineInfo lineInfo;

  /// The language version information.
  LibraryLanguageVersion? languageVersion;

  @override
  final FeatureSet featureSet;

  /// Nodes that were parsed, but happened at locations where they aren't
  /// allowed.
  ///
  /// Instead of dropping them, we remember them here. Quick fixes can look
  /// here to determine which source range to remove.
  final List<AstNodeImpl> invalidNodes;

  /// Initializes a newly created compilation unit to have the given directives
  /// and declarations.
  ///
  /// The [scriptTag] can be `null` if there's no script tag in the compilation
  /// unit.
  ///
  /// The list of [directives] can be `null` if there are no directives in the
  /// compilation unit.
  ///
  /// The list of [declarations] can be `null` if there are no declarations in
  /// the compilation unit.
  CompilationUnitImpl({
    required this.beginToken,
    required ScriptTagImpl? scriptTag,
    required List<DirectiveImpl>? directives,
    required List<CompilationUnitMemberImpl>? declarations,
    required this.endToken,
    required this.featureSet,
    required this.lineInfo,
    required this.invalidNodes,
  }) : _scriptTag = scriptTag {
    _becomeParentOf(_scriptTag);
    _directives._initialize(this, directives);
    _declarations._initialize(this, declarations);
  }

  @override
  NodeListImpl<CompilationUnitMemberImpl> get declarations => _declarations;

  @experimental
  @override
  LibraryFragment? get declaredFragment => declaredElement as LibraryFragment?;

  @override
  NodeListImpl<DirectiveImpl> get directives => _directives;

  @override
  LanguageVersionToken? get languageVersionToken {
    Token? targetToken = beginToken;
    if (targetToken.type == TokenType.SCRIPT_TAG) {
      targetToken = targetToken.next;
    }

    Token? comment = targetToken?.precedingComments;
    while (comment != null) {
      if (comment is LanguageVersionToken) {
        return comment;
      }
      comment = comment.next;
    }
    return null;
  }

  @override
  int get length {
    var endToken = this.endToken;
    return endToken.offset + endToken.length;
  }

  @override
  int get offset => 0;

  @override
  ScriptTagImpl? get scriptTag => _scriptTag;

  set scriptTag(ScriptTagImpl? scriptTag) {
    _scriptTag = _becomeParentOf(scriptTag);
  }

  @override
  List<AstNode> get sortedDirectivesAndDeclarations {
    return <AstNode>[
      ..._directives,
      ..._declarations,
    ]..sort(AstNode.LEXICAL_ORDER);
  }

  @override
  ChildEntities get _childEntities {
    return ChildEntities()
      ..addNode('scriptTag', scriptTag)
      ..addNodeList('directives', directives)
      ..addNodeList('declarations', declarations);
  }

  /// Whether all of the directives are lexically before any declarations.
  bool get _directivesAreBeforeDeclarations {
    if (_directives.isEmpty || _declarations.isEmpty) {
      return true;
    }
    Directive lastDirective = _directives[_directives.length - 1];
    CompilationUnitMember firstDeclaration = _declarations[0];
    return lastDirective.offset < firstDeclaration.offset;
  }

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitCompilationUnit(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _scriptTag?.accept(visitor);
    if (_directivesAreBeforeDeclarations) {
      _directives.accept(visitor);
      _declarations.accept(visitor);
    } else {
      List<AstNode> sortedMembers = sortedDirectivesAndDeclarations;
      int length = sortedMembers.length;
      for (int i = 0; i < length; i++) {
        AstNode child = sortedMembers[i];
        child.accept(visitor);
      }
    }
  }
}

/// A node that declares one or more names within the scope of a compilation
/// unit.
///
///    compilationUnitMember ::=
///        [ClassDeclaration]
///      | [MixinDeclaration]
///      | [ExtensionDeclaration]
///      | [EnumDeclaration]
///      | [TypeAlias]
///      | [FunctionDeclaration]
///      | [TopLevelVariableDeclaration]
abstract final class CompilationUnitMember implements Declaration {}

sealed class CompilationUnitMemberImpl extends DeclarationImpl
    implements CompilationUnitMember {
  /// Initializes a newly created compilation unit member.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the member
  /// doesn't have the corresponding attribute.
  CompilationUnitMemberImpl({
    required super.comment,
    required super.metadata,
  });
}

/// A potentially compound assignment.
///
/// A compound assignment is any node in which a single expression is used to
/// specify both where to access a value to be operated on (the "read") and to
/// specify where to store the result of the operation (the "write"). This
/// happens in an [AssignmentExpression] when the assignment operator is a
/// compound assignment operator, and in a [PrefixExpression] or
/// [PostfixExpression] when the operator is an increment operator.
abstract final class CompoundAssignmentExpression implements Expression {
  /// The element that is used to read the value, or `null` if this node isn't a
  /// compound assignment, if the AST structure hasn't been resolved, or if the
  /// target couldn't be resolved.
  ///
  /// In valid code this element can be a [LocalVariableElement], a
  /// [ParameterElement], or a [PropertyAccessorElement] getter.
  ///
  /// In invalid code this element is `null`. For example, in `int += 2`, for
  /// recovery purposes, [writeElement] is filled, and can be used for
  /// navigation.
  Element? get readElement;

  /// The element that is used to read the value.
  ///
  /// Returns `null` if this node isn't a compound assignment, if the AST
  /// structure hasn't been resolved, or if the target couldn't be resolved.
  ///
  /// In valid code this element can be a [LocalVariableElement2], a
  /// [FormalParameterElement], or a [GetterElement].
  ///
  /// In invalid code this element is `null`. For example, in `int += 2`. In
  /// such cases, for recovery purposes, [writeElement] is filled, and can be
  /// used for navigation.
  @experimental
  Element2? get readElement2;

  /// The type of the value read with the [readElement], or `null` if this node
  /// isn't a compound assignment.
  ///
  /// Returns the type `dynamic` if the code is invalid, if the AST structure
  /// hasn't been resolved, or if the target couldn't be resolved.
  DartType? get readType;

  /// The element that is used to write the result, or `null` if the AST
  /// structure hasn't been resolved, or if the target couldn't be resolved.
  ///
  /// In valid code this is a [LocalVariableElement], [ParameterElement], or a
  /// [PropertyAccessorElement] setter.
  ///
  /// In invalid code, for recovery, we might use other elements, for example a
  /// [PropertyAccessorElement] getter `myGetter = 0` even though the getter
  /// can't be used to write a value. We do this to help the user to navigate
  /// to the getter, and maybe add the corresponding setter.
  ///
  /// If this node is a compound assignment, e. g. `x += 2`, both [readElement]
  /// and [writeElement] could be non-`null`.
  Element? get writeElement;

  /// The element that is used to write the result.
  ///
  /// Returns `null` if the AST structure hasn't been resolved, or if the target
  /// couldn't be resolved.
  ///
  /// In valid code this is a [LocalVariableElement2], [FormalParameterElement],
  /// or a [SetterElement].
  ///
  /// In invalid code, for recovery, we might use other elements, for example a
  /// [GetterElement] `myGetter = 0` even though the getter can't be used to set
  /// a value. We do this to help the user to navigate to the getter, and maybe
  /// add the corresponding setter.
  ///
  /// If this node is a compound assignment, such as `x += y`, both
  /// [readElement] and [writeElement] could be non-`null`.
  @experimental
  Element2? get writeElement2;

  /// The type of the target of the assignment.
  ///
  /// The types of assigned values must be subtypes of this type.
  ///
  /// If the target couldn't be resolved, this type is `dynamic`.
  DartType? get writeType;
}

base mixin CompoundAssignmentExpressionImpl
    implements CompoundAssignmentExpression {
  @override
  Element? readElement;

  @override
  Element? writeElement;

  @override
  DartType? readType;

  @override
  DartType? writeType;

  @experimental
  @override
  Element2? get readElement2 {
    if (readElement is Fragment) {
      return (readElement as Fragment).element;
    } else if (readElement is Element2) {
      return readElement as Element2;
    }
    return null;
  }

  @experimental
  @override
  Element2? get writeElement2 => writeElement.asElement2;
}

/// A conditional expression.
///
///    conditionalExpression ::=
///        [Expression] '?' [Expression] ':' [Expression]
abstract final class ConditionalExpression implements Expression {
  /// The token used to separate the then expression from the else expression.
  Token get colon;

  /// The condition used to determine which of the expressions is executed next.
  Expression get condition;

  /// The expression that is executed if the condition evaluates to `false`.
  Expression get elseExpression;

  /// The token used to separate the condition from the then expression.
  Token get question;

  /// The expression that is executed if the condition evaluates to `true`.
  Expression get thenExpression;
}

final class ConditionalExpressionImpl extends ExpressionImpl
    implements ConditionalExpression {
  ExpressionImpl _condition;

  @override
  final Token question;

  ExpressionImpl _thenExpression;

  @override
  final Token colon;

  ExpressionImpl _elseExpression;

  /// Initializes a newly created conditional expression.
  ConditionalExpressionImpl({
    required ExpressionImpl condition,
    required this.question,
    required ExpressionImpl thenExpression,
    required this.colon,
    required ExpressionImpl elseExpression,
  })  : _condition = condition,
        _thenExpression = thenExpression,
        _elseExpression = elseExpression {
    _becomeParentOf(_condition);
    _becomeParentOf(_thenExpression);
    _becomeParentOf(_elseExpression);
  }

  @override
  Token get beginToken => _condition.beginToken;

  @override
  ExpressionImpl get condition => _condition;

  set condition(ExpressionImpl expression) {
    _condition = _becomeParentOf(expression);
  }

  @override
  ExpressionImpl get elseExpression => _elseExpression;

  set elseExpression(ExpressionImpl expression) {
    _elseExpression = _becomeParentOf(expression);
  }

  @override
  Token get endToken => _elseExpression.endToken;

  @override
  Precedence get precedence => Precedence.conditional;

  @override
  ExpressionImpl get thenExpression => _thenExpression;

  set thenExpression(ExpressionImpl expression) {
    _thenExpression = _becomeParentOf(expression);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('condition', condition)
    ..addToken('question', question)
    ..addNode('thenExpression', thenExpression)
    ..addToken('colon', colon)
    ..addNode('elseExpression', elseExpression);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitConditionalExpression(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitConditionalExpression(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _condition.accept(visitor);
    _thenExpression.accept(visitor);
    _elseExpression.accept(visitor);
  }
}

/// A configuration in either an import or export directive.
///
///    configuration ::=
///        'if' '(' test ')' uri
///
///    test ::=
///        dottedName ('==' stringLiteral)?
///
///    dottedName ::=
///        identifier ('.' identifier)*
abstract final class Configuration implements AstNode {
  /// The token for the equal operator, or `null` if the condition doesn't
  /// include an equality test.
  Token? get equalToken;

  /// The token for the `if` keyword.
  Token get ifKeyword;

  /// The token for the left parenthesis.
  Token get leftParenthesis;

  /// The name of the declared variable whose value is being used in the
  /// condition.
  DottedName get name;

  /// The result of resolving [uri].
  DirectiveUri? get resolvedUri;

  /// The token for the right parenthesis.
  Token get rightParenthesis;

  /// The URI of the implementation library to be used if the condition is
  /// `true`.
  StringLiteral get uri;

  /// The value to which the value of the declared variable is compared, or
  /// `null` if the condition doesn't include an equality test.
  StringLiteral? get value;
}

final class ConfigurationImpl extends AstNodeImpl implements Configuration {
  @override
  final Token ifKeyword;

  @override
  final Token leftParenthesis;

  DottedNameImpl _name;

  @override
  final Token? equalToken;

  StringLiteralImpl? _value;

  @override
  final Token rightParenthesis;

  StringLiteralImpl _uri;

  @override
  DirectiveUri? resolvedUri;

  ConfigurationImpl({
    required this.ifKeyword,
    required this.leftParenthesis,
    required DottedNameImpl name,
    required this.equalToken,
    required StringLiteralImpl? value,
    required this.rightParenthesis,
    required StringLiteralImpl uri,
  })  : _name = name,
        _value = value,
        _uri = uri {
    _becomeParentOf(_name);
    _becomeParentOf(_value);
    _becomeParentOf(_uri);
  }

  @override
  Token get beginToken => ifKeyword;

  @override
  Token get endToken => _uri.endToken;

  @override
  DottedNameImpl get name => _name;

  set name(DottedNameImpl name) {
    _name = _becomeParentOf(name);
  }

  @override
  StringLiteralImpl get uri => _uri;

  set uri(StringLiteralImpl uri) {
    _uri = _becomeParentOf(uri);
  }

  @override
  StringLiteralImpl? get value => _value;

  set value(StringLiteralImpl? value) {
    _value = _becomeParentOf(value as StringLiteralImpl);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('ifKeyword', ifKeyword)
    ..addToken('leftParenthesis', leftParenthesis)
    ..addNode('name', name)
    ..addToken('equalToken', equalToken)
    ..addNode('value', value)
    ..addToken('rightParenthesis', rightParenthesis)
    ..addNode('uri', uri);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitConfiguration(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _name.accept(visitor);
    _value?.accept(visitor);
    _uri.accept(visitor);
  }
}

final class ConstantContextForExpressionImpl extends AstNodeImpl {
  final Element variable;
  final ExpressionImpl expression;

  ConstantContextForExpressionImpl(this.variable, this.expression) {
    _becomeParentOf(expression);
  }

  @override
  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}

/// A constant expression being used as a pattern.
///
/// The only expressions that can be validly used as a pattern are
/// - `bool` literals
/// - `double` literals
/// - `int` literals
/// - `null` literals
/// - `String` literals
/// - references to constant variables
/// - constant constructor invocations
/// - constant list literals
/// - constant set or map literals
/// - constant expressions wrapped in parentheses and preceded by the `const`
///   keyword
///
/// This node is also used to recover from cases where a different kind of
/// expression is used as a pattern, so clients need to handle the case where
/// the expression isn't one of the valid alternatives.
///
///    constantPattern ::=
///        'const'? [Expression]
abstract final class ConstantPattern implements DartPattern {
  /// The `const` keyword, or `null` if the expression isn't preceded by the
  /// keyword `const`.
  Token? get constKeyword;

  /// The constant expression being used as a pattern.
  Expression get expression;
}

final class ConstantPatternImpl extends DartPatternImpl
    implements ConstantPattern {
  @override
  final Token? constKeyword;

  ExpressionImpl _expression;

  ConstantPatternImpl({
    required this.constKeyword,
    required ExpressionImpl expression,
  }) : _expression = expression {
    _becomeParentOf(expression);
  }

  @override
  Token get beginToken => constKeyword ?? expression.beginToken;

  @override
  Token get endToken => expression.endToken;

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  PatternPrecedence get precedence => PatternPrecedence.primary;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('const', constKeyword)
    ..addNode('expression', expression);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitConstantPattern(this);

  @override
  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
    return resolverVisitor
        .analyzeConstantPatternSchema()
        .unwrapTypeSchemaView();
  }

  @override
  PatternResult<DartType> resolvePattern(
    ResolverVisitor resolverVisitor,
    SharedMatchContext context,
  ) {
    inferenceLogWriter?.enterPattern(this);
    var analysisResult =
        resolverVisitor.analyzeConstantPattern(context, this, expression);
    expression = resolverVisitor.popRewrite()!;
    inferenceLogWriter?.exitPattern(this);
    return analysisResult;
  }

  @override
  void visitChildren(AstVisitor visitor) {
    expression.accept(visitor);
  }
}

/// A constructor declaration.
///
///    constructorDeclaration ::=
///        constructorSignature [FunctionBody]?
///      | constructorName formalParameterList ':' 'this'
///        ('.' [SimpleIdentifier])? arguments
///
///    constructorSignature ::=
///        'external'? constructorName formalParameterList initializerList?
///      | 'external'? 'factory' factoryName formalParameterList
///        initializerList?
///      | 'external'? 'const'  constructorName formalParameterList
///        initializerList?
///
///    constructorName ::=
///        [SimpleIdentifier] ('.' name)?
///
///    factoryName ::=
///        [Identifier] ('.' [SimpleIdentifier])?
///
///    initializerList ::=
///        ':' [ConstructorInitializer] (',' [ConstructorInitializer])*
abstract final class ConstructorDeclaration
    implements ClassMember, FragmentDeclaration {
  /// The `augment` keyword, or `null` if the keyword was absent.
  Token? get augmentKeyword;

  /// The body of the constructor.
  FunctionBody get body;

  /// The token for the `const` keyword, or `null` if the constructor isn't a
  /// const constructor.
  Token? get constKeyword;

  @override
  ConstructorElement? get declaredElement;

  @experimental
  @override
  ConstructorFragment? get declaredFragment;

  /// The token for the `external` keyword to the given [token].
  Token? get externalKeyword;

  /// The token for the `factory` keyword, or `null` if the constructor isn't a
  /// factory constructor.
  Token? get factoryKeyword;

  /// The initializers associated with the constructor.
  NodeList<ConstructorInitializer> get initializers;

  /// The name of the constructor, or `null` if the constructor being declared
  /// is unnamed.
  Token? get name;

  /// The parameters associated with the constructor.
  FormalParameterList get parameters;

  /// The token for the period before the constructor name, or `null` if the
  /// constructor being declared is unnamed.
  Token? get period;

  /// The name of the constructor to which this constructor is redirected, or
  /// `null` if this isn't a redirecting factory constructor.
  ConstructorName? get redirectedConstructor;

  /// The type of object being created.
  ///
  /// This can be different than the type in which the constructor is being
  /// declared if the constructor is the implementation of a factory
  /// constructor.
  Identifier get returnType;

  /// The token for the separator (colon or equals) before the initializer list
  /// or redirection, or `null` if there are neither initializers nor a
  /// redirection.
  Token? get separator;
}

final class ConstructorDeclarationImpl extends ClassMemberImpl
    implements ConstructorDeclaration {
  @override
  final Token? augmentKeyword;

  @override
  final Token? externalKeyword;

  @override
  Token? constKeyword;

  @override
  final Token? factoryKeyword;

  IdentifierImpl _returnType;

  @override
  final Token? period;

  @override
  final Token? name;

  FormalParameterListImpl _parameters;

  @override
  Token? separator;

  final NodeListImpl<ConstructorInitializerImpl> _initializers =
      NodeListImpl._();

  ConstructorNameImpl? _redirectedConstructor;

  FunctionBodyImpl _body;

  @override
  ConstructorElementImpl? declaredElement;

  /// Initializes a newly created constructor declaration.
  ///
  /// The [externalKeyword] can be `null` if the constructor isn't external.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// constructor doesn't have the corresponding attribute.
  ///
  /// The [constKeyword] can be `null` if the constructor can't be used to
  /// create a constant.
  ///
  /// The [factoryKeyword] can be `null` if the constructor isn't a factory.
  ///
  /// The [period] and [name] can both be `null` if the constructor isn't a
  /// named constructor.
  ///
  /// The [separator] can be `null` if the constructor doesn't have any
  /// initializers and doesn't redirect to a different constructor.
  ///
  /// The list of [initializers] can be `null` if the constructor doesn't have
  /// any initializers.
  ///
  /// The [redirectedConstructor] can be `null` if the constructor doesn't
  /// redirect to a different constructor.
  ///
  /// The [body] can be `null` if the constructor doesn't have a body.
  ConstructorDeclarationImpl({
    required super.comment,
    required super.metadata,
    required this.augmentKeyword,
    required this.externalKeyword,
    required this.constKeyword,
    required this.factoryKeyword,
    required IdentifierImpl returnType,
    required this.period,
    required this.name,
    required FormalParameterListImpl parameters,
    required this.separator,
    required List<ConstructorInitializerImpl>? initializers,
    required ConstructorNameImpl? redirectedConstructor,
    required FunctionBodyImpl body,
  })  : _returnType = returnType,
        _parameters = parameters,
        _redirectedConstructor = redirectedConstructor,
        _body = body {
    _becomeParentOf(_returnType);
    _becomeParentOf(_parameters);
    _initializers._initialize(this, initializers);
    _becomeParentOf(_redirectedConstructor);
    _becomeParentOf(_body);
  }

  @override
  FunctionBodyImpl get body => _body;

  set body(FunctionBodyImpl functionBody) {
    _body = _becomeParentOf(functionBody);
  }

  @experimental
  @override
  ConstructorFragment? get declaredFragment =>
      declaredElement as ConstructorFragment;

  @override
  Token get endToken {
    return _body.endToken;
  }

  @override
  Token get firstTokenAfterCommentAndMetadata {
    return Token.lexicallyFirst(
            externalKeyword, constKeyword, factoryKeyword, augmentKeyword) ??
        _returnType.beginToken;
  }

  @override
  NodeListImpl<ConstructorInitializerImpl> get initializers => _initializers;

  /// Whether this is a trivial constructor.
  ///
  /// A trivial constructor is a generative constructor that isn't a redirecting
  /// constructor, declares no parameters, has no initializer list, has no body,
  /// and isn't external.
  bool get isTrivial =>
      redirectedConstructor == null &&
      parameters.parameters.isEmpty &&
      initializers.isEmpty &&
      body is EmptyFunctionBody &&
      externalKeyword == null;

  @override
  FormalParameterListImpl get parameters => _parameters;

  set parameters(FormalParameterListImpl parameters) {
    _parameters = _becomeParentOf(parameters);
  }

  @override
  ConstructorNameImpl? get redirectedConstructor => _redirectedConstructor;

  set redirectedConstructor(ConstructorNameImpl? redirectedConstructor) {
    _redirectedConstructor =
        _becomeParentOf(redirectedConstructor as ConstructorNameImpl);
  }

  @override
  IdentifierImpl get returnType => _returnType;

  set returnType(IdentifierImpl typeName) {
    _returnType = _becomeParentOf(typeName);
  }

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('augmentKeyword', augmentKeyword)
    ..addToken('externalKeyword', externalKeyword)
    ..addToken('constKeyword', constKeyword)
    ..addToken('factoryKeyword', factoryKeyword)
    ..addNode('returnType', returnType)
    ..addToken('period', period)
    ..addToken('name', name)
    ..addNode('parameters', parameters)
    ..addToken('separator', separator)
    ..addNodeList('initializers', initializers)
    ..addNode('redirectedConstructor', redirectedConstructor)
    ..addNode('body', body);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitConstructorDeclaration(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _returnType.accept(visitor);
    _parameters.accept(visitor);
    _initializers.accept(visitor);
    _redirectedConstructor?.accept(visitor);
    _body.accept(visitor);
  }
}

/// The initialization of a field within a constructor's initialization list.
///
///    fieldInitializer ::=
///        ('this' '.')? [SimpleIdentifier] '=' [Expression]
abstract final class ConstructorFieldInitializer
    implements ConstructorInitializer {
  /// The token for the equal sign between the field name and the expression.
  Token get equals;

  /// The expression computing the value to which the field is initialized.
  Expression get expression;

  /// The name of the field being initialized.
  SimpleIdentifier get fieldName;

  /// The token for the period after the `this` keyword, or `null` if there's no
  /// `this` keyword.
  Token? get period;

  /// The token for the `this` keyword, or `null` if there's no `this` keyword.
  Token? get thisKeyword;
}

final class ConstructorFieldInitializerImpl extends ConstructorInitializerImpl
    implements ConstructorFieldInitializer {
  @override
  final Token? thisKeyword;

  @override
  final Token? period;

  SimpleIdentifierImpl _fieldName;

  @override
  final Token equals;

  ExpressionImpl _expression;

  /// Initializes a newly created field initializer to initialize the field with
  /// the given name to the value of the given expression.
  ///
  /// The [thisKeyword] and [period] can be `null` if the `this` keyword isn't
  /// specified.
  ConstructorFieldInitializerImpl({
    required this.thisKeyword,
    required this.period,
    required SimpleIdentifierImpl fieldName,
    required this.equals,
    required ExpressionImpl expression,
  })  : _fieldName = fieldName,
        _expression = expression {
    _becomeParentOf(_fieldName);
    _becomeParentOf(_expression);
  }

  @override
  Token get beginToken {
    if (thisKeyword case var thisKeyword?) {
      return thisKeyword;
    }
    return _fieldName.beginToken;
  }

  @override
  Token get endToken => _expression.endToken;

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  SimpleIdentifierImpl get fieldName => _fieldName;

  set fieldName(SimpleIdentifierImpl identifier) {
    _fieldName = _becomeParentOf(identifier);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('thisKeyword', thisKeyword)
    ..addToken('period', period)
    ..addNode('fieldName', fieldName)
    ..addToken('equals', equals)
    ..addNode('expression', expression);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitConstructorFieldInitializer(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _fieldName.accept(visitor);
    _expression.accept(visitor);
  }
}

/// A node that can occur in the initializer list of a constructor declaration.
///
///    constructorInitializer ::=
///        [SuperConstructorInvocation]
///      | [ConstructorFieldInitializer]
///      | [RedirectingConstructorInvocation]
sealed class ConstructorInitializer implements AstNode {}

sealed class ConstructorInitializerImpl extends AstNodeImpl
    implements ConstructorInitializer {}

/// The name of a constructor.
///
///    constructorName ::=
///        type ('.' identifier)?
abstract final class ConstructorName
    implements AstNode, ConstructorReferenceNode {
  /// The name of the constructor, or `null` if the specified constructor is the
  /// unnamed constructor and the name `new` wasn't explicitly used.
  SimpleIdentifier? get name;

  /// The token for the period before the constructor name, or `null` if the
  /// specified constructor is the unnamed constructor.
  Token? get period;

  /// The name of the type defining the constructor.
  NamedType get type;
}

final class ConstructorNameImpl extends AstNodeImpl implements ConstructorName {
  NamedTypeImpl _type;

  @override
  Token? period;

  SimpleIdentifierImpl? _name;

  @override
  ConstructorElement? staticElement;

  /// Initializes a newly created constructor name.
  ///
  /// The [period] and [name] can be `null` if the constructor being named is
  /// the unnamed constructor.
  ConstructorNameImpl({
    required NamedTypeImpl type,
    required this.period,
    required SimpleIdentifierImpl? name,
  })  : _type = type,
        _name = name {
    _becomeParentOf(_type);
    _becomeParentOf(_name);
  }

  @override
  Token get beginToken => _type.beginToken;

  @experimental
  @override
  ConstructorElement2? get element =>
      staticElement?.asElement2 as ConstructorElement2?;

  @override
  Token get endToken {
    if (name case var name?) {
      return name.endToken;
    }
    return _type.endToken;
  }

  @override
  SimpleIdentifierImpl? get name => _name;

  set name(SimpleIdentifierImpl? name) {
    _name = _becomeParentOf(name);
  }

  @override
  NamedTypeImpl get type => _type;

  set type(NamedTypeImpl type) {
    _type = _becomeParentOf(type);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('type', type)
    ..addToken('period', period)
    ..addNode('name', name);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitConstructorName(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _type.accept(visitor);
    _name?.accept(visitor);
  }
}

/// An expression representing a reference to a constructor.
///
/// For example, the expression `List.filled` in `var x = List.filled;`.
///
/// Objects of this type aren't produced directly by the parser (because the
/// parser can't tell whether an identifier refers to a type); they are
/// produced at resolution time.
abstract final class ConstructorReference
    implements Expression, CommentReferableExpression {
  /// The constructor being referenced.
  ConstructorName get constructorName;
}

final class ConstructorReferenceImpl extends CommentReferableExpressionImpl
    implements ConstructorReference {
  ConstructorNameImpl _constructorName;

  ConstructorReferenceImpl({
    required ConstructorNameImpl constructorName,
  }) : _constructorName = constructorName {
    _becomeParentOf(_constructorName);
  }

  @override
  Token get beginToken => constructorName.beginToken;

  @override
  ConstructorNameImpl get constructorName => _constructorName;

  set constructorName(ConstructorNameImpl value) {
    _constructorName = _becomeParentOf(value);
  }

  @override
  Token get endToken => constructorName.endToken;

  @override
  Precedence get precedence => Precedence.postfix;

  @override
  ChildEntities get _childEntities =>
      ChildEntities()..addNode('constructorName', constructorName);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitConstructorReference(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitConstructorReference(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    constructorName.accept(visitor);
  }
}

/// An AST node that makes reference to a constructor.
abstract final class ConstructorReferenceNode implements AstNode {
  /// The element associated with the referenced constructor based on static
  /// type information.
  ///
  /// Returns `null` if the AST structure hasn't been resolved or if the
  /// constructor couldn't be resolved.
  @experimental
  ConstructorElement2? get element;

  /// The element associated with the referenced constructor based on static
  /// type information, or `null` if the AST structure hasn't been resolved or
  /// if the constructor couldn't be resolved.
  ConstructorElement? get staticElement;
}

/// The name of a constructor being invoked.
///
///    constructorSelector ::=
///        '.' identifier
abstract final class ConstructorSelector implements AstNode {
  /// The constructor name.
  SimpleIdentifier get name;

  /// The period before the constructor name.
  Token get period;
}

final class ConstructorSelectorImpl extends AstNodeImpl
    implements ConstructorSelector {
  @override
  final Token period;

  @override
  final SimpleIdentifierImpl name;

  ConstructorSelectorImpl({
    required this.period,
    required this.name,
  }) {
    _becomeParentOf(name);
  }

  @override
  Token get beginToken => period;

  @override
  Token get endToken => name.token;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('period', period)
    ..addNode('name', name);

  @override
  E? accept<E>(AstVisitor<E> visitor) {
    return visitor.visitConstructorSelector(this);
  }

  @override
  void visitChildren(AstVisitor visitor) {}
}

/// A continue statement.
///
///    continueStatement ::=
///        'continue' [SimpleIdentifier]? ';'
abstract final class ContinueStatement implements Statement {
  /// The token representing the `continue` keyword.
  Token get continueKeyword;

  /// The label associated with the statement, or `null` if there's no label.
  SimpleIdentifier? get label;

  /// The semicolon terminating the statement.
  Token get semicolon;

  /// The node to which this continue statement is continuing, or `null` if the
  /// AST hasn't yet been resolved or if the target couldn't be resolved.
  ///
  /// This is either a [Statement] (in the case of continuing a loop), or a
  /// [SwitchMember] (in the case of continuing from one switch case to
  /// another).
  ///
  /// Note that if the source code has errors, the target might be invalid.
  /// For example, the target might be in an enclosing function.
  AstNode? get target;
}

final class ContinueStatementImpl extends StatementImpl
    implements ContinueStatement {
  @override
  final Token continueKeyword;

  SimpleIdentifierImpl? _label;

  @override
  final Token semicolon;

  @override
  AstNode? target;

  /// Initializes a newly created continue statement.
  ///
  /// The [label] can be `null` if there's no label associated with the
  /// statement.
  ContinueStatementImpl({
    required this.continueKeyword,
    required SimpleIdentifierImpl? label,
    required this.semicolon,
  }) : _label = label {
    _becomeParentOf(_label);
  }

  @override
  Token get beginToken => continueKeyword;

  @override
  Token get endToken => semicolon;

  @override
  SimpleIdentifierImpl? get label => _label;

  set label(SimpleIdentifierImpl? identifier) {
    _label = _becomeParentOf(identifier);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('continueKeyword', continueKeyword)
    ..addNode('label', label)
    ..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitContinueStatement(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _label?.accept(visitor);
  }
}

/// A pattern.
///
///    pattern ::=
///        [AssignedVariablePattern]
///      | [DeclaredVariablePattern]
///      | [CastPattern]
///      | [ConstantPattern]
///      | [ListPattern]
///      | [LogicalAndPattern]
///      | [LogicalOrPattern]
///      | [MapPattern]
///      | [NullAssertPattern]
///      | [NullCheckPattern]
///      | [ObjectPattern]
///      | [ParenthesizedPattern]
///      | [RecordPattern]
///      | [RelationalPattern]
sealed class DartPattern implements AstNode, ListPatternElement {
  /// The matched value type, or `null` if the node isn't resolved yet.
  DartType? get matchedValueType;

  /// The precedence of this pattern.
  ///
  /// The precedence is a positive integer value that defines how the source
  /// code is parsed into an AST. For example `a | b & c` is parsed as `a | (b
  /// & c)` because the precedence of `&` is greater than the precedence of `|`.
  PatternPrecedence get precedence;

  /// If this pattern is a parenthesized pattern, the result of unwrapping the
  /// pattern inside the parentheses. Otherwise, this pattern.
  DartPattern get unParenthesized;
}

sealed class DartPatternImpl extends AstNodeImpl
    implements DartPattern, ListPatternElementImpl {
  @override
  DartType? matchedValueType;

  /// The context for this pattern.
  ///
  /// The possible contexts are
  /// - Declaration context:
  ///     [ForEachPartsWithPatternImpl]
  ///     [PatternVariableDeclarationImpl]
  /// - Assignment context: [PatternAssignmentImpl]
  /// - Matching context: [GuardedPatternImpl]
  AstNodeImpl? get patternContext {
    for (DartPatternImpl current = this;;) {
      var parent = current.parent;
      if (parent is MapPatternEntry) {
        parent = parent.parent;
      } else if (parent is PatternFieldImpl) {
        parent = parent.parent;
      } else if (parent is RestPatternElementImpl) {
        parent = parent.parent;
      }
      if (parent is ForEachPartsWithPatternImpl) {
        return parent;
      } else if (parent is PatternVariableDeclarationImpl) {
        return parent;
      } else if (parent is PatternAssignmentImpl) {
        return parent;
      } else if (parent is GuardedPatternImpl) {
        return parent;
      } else if (parent is DartPatternImpl) {
        current = parent;
      } else {
        return null;
      }
    }
  }

  @override
  DartPattern get unParenthesized => this;

  /// The variable pattern, itself, or wrapped in a unary pattern.
  VariablePatternImpl? get variablePattern => null;

  DartType computePatternSchema(ResolverVisitor resolverVisitor);

  /// Dispatches this pattern to the [resolver], with the given [context]
  /// information.
  ///
  /// Note: most code shouldn't call this method directly, but should instead
  /// call [ResolverVisitor.dispatchPattern], which has some special logic for
  /// handling dynamic contexts.
  PatternResult<DartType> resolvePattern(
    ResolverVisitor resolverVisitor,
    SharedMatchContext context,
  );
}

/// A node that represents the declaration of one or more names.
///
/// Each declared name is visible within a name scope.
abstract final class Declaration implements AnnotatedNode {
  /// The element associated with this declaration, or `null` if either this
  /// node corresponds to a list of declarations or if the AST structure hasn't
  /// been resolved.
  Element? get declaredElement;
}

sealed class DeclarationImpl extends AnnotatedNodeImpl implements Declaration {
  /// Initializes a newly created declaration.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// declaration doesn't have the corresponding attribute.
  DeclarationImpl({
    required super.comment,
    required super.metadata,
  });
}

/// The declaration of a single identifier.
///
///    declaredIdentifier ::=
///        [Annotation] finalConstVarOrType [SimpleIdentifier]
abstract final class DeclaredIdentifier implements Declaration {
  @override
  LocalVariableElement? get declaredElement;

  /// The element associated with this declaration.
  ///
  /// Returns `null` if either this node corresponds to a list of declarations
  /// or if the AST structure hasn't been resolved.
  @experimental
  LocalVariableElement2? get declaredElement2;

  /// Whether this variable was declared with the 'const' modifier.
  bool get isConst;

  /// Whether this variable was declared with the 'final' modifier.
  ///
  /// Returns `false` for variables that are declared with the 'const' modifier
  /// even though they are implicitly final.
  bool get isFinal;

  /// The token representing either the `final`, `const` or `var` keyword, or
  /// `null` if no keyword was used.
  Token? get keyword;

  /// The name of the variable being declared.
  Token get name;

  /// The name of the declared type of the parameter, or `null` if the parameter
  /// doesn't have a declared type.
  TypeAnnotation? get type;
}

final class DeclaredIdentifierImpl extends DeclarationImpl
    implements DeclaredIdentifier {
  @override
  final Token? keyword;

  TypeAnnotationImpl? _type;

  @override
  final Token name;

  @override
  LocalVariableElementImpl? declaredElement;

  /// Initializes a newly created formal parameter.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// declaration doesn't have the corresponding attribute.
  ///
  /// The [keyword] can be `null` if a type name is given.
  ///
  /// The [type] must be `null` if the keyword is `var`.
  DeclaredIdentifierImpl({
    required super.comment,
    required super.metadata,
    required this.keyword,
    required TypeAnnotationImpl? type,
    required this.name,
  }) : _type = type {
    _becomeParentOf(_type);
  }

  @experimental
  @override
  LocalVariableElement2? get declaredElement2 {
    return declaredElement.asElement2 as LocalVariableElementImpl2?;
  }

  @override
  Token get endToken => name;

  @override
  Token get firstTokenAfterCommentAndMetadata {
    return keyword ?? _type?.beginToken ?? name;
  }

  @override
  bool get isConst => keyword?.keyword == Keyword.CONST;

  @override
  bool get isFinal => keyword?.keyword == Keyword.FINAL;

  @override
  TypeAnnotationImpl? get type => _type;

  set type(TypeAnnotationImpl? type) {
    _type = _becomeParentOf(type);
  }

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('keyword', keyword)
    ..addNode('type', type)
    ..addToken('name', name);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitDeclaredIdentifier(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _type?.accept(visitor);
  }
}

/// A variable pattern that declares a variable.
///
///    variablePattern ::=
///        ( 'var' | 'final' | 'final'? [TypeAnnotation])? [Identifier]
sealed class DeclaredVariablePattern implements VariablePattern {
  /// The element associated with this declaration, or `null` if the AST
  /// structure hasn't been resolved.
  BindPatternVariableElement? get declaredElement;

  /// The element declared by this declaration.
  ///
  /// Returns `null` if the AST structure hasn't been resolved.
  @experimental
  BindPatternVariableElement2? get declaredElement2;

  /// The `var` or `final` keyword.
  Token? get keyword;

  /// The type that the variable is required to match, or `null` if any type is
  /// matched.
  TypeAnnotation? get type;
}

final class DeclaredVariablePatternImpl extends VariablePatternImpl
    implements DeclaredVariablePattern {
  @override
  BindPatternVariableElementImpl? declaredElement;

  @override
  final Token? keyword;

  @override
  final TypeAnnotationImpl? type;

  DeclaredVariablePatternImpl({
    required this.keyword,
    required this.type,
    required super.name,
  }) {
    _becomeParentOf(type);
  }

  @override
  Token get beginToken => keyword ?? type?.beginToken ?? name;

  @experimental
  @override
  BindPatternVariableElement2? get declaredElement2 {
    return declaredElement?.element2;
  }

  @override
  Token get endToken => name;

  /// The `final` keyword, or `null` if the `final` keyword isn't used.
  Token? get finalKeyword {
    var keyword = this.keyword;
    if (keyword != null && keyword.keyword == Keyword.FINAL) {
      return keyword;
    }
    return null;
  }

  @override
  PatternPrecedence get precedence => PatternPrecedence.primary;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('keyword', keyword)
    ..addNode('type', type)
    ..addToken('name', name);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitDeclaredVariablePattern(this);

  @override
  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
    return resolverVisitor
        .analyzeDeclaredVariablePatternSchema(
            type?.typeOrThrow.wrapSharedTypeView())
        .unwrapTypeSchemaView();
  }

  @override
  PatternResult<DartType> resolvePattern(
    ResolverVisitor resolverVisitor,
    SharedMatchContext context,
  ) {
    inferenceLogWriter?.enterPattern(this);
    var result = resolverVisitor.analyzeDeclaredVariablePattern(
        context,
        this,
        declaredElement!,
        declaredElement!.name,
        type?.typeOrThrow.wrapSharedTypeView());
    declaredElement!.type = result.staticType.unwrapTypeView();

    resolverVisitor.checkPatternNeverMatchesValueType(
      context: context,
      pattern: this,
      requiredType: result.staticType.unwrapTypeView(),
      matchedValueType: result.matchedValueType.unwrapTypeView(),
    );
    inferenceLogWriter?.exitPattern(this);

    return result;
  }

  @override
  void visitChildren(AstVisitor visitor) {
    type?.accept(visitor);
  }
}

/// A formal parameter with a default value.
///
/// There are two kinds of parameters that are both represented by this class:
/// named formal parameters and positional formal parameters.
///
///    defaultFormalParameter ::=
///        [NormalFormalParameter] ('=' [Expression])?
///
///    defaultNamedParameter ::=
///        [NormalFormalParameter] (':' [Expression])?
abstract final class DefaultFormalParameter implements FormalParameter {
  /// The expression computing the default value for the parameter, or `null` if
  /// there's no default value.
  Expression? get defaultValue;

  /// The formal parameter with which the default value is associated.
  NormalFormalParameter get parameter;

  /// The token separating the parameter from the default value, or `null` if
  /// there's no default value.
  Token? get separator;
}

final class DefaultFormalParameterImpl extends FormalParameterImpl
    implements DefaultFormalParameter {
  NormalFormalParameterImpl _parameter;

  @override
  ParameterKind kind;

  @override
  final Token? separator;

  ExpressionImpl? _defaultValue;

  /// Initializes a newly created default formal parameter.
  ///
  /// The [separator] and [defaultValue] can be `null` if there's no default
  /// value.
  DefaultFormalParameterImpl({
    required NormalFormalParameterImpl parameter,
    required this.kind,
    required this.separator,
    required ExpressionImpl? defaultValue,
  })  : _parameter = parameter,
        _defaultValue = defaultValue {
    _becomeParentOf(_parameter);
    _becomeParentOf(_defaultValue);
  }

  @override
  Token get beginToken => _parameter.beginToken;

  @override
  Token? get covariantKeyword => null;

  @override
  ParameterElementImpl? get declaredElement => _parameter.declaredElement;

  @experimental
  @override
  FormalParameterFragment? get declaredFragment => _parameter.declaredFragment;

  @override
  ExpressionImpl? get defaultValue => _defaultValue;

  set defaultValue(ExpressionImpl? expression) {
    _defaultValue = _becomeParentOf(expression);
  }

  @override
  Token get endToken {
    if (defaultValue case var defaultValue?) {
      return defaultValue.endToken;
    }
    return _parameter.endToken;
  }

  @override
  bool get isConst => _parameter.isConst;

  @override
  bool get isExplicitlyTyped => _parameter.isExplicitlyTyped;

  @override
  bool get isFinal => _parameter.isFinal;

  @override
  NodeListImpl<AnnotationImpl> get metadata => _parameter.metadata;

  @override
  Token? get name => _parameter.name;

  @override
  NormalFormalParameterImpl get parameter => _parameter;

  set parameter(NormalFormalParameterImpl formalParameter) {
    _parameter = _becomeParentOf(formalParameter);
  }

  @override
  Token? get requiredKeyword => null;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('parameter', parameter)
    ..addToken('separator', separator)
    ..addNode('defaultValue', defaultValue);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitDefaultFormalParameter(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _parameter.accept(visitor);
    _defaultValue?.accept(visitor);
  }
}

/// A node that represents a directive.
///
///    directive ::=
///        [ExportDirective]
///      | [ImportDirective]
///      | [LibraryDirective]
///      | [PartDirective]
///      | [PartOfDirective]
sealed class Directive implements AnnotatedNode {
  /// The element associated with this directive, or `null` if the AST structure
  /// hasn't been resolved or if this directive couldn't be resolved.
  Element? get element;
}

sealed class DirectiveImpl extends AnnotatedNodeImpl implements Directive {
  ElementImpl? _element;

  /// Initializes a newly create directive.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// directive doesn't have the corresponding attribute.
  DirectiveImpl({
    required super.comment,
    required super.metadata,
  });

  @override
  ElementImpl? get element => _element;

  set element(ElementImpl? element) {
    _element = element;
  }
}

/// A do statement.
///
///    doStatement ::=
///        'do' [Statement] 'while' '(' [Expression] ')' ';'
abstract final class DoStatement implements Statement {
  /// The body of the loop.
  Statement get body;

  /// The condition that determines when the loop terminates.
  Expression get condition;

  /// The token representing the `do` keyword.
  Token get doKeyword;

  /// The left parenthesis.
  Token get leftParenthesis;

  /// The right parenthesis.
  Token get rightParenthesis;

  /// The semicolon terminating the statement.
  Token get semicolon;

  /// The token representing the `while` keyword.
  Token get whileKeyword;
}

final class DoStatementImpl extends StatementImpl implements DoStatement {
  @override
  final Token doKeyword;

  StatementImpl _body;

  @override
  final Token whileKeyword;

  @override
  final Token leftParenthesis;

  ExpressionImpl _condition;

  @override
  final Token rightParenthesis;

  @override
  final Token semicolon;

  /// Initializes a newly created do loop.
  DoStatementImpl({
    required this.doKeyword,
    required StatementImpl body,
    required this.whileKeyword,
    required this.leftParenthesis,
    required ExpressionImpl condition,
    required this.rightParenthesis,
    required this.semicolon,
  })  : _body = body,
        _condition = condition {
    _becomeParentOf(_body);
    _becomeParentOf(_condition);
  }

  @override
  Token get beginToken => doKeyword;

  @override
  StatementImpl get body => _body;

  set body(StatementImpl statement) {
    _body = _becomeParentOf(statement);
  }

  @override
  ExpressionImpl get condition => _condition;

  set condition(ExpressionImpl expression) {
    _condition = _becomeParentOf(expression);
  }

  @override
  Token get endToken => semicolon;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('doKeyword', doKeyword)
    ..addNode('body', body)
    ..addToken('whileKeyword', whileKeyword)
    ..addToken('leftParenthesis', leftParenthesis)
    ..addNode('condition', condition)
    ..addToken('rightParenthesis', rightParenthesis)
    ..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitDoStatement(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _body.accept(visitor);
    _condition.accept(visitor);
  }
}

/// A dotted name, used in a configuration within an import or export directive.
///
///    dottedName ::=
///        [SimpleIdentifier] ('.' [SimpleIdentifier])*
abstract final class DottedName implements AstNode {
  /// The components of the identifier.
  NodeList<SimpleIdentifier> get components;
}

final class DottedNameImpl extends AstNodeImpl implements DottedName {
  final NodeListImpl<SimpleIdentifierImpl> _components = NodeListImpl._();

  /// Initializes a newly created dotted name.
  ///
  /// The list of [components] must contain at least one element.
  DottedNameImpl({
    required List<SimpleIdentifierImpl> components,
  }) {
    _components._initialize(this, components);
  }

  @override
  Token get beginToken => _components.beginToken!;

  @override
  NodeListImpl<SimpleIdentifierImpl> get components => _components;

  @override
  Token get endToken => _components.endToken!;

  @override
  // TODO(paulberry): add "." tokens.
  ChildEntities get _childEntities =>
      ChildEntities()..addNodeList('components', components);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitDottedName(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _components.accept(visitor);
  }
}

/// A floating point literal expression.
///
///    doubleLiteral ::=
///        decimalDigit+ ('.' decimalDigit*)? exponent?
///      | '.' decimalDigit+ exponent?
///
///    exponent ::=
///        ('e' | 'E') ('+' | '-')? decimalDigit+
abstract final class DoubleLiteral implements Literal {
  /// The token representing the literal.
  Token get literal;

  /// The value of the literal.
  double get value;
}

final class DoubleLiteralImpl extends LiteralImpl implements DoubleLiteral {
  @override
  final Token literal;

  @override
  double value;

  /// Initializes a newly created floating point literal.
  DoubleLiteralImpl({
    required this.literal,
    required this.value,
  });

  @override
  Token get beginToken => literal;

  @override
  Token get endToken => literal;

  @override
  ChildEntities get _childEntities =>
      ChildEntities()..addToken('literal', literal);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitDoubleLiteral(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitDoubleLiteral(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    // There are no children to visit.
  }
}

/// An empty function body.
///
/// An empty function body can only appear in constructors or abstract methods.
///
///    emptyFunctionBody ::=
///        ';'
abstract final class EmptyFunctionBody implements FunctionBody {
  /// The token representing the semicolon that marks the end of the function
  /// body.
  Token get semicolon;
}

final class EmptyFunctionBodyImpl extends FunctionBodyImpl
    implements EmptyFunctionBody {
  @override
  final Token semicolon;

  /// Initializes a newly created function body.
  EmptyFunctionBodyImpl({
    required this.semicolon,
  });

  @override
  Token get beginToken => semicolon;

  @override
  Token get endToken => semicolon;

  @override
  ChildEntities get _childEntities =>
      ChildEntities()..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitEmptyFunctionBody(this);

  @override
  DartType resolve(ResolverVisitor resolver, DartType? imposedType) =>
      resolver.visitEmptyFunctionBody(this, imposedType: imposedType);

  @override
  void visitChildren(AstVisitor visitor) {
    // Empty function bodies have no children.
  }
}

/// An empty statement.
///
///    emptyStatement ::=
///        ';'
abstract final class EmptyStatement implements Statement {
  /// The semicolon terminating the statement.
  Token get semicolon;
}

final class EmptyStatementImpl extends StatementImpl implements EmptyStatement {
  @override
  final Token semicolon;

  /// Initializes a newly created empty statement.
  EmptyStatementImpl({
    required this.semicolon,
  });

  @override
  Token get beginToken => semicolon;

  @override
  Token get endToken => semicolon;

  @override
  bool get isSynthetic => semicolon.isSynthetic;

  @override
  ChildEntities get _childEntities =>
      ChildEntities()..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitEmptyStatement(this);

  @override
  void visitChildren(AstVisitor visitor) {
    // There are no children to visit.
  }
}

/// The arguments part of an enum constant.
///
///    enumConstantArguments ::=
///        [TypeArgumentList]? [ConstructorSelector]? [ArgumentList]
abstract final class EnumConstantArguments implements AstNode {
  /// The explicit arguments (there are always implicit `index` and `name`
  /// leading arguments) to the invoked constructor.
  ArgumentList get argumentList;

  /// The selector of the constructor that is invoked by this enum constant, or
  /// `null` if the default constructor is invoked.
  ConstructorSelector? get constructorSelector;

  /// The type arguments applied to the enclosing enum declaration when invoking
  /// the constructor, or `null` if no type arguments were provided.
  TypeArgumentList? get typeArguments;
}

final class EnumConstantArgumentsImpl extends AstNodeImpl
    implements EnumConstantArguments {
  @override
  final TypeArgumentListImpl? typeArguments;

  @override
  final ConstructorSelectorImpl? constructorSelector;

  @override
  final ArgumentListImpl argumentList;

  EnumConstantArgumentsImpl({
    required this.typeArguments,
    required this.constructorSelector,
    required this.argumentList,
  }) {
    _becomeParentOf(typeArguments);
    _becomeParentOf(constructorSelector);
    _becomeParentOf(argumentList);
  }

  @override
  Token get beginToken =>
      (typeArguments ?? constructorSelector ?? argumentList).beginToken;

  @override
  Token get endToken => argumentList.endToken;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('typeArguments', typeArguments)
    ..addNode('constructorSelector', constructorSelector)
    ..addNode('argumentList', argumentList);

  @override
  E? accept<E>(AstVisitor<E> visitor) {
    return visitor.visitEnumConstantArguments(this);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    typeArguments?.accept(visitor);
    constructorSelector?.accept(visitor);
    argumentList.accept(visitor);
  }
}

/// The declaration of an enum constant.
abstract final class EnumConstantDeclaration implements FragmentDeclaration {
  /// The explicit arguments (there are always implicit `index` and `name`
  /// leading arguments) to the invoked constructor, or `null` if this constant
  /// doesn't provide any explicit arguments.
  EnumConstantArguments? get arguments;

  /// The `augment` keyword, or `null` if the keyword was absent.
  @experimental
  Token? get augmentKeyword;

  /// The constructor that is invoked by this enum constant, or `null` if the
  /// AST structure hasn't been resolved, or if the constructor couldn't be
  /// resolved.
  ConstructorElement? get constructorElement;

  /// The constructor that's invoked by this enum constant.
  ///
  /// Returns `null` if the AST structure hasn't been resolved, or if the
  /// constructor couldn't be resolved.
  @experimental
  ConstructorElement2? get constructorElement2;

  @override
  FieldElement? get declaredElement;

  @experimental
  @override
  FieldFragment? get declaredFragment;

  /// The name of the constant.
  Token get name;
}

final class EnumConstantDeclarationImpl extends DeclarationImpl
    implements EnumConstantDeclaration {
  @override
  final Token? augmentKeyword;

  @override
  final Token name;

  @override
  FieldElementImpl? declaredElement;

  @override
  final EnumConstantArgumentsImpl? arguments;

  @override
  ConstructorElement? constructorElement;

  /// Initializes a newly created enum constant declaration.
  ///
  /// Either or both of the [documentationComment] and [metadata] can be `null`
  /// if the constant doesn't have the corresponding attributes.
  EnumConstantDeclarationImpl({
    required super.comment,
    required super.metadata,
    required this.augmentKeyword,
    required this.name,
    required this.arguments,
  }) {
    _becomeParentOf(arguments);
  }

  @experimental
  @override
  ConstructorElement2? get constructorElement2 =>
      constructorElement?.asElement2 as ConstructorElement2?;

  @experimental
  @override
  FieldFragment? get declaredFragment => declaredElement as FieldFragment?;

  @override
  Token get endToken => arguments?.endToken ?? name;

  @override
  Token get firstTokenAfterCommentAndMetadata => augmentKeyword ?? name;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('augmentKeyword', augmentKeyword)
    ..addToken('name', name)
    ..addNode('arguments', arguments);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitEnumConstantDeclaration(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    arguments?.accept(visitor);
  }
}

/// The declaration of an enumeration.
///
///    enumType ::=
///        metadata 'enum' name [TypeParameterList]?
///        [WithClause]? [ImplementsClause]? '{' [SimpleIdentifier]
///        (',' [SimpleIdentifier])* (';' [ClassMember]+)? '}'
abstract final class EnumDeclaration
    implements NamedCompilationUnitMember, FragmentDeclaration {
  /// The `augment` keyword, or `null` if the keyword was absent.
  @experimental
  Token? get augmentKeyword;

  /// The enumeration constants being declared.
  NodeList<EnumConstantDeclaration> get constants;

  @override
  EnumElement? get declaredElement;

  @experimental
  @override
  EnumFragment? get declaredFragment;

  /// The `enum` keyword.
  Token get enumKeyword;

  /// The `implements` clause for the enumeration, or `null` if the enumeration
  /// doesn't implement any interfaces.
  ImplementsClause? get implementsClause;

  /// The left curly bracket.
  Token get leftBracket;

  /// The members declared by the enumeration.
  NodeList<ClassMember> get members;

  /// The right curly bracket.
  Token get rightBracket;

  /// The optional semicolon after the last constant.
  Token? get semicolon;

  /// The type parameters for the enumeration, or `null` if the enumeration
  /// doesn't have any type parameters.
  TypeParameterList? get typeParameters;

  /// The `with` clause for the enumeration, or `null` if the enumeration
  /// doesn't have a `with` clause.
  WithClause? get withClause;
}

final class EnumDeclarationImpl extends NamedCompilationUnitMemberImpl
    with AstNodeWithNameScopeMixin
    implements EnumDeclaration {
  @override
  final Token? augmentKeyword;

  @override
  final Token enumKeyword;

  TypeParameterListImpl? _typeParameters;

  WithClauseImpl? _withClause;

  ImplementsClauseImpl? _implementsClause;

  @override
  final Token leftBracket;

  final NodeListImpl<EnumConstantDeclarationImpl> _constants = NodeListImpl._();

  @override
  final Token? semicolon;

  final NodeListImpl<ClassMemberImpl> _members = NodeListImpl._();

  @override
  final Token rightBracket;

  @override
  EnumElementImpl? declaredElement;

  /// Initializes a newly created enumeration declaration.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// declaration doesn't have the corresponding attribute.
  ///
  /// The list of [constants] must contain at least one value.
  EnumDeclarationImpl({
    required super.comment,
    required super.metadata,
    required this.augmentKeyword,
    required this.enumKeyword,
    required super.name,
    required TypeParameterListImpl? typeParameters,
    required WithClauseImpl? withClause,
    required ImplementsClauseImpl? implementsClause,
    required this.leftBracket,
    required List<EnumConstantDeclarationImpl> constants,
    required this.semicolon,
    required List<ClassMemberImpl> members,
    required this.rightBracket,
  })  : _typeParameters = typeParameters,
        _withClause = withClause,
        _implementsClause = implementsClause {
    _becomeParentOf(_typeParameters);
    _becomeParentOf(_withClause);
    _becomeParentOf(_implementsClause);
    _constants._initialize(this, constants);
    _members._initialize(this, members);
  }

  @override
  NodeListImpl<EnumConstantDeclarationImpl> get constants => _constants;

  @experimental
  @override
  EnumFragment? get declaredFragment => declaredElement as EnumFragment?;

  @override
  Token get endToken => rightBracket;

  @override
  Token get firstTokenAfterCommentAndMetadata => augmentKeyword ?? enumKeyword;

  @override
  ImplementsClauseImpl? get implementsClause => _implementsClause;

  set implementsClause(ImplementsClauseImpl? implementsClause) {
    _implementsClause = _becomeParentOf(implementsClause);
  }

  @override
  NodeListImpl<ClassMemberImpl> get members => _members;

  @override
  TypeParameterListImpl? get typeParameters => _typeParameters;

  set typeParameters(TypeParameterListImpl? typeParameters) {
    _typeParameters = _becomeParentOf(typeParameters);
  }

  @override
  WithClauseImpl? get withClause => _withClause;

  set withClause(WithClauseImpl? withClause) {
    _withClause = _becomeParentOf(withClause);
  }

  @override
  // TODO(brianwilkerson): Add commas?
  ChildEntities get _childEntities => super._childEntities
    ..addToken('augmentKeyword', augmentKeyword)
    ..addToken('enumKeyword', enumKeyword)
    ..addToken('name', name)
    ..addNode('typeParameters', typeParameters)
    ..addNode('withClause', withClause)
    ..addNode('implementsClause', implementsClause)
    ..addToken('leftBracket', leftBracket)
    ..addNodeList('constants', constants)
    ..addToken('semicolon', semicolon)
    ..addNodeList('members', members)
    ..addToken('rightBracket', rightBracket);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitEnumDeclaration(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _typeParameters?.accept(visitor);
    _withClause?.accept(visitor);
    _implementsClause?.accept(visitor);
    _constants.accept(visitor);
    _members.accept(visitor);
  }
}

/// An export directive.
///
///    exportDirective ::=
///        [Annotation] 'export' [StringLiteral] [Combinator]* ';'
abstract final class ExportDirective implements NamespaceDirective {
  /// The element associated with this directive, or `null` if the AST structure
  /// hasn't been resolved.
  @override
  LibraryExportElement? get element;

  /// The token representing the `export` keyword.
  Token get exportKeyword;

  /// Information about this export directive.
  ///
  /// Returns `null` if the AST structure hasn't been resolved.
  @experimental
  LibraryExport? get libraryExport;
}

final class ExportDirectiveImpl extends NamespaceDirectiveImpl
    implements ExportDirective {
  @override
  final Token exportKeyword;

  /// Initializes a newly created export directive.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// directive doesn't have the corresponding attribute.
  ///
  /// The list of [combinators] can be `null` if there are no combinators.
  ExportDirectiveImpl({
    required super.comment,
    required super.metadata,
    required this.exportKeyword,
    required super.uri,
    required super.configurations,
    required super.combinators,
    required super.semicolon,
  });

  @override
  LibraryExportElementImpl? get element {
    return super.element as LibraryExportElementImpl?;
  }

  @override
  Token get firstTokenAfterCommentAndMetadata => exportKeyword;

  @experimental
  @override
  LibraryExport? get libraryExport => element as LibraryExport?;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('exportKeyword', exportKeyword)
    ..addNode('uri', uri)
    ..addNodeList('combinators', combinators)
    ..addNodeList('configurations', configurations)
    ..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitExportDirective(this);

  @override
  void visitChildren(AstVisitor visitor) {
    configurations.accept(visitor);
    super.visitChildren(visitor);
    combinators.accept(visitor);
  }
}

/// A node that represents an expression.
///
///    expression ::=
///        [AssignmentExpression]
///      | [ConditionalExpression] cascadeSection*
///      | [ThrowExpression]
abstract final class Expression implements CollectionElement {
  /// The parameter element representing the parameter to which the value of
  /// this expression is bound.
  ///
  /// Returns `null` if any of these conditions are false:
  /// - this expression is an argument to an invocation
  /// - the AST structure has been resolved
  /// - the function being invoked is known based on static type information
  /// - this expression corresponds to one of the parameters of the function
  ///   being invoked
  @experimental
  FormalParameterElement? get correspondingParameter;

  /// Whether this expression is in a constant context.
  ///
  /// An expression _e_ is said to _occur in a constant context_,
  /// - if _e_ is an element of a constant list literal, or a key or value of an
  ///   entry of a constant map literal.
  /// - if _e_ is an actual argument of a constant object expression or of a
  ///   metadata annotation.
  /// - if _e_ is the initializing expression of a constant variable
  ///   declaration.
  /// - if _e_ is a switch case expression.
  /// - if _e_ is an immediate subexpression of an expression _e1_ which occurs
  ///   in a constant context, unless _e1_ is a `throw` expression or a function
  ///   literal.
  ///
  /// This roughly means that everything which is inside a syntactically
  /// constant expression is in a constant context. A `throw` expression is
  /// currently not allowed in a constant expression, but extensions affecting
  /// that status might be considered. A similar situation arises for function
  /// literals.
  ///
  /// Note that the default value of an optional formal parameter is _not_ a
  /// constant context. This choice reserves some freedom to modify the
  /// semantics of default values.
  bool get inConstantContext;

  /// Whether this expression is syntactically valid for the LHS of an
  /// [AssignmentExpression].
  bool get isAssignable;

  /// The precedence of this expression.
  ///
  /// The precedence is a positive integer value that defines how the source
  /// code is parsed into an AST. For example `a * b + c` is parsed as
  /// `(a * b) + c` because the precedence of `*` is greater than the precedence
  /// of `+`.
  Precedence get precedence;

  /// The parameter element representing the parameter to which the value of
  /// this expression is bound, or `null` if any of these conditions are not
  /// `true`
  /// - this expression is an argument to an invocation
  /// - the AST structure is resolved
  /// - the function being invoked is known based on static type information
  /// - this expression corresponds to one of the parameters of the function
  ///   being invoked
  ParameterElement? get staticParameterElement;

  /// The static type of this expression, or `null` if the AST structure hasn't
  /// been resolved.
  DartType? get staticType;

  /// If this expression is a parenthesized expression, returns the result of
  /// unwrapping the expression inside the parentheses. Otherwise, returns this
  /// expression.
  Expression get unParenthesized;
}

/// A function body consisting of a single expression.
///
///    expressionFunctionBody ::=
///        'async'? '=>' [Expression] ';'
abstract final class ExpressionFunctionBody implements FunctionBody {
  /// The expression representing the body of the function.
  Expression get expression;

  /// The token introducing the expression that represents the body of the
  /// function.
  Token get functionDefinition;

  /// The token representing the `async` keyword, or `null` if there's no such
  /// keyword.
  @override
  Token? get keyword;

  /// The semicolon terminating the statement.
  Token? get semicolon;

  /// The star following the `async` keyword, or `null` if there's no star.
  ///
  /// It's an error for an expression function body to feature the star, but
  /// the parser accepts it.
  @override
  Token? get star;
}

final class ExpressionFunctionBodyImpl extends FunctionBodyImpl
    with AstNodeWithNameScopeMixin
    implements ExpressionFunctionBody {
  @override
  final Token? keyword;

  @override
  final Token? star;

  @override
  final Token functionDefinition;

  ExpressionImpl _expression;

  @override
  final Token? semicolon;

  /// Initializes a newly created function body consisting of a block of
  /// statements.
  ///
  /// The [keyword] can be `null` if the function body isn't an async function
  /// body.
  ExpressionFunctionBodyImpl({
    required this.keyword,
    required this.star,
    required this.functionDefinition,
    required ExpressionImpl expression,
    required this.semicolon,
  }) : _expression = expression {
    _becomeParentOf(_expression);
  }

  @override
  Token get beginToken {
    if (keyword case var keyword?) {
      return keyword;
    }
    return functionDefinition;
  }

  @override
  Token get endToken {
    if (semicolon case var semicolon?) {
      return semicolon;
    }
    return _expression.endToken;
  }

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  bool get isAsynchronous => keyword?.lexeme == Keyword.ASYNC.lexeme;

  @override
  bool get isGenerator => star != null;

  @override
  bool get isSynchronous => keyword?.lexeme != Keyword.ASYNC.lexeme;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('keyword', keyword)
    ..addToken('star', star)
    ..addToken('functionDefinition', functionDefinition)
    ..addNode('expression', expression)
    ..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitExpressionFunctionBody(this);

  @override
  DartType resolve(ResolverVisitor resolver, DartType? imposedType) =>
      resolver.visitExpressionFunctionBody(this, imposedType: imposedType);

  @override
  void visitChildren(AstVisitor visitor) {
    _expression.accept(visitor);
  }
}

sealed class ExpressionImpl extends AstNodeImpl
    implements CollectionElementImpl, Expression {
  DartType? _staticType;

  @experimental
  @override
  FormalParameterElement? get correspondingParameter {
    if (staticParameterElement case FormalParameterFragment fragment) {
      return fragment.element;
    }
    return null;
  }

  @override
  bool get inConstantContext {
    return constantContext(includeSelf: false) != null;
  }

  @override
  bool get isAssignable => false;

  @override
  ParameterElement? get staticParameterElement {
    var parent = this.parent;
    if (parent is ArgumentListImpl) {
      return parent._getStaticParameterElementFor(this);
    } else if (parent is IndexExpressionImpl) {
      if (identical(parent.index, this)) {
        return parent._staticParameterElementForIndex;
      }
    } else if (parent is BinaryExpressionImpl) {
      // TODO(scheglov): https://github.com/dart-lang/sdk/issues/49102
      if (identical(parent.rightOperand, this)) {
        var parameters = parent.staticInvokeType?.parameters;
        if (parameters != null && parameters.isNotEmpty) {
          return parameters[0];
        }
        return null;
      }
    } else if (parent is AssignmentExpressionImpl) {
      if (identical(parent.rightHandSide, this)) {
        return parent._staticParameterElementForRightHandSide;
      }
    } else if (parent is PrefixExpressionImpl) {
      // TODO(scheglov): This doesn't look right, there's no element for
      // the operand, for `a++` we invoke `a = a + 1`, so the parameter
      // is for `1`, not for `a`.
      return parent._staticParameterElementForOperand;
    } else if (parent is PostfixExpressionImpl) {
      // TODO(scheglov): The same as above.
      return parent._staticParameterElementForOperand;
    }
    return null;
  }

  @override
  DartType? get staticType => _staticType;

  @override
  ExpressionImpl get unParenthesized => this;

  /// Returns the [AstNode] that puts node into the constant context, and
  /// the explicit `const` keyword of that node. The keyword might be absent
  /// if the constness is implicit.
  ///
  /// Returns `null` if node is not in the constant context.
  (AstNode, Token?)? constantContext({
    required bool includeSelf,
  }) {
    AstNode? current = this;
    if (!includeSelf) {
      current = current.parent;
    }

    while (true) {
      switch (current) {
        case Annotation():
          return (current, null);
        case ConstantContextForExpressionImpl():
          return (current, null);
        case ConstantPatternImpl():
          if (current.constKeyword case var constKeyword?) {
            return (current, constKeyword);
          }
          return null;
        case EnumConstantArguments():
          return (current, null);
        case InstanceCreationExpression():
          var keyword = current.keyword;
          if (keyword != null && keyword.keyword == Keyword.CONST) {
            return (current, keyword);
          }
        case RecordLiteral():
          if (current.constKeyword case var constKeyword?) {
            return (current, constKeyword);
          }
        case SwitchCase():
          return (current, null);
        case TypedLiteralImpl():
          if (current.constKeyword case var constKeyword?) {
            return (current, constKeyword);
          }
        case VariableDeclarationList():
          var keyword = current.keyword;
          if (keyword != null && keyword.keyword == Keyword.CONST) {
            return (current, keyword);
          }
          return null;
        case ArgumentList():
        case Expression():
        case IfElement():
        case ForElement():
        case MapLiteralEntry():
        case SpreadElement():
        case VariableDeclaration():
          break;
        default:
          return null;
      }
      current = current?.parent;
    }
  }

  /// Record that the static type of the given node is the given type.
  ///
  /// @param expression the node whose type is to be recorded
  /// @param type the static type of the node
  void recordStaticType(DartType type, {required ResolverVisitor resolver}) {
    _staticType = type;
    if (type.isBottom) {
      resolver.flowAnalysis.flow?.handleExit();
    }
    inferenceLogWriter?.recordStaticType(this, type);
  }

  @override
  void resolveElement(
      ResolverVisitor resolver, CollectionLiteralContext? context) {
    resolver.analyzeExpression(
        this,
        SharedTypeSchemaView(
            context?.elementType ?? UnknownInferredType.instance));
  }

  /// Dispatches this expression to the [resolver], with the given [contextType]
  /// information.
  ///
  /// Note: most code shouldn't call this method directly, but should instead
  /// call [ResolverVisitor.dispatchExpression], which has some special logic
  /// for handling dynamic contexts.
  void resolveExpression(ResolverVisitor resolver, DartType contextType);

  /// Records that the static type of `this` is [type], without triggering any
  /// [ResolverVisitor] behaviors.
  ///
  /// This is used when the expression AST node occurs in a place where it is
  /// not technically a true expression, but the analyzer chooses to assign it a
  /// static type anyway (e.g. the [SimpleIdentifier] representing the method
  /// name in a method invocation).
  void setPseudoExpressionStaticType(DartType? type) {
    _staticType = type;
  }
}

/// An expression used as a statement.
///
///    expressionStatement ::=
///        [Expression]? ';'
abstract final class ExpressionStatement implements Statement {
  /// The expression that comprises the statement.
  Expression get expression;

  /// The semicolon terminating the statement, or `null` if the expression is a
  /// function expression and therefore isn't followed by a semicolon.
  Token? get semicolon;
}

final class ExpressionStatementImpl extends StatementImpl
    implements ExpressionStatement {
  ExpressionImpl _expression;

  @override
  final Token? semicolon;

  /// Initializes a newly created expression statement.
  ExpressionStatementImpl({
    required ExpressionImpl expression,
    required this.semicolon,
  }) : _expression = expression {
    _becomeParentOf(_expression);
  }

  @override
  Token get beginToken => _expression.beginToken;

  @override
  Token get endToken {
    if (semicolon case var semicolon?) {
      return semicolon;
    }
    return _expression.endToken;
  }

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  bool get isSynthetic =>
      _expression.isSynthetic && (semicolon == null || semicolon!.isSynthetic);

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('expression', expression)
    ..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitExpressionStatement(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _expression.accept(visitor);
  }
}

/// The "extends" clause in a class declaration.
///
///    extendsClause ::=
///        'extends' [NamedType]
abstract final class ExtendsClause implements AstNode {
  /// The token representing the `extends` keyword.
  Token get extendsKeyword;

  /// The name of the class that is being extended.
  NamedType get superclass;
}

final class ExtendsClauseImpl extends AstNodeImpl implements ExtendsClause {
  @override
  final Token extendsKeyword;

  NamedTypeImpl _superclass;

  /// Initializes a newly created extends clause.
  ExtendsClauseImpl({
    required this.extendsKeyword,
    required NamedTypeImpl superclass,
  }) : _superclass = superclass {
    _becomeParentOf(_superclass);
  }

  @override
  Token get beginToken => extendsKeyword;

  @override
  Token get endToken => _superclass.endToken;

  @override
  NamedTypeImpl get superclass => _superclass;

  set superclass(NamedTypeImpl name) {
    _superclass = _becomeParentOf(name);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('extendsKeyword', extendsKeyword)
    ..addNode('superclass', superclass);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitExtendsClause(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _superclass.accept(visitor);
  }
}

/// The declaration of an extension of a type.
///
///    extension ::=
///        'extension' [SimpleIdentifier]? [TypeParameterList]?
///        'on' [TypeAnnotation] [ShowClause]? [HideClause]?
///        '{' [ClassMember]* '}'
abstract final class ExtensionDeclaration
    implements CompilationUnitMember, FragmentDeclaration {
  /// The `augment` keyword, or `null` if the keyword was absent.
  @experimental
  Token? get augmentKeyword;

  @override
  ExtensionElement? get declaredElement;

  @experimental
  @override
  ExtensionFragment? get declaredFragment;

  /// The token representing the `extension` keyword.
  Token get extensionKeyword;

  /// The left curly bracket.
  Token get leftBracket;

  /// The members being added to the extended class.
  NodeList<ClassMember> get members;

  /// The name of the extension, or `null` if the extension doesn't have a name.
  Token? get name;

  /// The `on` clause, `null` if an augmentation.
  ExtensionOnClause? get onClause;

  /// The right curly bracket.
  Token get rightBracket;

  /// The token representing the `type` keyword.
  Token? get typeKeyword;

  /// The type parameters for the extension, or `null` if the extension doesn't
  /// have any type parameters.
  TypeParameterList? get typeParameters;
}

final class ExtensionDeclarationImpl extends CompilationUnitMemberImpl
    with AstNodeWithNameScopeMixin
    implements ExtensionDeclaration {
  @override
  final Token? augmentKeyword;

  @override
  final Token extensionKeyword;

  @override
  final Token? typeKeyword;

  @override
  final Token? name;

  TypeParameterListImpl? _typeParameters;

  @override
  ExtensionOnClauseImpl? onClause;

  @override
  final Token leftBracket;

  final NodeListImpl<ClassMemberImpl> _members = NodeListImpl._();

  @override
  final Token rightBracket;

  @override
  ExtensionElementImpl? declaredElement;

  ExtensionDeclarationImpl({
    required super.comment,
    required super.metadata,
    required this.augmentKeyword,
    required this.extensionKeyword,
    required this.typeKeyword,
    required this.name,
    required TypeParameterListImpl? typeParameters,
    required this.onClause,
    required this.leftBracket,
    required List<ClassMemberImpl> members,
    required this.rightBracket,
  }) : _typeParameters = typeParameters {
    _becomeParentOf(_typeParameters);
    _becomeParentOf(onClause);
    _members._initialize(this, members);
  }

  @experimental
  @override
  ExtensionFragment? get declaredFragment =>
      declaredElement as ExtensionFragment?;

  @override
  Token get endToken => rightBracket;

  @override
  Token get firstTokenAfterCommentAndMetadata =>
      augmentKeyword ?? extensionKeyword;

  @override
  NodeListImpl<ClassMemberImpl> get members => _members;

  @override
  TypeParameterListImpl? get typeParameters => _typeParameters;

  set typeParameters(TypeParameterListImpl? typeParameters) {
    _typeParameters = _becomeParentOf(typeParameters);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('augmentKeyword', augmentKeyword)
    ..addToken('extensionKeyword', extensionKeyword)
    ..addToken('name', name)
    ..addNode('typeParameters', typeParameters)
    ..addNode('onClause', onClause)
    ..addToken('leftBracket', leftBracket)
    ..addNodeList('members', members)
    ..addToken('rightBracket', rightBracket);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitExtensionDeclaration(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _typeParameters?.accept(visitor);
    onClause?.accept(visitor);
    _members.accept(visitor);
  }
}

/// The `on` clause in an extension declaration.
///
///    onClause ::= 'on' [TypeAnnotation]
abstract final class ExtensionOnClause implements AstNode {
  /// The extended type.
  TypeAnnotation get extendedType;

  /// The 'on' keyword.
  Token get onKeyword;
}

final class ExtensionOnClauseImpl extends AstNodeImpl
    implements ExtensionOnClause {
  @override
  final Token onKeyword;

  @override
  final TypeAnnotationImpl extendedType;

  ExtensionOnClauseImpl({
    required this.onKeyword,
    required this.extendedType,
  }) {
    _becomeParentOf(extendedType);
  }

  @override
  Token get beginToken => onKeyword;

  @override
  Token get endToken => extendedType.endToken;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('onKeyword', onKeyword)
    ..addNode('extendedType', extendedType);

  @override
  E? accept<E>(AstVisitor<E> visitor) {
    return visitor.visitExtensionOnClause(this);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    extendedType.accept(visitor);
  }
}

/// An override to force resolution to choose a member from a specific
/// extension.
///
///    extensionOverride ::=
///        [Identifier] [TypeArgumentList]? [ArgumentList]
abstract final class ExtensionOverride implements Expression {
  /// The list of arguments to the override.
  ///
  /// In valid code this contains a single argument that evaluates to the object
  /// being extended.
  ArgumentList get argumentList;

  /// The forced extension element.
  ExtensionElement get element;

  /// The extension that resolution will use to resolve member references.
  @experimental
  ExtensionElement2 get element2;

  /// The actual type extended by this override, produced by applying
  /// [typeArgumentTypes] to the generic type extended by the extension, or
  /// `null` if the AST structure hasn't been resolved.
  DartType? get extendedType;

  /// The optional import prefix before [name].
  ImportPrefixReference? get importPrefix;

  /// Whether this override is null aware (as opposed to non-null).
  bool get isNullAware;

  /// The name of the extension being selected.
  Token get name;

  /// The type arguments to be applied to the extension, or `null` if there are
  /// no type arguments.
  TypeArgumentList? get typeArguments;

  /// The actual type arguments to be applied to the extension, either
  /// explicitly specified in [typeArguments], or inferred, or `null` if the AST
  /// structure hasn't been resolved.
  ///
  /// An empty list if the extension doesn't have type arguments.
  List<DartType>? get typeArgumentTypes;
}

final class ExtensionOverrideImpl extends ExpressionImpl
    implements ExtensionOverride {
  @override
  final ImportPrefixReferenceImpl? importPrefix;

  @override
  final Token name;

  @override
  final ExtensionElement element;

  TypeArgumentListImpl? _typeArguments;

  ArgumentListImpl _argumentList;

  @override
  List<DartType>? typeArgumentTypes;

  @override
  DartType? extendedType;

  ExtensionOverrideImpl({
    required this.importPrefix,
    required this.name,
    required TypeArgumentListImpl? typeArguments,
    required ArgumentListImpl argumentList,
    required this.element,
  })  : _typeArguments = typeArguments,
        _argumentList = argumentList {
    _becomeParentOf(importPrefix);
    _becomeParentOf(_typeArguments);
    _becomeParentOf(_argumentList);
  }

  @override
  ArgumentListImpl get argumentList => _argumentList;

  set argumentList(ArgumentListImpl argumentList) {
    _argumentList = _becomeParentOf(argumentList);
  }

  @override
  Token get beginToken => importPrefix?.name ?? name;

  @experimental
  @override
  ExtensionElement2 get element2 => (element as ExtensionFragment).element;

  @override
  Token get endToken => _argumentList.endToken;

  @override
  bool get isNullAware {
    var nextType = argumentList.endToken.next!.type;
    return nextType == TokenType.QUESTION_PERIOD ||
        nextType == TokenType.QUESTION;
  }

  @override
  Precedence get precedence => Precedence.postfix;

  @override
  TypeArgumentListImpl? get typeArguments => _typeArguments;

  set typeArguments(TypeArgumentListImpl? typeArguments) {
    _typeArguments = _becomeParentOf(typeArguments);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('importPrefix', importPrefix)
    ..addToken('name', name)
    ..addNode('typeArguments', typeArguments)
    ..addNode('argumentList', argumentList);

  @override
  E? accept<E>(AstVisitor<E> visitor) {
    return visitor.visitExtensionOverride(this);
  }

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitExtensionOverride(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    importPrefix?.accept(visitor);
    _typeArguments?.accept(visitor);
    _argumentList.accept(visitor);
  }
}

/// The declaration of an extension type.
///
///    <extensionTypeDeclaration> ::=
///        'extension' 'type' 'const'? <typeIdentifier> <typeParameters>?
///        <representationDeclaration> <interfaces>?
///        '{'
///            (<metadata> <extensionTypeMemberDeclaration>)*
///        '}'
@experimental
abstract final class ExtensionTypeDeclaration
    implements NamedCompilationUnitMember, FragmentDeclaration {
  /// The `augment` keyword, or `null` if the keyword was absent.
  @experimental
  Token? get augmentKeyword;

  /// The `const` keyword.
  Token? get constKeyword;

  @override
  ExtensionTypeElement? get declaredElement;

  @experimental
  @override
  ExtensionTypeFragment? get declaredFragment;

  /// The `extension` keyword.
  Token get extensionKeyword;

  /// The `implements` clause.
  ImplementsClause? get implementsClause;

  /// The left curly bracket.
  Token get leftBracket;

  /// The members.
  NodeList<ClassMember> get members;

  /// The representation declaration.
  RepresentationDeclaration get representation;

  /// The right curly bracket.
  Token get rightBracket;

  /// The `type` keyword.
  Token get typeKeyword;

  /// The type parameters.
  TypeParameterList? get typeParameters;
}

final class ExtensionTypeDeclarationImpl extends NamedCompilationUnitMemberImpl
    with AstNodeWithNameScopeMixin
    implements ExtensionTypeDeclaration {
  @override
  final Token? augmentKeyword;

  @override
  final Token extensionKeyword;

  @override
  final Token typeKeyword;

  @override
  final Token? constKeyword;

  @override
  final TypeParameterListImpl? typeParameters;

  @override
  final RepresentationDeclarationImpl representation;

  @override
  final ImplementsClauseImpl? implementsClause;

  @override
  final Token leftBracket;

  @override
  final NodeListImpl<ClassMemberImpl> members = NodeListImpl._();

  @override
  final Token rightBracket;

  @override
  ExtensionTypeElementImpl? declaredElement;

  ExtensionTypeDeclarationImpl({
    required super.comment,
    required super.metadata,
    required this.augmentKeyword,
    required this.extensionKeyword,
    required this.typeKeyword,
    required this.constKeyword,
    required super.name,
    required this.typeParameters,
    required this.representation,
    required this.implementsClause,
    required this.leftBracket,
    required List<ClassMemberImpl> members,
    required this.rightBracket,
  }) {
    _becomeParentOf(typeParameters);
    _becomeParentOf(representation);
    _becomeParentOf(implementsClause);
    this.members._initialize(this, members);
  }

  @experimental
  @override
  ExtensionTypeFragment? get declaredFragment =>
      declaredElement as ExtensionTypeFragment;

  @override
  Token get endToken => rightBracket;

  @override
  Token get firstTokenAfterCommentAndMetadata =>
      augmentKeyword ?? extensionKeyword;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('augmentKeyword', augmentKeyword)
    ..addToken('extensionKeyword', extensionKeyword)
    ..addToken('typeKeyword', typeKeyword)
    ..addToken('constKeyword', constKeyword)
    ..addToken('name', name)
    ..addNode('typeParameters', typeParameters)
    ..addNode('representation', representation)
    ..addNode('implementsClause', implementsClause)
    ..addToken('leftBracket', leftBracket)
    ..addNodeList('members', members)
    ..addToken('rightBracket', rightBracket);

  @override
  E? accept<E>(AstVisitor<E> visitor) {
    return visitor.visitExtensionTypeDeclaration(this);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    typeParameters?.accept(visitor);
    representation.accept(visitor);
    implementsClause?.accept(visitor);
    members.accept(visitor);
  }
}

/// The declaration of one or more fields of the same type.
///
///    fieldDeclaration ::=
///        'static' 'const' <type>? <staticFinalDeclarationList>
///      | 'static' 'final' <type>? <staticFinalDeclarationList>
///      | 'static' 'late' 'final' <type>? <initializedIdentifierList>
///      | 'static' 'late'? <varOrType> <initializedIdentifierList>
///      | 'covariant' 'late'? <varOrType> <initializedIdentifierList>
///      | 'late'? 'final' <type>? <initializedIdentifierList>
///      | 'late'? <varOrType> <initializedIdentifierList>
///      | 'external' ('static'? <finalVarOrType> | 'covariant' <varOrType>)
///            <identifierList>
///      | 'abstract' (<finalVarOrType> | 'covariant' <varOrType>)
///            <identifierList>
///
/// (Note: there's no `<fieldDeclaration>` production in the grammar; this is a
/// subset of the grammar production `<declaration>`, which encompasses
/// everything that can appear inside a class declaration except methods).
abstract final class FieldDeclaration implements ClassMember {
  /// The `abstract` keyword, or `null` if the keyword isn't used.
  Token? get abstractKeyword;

  /// The `augment` keyword, or `null` if the keyword was absent.
  @experimental
  Token? get augmentKeyword;

  /// The `covariant` keyword, or `null` if the keyword isn't used.
  Token? get covariantKeyword;

  /// The `external` keyword, or `null` if the keyword isn't used.
  Token? get externalKeyword;

  /// The fields being declared.
  VariableDeclarationList get fields;

  /// Whether the fields are declared to be static.
  bool get isStatic;

  /// The semicolon terminating the declaration.
  Token get semicolon;

  /// The token representing the `static` keyword, or `null` if the fields
  /// aren't static.
  Token? get staticKeyword;
}

final class FieldDeclarationImpl extends ClassMemberImpl
    implements FieldDeclaration {
  @override
  final Token? abstractKeyword;

  @override
  final Token? augmentKeyword;

  @override
  final Token? covariantKeyword;

  @override
  final Token? externalKeyword;

  @override
  final Token? staticKeyword;

  VariableDeclarationListImpl _fieldList;

  @override
  final Token semicolon;

  /// Initializes a newly created field declaration.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// declaration doesn't have the corresponding attribute.
  ///
  /// The [staticKeyword] can be `null` if the field isn't a static field.
  FieldDeclarationImpl({
    required super.comment,
    required super.metadata,
    required this.abstractKeyword,
    required this.augmentKeyword,
    required this.covariantKeyword,
    required this.externalKeyword,
    required this.staticKeyword,
    required VariableDeclarationListImpl fieldList,
    required this.semicolon,
  }) : _fieldList = fieldList {
    _becomeParentOf(_fieldList);
  }

  @override
  Element? get declaredElement => null;

  @override
  Token get endToken => semicolon;

  @override
  VariableDeclarationListImpl get fields => _fieldList;

  set fields(VariableDeclarationListImpl fields) {
    _fieldList = _becomeParentOf(fields);
  }

  @override
  Token get firstTokenAfterCommentAndMetadata {
    return Token.lexicallyFirst(abstractKeyword, augmentKeyword,
            externalKeyword, covariantKeyword, staticKeyword) ??
        _fieldList.beginToken;
  }

  @override
  bool get isStatic => staticKeyword != null;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('abstractKeyword', abstractKeyword)
    ..addToken('augmentKeyword', augmentKeyword)
    ..addToken('covariantKeyword', covariantKeyword)
    ..addToken('externalKeyword', externalKeyword)
    ..addToken('staticKeyword', staticKeyword)
    ..addNode('fields', fields)
    ..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitFieldDeclaration(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _fieldList.accept(visitor);
  }
}

/// A field formal parameter.
///
///    fieldFormalParameter ::=
///        ('final' [TypeAnnotation] | 'const' [TypeAnnotation] | 'var' |
///        [TypeAnnotation])?
///        'this' '.' name ([TypeParameterList]? [FormalParameterList])?
abstract final class FieldFormalParameter implements NormalFormalParameter {
  /// The token representing either the `final`, `const` or `var` keyword, or
  /// `null` if no keyword was used.
  Token? get keyword;

  @override
  Token get name;

  /// The parameters of the function-typed parameter, or `null` if this isn't a
  /// function-typed field formal parameter.
  FormalParameterList? get parameters;

  /// The token representing the period.
  Token get period;

  /// The question mark indicating that the function type is nullable, or `null`
  /// if there's no question mark, which will always be the case when the
  /// parameter doesn't use the older style for denoting a function typed
  /// parameter.
  ///
  /// If the parameter is function-typed, and has the question mark, then its
  /// function type is nullable. Having a nullable function type means that the
  /// parameter can be `null`.
  Token? get question;

  /// The token representing the `this` keyword.
  Token get thisKeyword;

  /// The declared type of the parameter, or `null` if the parameter doesn't
  /// have a declared type.
  ///
  /// If this is a function-typed field formal parameter this is the return type
  /// of the function.
  TypeAnnotation? get type;

  /// The type parameters associated with this method, or `null` if this method
  /// isn't a generic method.
  TypeParameterList? get typeParameters;
}

final class FieldFormalParameterImpl extends NormalFormalParameterImpl
    implements FieldFormalParameter {
  @override
  final Token? keyword;

  TypeAnnotationImpl? _type;

  @override
  final Token thisKeyword;

  @override
  final Token period;

  TypeParameterListImpl? _typeParameters;

  FormalParameterListImpl? _parameters;

  @override
  final Token? question;

  /// Initializes a newly created formal parameter.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// parameter doesn't have the corresponding attribute.
  ///
  /// The [keyword] can be `null` if there's a type.
  ///
  /// The [type] must be `null` if the keyword is `var`.
  ///
  /// The [thisKeyword] and [period] can be `null` if the keyword `this` isn't
  /// provided.
  ///
  /// The [parameters] can be `null` if this isn't a function-typed field formal
  /// parameter.
  FieldFormalParameterImpl({
    required super.comment,
    required super.metadata,
    required super.covariantKeyword,
    required super.requiredKeyword,
    required this.keyword,
    required TypeAnnotationImpl? type,
    required this.thisKeyword,
    required this.period,
    required super.name,
    required TypeParameterListImpl? typeParameters,
    required FormalParameterListImpl? parameters,
    required this.question,
  })  : _type = type,
        _typeParameters = typeParameters,
        _parameters = parameters {
    _becomeParentOf(_type);
    _becomeParentOf(_typeParameters);
    _becomeParentOf(_parameters);
  }

  @override
  Token get endToken {
    return question ?? _parameters?.endToken ?? name;
  }

  @override
  Token get firstTokenAfterCommentAndMetadata =>
      requiredKeyword ??
      covariantKeyword ??
      keyword ??
      type?.beginToken ??
      thisKeyword;

  @override
  bool get isConst => keyword?.keyword == Keyword.CONST;

  @override
  bool get isExplicitlyTyped => _parameters != null || _type != null;

  @override
  bool get isFinal => keyword?.keyword == Keyword.FINAL;

  @override
  Token get name => super.name!;

  @override
  FormalParameterListImpl? get parameters => _parameters;

  set parameters(FormalParameterListImpl? parameters) {
    _parameters = _becomeParentOf(parameters);
  }

  @override
  TypeAnnotationImpl? get type => _type;

  set type(TypeAnnotationImpl? type) {
    _type = _becomeParentOf(type as TypeAnnotationImpl);
  }

  @override
  TypeParameterListImpl? get typeParameters => _typeParameters;

  set typeParameters(TypeParameterListImpl? typeParameters) {
    _typeParameters = _becomeParentOf(typeParameters);
  }

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('keyword', keyword)
    ..addNode('type', type)
    ..addToken('thisKeyword', thisKeyword)
    ..addToken('period', period)
    ..addToken('name', name)
    ..addNode('typeParameters', typeParameters)
    ..addNode('parameters', parameters);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitFieldFormalParameter(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _type?.accept(visitor);
    _typeParameters?.accept(visitor);
    _parameters?.accept(visitor);
  }
}

/// The parts of a for-each loop that control the iteration.
sealed class ForEachParts implements ForLoopParts {
  /// The token representing the `in` keyword.
  Token get inKeyword;

  /// The expression evaluated to produce the iterator.
  Expression get iterable;
}

sealed class ForEachPartsImpl extends ForLoopPartsImpl implements ForEachParts {
  @override
  final Token inKeyword;

  ExpressionImpl _iterable;

  /// Initializes a newly created for-each statement whose loop control variable
  /// is declared internally (in the for-loop part).
  ///
  /// The [awaitKeyword] can be `null` if this isn't an asynchronous for loop.
  ForEachPartsImpl({
    required this.inKeyword,
    required ExpressionImpl iterable,
  }) : _iterable = iterable {
    _becomeParentOf(_iterable);
  }

  @override
  Token get beginToken => inKeyword;

  @override
  Token get endToken => _iterable.endToken;

  @override
  ExpressionImpl get iterable => _iterable;

  set iterable(ExpressionImpl expression) {
    _iterable = _becomeParentOf(expression);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('inKeyword', inKeyword)
    ..addNode('iterable', iterable);

  @override
  void visitChildren(AstVisitor visitor) {
    _iterable.accept(visitor);
  }
}

/// The parts of a for-each loop that control the iteration when the loop
/// variable is declared as part of the for loop.
///
///   forLoopParts ::=
///       [DeclaredIdentifier] 'in' [Expression]
abstract final class ForEachPartsWithDeclaration implements ForEachParts {
  /// The declaration of the loop variable.
  DeclaredIdentifier get loopVariable;
}

final class ForEachPartsWithDeclarationImpl extends ForEachPartsImpl
    implements ForEachPartsWithDeclaration {
  DeclaredIdentifierImpl _loopVariable;

  /// Initializes a newly created for-each statement whose loop control variable
  /// is declared internally (inside the for-loop part).
  ForEachPartsWithDeclarationImpl({
    required DeclaredIdentifierImpl loopVariable,
    required super.inKeyword,
    required super.iterable,
  }) : _loopVariable = loopVariable {
    _becomeParentOf(_loopVariable);
  }

  @override
  Token get beginToken => _loopVariable.beginToken;

  @override
  DeclaredIdentifierImpl get loopVariable => _loopVariable;

  set loopVariable(DeclaredIdentifierImpl variable) {
    _loopVariable = _becomeParentOf(variable);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('loopVariable', loopVariable)
    ..addAll(super._childEntities);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitForEachPartsWithDeclaration(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _loopVariable.accept(visitor);
    super.visitChildren(visitor);
  }
}

/// The parts of a for-each loop that control the iteration when the loop
/// variable is declared outside of the for loop.
///
///   forLoopParts ::=
///       [SimpleIdentifier] 'in' [Expression]
abstract final class ForEachPartsWithIdentifier implements ForEachParts {
  /// The loop variable.
  SimpleIdentifier get identifier;
}

final class ForEachPartsWithIdentifierImpl extends ForEachPartsImpl
    implements ForEachPartsWithIdentifier {
  SimpleIdentifierImpl _identifier;

  /// Initializes a newly created for-each statement whose loop control variable
  /// is declared externally (outside the for-loop part).
  ForEachPartsWithIdentifierImpl({
    required SimpleIdentifierImpl identifier,
    required super.inKeyword,
    required super.iterable,
  }) : _identifier = identifier {
    _becomeParentOf(_identifier);
  }

  @override
  Token get beginToken => _identifier.beginToken;

  @override
  SimpleIdentifierImpl get identifier => _identifier;

  set identifier(SimpleIdentifierImpl identifier) {
    _identifier = _becomeParentOf(identifier);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('identifier', identifier)
    ..addAll(super._childEntities);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitForEachPartsWithIdentifier(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _identifier.accept(visitor);
    _iterable.accept(visitor);
  }
}

/// A for-loop part with a pattern.
///
///    forEachPartsWithPattern ::=
///        ( 'final' | 'var' ) [DartPattern] 'in' [Expression]
abstract final class ForEachPartsWithPattern implements ForEachParts {
  /// The `var` or `final` keyword introducing the pattern.
  Token get keyword;

  /// The annotations associated with this node.
  NodeList<Annotation> get metadata;

  /// The pattern used to match the expression.
  DartPattern get pattern;
}

final class ForEachPartsWithPatternImpl extends ForEachPartsImpl
    implements ForEachPartsWithPattern {
  final NodeListImpl<AnnotationImpl> _metadata = NodeListImpl._();

  @override
  final Token keyword;

  @override
  final DartPatternImpl pattern;

  /// Variables declared in [pattern].
  late final List<BindPatternVariableElementImpl> variables;

  ForEachPartsWithPatternImpl({
    required List<AnnotationImpl>? metadata,
    required this.keyword,
    required this.pattern,
    required super.inKeyword,
    required super.iterable,
  }) {
    _metadata._initialize(this, metadata);
    _becomeParentOf(pattern);
  }

  @override
  Token get beginToken {
    if (_metadata.isEmpty) {
      return keyword;
    } else {
      return _metadata.beginToken!;
    }
  }

  /// If [keyword] is `final`, returns it.
  Token? get finalKeyword {
    if (keyword.keyword == Keyword.FINAL) {
      return keyword;
    }
    return null;
  }

  @override
  NodeListImpl<AnnotationImpl> get metadata => _metadata;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNodeList('metadata', metadata)
    ..addToken('keyword', keyword)
    ..addNode('pattern', pattern)
    ..addAll(super._childEntities);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitForEachPartsWithPattern(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _metadata.accept(visitor);
    pattern.accept(visitor);
    super.visitChildren(visitor);
  }
}

/// The basic structure of a for element.
abstract final class ForElement implements CollectionElement {
  /// The token representing the `await` keyword, or `null` if there was no
  /// `await` keyword.
  Token? get awaitKeyword;

  /// The body of the loop.
  CollectionElement get body;

  /// The token representing the `for` keyword.
  Token get forKeyword;

  /// The parts of the for element that control the iteration.
  ForLoopParts get forLoopParts;

  /// The left parenthesis.
  Token get leftParenthesis;

  /// The right parenthesis.
  Token get rightParenthesis;
}

final class ForElementImpl extends CollectionElementImpl
    with AstNodeWithNameScopeMixin
    implements ForElement {
  @override
  final Token? awaitKeyword;

  @override
  final Token forKeyword;

  @override
  final Token leftParenthesis;

  ForLoopPartsImpl _forLoopParts;

  @override
  final Token rightParenthesis;

  CollectionElementImpl _body;

  /// Initializes a newly created for element.
  ForElementImpl({
    required this.awaitKeyword,
    required this.forKeyword,
    required this.leftParenthesis,
    required ForLoopPartsImpl forLoopParts,
    required this.rightParenthesis,
    required CollectionElementImpl body,
  })  : _forLoopParts = forLoopParts,
        _body = body {
    _becomeParentOf(_forLoopParts);
    _becomeParentOf(_body);
  }

  @override
  Token get beginToken => awaitKeyword ?? forKeyword;

  @override
  CollectionElementImpl get body => _body;

  set body(CollectionElementImpl statement) {
    _body = _becomeParentOf(statement);
  }

  @override
  Token get endToken => _body.endToken;

  @override
  ForLoopPartsImpl get forLoopParts => _forLoopParts;

  set forLoopParts(ForLoopPartsImpl forLoopParts) {
    _forLoopParts = _becomeParentOf(forLoopParts);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('awaitKeyword', awaitKeyword)
    ..addToken('forKeyword', forKeyword)
    ..addToken('leftParenthesis', leftParenthesis)
    ..addNode('forLoopParts', forLoopParts)
    ..addToken('rightParenthesis', rightParenthesis)
    ..addNode('body', body);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitForElement(this);

  @override
  void resolveElement(
      ResolverVisitor resolver, CollectionLiteralContext? context) {
    resolver.visitForElement(this, context: context);
    resolver.pushRewrite(null);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _forLoopParts.accept(visitor);
    _body.accept(visitor);
  }
}

/// The parts of a for or for-each loop that control the iteration.
///
///   forLoopParts ::=
///       [VariableDeclaration] ';' [Expression]? ';' expressionList?
///     | [Expression]? ';' [Expression]? ';' expressionList?
///     | [DeclaredIdentifier] 'in' [Expression]
///     | [SimpleIdentifier] 'in' [Expression]
///
///   expressionList ::=
///       [Expression] (',' [Expression])*
sealed class ForLoopParts implements AstNode {}

sealed class ForLoopPartsImpl extends AstNodeImpl implements ForLoopParts {}

/// A node representing a parameter to a function.
///
///    formalParameter ::=
///        [NormalFormalParameter]
///      | [DefaultFormalParameter]
sealed class FormalParameter implements AstNode {
  /// The `covariant` keyword, or `null` if the keyword isn't used.
  Token? get covariantKeyword;

  /// The element representing this parameter, or `null` if this parameter
  /// hasn't been resolved.
  ParameterElement? get declaredElement;

  ///The fragment declared by this parameter.
  ///
  /// Returns `null` if this parameter hasn't been resolved.
  @experimental
  FormalParameterFragment? get declaredFragment;

  /// Whether this parameter was declared with the 'const' modifier.
  bool get isConst;

  /// Whether the parameter has an explicit type.
  bool get isExplicitlyTyped;

  /// Whether this parameter was declared with the 'final' modifier.
  ///
  /// Returns `false` for parameters that are declared with the 'const' modifier
  /// even though they are implicitly final.
  bool get isFinal;

  /// Whether this parameter is a named parameter.
  ///
  /// Named parameters can either be required or optional.
  bool get isNamed;

  /// Whether this parameter is an optional parameter.
  ///
  /// Optional parameters can either be positional or named.
  bool get isOptional;

  /// Whether this parameter is both an optional and named parameter.
  bool get isOptionalNamed;

  /// Whether this parameter is both an optional and positional
  /// parameter.
  bool get isOptionalPositional;

  /// Whether this parameter is a positional parameter.
  ///
  /// Positional parameters can either be required or optional.
  bool get isPositional;

  /// Whether this parameter is a required parameter.
  ///
  /// Required parameters can either be positional or named.
  ///
  /// Note: this returns `false` for a named parameter that is annotated with
  /// the `@required` annotation.
  bool get isRequired;

  /// Whether this parameter is both a required and named parameter.
  ///
  /// Note: this returns `false` for a named parameter that is annotated with
  /// the `@required` annotation.
  bool get isRequiredNamed;

  /// Whether this parameter is both a required and positional parameter.
  bool get isRequiredPositional;

  /// The annotations associated with this parameter.
  NodeList<Annotation> get metadata;

  /// The name of the parameter being declared, or `null` if the parameter
  /// doesn't have a name, such as when it's part of a generic function type.
  Token? get name;

  /// The `required` keyword, or `null` if the keyword isn't used.
  Token? get requiredKeyword;
}

sealed class FormalParameterImpl extends AstNodeImpl
    implements FormalParameter {
  @override
  ParameterElementImpl? declaredElement;

  @experimental
  @override
  FormalParameterFragment? get declaredFragment =>
      declaredElement as FormalParameterFragment?;

  @override
  bool get isNamed => kind.isNamed;

  @override
  bool get isOptional => kind.isOptional;

  @override
  bool get isOptionalNamed => kind.isOptionalNamed;

  @override
  bool get isOptionalPositional => kind.isOptionalPositional;

  @override
  bool get isPositional => kind.isPositional;

  @override
  bool get isRequired => kind.isRequired;

  @override
  bool get isRequiredNamed => kind.isRequiredNamed;

  @override
  bool get isRequiredPositional => kind.isRequiredPositional;

  /// The kind of this parameter.
  ParameterKind get kind;

  @override
  NodeList<AnnotationImpl> get metadata;
}

/// The formal parameter list of a method declaration, function declaration, or
/// function type alias.
///
/// While the grammar requires all required positional parameters to be first,
/// optionally being followed by either optional positional parameters or named
/// parameters (but not both), this class doesn't enforce those constraints. All
/// parameters are flattened into a single list, which can have any or all kinds
/// of parameters (normal, named, and positional) in any order.
///
///    formalParameterList ::=
///        '(' ')'
///      | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
///      | '(' optionalFormalParameters ')'
///
///    normalFormalParameters ::=
///        [NormalFormalParameter] (',' [NormalFormalParameter])*
///
///    optionalFormalParameters ::=
///        optionalPositionalFormalParameters
///      | namedFormalParameters
///
///    optionalPositionalFormalParameters ::=
///        '[' [DefaultFormalParameter] (',' [DefaultFormalParameter])* ']'
///
///    namedFormalParameters ::=
///        '{' [DefaultFormalParameter] (',' [DefaultFormalParameter])* '}'
abstract final class FormalParameterList implements AstNode {
  /// The left square bracket ('[') or left curly brace ('{') introducing the
  /// optional or named parameters, or `null` if there are neither optional nor
  /// named parameters.
  Token? get leftDelimiter;

  /// The left parenthesis.
  Token get leftParenthesis;

  /// A list containing the elements representing the parameters in this list.
  ///
  /// The list contains `null`s if the parameters in this list haven't been
  /// resolved.
  List<ParameterElement?> get parameterElements;

  /// A list containing the fragments representing the parameters in this list.
  ///
  /// The list contains `null`s if the parameters in this list haven't been
  /// resolved.
  @experimental
  List<FormalParameterFragment?> get parameterFragments;

  /// The parameters associated with the method.
  NodeList<FormalParameter> get parameters;

  /// The right square bracket (']') or right curly brace ('}') terminating the
  /// optional or named parameters, or `null` if there are neither optional nor
  /// named parameters.
  Token? get rightDelimiter;

  /// The right parenthesis.
  Token get rightParenthesis;
}

final class FormalParameterListImpl extends AstNodeImpl
    implements FormalParameterList {
  @override
  final Token leftParenthesis;

  final NodeListImpl<FormalParameterImpl> _parameters = NodeListImpl._();

  @override
  final Token? leftDelimiter;

  @override
  final Token? rightDelimiter;

  @override
  final Token rightParenthesis;

  /// Initializes a newly created parameter list.
  ///
  /// The [leftDelimiter] and [rightDelimiter] can be `null` if there are no
  /// optional or named parameters, but it must be the case that either both are
  /// `null` or that both are non-`null`.
  FormalParameterListImpl({
    required this.leftParenthesis,
    required List<FormalParameterImpl> parameters,
    required this.leftDelimiter,
    required this.rightDelimiter,
    required this.rightParenthesis,
  }) {
    _parameters._initialize(this, parameters);
  }

  @override
  Token get beginToken => leftParenthesis;

  @override
  Token get endToken => rightParenthesis;

  @override
  List<ParameterElement?> get parameterElements {
    int count = _parameters.length;
    var types = <ParameterElement?>[];
    for (int i = 0; i < count; i++) {
      types.add(_parameters[i].declaredElement);
    }
    return types;
  }

  @experimental
  @override
  List<FormalParameterFragment?> get parameterFragments =>
      parameterElements.cast<FormalParameterFragment?>();

  @override
  NodeListImpl<FormalParameterImpl> get parameters => _parameters;

  @override
  ChildEntities get _childEntities {
    // TODO(paulberry): include commas.
    var result = ChildEntities()..addToken('leftParenthesis', leftParenthesis);
    bool leftDelimiterNeeded = leftDelimiter != null;
    int length = _parameters.length;
    for (int i = 0; i < length; i++) {
      FormalParameter parameter = _parameters[i];
      if (leftDelimiterNeeded && leftDelimiter!.offset < parameter.offset) {
        result.addToken('leftDelimiter', leftDelimiter);
        leftDelimiterNeeded = false;
      }
      result.addNode('parameter', parameter);
    }
    return result
      ..addToken('rightDelimiter', rightDelimiter)
      ..addToken('rightParenthesis', rightParenthesis);
  }

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitFormalParameterList(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _parameters.accept(visitor);
  }
}

/// The parts of a for loop that control the iteration.
///
///   forLoopParts ::=
///       [VariableDeclaration] ';' [Expression]? ';' expressionList?
///     | [Expression]? ';' [Expression]? ';' expressionList?
sealed class ForParts implements ForLoopParts {
  /// The condition used to determine when to terminate the loop, or `null` if
  /// there's no condition.
  Expression? get condition;

  /// The semicolon separating the initializer and the condition.
  Token get leftSeparator;

  /// The semicolon separating the condition and the updater.
  Token get rightSeparator;

  /// The list of expressions run after each execution of the loop body.
  NodeList<Expression> get updaters;
}

sealed class ForPartsImpl extends ForLoopPartsImpl implements ForParts {
  @override
  final Token leftSeparator;

  ExpressionImpl? _condition;

  @override
  final Token rightSeparator;

  final NodeListImpl<ExpressionImpl> _updaters = NodeListImpl._();

  /// Initializes a newly created for statement.
  ///
  /// Either the [variableList] or the [initialization] must be `null`.
  ///
  /// Either the [condition] and the list of [updaters] can be `null` if the
  /// loop doesn't have the corresponding attribute.
  ForPartsImpl({
    required this.leftSeparator,
    required ExpressionImpl? condition,
    required this.rightSeparator,
    required List<ExpressionImpl>? updaters,
  }) : _condition = condition {
    _becomeParentOf(_condition);
    _updaters._initialize(this, updaters);
  }

  @override
  Token get beginToken => leftSeparator;

  @override
  ExpressionImpl? get condition => _condition;

  set condition(ExpressionImpl? expression) {
    _condition = _becomeParentOf(expression);
  }

  @override
  Token get endToken => _updaters.endToken ?? rightSeparator;

  @override
  NodeListImpl<ExpressionImpl> get updaters => _updaters;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('leftSeparator', leftSeparator)
    ..addNode('condition', condition)
    ..addToken('rightSeparator', rightSeparator)
    ..addNodeList('updaters', updaters);

  @override
  void visitChildren(AstVisitor visitor) {
    _condition?.accept(visitor);
    _updaters.accept(visitor);
  }
}

/// The parts of a for loop that control the iteration when there are one or
/// more variable declarations as part of the for loop.
///
///   forLoopParts ::=
///       [VariableDeclarationList] ';' [Expression]? ';' expressionList?
abstract final class ForPartsWithDeclarations implements ForParts {
  /// The declaration of the loop variables.
  VariableDeclarationList get variables;
}

final class ForPartsWithDeclarationsImpl extends ForPartsImpl
    implements ForPartsWithDeclarations {
  VariableDeclarationListImpl _variableList;

  /// Initializes a newly created for statement.
  ///
  /// Both the [condition] and the list of [updaters] can be `null` if the loop
  /// doesn't have the corresponding attribute.
  ForPartsWithDeclarationsImpl({
    required VariableDeclarationListImpl variableList,
    required super.leftSeparator,
    required super.condition,
    required super.rightSeparator,
    required super.updaters,
  }) : _variableList = variableList {
    _becomeParentOf(_variableList);
  }

  @override
  Token get beginToken => _variableList.beginToken;

  @override
  VariableDeclarationListImpl get variables => _variableList;

  set variables(VariableDeclarationListImpl? variableList) {
    _variableList =
        _becomeParentOf(variableList as VariableDeclarationListImpl);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('variables', variables)
    ..addAll(super._childEntities);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitForPartsWithDeclarations(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _variableList.accept(visitor);
    super.visitChildren(visitor);
  }
}

/// The parts of a for loop that control the iteration when there are no
/// variable declarations as part of the for loop.
///
///   forLoopParts ::=
///       [Expression]? ';' [Expression]? ';' expressionList?
abstract final class ForPartsWithExpression implements ForParts {
  /// The initialization expression, or `null` if there's no initialization
  /// expression.
  ///
  /// Note that a for statement can't have both a variable list and an
  /// initialization expression, but can validly have neither.
  Expression? get initialization;
}

final class ForPartsWithExpressionImpl extends ForPartsImpl
    implements ForPartsWithExpression {
  ExpressionImpl? _initialization;

  /// Initializes a newly created for statement.
  ///
  /// Both the [condition] and the list of [updaters] can be `null` if the loop
  /// doesn't have the corresponding attribute.
  ForPartsWithExpressionImpl({
    required ExpressionImpl? initialization,
    required super.leftSeparator,
    required super.condition,
    required super.rightSeparator,
    required super.updaters,
  }) : _initialization = initialization {
    _becomeParentOf(_initialization);
  }

  @override
  Token get beginToken => initialization?.beginToken ?? super.beginToken;

  @override
  ExpressionImpl? get initialization => _initialization;

  set initialization(ExpressionImpl? initialization) {
    _initialization = _becomeParentOf(initialization);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('initialization', initialization)
    ..addAll(super._childEntities);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitForPartsWithExpression(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _initialization?.accept(visitor);
    super.visitChildren(visitor);
  }
}

/// The parts of a for loop that control the iteration when there's a pattern
/// declaration as part of the for loop.
///
///   forLoopParts ::=
///       [PatternVariableDeclaration] ';' [Expression]? ';' expressionList?
abstract final class ForPartsWithPattern implements ForParts {
  /// The declaration of the loop variables.
  PatternVariableDeclaration get variables;
}

final class ForPartsWithPatternImpl extends ForPartsImpl
    implements ForPartsWithPattern {
  @override
  final PatternVariableDeclarationImpl variables;

  ForPartsWithPatternImpl({
    required this.variables,
    required super.leftSeparator,
    required super.condition,
    required super.rightSeparator,
    required super.updaters,
  }) {
    _becomeParentOf(variables);
  }

  @override
  Token get beginToken => variables.beginToken;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('variables', variables)
    ..addAll(super._childEntities);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitForPartsWithPattern(this);

  @override
  void visitChildren(AstVisitor visitor) {
    variables.accept(visitor);
    super.visitChildren(visitor);
  }
}

/// A for or for-each statement.
///
///    forStatement ::=
///        'for' '(' forLoopParts ')' [Statement]
///
///    forLoopParts ::=
///       [VariableDeclaration] ';' [Expression]? ';' expressionList?
///     | [Expression]? ';' [Expression]? ';' expressionList?
///     | [DeclaredIdentifier] 'in' [Expression]
///     | [SimpleIdentifier] 'in' [Expression]
abstract final class ForStatement implements Statement {
  /// The token representing the `await` keyword, or `null` if there's no
  /// `await` keyword.
  Token? get awaitKeyword;

  /// The body of the loop.
  Statement get body;

  /// The token representing the `for` keyword.
  Token get forKeyword;

  /// The parts of the for element that control the iteration.
  ForLoopParts get forLoopParts;

  /// The left parenthesis.
  Token get leftParenthesis;

  /// The right parenthesis.
  Token get rightParenthesis;
}

final class ForStatementImpl extends StatementImpl
    with AstNodeWithNameScopeMixin
    implements ForStatement {
  @override
  final Token? awaitKeyword;

  @override
  final Token forKeyword;

  @override
  final Token leftParenthesis;

  ForLoopPartsImpl _forLoopParts;

  @override
  final Token rightParenthesis;

  StatementImpl _body;

  /// Initializes a newly created for statement.
  ForStatementImpl({
    required this.awaitKeyword,
    required this.forKeyword,
    required this.leftParenthesis,
    required ForLoopPartsImpl forLoopParts,
    required this.rightParenthesis,
    required StatementImpl body,
  })  : _forLoopParts = forLoopParts,
        _body = body {
    _becomeParentOf(_forLoopParts);
    _becomeParentOf(_body);
  }

  @override
  Token get beginToken => awaitKeyword ?? forKeyword;

  @override
  StatementImpl get body => _body;

  set body(StatementImpl statement) {
    _body = _becomeParentOf(statement);
  }

  @override
  Token get endToken => _body.endToken;

  @override
  ForLoopPartsImpl get forLoopParts => _forLoopParts;

  set forLoopParts(ForLoopPartsImpl forLoopParts) {
    _forLoopParts = _becomeParentOf(forLoopParts);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('awaitKeyword', awaitKeyword)
    ..addToken('forKeyword', forKeyword)
    ..addToken('leftParenthesis', leftParenthesis)
    ..addNode('forLoopParts', forLoopParts)
    ..addToken('rightParenthesis', rightParenthesis)
    ..addNode('body', body);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitForStatement(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _forLoopParts.accept(visitor);
    _body.accept(visitor);
  }
}

/// A declaration of a fragment of an element.
@experimental
abstract final class FragmentDeclaration implements Declaration {
  /// The fragment declared by this declaration.
  ///
  /// Returns `null` if the AST structure hasn't been resolved.
  @experimental
  Fragment? get declaredFragment;
}

/// A node representing the body of a function or method.
///
///    functionBody ::=
///        [BlockFunctionBody]
///      | [EmptyFunctionBody]
///      | [ExpressionFunctionBody]
///      | [NativeFunctionBody]
sealed class FunctionBody implements AstNode {
  /// Whether this function body is asynchronous.
  bool get isAsynchronous;

  /// Whether this function body is a generator.
  bool get isGenerator;

  /// Whether this function body is synchronous.
  bool get isSynchronous;

  /// The token representing the `async` or `sync` keyword, or `null` if there's
  /// no such keyword.
  Token? get keyword;

  /// The star following the `async` or `sync` keyword, or `null` if there's no
  /// star.
  Token? get star;

  /// If [variable] is a local variable or parameter declared anywhere within
  /// the top level function or method containing this [FunctionBody], return a
  /// boolean indicating whether [variable] is potentially mutated within the
  /// scope of its declaration.
  ///
  /// If [variable] isn't a local variable or parameter declared within the top
  /// level function or method containing this [FunctionBody], return `false`.
  ///
  /// Throws an exception if resolution hasn't been performed.
  bool isPotentiallyMutatedInScope(VariableElement variable);

  /// If [variable] is a local variable or parameter declared anywhere within
  /// the top level function or method containing this [FunctionBody], return a
  /// boolean indicating whether [variable] is potentially mutated within the
  /// scope of its declaration.
  ///
  /// If [variable] isn't a local variable or parameter declared within the top
  /// level function or method containing this [FunctionBody], return `false`.
  ///
  /// Throws an exception if resolution hasn't been performed.
  @experimental
  bool isPotentiallyMutatedInScope2(VariableElement2 variable);
}

sealed class FunctionBodyImpl extends AstNodeImpl implements FunctionBody {
  /// Additional information about local variables and parameters that are
  /// declared within this function body or any enclosing function body, or
  /// `null` if resolution hasn't yet been performed.
  LocalVariableInfo? localVariableInfo;

  /// The [BodyInferenceContext] that was used during type inference of this
  /// function body, or `null` if resolution hasn't yet been performed.
  BodyInferenceContext? bodyContext;

  @override
  bool get isAsynchronous => false;

  @override
  bool get isGenerator => false;

  @override
  bool get isSynchronous => true;

  @override
  Token? get keyword => null;

  @override
  Token? get star => null;

  @override
  bool isPotentiallyMutatedInScope(VariableElement variable) {
    if (localVariableInfo == null) {
      throw StateError('Resolution has not been performed');
    }
    return localVariableInfo!.potentiallyMutatedInScope.contains(variable);
  }

  @experimental
  @override
  bool isPotentiallyMutatedInScope2(VariableElement2 variable) {
    return switch (variable) {
      LocalVariableElementImpl2() =>
        isPotentiallyMutatedInScope(variable.wrappedElement),
      VariableElement() =>
        isPotentiallyMutatedInScope(variable as VariableElement),
      FormalParameterElement(:VariableElement firstFragment) =>
        isPotentiallyMutatedInScope(firstFragment),
      _ => false,
    };
  }

  /// Dispatch this function body to the resolver, imposing [imposedType] as the
  /// return type context for `return` statements.
  ///
  /// Returns value is the actual return type of the method.
  DartType resolve(ResolverVisitor resolver, DartType? imposedType);
}

/// A function declaration.
///
/// Wrapped in a [FunctionDeclarationStatement] to represent a local function
/// declaration, otherwise a top-level function declaration.
///
///    functionDeclaration ::=
///        'external' functionSignature
///      | functionSignature [FunctionBody]
///
///    functionSignature ::=
///        [Type]? ('get' | 'set')? name [FormalParameterList]
// TODO(brianwilkerson): This class represents both declarations that can be
//  augmented and declarations that can't be augmented. This results in getters
//  that are only sometimes applicable. Consider changing the class hierarchy so
//  that these two kinds of variables can be distinguished.
abstract final class FunctionDeclaration
    implements NamedCompilationUnitMember, FragmentDeclaration {
  /// The `augment` keyword, or `null` if there is no `augment` keyword.
  @experimental
  Token? get augmentKeyword;

  /// The element defined by this declaration.
  ///
  /// Returns `null` if the AST structure hasn't been resolved or if this node
  /// represents a top-level function.
  @override
  ExecutableElement? get declaredElement;

  /// The element defined by this local function declaration.
  ///
  /// Returns `null` if the AST structure hasn't been resolved or if this node
  /// is not a local function.
  LocalFunctionElement? get declaredElement2;

  /// The fragment declared by this declaration.
  ///
  /// Returns `null` if the AST structure hasn't been resolved or if this node
  /// represents a local function.
  @experimental
  @override
  ExecutableFragment? get declaredFragment;

  /// The token representing the `external` keyword, or `null` if this isn't an
  /// external function.
  Token? get externalKeyword;

  /// The function expression being wrapped.
  FunctionExpression get functionExpression;

  /// Whether this function declares a getter.
  bool get isGetter;

  /// Whether this function declares a setter.
  bool get isSetter;

  /// The token representing the `get` or `set` keyword, or `null` if this is a
  /// function declaration rather than a property declaration.
  Token? get propertyKeyword;

  /// The return type of the function, or `null` if no return type was declared.
  TypeAnnotation? get returnType;
}

final class FunctionDeclarationImpl extends NamedCompilationUnitMemberImpl
    with AstNodeWithNameScopeMixin
    implements FunctionDeclaration {
  @override
  final Token? augmentKeyword;

  @override
  final Token? externalKeyword;

  TypeAnnotationImpl? _returnType;

  @override
  final Token? propertyKeyword;

  FunctionExpressionImpl _functionExpression;

  @override
  ExecutableElementImpl? declaredElement;

  @override
  LocalFunctionElementImpl? declaredElement2;

  /// Initializes a newly created function declaration.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// function doesn't have the corresponding attribute.
  ///
  /// The [externalKeyword] can be `null` if the function isn't an external
  /// function.
  ///
  /// The [returnType] can be `null` if no return type was specified.
  ///
  /// The [propertyKeyword] can be `null` if the function is neither a getter or
  /// a setter.
  FunctionDeclarationImpl({
    required super.comment,
    required super.metadata,
    required this.augmentKeyword,
    required this.externalKeyword,
    required TypeAnnotationImpl? returnType,
    required this.propertyKeyword,
    required super.name,
    required FunctionExpressionImpl functionExpression,
  })  : _returnType = returnType,
        _functionExpression = functionExpression {
    _becomeParentOf(_returnType);
    _becomeParentOf(_functionExpression);
  }

  @experimental
  @override
  ExecutableFragment? get declaredFragment {
    if (declaredElement case ExecutableFragment fragment) {
      return fragment;
    }
    return null;
  }

  @override
  Token get endToken => _functionExpression.endToken;

  @override
  Token get firstTokenAfterCommentAndMetadata {
    return augmentKeyword ??
        externalKeyword ??
        _returnType?.beginToken ??
        propertyKeyword ??
        name;
  }

  @override
  FunctionExpressionImpl get functionExpression => _functionExpression;

  set functionExpression(FunctionExpressionImpl functionExpression) {
    _functionExpression = _becomeParentOf(functionExpression);
  }

  @override
  bool get isGetter => propertyKeyword?.keyword == Keyword.GET;

  @override
  bool get isSetter => propertyKeyword?.keyword == Keyword.SET;

  @override
  TypeAnnotationImpl? get returnType => _returnType;

  set returnType(TypeAnnotationImpl? type) {
    _returnType = _becomeParentOf(type as TypeAnnotationImpl);
  }

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('augmentKeyword', augmentKeyword)
    ..addToken('externalKeyword', externalKeyword)
    ..addNode('returnType', returnType)
    ..addToken('propertyKeyword', propertyKeyword)
    ..addToken('name', name)
    ..addNode('functionExpression', functionExpression);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitFunctionDeclaration(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _returnType?.accept(visitor);
    _functionExpression.accept(visitor);
  }
}

/// A [FunctionDeclaration] used as a statement.
abstract final class FunctionDeclarationStatement implements Statement {
  /// The function declaration being wrapped.
  FunctionDeclaration get functionDeclaration;
}

final class FunctionDeclarationStatementImpl extends StatementImpl
    implements FunctionDeclarationStatement {
  FunctionDeclarationImpl _functionDeclaration;

  /// Initializes a newly created function declaration statement.
  FunctionDeclarationStatementImpl({
    required FunctionDeclarationImpl functionDeclaration,
  }) : _functionDeclaration = functionDeclaration {
    _becomeParentOf(_functionDeclaration);
  }

  @override
  Token get beginToken => _functionDeclaration.beginToken;

  @override
  Token get endToken => _functionDeclaration.endToken;

  @override
  FunctionDeclarationImpl get functionDeclaration => _functionDeclaration;

  set functionDeclaration(FunctionDeclarationImpl functionDeclaration) {
    _functionDeclaration = _becomeParentOf(functionDeclaration);
  }

  @override
  ChildEntities get _childEntities =>
      ChildEntities()..addNode('functionDeclaration', functionDeclaration);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitFunctionDeclarationStatement(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _functionDeclaration.accept(visitor);
  }
}

/// A function expression.
///
///    functionExpression ::=
///        [TypeParameterList]? [FormalParameterList] [FunctionBody]
abstract final class FunctionExpression implements Expression {
  /// The body of the function.
  FunctionBody get body;

  /// The element associated with the function, or `null` if the AST structure
  /// hasn't been resolved.
  ExecutableElement? get declaredElement;

  /// The element defined by this function expression.
  ///
  /// Returns `null` if the AST structure hasn't been resolved.
  ///
  /// Returns `null` if this expression is not a closure, and the parent is
  /// not a local function.
  @experimental
  LocalFunctionElement? get declaredElement2;

  /// The fragment declared by this function expression.
  ///
  /// Returns `null` if the AST structure hasn't been resolved.
  ///
  /// Returns `null` is thie expression is a closure, or the parent is a
  /// local function.
  @experimental
  ExecutableFragment? get declaredFragment;

  /// The parameters associated with the function, or `null` if the function is
  /// part of a top-level getter.
  FormalParameterList? get parameters;

  /// The type parameters associated with this method, or `null` if this method
  /// isn't a generic method.
  TypeParameterList? get typeParameters;
}

final class FunctionExpressionImpl extends ExpressionImpl
    implements FunctionExpression {
  TypeParameterListImpl? _typeParameters;

  FormalParameterListImpl? _parameters;

  FunctionBodyImpl _body;

  /// Whether a function type was supplied via context for this function
  /// expression.
  ///
  /// Returns `false` if resolution hasn't been performed yet.
  bool wasFunctionTypeSupplied = false;

  @override
  ExecutableElementImpl? declaredElement;

  @override
  LocalFunctionElementImpl? declaredElement2;

  /// Initializes a newly created function declaration.
  FunctionExpressionImpl({
    required TypeParameterListImpl? typeParameters,
    required FormalParameterListImpl? parameters,
    required FunctionBodyImpl body,
  })  : _typeParameters = typeParameters,
        _parameters = parameters,
        _body = body {
    _becomeParentOf(_typeParameters);
    _becomeParentOf(_parameters);
    _becomeParentOf(_body);
  }

  @override
  Token get beginToken {
    if (typeParameters case var typeParameters?) {
      return typeParameters.beginToken;
    } else if (parameters case var parameters?) {
      return parameters.beginToken;
    }
    return _body.beginToken;
  }

  @override
  FunctionBodyImpl get body => _body;

  set body(FunctionBodyImpl functionBody) {
    _body = _becomeParentOf(functionBody);
  }

  @override
  ExecutableFragment? get declaredFragment {
    if (declaredElement?.enclosingElement3 is CompilationUnitElement) {
      return declaredElement;
    }
    return null;
  }

  @override
  Token get endToken {
    return _body.endToken;
  }

  @override
  FormalParameterListImpl? get parameters => _parameters;

  set parameters(FormalParameterListImpl? parameters) {
    _parameters = _becomeParentOf(parameters);
  }

  @override
  Precedence get precedence => Precedence.primary;

  DartType get returnType {
    // If a closure, or a local function.
    if (declaredElement2 case var declaredElement?) {
      return declaredElement.returnType;
    }
    // SAFETY: must be a top-level function.
    return declaredFragment!.element.returnType;
  }

  @override
  TypeParameterListImpl? get typeParameters => _typeParameters;

  set typeParameters(TypeParameterListImpl? typeParameters) {
    _typeParameters = _becomeParentOf(typeParameters);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('typeParameters', typeParameters)
    ..addNode('parameters', parameters)
    ..addNode('body', body);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitFunctionExpression(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitFunctionExpression(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _typeParameters?.accept(visitor);
    _parameters?.accept(visitor);
    _body.accept(visitor);
  }
}

/// The invocation of a function resulting from evaluating an expression.
///
/// Invocations of methods and other forms of functions are represented by
/// [MethodInvocation] nodes. Invocations of getters and setters are represented
/// by either [PrefixedIdentifier] or [PropertyAccess] nodes.
///
///    functionExpressionInvocation ::=
///        [Expression] [TypeArgumentList]? [ArgumentList]
abstract final class FunctionExpressionInvocation
    implements NullShortableExpression, InvocationExpression {
  /// The element associated with the function being invoked based on static
  /// type information.
  ///
  /// Returns `null` if the AST structure hasn't been resolved or the function
  /// couldn't be resolved.
  @experimental
  ExecutableElement2? get element;

  /// The expression producing the function being invoked.
  @override
  Expression get function;

  /// The element associated with the function being invoked based on static
  /// type information, or `null` if the AST structure hasn't been resolved or
  /// the function couldn't be resolved.
  ExecutableElement? get staticElement;
}

final class FunctionExpressionInvocationImpl extends InvocationExpressionImpl
    with NullShortableExpressionImpl
    implements FunctionExpressionInvocation {
  ExpressionImpl _function;

  @override
  ExecutableElement? staticElement;

  /// Initializes a newly created function expression invocation.
  FunctionExpressionInvocationImpl({
    required ExpressionImpl function,
    required super.typeArguments,
    required super.argumentList,
  }) : _function = function {
    _becomeParentOf(_function);
  }

  @override
  Token get beginToken => _function.beginToken;

  @experimental
  @override
  ExecutableElement2? get element =>
      staticElement?.asElement2 as ExecutableElement2?;

  @override
  Token get endToken => _argumentList.endToken;

  @override
  ExpressionImpl get function => _function;

  set function(ExpressionImpl expression) {
    _function = _becomeParentOf(expression);
  }

  @override
  Precedence get precedence => Precedence.postfix;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('function', function)
    ..addNode('typeArguments', typeArguments)
    ..addNode('argumentList', argumentList);

  @override
  AstNode? get _nullShortingExtensionCandidate => parent;

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitFunctionExpressionInvocation(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitFunctionExpressionInvocation(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _function.accept(visitor);
    _typeArguments?.accept(visitor);
    _argumentList.accept(visitor);
  }

  @override
  bool _extendsNullShorting(Expression descendant) =>
      identical(descendant, _function);
}

/// An expression representing a reference to a function, possibly with type
/// arguments applied to it.
///
/// For example, the expression `print` in `var x = print;`.
abstract final class FunctionReference
    implements Expression, CommentReferableExpression {
  /// The function being referenced.
  ///
  /// In error-free code, this is either a [SimpleIdentifier] (indicating a
  /// function that is in scope), a [PrefixedIdentifier] (indicating a either
  /// function imported via prefix or a static method in a class), or a
  /// [PropertyAccess] (indicating a static method in a class imported via
  /// prefix). In code with errors, this could be other kinds of expressions.
  /// For example, `(...)<int>` parses as a [FunctionReference] whose referent
  /// is a [ParenthesizedExpression].
  Expression get function;

  /// The type arguments being applied to the function, or `null` if there are
  /// no type arguments.
  TypeArgumentList? get typeArguments;

  /// The actual type arguments being applied to the function, either
  /// explicitly specified in [typeArguments], or inferred.
  ///
  /// An empty list if the function doesn't have type parameters, or `null` if
  /// the AST structure hasn't been resolved.
  List<DartType>? get typeArgumentTypes;
}

final class FunctionReferenceImpl extends CommentReferableExpressionImpl
    implements FunctionReference {
  ExpressionImpl _function;

  TypeArgumentListImpl? _typeArguments;

  @override
  List<DartType>? typeArgumentTypes;

  FunctionReferenceImpl({
    required ExpressionImpl function,
    required TypeArgumentListImpl? typeArguments,
  })  : _function = function,
        _typeArguments = typeArguments {
    _becomeParentOf(_function);
    _becomeParentOf(_typeArguments);
  }

  @override
  Token get beginToken => function.beginToken;

  @override
  Token get endToken => typeArguments?.endToken ?? function.endToken;

  @override
  ExpressionImpl get function => _function;

  set function(ExpressionImpl value) {
    _function = _becomeParentOf(value);
  }

  @override
  Precedence get precedence =>
      typeArguments == null ? function.precedence : Precedence.postfix;

  @override
  TypeArgumentListImpl? get typeArguments => _typeArguments;

  set typeArguments(TypeArgumentListImpl? value) {
    _typeArguments = _becomeParentOf(value);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('function', function)
    ..addNode('typeArguments', typeArguments);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitFunctionReference(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitFunctionReference(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    function.accept(visitor);
    typeArguments?.accept(visitor);
  }
}

/// A function type alias.
///
///    functionTypeAlias ::=
///        'typedef' functionPrefix [TypeParameterList]?
///        [FormalParameterList] ';'
///
///    functionPrefix ::=
///        [TypeAnnotation]? [SimpleIdentifier]
abstract final class FunctionTypeAlias
    implements TypeAlias, FragmentDeclaration {
  @override
  TypeAliasElement? get declaredElement;

  @experimental
  @override
  TypeAliasFragment? get declaredFragment;

  /// The parameters associated with the function type.
  FormalParameterList get parameters;

  /// The return type of the function type being defined, or `null` if no return
  /// type was given.
  TypeAnnotation? get returnType;

  /// The type parameters for the function type, or `null` if the function type
  /// doesn't have any type parameters.
  TypeParameterList? get typeParameters;
}

final class FunctionTypeAliasImpl extends TypeAliasImpl
    implements FunctionTypeAlias {
  TypeAnnotationImpl? _returnType;

  TypeParameterListImpl? _typeParameters;

  FormalParameterListImpl _parameters;

  @override
  TypeAliasElementImpl? declaredElement;

  /// Initializes a newly created function type alias.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// function doesn't have the corresponding attribute.
  ///
  /// The [returnType] can be `null` if no return type was specified.
  ///
  /// The [typeParameters] can be `null` if the function has no type parameters.
  FunctionTypeAliasImpl({
    required super.comment,
    required super.metadata,
    required super.augmentKeyword,
    required super.typedefKeyword,
    required TypeAnnotationImpl? returnType,
    required super.name,
    required TypeParameterListImpl? typeParameters,
    required FormalParameterListImpl parameters,
    required super.semicolon,
  })  : _returnType = returnType,
        _typeParameters = typeParameters,
        _parameters = parameters {
    _becomeParentOf(_returnType);
    _becomeParentOf(_typeParameters);
    _becomeParentOf(_parameters);
  }

  @experimental
  @override
  TypeAliasFragment? get declaredFragment =>
      declaredElement as TypeAliasFragment?;

  @override
  FormalParameterListImpl get parameters => _parameters;

  set parameters(FormalParameterListImpl parameters) {
    _parameters = _becomeParentOf(parameters);
  }

  @override
  TypeAnnotationImpl? get returnType => _returnType;

  set returnType(TypeAnnotationImpl? type) {
    _returnType = _becomeParentOf(type);
  }

  @override
  TypeParameterListImpl? get typeParameters => _typeParameters;

  set typeParameters(TypeParameterListImpl? typeParameters) {
    _typeParameters = _becomeParentOf(typeParameters);
  }

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('augmentKeyword', augmentKeyword)
    ..addToken('typedefKeyword', typedefKeyword)
    ..addNode('returnType', returnType)
    ..addToken('name', name)
    ..addNode('typeParameters', typeParameters)
    ..addNode('parameters', parameters)
    ..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitFunctionTypeAlias(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _returnType?.accept(visitor);
    _typeParameters?.accept(visitor);
    _parameters.accept(visitor);
  }
}

/// A function-typed formal parameter.
///
///    functionSignature ::=
///        [TypeAnnotation]? name [TypeParameterList]?
///        [FormalParameterList] '?'?
abstract final class FunctionTypedFormalParameter
    implements NormalFormalParameter {
  @override
  Token get name;

  /// The parameters of the function-typed parameter.
  FormalParameterList get parameters;

  /// The question mark indicating that the function type is nullable, or `null`
  /// if there's no question mark.
  ///
  /// Having a nullable function type means that the parameter can be null.
  Token? get question;

  /// The return type of the function, or `null` if the function doesn't have a
  /// return type.
  TypeAnnotation? get returnType;

  /// The type parameters associated with this function, or `null` if this
  /// function isn't a generic function.
  TypeParameterList? get typeParameters;
}

final class FunctionTypedFormalParameterImpl extends NormalFormalParameterImpl
    implements FunctionTypedFormalParameter {
  TypeAnnotationImpl? _returnType;

  TypeParameterListImpl? _typeParameters;

  FormalParameterListImpl _parameters;

  @override
  final Token? question;

  /// Initializes a newly created formal parameter.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// parameter doesn't have the corresponding attribute.
  ///
  /// The [returnType] can be `null` if no return type was specified.
  FunctionTypedFormalParameterImpl({
    required super.comment,
    required super.metadata,
    required super.covariantKeyword,
    required super.requiredKeyword,
    required TypeAnnotationImpl? returnType,
    required super.name,
    required TypeParameterListImpl? typeParameters,
    required FormalParameterListImpl parameters,
    required this.question,
  })  : _returnType = returnType,
        _typeParameters = typeParameters,
        _parameters = parameters {
    _becomeParentOf(_returnType);
    _becomeParentOf(_typeParameters);
    _becomeParentOf(_parameters);
  }

  @override
  Token get endToken => question ?? _parameters.endToken;

  @override
  Token get firstTokenAfterCommentAndMetadata =>
      requiredKeyword ?? covariantKeyword ?? returnType?.beginToken ?? name;

  @override
  bool get isConst => false;

  @override
  bool get isExplicitlyTyped => true;

  @override
  bool get isFinal => false;

  @override
  Token get name => super.name!;

  @override
  FormalParameterListImpl get parameters => _parameters;

  set parameters(FormalParameterListImpl parameters) {
    _parameters = _becomeParentOf(parameters);
  }

  @override
  TypeAnnotationImpl? get returnType => _returnType;

  set returnType(TypeAnnotationImpl? type) {
    _returnType = _becomeParentOf(type);
  }

  @override
  TypeParameterListImpl? get typeParameters => _typeParameters;

  set typeParameters(TypeParameterListImpl? typeParameters) {
    _typeParameters = _becomeParentOf(typeParameters);
  }

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addNode('returnType', returnType)
    ..addToken('name', name)
    ..addNode('parameters', parameters);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitFunctionTypedFormalParameter(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _returnType?.accept(visitor);
    _typeParameters?.accept(visitor);
    _parameters.accept(visitor);
  }
}

/// An anonymous function type.
///
///    functionType ::=
///        [TypeAnnotation]? 'Function' [TypeParameterList]?
///        [FormalParameterList] '?'?
///
/// where the FormalParameterList is being used to represent the following
/// grammar, despite the fact that FormalParameterList can represent a much
/// larger grammar than the one below. This is done in order to simplify the
/// implementation.
///
///    parameterTypeList ::=
///        () |
///        ( normalParameterTypes ,? ) |
///        ( normalParameterTypes , optionalParameterTypes ) |
///        ( optionalParameterTypes )
///    namedParameterTypes ::=
///        { namedParameterType (, namedParameterType)* ,? }
///    namedParameterType ::=
///        [TypeAnnotation]? [SimpleIdentifier]
///    normalParameterTypes ::=
///        normalParameterType (, normalParameterType)*
///    normalParameterType ::=
///        [TypeAnnotation] [SimpleIdentifier]?
///    optionalParameterTypes ::=
///        optionalPositionalParameterTypes | namedParameterTypes
///    optionalPositionalParameterTypes ::=
///        [ normalParameterTypes ,? ]
abstract final class GenericFunctionType implements TypeAnnotation {
  /// The `Function` keyword.
  Token get functionKeyword;

  /// The parameters associated with the function type.
  FormalParameterList get parameters;

  /// The return type of the function type being defined, or `null` if no return
  /// type was given.
  TypeAnnotation? get returnType;

  /// The type parameters for the function type, or `null` if the function type
  /// doesn't have any type parameters.
  TypeParameterList? get typeParameters;
}

final class GenericFunctionTypeImpl extends TypeAnnotationImpl
    with AstNodeWithNameScopeMixin
    implements GenericFunctionType {
  TypeAnnotationImpl? _returnType;

  @override
  final Token functionKeyword;

  TypeParameterListImpl? _typeParameters;

  FormalParameterListImpl _parameters;

  @override
  final Token? question;

  @override
  DartType? type;

  /// The element associated with the function type, or `null` if the AST
  /// structure hasn't been resolved.
  GenericFunctionTypeElementImpl? declaredElement;

  /// Initializes a newly created generic function type.
  GenericFunctionTypeImpl({
    required TypeAnnotationImpl? returnType,
    required this.functionKeyword,
    required TypeParameterListImpl? typeParameters,
    required FormalParameterListImpl parameters,
    required this.question,
  })  : _returnType = returnType,
        _typeParameters = typeParameters,
        _parameters = parameters {
    _becomeParentOf(_returnType);
    _becomeParentOf(_typeParameters);
    _becomeParentOf(_parameters);
  }

  @override
  Token get beginToken => _returnType?.beginToken ?? functionKeyword;

  @override
  Token get endToken => question ?? _parameters.endToken;

  @override
  FormalParameterListImpl get parameters => _parameters;

  set parameters(FormalParameterListImpl parameters) {
    _parameters = _becomeParentOf(parameters);
  }

  @override
  TypeAnnotationImpl? get returnType => _returnType;

  set returnType(TypeAnnotationImpl? type) {
    _returnType = _becomeParentOf(type);
  }

  @override
  TypeParameterListImpl? get typeParameters => _typeParameters;

  set typeParameters(TypeParameterListImpl? typeParameters) {
    _typeParameters = _becomeParentOf(typeParameters);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('returnType', returnType)
    ..addToken('functionKeyword', functionKeyword)
    ..addNode('typeParameters', typeParameters)
    ..addNode('parameters', parameters)
    ..addToken('question', question);

  @override
  E? accept<E>(AstVisitor<E> visitor) {
    return visitor.visitGenericFunctionType(this);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _returnType?.accept(visitor);
    _typeParameters?.accept(visitor);
    _parameters.accept(visitor);
  }
}

/// A generic type alias.
///
///    functionTypeAlias ::=
///        'typedef' [SimpleIdentifier] [TypeParameterList]? =
///        [FunctionType] ';'
abstract final class GenericTypeAlias
    implements TypeAlias, FragmentDeclaration {
  /// The equal sign separating the name being defined from the function type.
  Token get equals;

  /// The type of function being defined by the alias, or `null` if the
  /// non-function type aliases feature is enabled and the denoted type isn't a
  /// [GenericFunctionType].
  GenericFunctionType? get functionType;

  /// The type being defined by the alias.
  TypeAnnotation get type;

  /// The type parameters for the function type, or `null` if the function type
  /// doesn't have any type parameters.
  TypeParameterList? get typeParameters;
}

final class GenericTypeAliasImpl extends TypeAliasImpl
    with AstNodeWithNameScopeMixin
    implements GenericTypeAlias {
  TypeAnnotationImpl _type;

  TypeParameterListImpl? _typeParameters;

  @override
  final Token equals;

  @override
  ElementImpl? declaredElement;

  /// Initializes a newly created generic type alias.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// variable list doesn't have the corresponding attribute.
  ///
  /// The [typeParameters] can be `null` if there are no type parameters.
  GenericTypeAliasImpl({
    required super.comment,
    required super.metadata,
    required super.augmentKeyword,
    required super.typedefKeyword,
    required super.name,
    required TypeParameterListImpl? typeParameters,
    required this.equals,
    required TypeAnnotationImpl type,
    required super.semicolon,
  })  : _typeParameters = typeParameters,
        _type = type {
    _becomeParentOf(_typeParameters);
    _becomeParentOf(_type);
  }

  @experimental
  @override
  Fragment? get declaredFragment => declaredElement as Fragment?;

  @override
  GenericFunctionType? get functionType {
    var type = _type;
    return type is GenericFunctionTypeImpl ? type : null;
  }

  set functionType(GenericFunctionType? functionType) {
    _type = _becomeParentOf(functionType as GenericFunctionTypeImpl?)!;
  }

  @override
  TypeAnnotationImpl get type => _type;

  set type(TypeAnnotationImpl typeAnnotation) {
    _type = _becomeParentOf(typeAnnotation);
  }

  @override
  TypeParameterListImpl? get typeParameters => _typeParameters;

  set typeParameters(TypeParameterListImpl? typeParameters) {
    _typeParameters = _becomeParentOf(typeParameters);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNodeList('metadata', metadata)
    ..addToken('augmentKeyword', augmentKeyword)
    ..addToken('typedefKeyword', typedefKeyword)
    ..addToken('name', name)
    ..addNode('typeParameters', typeParameters)
    ..addToken('equals', equals)
    ..addNode('type', type);

  @override
  E? accept<E>(AstVisitor<E> visitor) {
    return visitor.visitGenericTypeAlias(this);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _typeParameters?.accept(visitor);
    _type.accept(visitor);
  }
}

/// The pattern with an optional [WhenClause].
///
///    guardedPattern ::=
///        [DartPattern] [WhenClause]?
abstract final class GuardedPattern implements AstNode {
  /// The pattern controlling whether the statements are executed.
  DartPattern get pattern;

  /// The clause controlling whether the statements are be executed.
  WhenClause? get whenClause;
}

final class GuardedPatternImpl extends AstNodeImpl implements GuardedPattern {
  @override
  final DartPatternImpl pattern;

  /// Variables declared in [pattern], available in [whenClause] guard, and
  /// to the `ifTrue` node.
  late Map<String, PatternVariableElementImpl> variables;

  @override
  final WhenClauseImpl? whenClause;

  GuardedPatternImpl({
    required this.pattern,
    required this.whenClause,
  }) {
    _becomeParentOf(pattern);
    _becomeParentOf(whenClause);
  }

  @override
  Token get beginToken => pattern.beginToken;

  @override
  Token get endToken => whenClause?.endToken ?? pattern.endToken;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addNode('pattern', pattern)
    ..addNode('whenClause', whenClause);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitGuardedPattern(this);

  @override
  void visitChildren(AstVisitor visitor) {
    pattern.accept(visitor);
    whenClause?.accept(visitor);
  }
}

/// A combinator that restricts the names being imported to those that aren't
/// in a given list.
///
///    hideCombinator ::=
///        'hide' [SimpleIdentifier] (',' [SimpleIdentifier])*
abstract final class HideCombinator implements Combinator {
  /// The list of names from the library that are hidden by this combinator.
  NodeList<SimpleIdentifier> get hiddenNames;
}

final class HideCombinatorImpl extends CombinatorImpl
    implements HideCombinator {
  final NodeListImpl<SimpleIdentifierImpl> _hiddenNames = NodeListImpl._();

  /// Initializes a newly created import show combinator.
  HideCombinatorImpl({
    required super.keyword,
    required List<SimpleIdentifierImpl> hiddenNames,
  }) {
    _hiddenNames._initialize(this, hiddenNames);
  }

  @override
  Token get endToken => _hiddenNames.endToken!;

  @override
  NodeListImpl<SimpleIdentifierImpl> get hiddenNames => _hiddenNames;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('keyword', keyword)
    ..addNodeList('hiddenNames', hiddenNames);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitHideCombinator(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _hiddenNames.accept(visitor);
  }
}

/// A node that represents an identifier.
///
///    identifier ::=
///        [SimpleIdentifier]
///      | [PrefixedIdentifier]
sealed class Identifier implements Expression, CommentReferableExpression {
  /// The element associated with this identifier based on static type
  /// information.
  ///
  /// Returns `null` if the AST structure hasn't been resolved or if this
  /// identifier couldn't be resolved. One example of the latter case is an
  /// identifier that isn't defined within the scope in which it appears.
  @experimental
  Element2? get element;

  /// The lexical representation of the identifier.
  String get name;

  /// The element associated with this identifier based on static type
  /// information, or `null` if the AST structure hasn't been resolved or if
  /// this identifier couldn't be resolved. One example of the latter case is an
  /// identifier that isn't defined within the scope in which it appears.
  Element? get staticElement;

  /// Returns `true` if the given [name] is visible only within the library in
  /// which it's declared.
  static bool isPrivateName(String name) => name.isNotEmpty && name[0] == "_";
}

sealed class IdentifierImpl extends CommentReferableExpressionImpl
    implements Identifier {
  @experimental
  @override
  Element2? get element {
    return staticElement.asElement2;
  }

  @override
  bool get isAssignable => true;
}

/// The basic structure of an if element.
abstract final class IfElement implements CollectionElement {
  /// The `case` clause used to match a pattern against the [expression].
  CaseClause? get caseClause;

  /// The statement that is executed if the condition evaluates to `false`, or
  /// `null` if there's no else statement.
  CollectionElement? get elseElement;

  /// The token representing the `else` keyword, or `null` if there's no else
  /// expression.
  Token? get elseKeyword;

  /// The expression used to either determine which of the statements is
  /// executed next or to compute the value to be matched against the pattern in
  /// the `case` clause.
  Expression get expression;

  /// The token representing the `if` keyword.
  Token get ifKeyword;

  /// The left parenthesis.
  Token get leftParenthesis;

  /// The right parenthesis.
  Token get rightParenthesis;

  /// The statement that is executed if the condition evaluates to `true`.
  CollectionElement get thenElement;
}

final class IfElementImpl extends CollectionElementImpl
    implements IfElement, IfElementOrStatementImpl<CollectionElementImpl> {
  @override
  final Token ifKeyword;

  @override
  final Token leftParenthesis;

  ExpressionImpl _expression;

  @override
  final CaseClauseImpl? caseClause;

  @override
  final Token rightParenthesis;

  @override
  final Token? elseKeyword;

  CollectionElementImpl _thenElement;

  CollectionElementImpl? _elseElement;

  /// Initializes a newly created for element.
  IfElementImpl({
    required this.ifKeyword,
    required this.leftParenthesis,
    required ExpressionImpl expression,
    required this.caseClause,
    required this.rightParenthesis,
    required CollectionElementImpl thenElement,
    required this.elseKeyword,
    required CollectionElementImpl? elseElement,
  })  : _expression = expression,
        _thenElement = thenElement,
        _elseElement = elseElement {
    _becomeParentOf(_expression);
    _becomeParentOf(caseClause);
    _becomeParentOf(_thenElement);
    _becomeParentOf(_elseElement);
  }

  @override
  Token get beginToken => ifKeyword;

  set condition(ExpressionImpl condition) {
    _expression = _becomeParentOf(condition);
  }

  @override
  CollectionElementImpl? get elseElement => _elseElement;

  set elseElement(CollectionElementImpl? element) {
    _elseElement = _becomeParentOf(element);
  }

  @override
  Token get endToken => _elseElement?.endToken ?? _thenElement.endToken;

  @override
  ExpressionImpl get expression => _expression;

  @override
  CollectionElementImpl? get ifFalse => elseElement;

  @override
  CollectionElementImpl get ifTrue => thenElement;

  @override
  CollectionElementImpl get thenElement => _thenElement;

  set thenElement(CollectionElementImpl element) {
    _thenElement = _becomeParentOf(element);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('ifKeyword', ifKeyword)
    ..addToken('leftParenthesis', leftParenthesis)
    ..addNode('expression', expression)
    ..addNode('caseClause', caseClause)
    ..addToken('rightParenthesis', rightParenthesis)
    ..addNode('thenElement', thenElement)
    ..addToken('elseKeyword', elseKeyword)
    ..addNode('elseElement', elseElement);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitIfElement(this);

  @override
  void resolveElement(
      ResolverVisitor resolver, CollectionLiteralContext? context) {
    resolver.visitIfElement(this, context: context);
    resolver.pushRewrite(null);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    expression.accept(visitor);
    caseClause?.accept(visitor);
    _thenElement.accept(visitor);
    _elseElement?.accept(visitor);
  }
}

sealed class IfElementOrStatementImpl<E extends AstNodeImpl>
    implements AstNodeImpl {
  /// The `case` clause used to match a pattern against the [expression].
  CaseClauseImpl? get caseClause;

  /// The expression used to either determine which of the statements is
  /// executed next or to compute the value matched against the pattern in the
  /// `case` clause.
  ExpressionImpl get expression;

  /// The node that is executed if the condition evaluates to `false`.
  E? get ifFalse;

  /// The node that is executed if the condition evaluates to `true`.
  E get ifTrue;
}

/// An if statement.
///
///    ifStatement ::=
///        'if' '(' [Expression] [CaseClause]? ')'[Statement]
///        ('else' [Statement])?
abstract final class IfStatement implements Statement {
  /// The `case` clause used to match a pattern against the [expression].
  CaseClause? get caseClause;

  /// The token representing the `else` keyword, or `null` if there's no else
  /// statement.
  Token? get elseKeyword;

  /// The statement that is executed if the condition evaluates to `false`, or
  /// `null` if there's no else statement.
  Statement? get elseStatement;

  /// The expression used to either determine which of the statements is
  /// executed next or to compute the value matched against the pattern in the
  /// `case` clause.
  Expression get expression;

  /// The token representing the `if` keyword.
  // TODO(scheglov): Extract shared `IfCondition`, see the patterns spec.
  Token get ifKeyword;

  /// The left parenthesis.
  Token get leftParenthesis;

  /// The right parenthesis.
  Token get rightParenthesis;

  /// The statement that is executed if the condition evaluates to `true`.
  Statement get thenStatement;
}

final class IfStatementImpl extends StatementImpl
    implements IfStatement, IfElementOrStatementImpl<StatementImpl> {
  @override
  final Token ifKeyword;

  @override
  final Token leftParenthesis;

  ExpressionImpl _expression;

  @override
  final CaseClauseImpl? caseClause;

  @override
  final Token rightParenthesis;

  @override
  final Token? elseKeyword;

  StatementImpl _thenStatement;

  StatementImpl? _elseStatement;

  /// Initializes a newly created if statement.
  ///
  /// The [elseKeyword] and [elseStatement] can be `null` if there's no else
  /// clause.
  IfStatementImpl({
    required this.ifKeyword,
    required this.leftParenthesis,
    required ExpressionImpl expression,
    required this.caseClause,
    required this.rightParenthesis,
    required StatementImpl thenStatement,
    required this.elseKeyword,
    required StatementImpl? elseStatement,
  })  : _expression = expression,
        _thenStatement = thenStatement,
        _elseStatement = elseStatement {
    _becomeParentOf(_expression);
    _becomeParentOf(caseClause);
    _becomeParentOf(_thenStatement);
    _becomeParentOf(_elseStatement);
  }

  @override
  Token get beginToken => ifKeyword;

  set condition(ExpressionImpl condition) {
    _expression = _becomeParentOf(condition);
  }

  @override
  StatementImpl? get elseStatement => _elseStatement;

  set elseStatement(StatementImpl? statement) {
    _elseStatement = _becomeParentOf(statement);
  }

  @override
  Token get endToken {
    if (elseStatement case var elseStatement?) {
      return elseStatement.endToken;
    }
    return _thenStatement.endToken;
  }

  @override
  ExpressionImpl get expression => _expression;

  @override
  StatementImpl? get ifFalse => elseStatement;

  @override
  StatementImpl get ifTrue => thenStatement;

  @override
  StatementImpl get thenStatement => _thenStatement;

  set thenStatement(StatementImpl statement) {
    _thenStatement = _becomeParentOf(statement);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('ifKeyword', ifKeyword)
    ..addToken('leftParenthesis', leftParenthesis)
    ..addNode('expression', expression)
    ..addNode('caseClause', caseClause)
    ..addToken('rightParenthesis', rightParenthesis)
    ..addNode('thenStatement', thenStatement)
    ..addToken('elseKeyword', elseKeyword)
    ..addNode('elseStatement', elseStatement);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitIfStatement(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _expression.accept(visitor);
    caseClause?.accept(visitor);
    _thenStatement.accept(visitor);
    _elseStatement?.accept(visitor);
  }
}

/// The "implements" clause in an class declaration.
///
///    implementsClause ::=
///        'implements' [NamedType] (',' [NamedType])*
abstract final class ImplementsClause implements AstNode {
  /// The token representing the `implements` keyword.
  Token get implementsKeyword;

  /// The list of the interfaces that are being implemented.
  NodeList<NamedType> get interfaces;
}

final class ImplementsClauseImpl extends AstNodeImpl
    implements ImplementsClause {
  @override
  final Token implementsKeyword;

  final NodeListImpl<NamedTypeImpl> _interfaces = NodeListImpl._();

  /// Initializes a newly created implements clause.
  ImplementsClauseImpl({
    required this.implementsKeyword,
    required List<NamedTypeImpl> interfaces,
  }) {
    _interfaces._initialize(this, interfaces);
  }

  @override
  Token get beginToken => implementsKeyword;

  @override
  Token get endToken => _interfaces.endToken ?? implementsKeyword;

  @override
  NodeListImpl<NamedTypeImpl> get interfaces => _interfaces;

  @override
  // TODO(paulberry): add commas.
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('implementsKeyword', implementsKeyword)
    ..addNodeList('interfaces', interfaces);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitImplementsClause(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _interfaces.accept(visitor);
  }
}

/// An expression representing an implicit 'call' method reference.
///
/// Objects of this type aren't produced directly by the parser (because the
/// parser can't tell whether an expression refers to a callable type); they
/// are produced at resolution time.
abstract final class ImplicitCallReference
    implements MethodReferenceExpression {
  /// The expression from which a `call` method is being referenced.
  Expression get expression;

  /// The element associated with the implicit `call` reference based on the
  /// static types.
  @override
  MethodElement get staticElement;

  /// The type arguments being applied to the tear-off, or `null` if there are
  /// no type arguments.
  TypeArgumentList? get typeArguments;

  /// The actual type arguments being applied to the tear-off, either explicitly
  /// specified in [typeArguments], or inferred.
  ///
  /// An empty list if the 'call' method doesn't have type parameters.
  List<DartType> get typeArgumentTypes;
}

final class ImplicitCallReferenceImpl extends ExpressionImpl
    implements ImplicitCallReference {
  ExpressionImpl _expression;

  TypeArgumentListImpl? _typeArguments;

  @override
  List<DartType> typeArgumentTypes;

  @override
  MethodElement staticElement;

  ImplicitCallReferenceImpl({
    required ExpressionImpl expression,
    required this.staticElement,
    required TypeArgumentListImpl? typeArguments,
    required this.typeArgumentTypes,
  })  : _expression = expression,
        _typeArguments = typeArguments {
    _becomeParentOf(_expression);
    _becomeParentOf(_typeArguments);
  }

  @override
  Token get beginToken => expression.beginToken;

  @experimental
  @override
  MethodElement2? get element => (staticElement as MethodFragment?)?.element;

  @override
  Token get endToken => typeArguments?.endToken ?? expression.endToken;

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl value) {
    _expression = _becomeParentOf(value);
  }

  @override
  Precedence get precedence =>
      typeArguments == null ? expression.precedence : Precedence.postfix;

  @override
  TypeArgumentListImpl? get typeArguments => _typeArguments;

  set typeArguments(TypeArgumentListImpl? value) {
    _typeArguments = _becomeParentOf(value);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('expression', expression)
    ..addNode('typeArguments', typeArguments);

  @override
  E? accept<E>(AstVisitor<E> visitor) {
    return visitor.visitImplicitCallReference(this);
  }

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitImplicitCallReference(this);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    expression.accept(visitor);
    typeArguments?.accept(visitor);
  }
}

/// An import directive.
///
///    importDirective ::=
///        [Annotation] 'import' [StringLiteral] ('as' identifier)?
///        [Combinator]* ';'
///      | [Annotation] 'import' [StringLiteral] 'deferred' 'as' identifier
///        [Combinator]* ';'
abstract final class ImportDirective implements NamespaceDirective {
  /// The token representing the `as` keyword, or `null` if the imported names
  /// aren't prefixed.
  Token? get asKeyword;

  /// The token representing the `deferred` keyword, or `null` if the imported
  /// URI isn't deferred.
  Token? get deferredKeyword;

  /// The element associated with this directive, or `null` if the AST structure
  /// hasn't been resolved.
  @override
  LibraryImportElement? get element;

  /// The token representing the `import` keyword.
  Token get importKeyword;

  /// Information about this import directive.
  ///
  /// Returns `null` if the AST structure hasn't been resolved.
  @experimental
  LibraryImport? get libraryImport;

  /// The prefix to be used with the imported names, or `null` if the imported
  /// names aren't prefixed.
  SimpleIdentifier? get prefix;
}

final class ImportDirectiveImpl extends NamespaceDirectiveImpl
    implements ImportDirective {
  @override
  final Token importKeyword;

  @override
  final Token? deferredKeyword;

  @override
  final Token? asKeyword;

  SimpleIdentifierImpl? _prefix;

  /// Initializes a newly created import directive.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// function doesn't have the corresponding attribute.
  ///
  /// The [deferredKeyword] can be `null` if the import isn't deferred.
  ///
  /// The [asKeyword] and [prefix] can be `null` if the import doesn't specify a
  /// prefix.
  ///
  /// The list of [combinators] can be `null` if there are no combinators.
  ImportDirectiveImpl({
    required super.comment,
    required super.metadata,
    required this.importKeyword,
    required super.uri,
    required super.configurations,
    required this.deferredKeyword,
    required this.asKeyword,
    required SimpleIdentifierImpl? prefix,
    required super.combinators,
    required super.semicolon,
  }) : _prefix = prefix {
    _becomeParentOf(_prefix);
  }

  @override
  LibraryImportElementImpl? get element =>
      super.element as LibraryImportElementImpl?;

  @override
  Token get firstTokenAfterCommentAndMetadata => importKeyword;

  @experimental
  @override
  LibraryImport? get libraryImport => element as LibraryImport?;

  @override
  SimpleIdentifierImpl? get prefix => _prefix;

  set prefix(SimpleIdentifierImpl? identifier) {
    _prefix = _becomeParentOf(identifier);
  }

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('importKeyword', importKeyword)
    ..addNode('uri', uri)
    ..addToken('deferredKeyword', deferredKeyword)
    ..addToken('asKeyword', asKeyword)
    ..addNode('prefix', prefix)
    ..addNodeList('combinators', combinators)
    ..addNodeList('configurations', configurations)
    ..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitImportDirective(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    configurations.accept(visitor);
    _prefix?.accept(visitor);
    combinators.accept(visitor);
  }

  /// Returns `true` if the non-URI components of the two directives are
  /// syntactically identical.
  ///
  /// URIs are checked outside to see if they resolve to the same absolute URI,
  /// so to the same library, regardless of the used syntax (absolute, relative,
  /// not normalized).
  static bool areSyntacticallyIdenticalExceptUri(
    NamespaceDirective node1,
    NamespaceDirective node2,
  ) {
    if (node1 is ImportDirective &&
        node2 is ImportDirective &&
        node1.prefix?.name != node2.prefix?.name) {
      return false;
    }

    bool areSameNames(
      List<SimpleIdentifier> names1,
      List<SimpleIdentifier> names2,
    ) {
      if (names1.length != names2.length) {
        return false;
      }
      for (var i = 0; i < names1.length; i++) {
        if (names1[i].name != names2[i].name) {
          return false;
        }
      }
      return true;
    }

    var combinators1 = node1.combinators;
    var combinators2 = node2.combinators;
    if (combinators1.length != combinators2.length) {
      return false;
    }
    for (var i = 0; i < combinators1.length; i++) {
      var combinator1 = combinators1[i];
      var combinator2 = combinators2[i];
      if (combinator1 is HideCombinator && combinator2 is HideCombinator) {
        if (!areSameNames(combinator1.hiddenNames, combinator2.hiddenNames)) {
          return false;
        }
      } else if (combinator1 is ShowCombinator &&
          combinator2 is ShowCombinator) {
        if (!areSameNames(combinator1.shownNames, combinator2.shownNames)) {
          return false;
        }
      } else {
        return false;
      }
    }

    return true;
  }
}

/// Reference to an import prefix name.
abstract final class ImportPrefixReference implements AstNode {
  /// The element to which [name] is resolved.
  ///
  /// Usually a [PrefixElement], but can be anything in invalid code.
  Element? get element;

  /// The element to which [name] is resolved.
  ///
  /// Usually a [PrefixElement2], but can be anything in invalid code.
  @experimental
  Element2? get element2;

  /// The name of the referenced import prefix.
  Token get name;

  /// The `.` that separates [name] from the following identifier.
  Token get period;
}

final class ImportPrefixReferenceImpl extends AstNodeImpl
    implements ImportPrefixReference {
  @override
  final Token name;

  @override
  final Token period;

  @override
  Element? element;

  ImportPrefixReferenceImpl({
    required this.name,
    required this.period,
  });

  @override
  Token get beginToken => name;

  @experimental
  @override
  Element2? get element2 {
    var element = this.element;
    if (element case PrefixElementImpl element) {
      return element.element2;
    } else if (element case Fragment fragment) {
      return fragment.element;
    } else if (element case Element2 element) {
      return element;
    }
    return null;
  }

  @override
  Token get endToken => period;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('name', name)
    ..addToken('period', period);

  @override
  E? accept<E>(AstVisitor<E> visitor) {
    return visitor.visitImportPrefixReference(this);
  }

  @override
  void visitChildren(AstVisitor visitor) {}
}

/// An index expression.
///
///    indexExpression ::=
///        [Expression] '[' [Expression] ']'
abstract final class IndexExpression
    implements NullShortableExpression, MethodReferenceExpression {
  /// The expression used to compute the index.
  Expression get index;

  /// Whether this expression is cascaded.
  ///
  /// If it is, then the target of this expression isn't stored locally but is
  /// stored in the nearest ancestor that is a [CascadeExpression].
  bool get isCascaded;

  /// Whether this index expression is null aware (as opposed to non-null).
  bool get isNullAware;

  /// The left square bracket.
  Token get leftBracket;

  /// The period (".." | "?..") before a cascaded index expression, or `null` if
  /// this index expression isn't part of a cascade expression.
  Token? get period;

  /// The question mark before the left bracket, or `null` if there's no
  /// question mark.
  Token? get question;

  /// The expression used to compute the object being indexed.
  ///
  /// If this index expression isn't part of a cascade expression, then this
  /// is the same as [target]. If this index expression is part of a cascade
  /// expression, then the target expression stored with the cascade expression
  /// is returned.
  Expression get realTarget;

  /// The right square bracket.
  Token get rightBracket;

  /// The expression used to compute the object being indexed, or `null` if this
  /// index expression is part of a cascade expression.
  ///
  /// Use [realTarget] to get the target independent of whether this is part of
  /// a cascade expression.
  Expression? get target;

  /// Returns `true` if this expression is computing a right-hand value (that
  /// is, if this expression is in a context where the operator '[]' is
  /// invoked).
  ///
  /// Note that [inGetterContext] and [inSetterContext] aren't opposites, nor
  /// are they mutually exclusive. In other words, it's possible for both
  /// methods to return `true` when invoked on the same node.
  // TODO(brianwilkerson): Convert this to a getter.
  bool inGetterContext();

  /// Returns `true` if this expression is computing a left-hand value (that is,
  /// if this expression is in a context where the operator '[]=' is
  /// invoked).
  ///
  /// Note that [inGetterContext] and [inSetterContext] aren't opposites, nor
  /// are they mutually exclusive. In other words, it's possible for both
  /// methods to return `true` when invoked on the same node.
  // TODO(brianwilkerson): Convert this to a getter.
  bool inSetterContext();
}

final class IndexExpressionImpl extends ExpressionImpl
    with NullShortableExpressionImpl
    implements IndexExpression {
  @override
  Token? period;

  ExpressionImpl? _target;

  @override
  final Token? question;

  @override
  final Token leftBracket;

  ExpressionImpl _index;

  @override
  final Token rightBracket;

  /// The element associated with the operator based on the static type of the
  /// target, or `null` if the AST structure hasn't been resolved or if the
  /// operator couldn't be resolved.
  @override
  MethodElement? staticElement;

  /// Initializes a newly created index expression that is a child of a cascade
  /// expression.
  IndexExpressionImpl.forCascade({
    required this.period,
    required this.question,
    required this.leftBracket,
    required ExpressionImpl index,
    required this.rightBracket,
  }) : _index = index {
    _becomeParentOf(_index);
  }

  /// Initializes a newly created index expression that isn't a child of a
  /// cascade expression.
  IndexExpressionImpl.forTarget({
    required ExpressionImpl? target,
    required this.question,
    required this.leftBracket,
    required ExpressionImpl index,
    required this.rightBracket,
  })  : _target = target,
        _index = index {
    _becomeParentOf(_target);
    _becomeParentOf(_index);
  }

  @override
  Token get beginToken {
    if (target case var target?) {
      return target.beginToken;
    }
    return period!;
  }

  @experimental
  @override
  MethodElement2? get element => staticElement?.asElement2 as MethodElement2?;

  @override
  Token get endToken => rightBracket;

  @override
  ExpressionImpl get index => _index;

  set index(ExpressionImpl expression) {
    _index = _becomeParentOf(expression);
  }

  @override
  bool get isAssignable => true;

  @override
  bool get isCascaded => period != null;

  @override
  bool get isNullAware {
    if (isCascaded) {
      return _ancestorCascade.isNullAware;
    }
    return question != null ||
        (leftBracket.type == TokenType.OPEN_SQUARE_BRACKET &&
            period != null &&
            period!.type == TokenType.QUESTION_PERIOD_PERIOD);
  }

  @override
  Precedence get precedence => Precedence.postfix;

  @override
  ExpressionImpl get realTarget {
    if (isCascaded) {
      return _ancestorCascade.target;
    }
    return _target!;
  }

  @override
  ExpressionImpl? get target => _target;

  set target(ExpressionImpl? expression) {
    _target = _becomeParentOf(expression);
  }

  /// The cascade that contains this [IndexExpression].
  ///
  /// We expect that [isCascaded] is `true`.
  CascadeExpressionImpl get _ancestorCascade {
    assert(isCascaded);
    for (var ancestor = parent!;; ancestor = ancestor.parent!) {
      if (ancestor is CascadeExpressionImpl) {
        return ancestor;
      }
    }
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('target', target)
    ..addToken('period', period)
    ..addToken('leftBracket', leftBracket)
    ..addNode('index', index)
    ..addToken('rightBracket', rightBracket);

  @override
  AstNode get _nullShortingExtensionCandidate => parent!;

  /// The parameter element representing the parameter to which the value of the
  /// index expression is bound, or `null` if the AST structure is not resolved,
  /// or the function being invoked is not known based on static type
  /// information.
  ParameterElement? get _staticParameterElementForIndex {
    Element? element = staticElement;

    var parent = this.parent;
    if (parent is CompoundAssignmentExpression) {
      element = parent.writeElement ?? parent.readElement;
    }

    if (element is ExecutableElement) {
      List<ParameterElement> parameters = element.parameters;
      if (parameters.isEmpty) {
        return null;
      }
      return parameters[0];
    }
    return null;
  }

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitIndexExpression(this);

  @override
  bool inGetterContext() {
    // TODO(brianwilkerson): Convert this to a getter.
    var parent = this.parent!;
    if (parent is AssignmentExpression) {
      AssignmentExpression assignment = parent;
      if (identical(assignment.leftHandSide, this) &&
          assignment.operator.type == TokenType.EQ) {
        return false;
      }
    }
    return true;
  }

  @override
  bool inSetterContext() {
    // TODO(brianwilkerson): Convert this to a getter.
    var parent = this.parent!;
    if (parent is PrefixExpression) {
      return parent.operator.type.isIncrementOperator;
    } else if (parent is PostfixExpression) {
      return parent.operator.type.isIncrementOperator;
    } else if (parent is AssignmentExpression) {
      return identical(parent.leftHandSide, this);
    }
    return false;
  }

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitIndexExpression(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _target?.accept(visitor);
    _index.accept(visitor);
  }

  @override
  bool _extendsNullShorting(Expression descendant) =>
      identical(descendant, _target);
}

/// An instance creation expression.
///
///    newExpression ::=
///        ('new' | 'const')? [NamedType] ('.' [SimpleIdentifier])?
///        [ArgumentList]
abstract final class InstanceCreationExpression implements Expression {
  /// The list of arguments to the constructor.
  ArgumentList get argumentList;

  /// The name of the constructor to be invoked.
  ConstructorName get constructorName;

  /// Whether this creation expression is used to invoke a constant constructor,
  /// either because the keyword `const` was explicitly provided or because no
  /// keyword was provided and this expression is in a constant context.
  bool get isConst;

  /// The `new` or `const` keyword used to indicate how an object should be
  /// created, or `null` if the keyword isn't explicitly provided.
  Token? get keyword;
}

final class InstanceCreationExpressionImpl extends ExpressionImpl
    implements InstanceCreationExpression {
  // TODO(brianwilkerson): Consider making InstanceCreationExpressionImpl extend
  // InvocationExpressionImpl. This would probably be a breaking change, but is
  // also probably worth it.

  @override
  Token? keyword;

  ConstructorNameImpl _constructorName;

  /// The type arguments associated with the constructor, rather than with the
  /// class in which the constructor is defined.
  ///
  /// It's always an error if there are type arguments because Dart doesn't
  /// currently support generic constructors, but we capture them in the AST in
  /// order to recover better.
  TypeArgumentListImpl? _typeArguments;

  ArgumentListImpl _argumentList;

  /// Initializes a newly created instance creation expression.
  InstanceCreationExpressionImpl({
    required this.keyword,
    required ConstructorNameImpl constructorName,
    required ArgumentListImpl argumentList,
    required TypeArgumentListImpl? typeArguments,
  })  : _constructorName = constructorName,
        _argumentList = argumentList,
        _typeArguments = typeArguments {
    _becomeParentOf(_constructorName);
    _becomeParentOf(_argumentList);
    _becomeParentOf(_typeArguments);
  }

  @override
  ArgumentListImpl get argumentList => _argumentList;

  set argumentList(ArgumentListImpl argumentList) {
    _argumentList = _becomeParentOf(argumentList);
  }

  @override
  Token get beginToken => keyword ?? _constructorName.beginToken;

  @override
  ConstructorNameImpl get constructorName => _constructorName;

  set constructorName(ConstructorNameImpl name) {
    _constructorName = _becomeParentOf(name);
  }

  @override
  Token get endToken => _argumentList.endToken;

  @override
  bool get isConst {
    if (!isImplicit) {
      return keyword!.keyword == Keyword.CONST;
    } else {
      return inConstantContext;
    }
  }

  /// Whether this is an implicit constructor invocation.
  bool get isImplicit => keyword == null;

  @override
  Precedence get precedence => Precedence.primary;

  /// The type arguments associated with the constructor, rather than with the
  /// class in which the constructor is defined.
  ///
  /// It's always an error if there are type arguments because Dart doesn't
  /// currently support generic constructors, but we capture them in the AST in
  /// order to recover better.
  TypeArgumentListImpl? get typeArguments => _typeArguments;

  set typeArguments(TypeArgumentListImpl? typeArguments) {
    _typeArguments = _becomeParentOf(typeArguments);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('keyword', keyword)
    ..addNode('constructorName', constructorName)
    ..addNode('typeArguments', typeArguments)
    ..addNode('argumentList', argumentList);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitInstanceCreationExpression(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitInstanceCreationExpression(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _constructorName.accept(visitor);
    _typeArguments?.accept(visitor);
    _argumentList.accept(visitor);
  }
}

/// An integer literal expression.
///
///    integerLiteral ::=
///        decimalIntegerLiteral
///      | hexadecimalIntegerLiteral
///
///    decimalIntegerLiteral ::=
///        decimalDigit+
///
///    hexadecimalIntegerLiteral ::=
///        '0x' hexadecimalDigit+
///      | '0X' hexadecimalDigit+
abstract final class IntegerLiteral implements Literal {
  /// The token representing the literal.
  Token get literal;

  /// The value of the literal, or `null` when [literal] doesn't represent a
  /// valid `int` value, for example because of overflow.
  int? get value;
}

final class IntegerLiteralImpl extends LiteralImpl implements IntegerLiteral {
  @override
  final Token literal;

  @override
  int? value = 0;

  /// Initializes a newly created integer literal.
  IntegerLiteralImpl({
    required this.literal,
    required this.value,
  });

  @override
  Token get beginToken => literal;

  @override
  Token get endToken => literal;

  /// Whether this literal's [parent] is a [PrefixExpression] of unary negation.
  ///
  /// Note: this does *not* indicate that the value itself is negated, just that
  /// the literal is the child of a negation operation. The literal value itself
  /// is always positive.
  bool get immediatelyNegated {
    var parent = this.parent!;
    return parent is PrefixExpression &&
        parent.operator.type == TokenType.MINUS;
  }

  @override
  ChildEntities get _childEntities =>
      ChildEntities()..addToken('literal', literal);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitIntegerLiteral(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitIntegerLiteral(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    // There are no children to visit.
  }

  static bool isValidAsDouble(String source) {
    // Less than 16 characters must be a valid double since it's less than
    // 9007199254740992, 0x10000000000000, both 16 characters and 53 bits.
    if (source.length < 16) {
      return true;
    }

    var fullPrecision = BigInt.tryParse(source);
    if (fullPrecision == null) {
      return false;
    }

    // Usually handled by the length check, however, we must check this before
    // constructing a mask later, or we'd get a negative-shift runtime error.
    var bitLengthAsInt = fullPrecision.bitLength;
    if (bitLengthAsInt <= 53) {
      return true;
    }

    // This would overflow the exponent (larger than maximum double).
    if (fullPrecision > BigInt.from(double.maxFinite)) {
      return false;
    }

    // Say [lexeme] uses 100 bits as an integer. The bottom 47 must be 0s -- so
    // construct a mask of 47 ones, via of 2^n - 1 where n is 47.
    var bottomMask = (BigInt.one << (bitLengthAsInt - 53)) - BigInt.one;

    return fullPrecision & bottomMask == BigInt.zero;
  }

  /// Whether the given [source] is a valid lexeme for an integer
  /// literal.
  ///
  /// The flag [isNegative] should be `true` if the lexeme is preceded by a
  /// unary negation operator.
  static bool isValidAsInteger(String source, bool isNegative) {
    // TODO(jmesserly): this depends on the platform int implementation, and
    // might not be accurate if run in a browser.
    //
    // (Prior to https://dart-review.googlesource.com/c/sdk/+/63023 there was
    // a partial implementation here which might be a good starting point.
    // _isValidDecimalLiteral relied on int.parse so that would need some fixes.
    // _isValidHexadecimalLiteral worked except for negative int64 max.)
    if (isNegative) source = '-$source';
    return int.tryParse(source) != null;
  }

  /// Suggests the nearest valid double to a user.
  ///
  /// If the integer they wrote requires more than a 53 bit mantissa, or more
  /// than 10 exponent bits, do them the favor of suggesting the nearest integer
  /// that would work for them.
  static double nearestValidDouble(String source) =>
      math.min(double.maxFinite, BigInt.parse(source).toDouble());
}

/// A node within a [StringInterpolation].
///
///    interpolationElement ::=
///        [InterpolationExpression]
///      | [InterpolationString]
sealed class InterpolationElement implements AstNode {}

sealed class InterpolationElementImpl extends AstNodeImpl
    implements InterpolationElement {}

/// An expression embedded in a string interpolation.
///
///    interpolationExpression ::=
///        '$' [SimpleIdentifier]
///      | '$' '{' [Expression] '}'
abstract final class InterpolationExpression implements InterpolationElement {
  /// The expression to be evaluated for the value to be converted into a
  /// string.
  Expression get expression;

  /// The token used to introduce the interpolation expression.
  ///
  /// This will either be `$` if the expression is a simple identifier or `${`
  /// if the expression is a full expression.
  Token get leftBracket;

  /// The right curly bracket, or `null` if the expression is an identifier
  /// without brackets.
  Token? get rightBracket;
}

final class InterpolationExpressionImpl extends InterpolationElementImpl
    implements InterpolationExpression {
  @override
  final Token leftBracket;

  ExpressionImpl _expression;

  @override
  final Token? rightBracket;

  /// Initializes a newly created interpolation expression.
  InterpolationExpressionImpl({
    required this.leftBracket,
    required ExpressionImpl expression,
    required this.rightBracket,
  }) : _expression = expression {
    _becomeParentOf(_expression);
  }

  @override
  Token get beginToken => leftBracket;

  @override
  Token get endToken => rightBracket ?? _expression.endToken;

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('leftBracket', leftBracket)
    ..addNode('expression', expression)
    ..addToken('rightBracket', rightBracket);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitInterpolationExpression(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _expression.accept(visitor);
  }
}

/// A non-empty substring of an interpolated string.
///
///    interpolationString ::=
///        characters
abstract final class InterpolationString implements InterpolationElement {
  /// The characters that are added to the string.
  Token get contents;

  /// The offset of the after-last contents character.
  int get contentsEnd;

  /// The offset of the first contents character.
  int get contentsOffset;

  /// The value of the literal.
  String get value;
}

final class InterpolationStringImpl extends InterpolationElementImpl
    implements InterpolationString {
  @override
  final Token contents;

  @override
  String value;

  /// Initializes a newly created string of characters that are part of a string
  /// interpolation.
  InterpolationStringImpl({
    required this.contents,
    required this.value,
  });

  @override
  Token get beginToken => contents;

  @override
  int get contentsEnd => offset + _lexemeHelper.end;

  @override
  int get contentsOffset => contents.offset + _lexemeHelper.start;

  @override
  Token get endToken => contents;

  @override
  StringInterpolation get parent => super.parent as StringInterpolation;

  @override
  ChildEntities get _childEntities =>
      ChildEntities()..addToken('contents', contents);

  StringLexemeHelper get _lexemeHelper {
    String lexeme = contents.lexeme;
    return StringLexemeHelper(lexeme, identical(this, parent.elements.first),
        identical(this, parent.elements.last));
  }

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitInterpolationString(this);

  @override
  void visitChildren(AstVisitor visitor) {}
}

/// The invocation of a function or method.
///
/// This will either be a [FunctionExpressionInvocation] or a
/// [MethodInvocation].
abstract final class InvocationExpression implements Expression {
  /// The list of arguments to the method.
  ArgumentList get argumentList;

  /// The expression that identifies the function or method being invoked.
  ///
  /// For example:
  ///
  ///     (o.m)<TArgs>(args); // target is `o.m`
  ///     o.m<TArgs>(args);   // target is `m`
  ///
  /// In either case, the [function.staticType] is the [staticInvokeType] before
  /// applying type arguments `TArgs`.
  Expression get function;

  /// The function type of the invocation based on the static type information,
  /// or `null` if the AST structure hasn't been resolved, or if the invoke
  /// couldn't be resolved.
  ///
  /// This is usually a [FunctionType], but it can also be `dynamic` or
  /// `Function`. In the case of interface types that have a `call` method, we
  /// store the type of that `call` method here as parameterized.
  DartType? get staticInvokeType;

  /// The type arguments to be applied to the method being invoked, or `null` if
  /// no type arguments were provided.
  TypeArgumentList? get typeArguments;

  /// The actual type arguments of the invocation, either explicitly specified
  /// in [typeArguments], or inferred, or `null` if the AST structure hasn't
  /// been resolved.
  ///
  /// An empty list if the [function] doesn't have type parameters.
  List<DartType>? get typeArgumentTypes;
}

sealed class InvocationExpressionImpl extends ExpressionImpl
    implements InvocationExpression {
  ArgumentListImpl _argumentList;

  TypeArgumentListImpl? _typeArguments;

  @override
  List<DartType>? typeArgumentTypes;

  @override
  DartType? staticInvokeType;

  /// Initializes a newly created invocation.
  InvocationExpressionImpl({
    required TypeArgumentListImpl? typeArguments,
    required ArgumentListImpl argumentList,
  })  : _typeArguments = typeArguments,
        _argumentList = argumentList {
    _becomeParentOf(_typeArguments);
    _becomeParentOf(_argumentList);
  }

  @override
  ArgumentListImpl get argumentList => _argumentList;

  set argumentList(ArgumentListImpl argumentList) {
    _argumentList = _becomeParentOf(argumentList);
  }

  @override
  TypeArgumentListImpl? get typeArguments => _typeArguments;

  set typeArguments(TypeArgumentListImpl? typeArguments) {
    _typeArguments = _becomeParentOf(typeArguments);
  }
}

/// An is expression.
///
///    isExpression ::=
///        [Expression] 'is' '!'? [TypeAnnotation]
abstract final class IsExpression implements Expression {
  /// The expression used to compute the value whose type is being tested.
  Expression get expression;

  /// The is operator.
  Token get isOperator;

  /// The not operator, or `null` if the sense of the test isn't negated.
  Token? get notOperator;

  /// The type being tested for.
  TypeAnnotation get type;
}

final class IsExpressionImpl extends ExpressionImpl implements IsExpression {
  ExpressionImpl _expression;

  @override
  final Token isOperator;

  @override
  final Token? notOperator;

  TypeAnnotationImpl _type;

  /// Initializes a newly created is expression.
  ///
  /// The [notOperator] can be `null` if the sense of the test isn't negated.
  IsExpressionImpl({
    required ExpressionImpl expression,
    required this.isOperator,
    required this.notOperator,
    required TypeAnnotationImpl type,
  })  : _expression = expression,
        _type = type {
    _becomeParentOf(_expression);
    _becomeParentOf(_type);
  }

  @override
  Token get beginToken => _expression.beginToken;

  @override
  Token get endToken => _type.endToken;

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  Precedence get precedence => Precedence.relational;

  @override
  TypeAnnotationImpl get type => _type;

  set type(TypeAnnotationImpl type) {
    _type = _becomeParentOf(type);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('expression', expression)
    ..addToken('isOperator', isOperator)
    ..addToken('notOperator', notOperator)
    ..addNode('type', type);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitIsExpression(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitIsExpression(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _expression.accept(visitor);
    _type.accept(visitor);
  }
}

/// A label on either a [LabeledStatement] or a [NamedExpression].
///
///    label ::=
///        [SimpleIdentifier] ':'
abstract final class Label implements AstNode {
  /// The colon that separates the label from the statement.
  Token get colon;

  /// The label being associated with the statement.
  SimpleIdentifier get label;
}

/// A statement that has a label associated with them.
///
///    labeledStatement ::=
///       [Label]+ [Statement]
abstract final class LabeledStatement implements Statement {
  /// The labels being associated with the statement.
  NodeList<Label> get labels;

  /// The statement with which the labels are being associated.
  Statement get statement;
}

final class LabeledStatementImpl extends StatementImpl
    implements LabeledStatement {
  final NodeListImpl<LabelImpl> _labels = NodeListImpl._();

  StatementImpl _statement;

  /// Initializes a newly created labeled statement.
  LabeledStatementImpl({
    required List<LabelImpl> labels,
    required StatementImpl statement,
  }) : _statement = statement {
    _labels._initialize(this, labels);
    _becomeParentOf(_statement);
  }

  @override
  Token get beginToken {
    if (_labels.isNotEmpty) {
      return _labels.beginToken!;
    }
    return _statement.beginToken;
  }

  @override
  Token get endToken => _statement.endToken;

  @override
  NodeListImpl<LabelImpl> get labels => _labels;

  @override
  StatementImpl get statement => _statement;

  set statement(StatementImpl statement) {
    _statement = _becomeParentOf(statement);
  }

  @override
  StatementImpl get unlabeled => _statement.unlabeled;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNodeList('labels', labels)
    ..addNode('statement', statement);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitLabeledStatement(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _labels.accept(visitor);
    _statement.accept(visitor);
  }
}

final class LabelImpl extends AstNodeImpl implements Label {
  SimpleIdentifierImpl _label;

  @override
  final Token colon;

  /// Initializes a newly created label.
  LabelImpl({
    required SimpleIdentifierImpl label,
    required this.colon,
  }) : _label = label {
    _becomeParentOf(_label);
  }

  @override
  Token get beginToken => _label.beginToken;

  @override
  Token get endToken => colon;

  @override
  SimpleIdentifierImpl get label => _label;

  set label(SimpleIdentifierImpl label) {
    _label = _becomeParentOf(label);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('label', label)
    ..addToken('colon', colon);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitLabel(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _label.accept(visitor);
  }
}

/// A library directive.
///
///    libraryDirective ::=
///        [Annotation] 'library' [LibraryIdentifier]? ';'
abstract final class LibraryDirective implements Directive {
  @override
  LibraryElement? get element;

  /// The element associated with this directive.
  ///
  /// Returns `null` if the AST structure hasn't been resolved or if this
  /// directive couldn't be resolved.
  @experimental
  LibraryElement2? get element2;

  /// The token representing the `library` keyword.
  Token get libraryKeyword;

  /// The name of the library being defined.
  LibraryIdentifier? get name2;

  /// The semicolon terminating the directive.
  Token get semicolon;
}

final class LibraryDirectiveImpl extends DirectiveImpl
    implements LibraryDirective {
  @override
  final Token libraryKeyword;

  LibraryIdentifierImpl? _name;

  @override
  final Token semicolon;

  /// Initializes a newly created library directive.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// directive doesn't have the corresponding attribute.
  LibraryDirectiveImpl({
    required super.comment,
    required super.metadata,
    required this.libraryKeyword,
    required LibraryIdentifierImpl? name,
    required this.semicolon,
  }) : _name = name {
    _becomeParentOf(_name);
  }

  @override
  LibraryElementImpl? get element {
    return super.element as LibraryElementImpl?;
  }

  @experimental
  @override
  LibraryElement2? get element2 => element as LibraryElement2?;

  @override
  Token get endToken => semicolon;

  @override
  Token get firstTokenAfterCommentAndMetadata => libraryKeyword;

  set name(LibraryIdentifierImpl? name) {
    _name = _becomeParentOf(name);
  }

  @override
  LibraryIdentifierImpl? get name2 => _name;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('libraryKeyword', libraryKeyword)
    ..addNode('name', name2)
    ..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitLibraryDirective(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _name?.accept(visitor);
  }
}

/// The identifier for a library.
///
///    libraryIdentifier ::=
///        [SimpleIdentifier] ('.' [SimpleIdentifier])*
abstract final class LibraryIdentifier implements Identifier {
  /// The components of the identifier.
  NodeList<SimpleIdentifier> get components;
}

final class LibraryIdentifierImpl extends IdentifierImpl
    implements LibraryIdentifier {
  final NodeListImpl<SimpleIdentifierImpl> _components = NodeListImpl._();

  /// Initializes a newly created prefixed identifier.
  LibraryIdentifierImpl({
    required List<SimpleIdentifierImpl> components,
  }) {
    _components._initialize(this, components);
  }

  @override
  Token get beginToken => _components.beginToken!;

  @override
  NodeListImpl<SimpleIdentifierImpl> get components => _components;

  @override
  Token get endToken => _components.endToken!;

  @override
  String get name {
    StringBuffer buffer = StringBuffer();
    bool needsPeriod = false;
    int length = _components.length;
    for (int i = 0; i < length; i++) {
      SimpleIdentifier identifier = _components[i];
      if (needsPeriod) {
        buffer.write(".");
      } else {
        needsPeriod = true;
      }
      buffer.write(identifier.name);
    }
    return considerCanonicalizeString(buffer.toString());
  }

  @override
  Precedence get precedence => Precedence.postfix;

  @override
  Element? get staticElement => null;

  @override
  // TODO(paulberry): add "." tokens.
  ChildEntities get _childEntities =>
      ChildEntities()..addNodeList('components', components);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitLibraryIdentifier(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitLibraryIdentifier(this);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _components.accept(visitor);
  }
}

/// A list literal.
///
///    listLiteral ::=
///        'const'? [TypeAnnotationList]? '[' elements? ']'
///
///    elements ::=
///        [CollectionElement] (',' [CollectionElement])* ','?
abstract final class ListLiteral implements TypedLiteral {
  /// The syntactic elements used to compute the elements of the list.
  NodeList<CollectionElement> get elements;

  /// The left square bracket.
  Token get leftBracket;

  /// The right square bracket.
  Token get rightBracket;
}

final class ListLiteralImpl extends TypedLiteralImpl implements ListLiteral {
  @override
  final Token leftBracket;

  final NodeListImpl<CollectionElementImpl> _elements = NodeListImpl._();

  @override
  final Token rightBracket;

  /// Initializes a newly created list literal.
  ///
  /// The [constKeyword] can be `null` if the literal isn't a constant.
  ///
  /// The [typeArguments] can be `null` if no type arguments were declared.
  ///
  /// The list of [elements] can be `null` if the list is empty.
  ListLiteralImpl({
    required super.constKeyword,
    required super.typeArguments,
    required this.leftBracket,
    required List<CollectionElementImpl> elements,
    required this.rightBracket,
  }) {
    _elements._initialize(this, elements);
  }

  @override
  Token get beginToken {
    if (constKeyword case var constKeyword?) {
      return constKeyword;
    }
    var typeArguments = this.typeArguments;
    if (typeArguments != null) {
      return typeArguments.beginToken;
    }
    return leftBracket;
  }

  @override
  NodeListImpl<CollectionElementImpl> get elements => _elements;

  @override
  Token get endToken => rightBracket;

  @override
  // TODO(paulberry): add commas.
  ChildEntities get _childEntities => super._childEntities
    ..addToken('leftBracket', leftBracket)
    ..addNodeList('elements', elements)
    ..addToken('rightBracket', rightBracket);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitListLiteral(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitListLiteral(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _elements.accept(visitor);
  }
}

/// A list pattern.
///
///    listPattern ::=
///        [TypeArgumentList]? '[' [DartPattern] (',' [DartPattern])* ','? ']'
abstract final class ListPattern implements DartPattern {
  /// The elements in this pattern.
  NodeList<ListPatternElement> get elements;

  /// The left square bracket.
  Token get leftBracket;

  /// The required type, specified by [typeArguments] or inferred from the
  /// matched value type, or `null` if the node isn't resolved yet.
  DartType? get requiredType;

  /// The right square bracket.
  Token get rightBracket;

  /// The type arguments associated with this pattern, or `null` if no type
  /// arguments were declared.
  TypeArgumentList? get typeArguments;
}

/// An element of a list pattern.
sealed class ListPatternElement implements AstNode {}

abstract final class ListPatternElementImpl
    implements AstNodeImpl, ListPatternElement {}

final class ListPatternImpl extends DartPatternImpl implements ListPattern {
  @override
  final TypeArgumentListImpl? typeArguments;

  @override
  final Token leftBracket;

  final NodeListImpl<ListPatternElementImpl> _elements = NodeListImpl._();

  @override
  final Token rightBracket;

  @override
  DartType? requiredType;

  ListPatternImpl({
    required this.typeArguments,
    required this.leftBracket,
    required List<ListPatternElementImpl> elements,
    required this.rightBracket,
  }) {
    _becomeParentOf(typeArguments);
    _elements._initialize(this, elements);
  }

  @override
  Token get beginToken => typeArguments?.beginToken ?? leftBracket;

  @override
  NodeList<ListPatternElementImpl> get elements => _elements;

  @override
  Token get endToken => rightBracket;

  @override
  PatternPrecedence get precedence => PatternPrecedence.primary;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addNode('typeArguments', typeArguments)
    ..addToken('leftBracket', leftBracket)
    ..addNodeList('elements', elements)
    ..addToken('rightBracket', rightBracket);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitListPattern(this);

  @override
  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
    var elementType = typeArguments?.arguments.elementAtOrNull(0)?.typeOrThrow;
    return resolverVisitor
        .analyzeListPatternSchema(
          elementType: elementType?.wrapSharedTypeView(),
          elements: elements,
        )
        .unwrapTypeSchemaView();
  }

  @override
  PatternResult<DartType> resolvePattern(
    ResolverVisitor resolverVisitor,
    SharedMatchContext context,
  ) {
    inferenceLogWriter?.enterPattern(this);
    var analysisResult = resolverVisitor.listPatternResolver
        .resolve(node: this, context: context);
    inferenceLogWriter?.exitPattern(this);
    return analysisResult;
  }

  @override
  void visitChildren(AstVisitor visitor) {
    typeArguments?.accept(visitor);
    elements.accept(visitor);
  }
}

/// A node that represents a literal expression.
///
///    literal ::=
///        [BooleanLiteral]
///      | [DoubleLiteral]
///      | [IntegerLiteral]
///      | [ListLiteral]
///      | [NullLiteral]
///      | [SetOrMapLiteral]
///      | [StringLiteral]
sealed class Literal implements Expression {}

sealed class LiteralImpl extends ExpressionImpl implements Literal {
  @override
  Precedence get precedence => Precedence.primary;
}

// TODO(scheglov): parse into actual `LocalFunctionDeclarationImpl`.
class LocalFunctionDeclarationView {
  final FunctionDeclarationImpl declaration;

  LocalFunctionDeclarationView(this.declaration);

  LocalFunctionElement? get declaredElement {
    return declaration.declaredElement2;
  }

  static LocalFunctionDeclarationView? of(AstNode declaration) {
    if (declaration is FunctionDeclarationImpl) {
      if (declaration.parent is FunctionDeclarationStatement) {
        return LocalFunctionDeclarationView(declaration);
      }
    }
    return null;
  }
}

/// Additional information about local variables within a function or method
/// produced at resolution time.
class LocalVariableInfo {
  /// The set of local variables and parameters that are potentially mutated
  /// within the scope of their declarations.
  final Set<VariableElement> potentiallyMutatedInScope = <VariableElement>{};
}

/// A logical-and pattern.
///
///    logicalAndPattern ::=
///        [DartPattern] '&&' [DartPattern]
abstract final class LogicalAndPattern implements DartPattern {
  /// The left sub-pattern.
  DartPattern get leftOperand;

  /// The `&&` operator.
  Token get operator;

  /// The right sub-pattern.
  DartPattern get rightOperand;
}

final class LogicalAndPatternImpl extends DartPatternImpl
    implements LogicalAndPattern {
  @override
  final DartPatternImpl leftOperand;

  @override
  final Token operator;

  @override
  final DartPatternImpl rightOperand;

  LogicalAndPatternImpl({
    required this.leftOperand,
    required this.operator,
    required this.rightOperand,
  }) {
    _becomeParentOf(leftOperand);
    _becomeParentOf(rightOperand);
  }

  @override
  Token get beginToken => leftOperand.beginToken;

  @override
  Token get endToken => rightOperand.endToken;

  @override
  PatternPrecedence get precedence => PatternPrecedence.logicalAnd;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addNode('leftOperand', leftOperand)
    ..addToken('operator', operator)
    ..addNode('rightOperand', rightOperand);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitLogicalAndPattern(this);

  @override
  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
    return resolverVisitor
        .analyzeLogicalAndPatternSchema(leftOperand, rightOperand)
        .unwrapTypeSchemaView();
  }

  @override
  PatternResult<DartType> resolvePattern(
    ResolverVisitor resolverVisitor,
    SharedMatchContext context,
  ) {
    inferenceLogWriter?.enterPattern(this);
    var analysisResult = resolverVisitor.analyzeLogicalAndPattern(
        context, this, leftOperand, rightOperand);
    inferenceLogWriter?.exitPattern(this);
    return analysisResult;
  }

  @override
  void visitChildren(AstVisitor visitor) {
    leftOperand.accept(visitor);
    rightOperand.accept(visitor);
  }
}

/// A logical-or pattern.
///
///    logicalOrPattern ::=
///        [DartPattern] '||' [DartPattern]
abstract final class LogicalOrPattern implements DartPattern {
  /// The left sub-pattern.
  DartPattern get leftOperand;

  /// The `||` operator.
  Token get operator;

  /// The right sub-pattern.
  DartPattern get rightOperand;
}

final class LogicalOrPatternImpl extends DartPatternImpl
    implements LogicalOrPattern {
  @override
  final DartPatternImpl leftOperand;

  @override
  final Token operator;

  @override
  final DartPatternImpl rightOperand;

  LogicalOrPatternImpl({
    required this.leftOperand,
    required this.operator,
    required this.rightOperand,
  }) {
    _becomeParentOf(leftOperand);
    _becomeParentOf(rightOperand);
  }

  @override
  Token get beginToken => leftOperand.beginToken;

  @override
  Token get endToken => rightOperand.endToken;

  @override
  PatternPrecedence get precedence => PatternPrecedence.logicalOr;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addNode('leftOperand', leftOperand)
    ..addToken('operator', operator)
    ..addNode('rightOperand', rightOperand);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitLogicalOrPattern(this);

  @override
  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
    return resolverVisitor
        .analyzeLogicalOrPatternSchema(leftOperand, rightOperand)
        .unwrapTypeSchemaView();
  }

  @override
  PatternResult<DartType> resolvePattern(
    ResolverVisitor resolverVisitor,
    SharedMatchContext context,
  ) {
    inferenceLogWriter?.enterPattern(this);
    var analysisResult = resolverVisitor.analyzeLogicalOrPattern(
        context, this, leftOperand, rightOperand);
    resolverVisitor.nullSafetyDeadCodeVerifier.flowEnd(rightOperand);
    inferenceLogWriter?.exitPattern(this);
    return analysisResult;
  }

  @override
  void visitChildren(AstVisitor visitor) {
    leftOperand.accept(visitor);
    rightOperand.accept(visitor);
  }
}

/// A single key/value pair in a map literal.
///
///    mapLiteralEntry ::=
///        '?'? [Expression] ':' '?'? [Expression]
abstract final class MapLiteralEntry implements CollectionElement {
  /// The expression computing the key with which the value is associated.
  Expression get key;

  /// The question prefix for the key that may present in null-aware map
  /// entries.
  Token? get keyQuestion;

  /// The colon that separates the key from the value.
  Token get separator;

  /// The expression computing the value that is associated with the key.
  Expression get value;

  /// The question prefix for the value that may present in null-aware map
  /// entries.
  Token? get valueQuestion;
}

final class MapLiteralEntryImpl extends CollectionElementImpl
    implements MapLiteralEntry {
  @override
  final Token? keyQuestion;

  ExpressionImpl _key;

  @override
  final Token separator;

  @override
  final Token? valueQuestion;

  ExpressionImpl _value;

  /// Initializes a newly created map literal entry.
  MapLiteralEntryImpl({
    required this.keyQuestion,
    required ExpressionImpl key,
    required this.separator,
    required this.valueQuestion,
    required ExpressionImpl value,
  })  : _key = key,
        _value = value {
    _becomeParentOf(_key);
    _becomeParentOf(_value);
  }

  @override
  Token get beginToken => keyQuestion ?? _key.beginToken;

  @override
  Token get endToken => _value.endToken;

  @override
  ExpressionImpl get key => _key;

  set key(ExpressionImpl string) {
    _key = _becomeParentOf(string);
  }

  @override
  ExpressionImpl get value => _value;

  set value(ExpressionImpl expression) {
    _value = _becomeParentOf(expression);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('keyQuestion', keyQuestion)
    ..addNode('key', key)
    ..addToken('separator', separator)
    ..addToken('valueQuestion', valueQuestion)
    ..addNode('value', value);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitMapLiteralEntry(this);

  @override
  void resolveElement(
      ResolverVisitor resolver, CollectionLiteralContext? context) {
    resolver.visitMapLiteralEntry(this, context: context);
    resolver.pushRewrite(null);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _key.accept(visitor);
    _value.accept(visitor);
  }
}

/// A map pattern.
///
///    mapPattern ::=
///        [TypeArgumentList]? '{' [MapPatternEntry] (',' [MapPatternEntry])*
///        ','? '}'
abstract final class MapPattern implements DartPattern {
  /// The elements in this pattern.
  NodeList<MapPatternElement> get elements;

  /// The left curly bracket.
  Token get leftBracket;

  /// The matched value type, or `null` if the node isn't resolved yet.
  DartType? get requiredType;

  /// The right curly bracket.
  Token get rightBracket;

  /// The type arguments associated with this pattern, or `null` if no type
  /// arguments were declared.
  TypeArgumentList? get typeArguments;
}

/// An element of a map pattern.
sealed class MapPatternElement implements AstNode {}

sealed class MapPatternElementImpl implements AstNodeImpl, MapPatternElement {}

/// An entry in a map pattern.
///
///    mapPatternEntry ::=
///        [Expression] ':' [DartPattern]
abstract final class MapPatternEntry implements AstNode, MapPatternElement {
  /// The expression computing the key of the entry to be matched.
  Expression get key;

  /// The colon that separates the key from the value.
  Token get separator;

  /// The pattern used to match the value.
  DartPattern get value;
}

final class MapPatternEntryImpl extends AstNodeImpl
    implements MapPatternEntry, MapPatternElementImpl {
  ExpressionImpl _key;

  @override
  final Token separator;

  @override
  final DartPatternImpl value;

  MapPatternEntryImpl({
    required ExpressionImpl key,
    required this.separator,
    required this.value,
  }) : _key = key {
    _becomeParentOf(_key);
    _becomeParentOf(value);
  }

  @override
  Token get beginToken => key.beginToken;

  @override
  Token get endToken => value.endToken;

  @override
  ExpressionImpl get key => _key;

  set key(ExpressionImpl key) {
    _key = _becomeParentOf(key);
  }

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addNode('key', key)
    ..addToken('separator', separator)
    ..addNode('value', value);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitMapPatternEntry(this);

  @override
  void visitChildren(AstVisitor visitor) {
    key.accept(visitor);
    value.accept(visitor);
  }
}

final class MapPatternImpl extends DartPatternImpl implements MapPattern {
  @override
  final TypeArgumentListImpl? typeArguments;

  @override
  final Token leftBracket;

  final NodeListImpl<MapPatternElementImpl> _elements = NodeListImpl._();

  @override
  final Token rightBracket;

  @override
  DartType? requiredType;

  MapPatternImpl({
    required this.typeArguments,
    required this.leftBracket,
    required List<MapPatternElementImpl> elements,
    required this.rightBracket,
  }) {
    _becomeParentOf(typeArguments);
    _elements._initialize(this, elements);
  }

  @override
  Token get beginToken => typeArguments?.beginToken ?? leftBracket;

  @override
  NodeList<MapPatternElementImpl> get elements => _elements;

  @override
  Token get endToken => rightBracket;

  @override
  PatternPrecedence get precedence => PatternPrecedence.primary;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addNode('typeArguments', typeArguments)
    ..addToken('leftBracket', leftBracket)
    ..addNodeList('elements', elements)
    ..addToken('rightBracket', rightBracket);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitMapPattern(this);

  @override
  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
    var typeArgumentNodes = this.typeArguments?.arguments;
    ({
      SharedTypeView<DartType> keyType,
      SharedTypeView<DartType> valueType
    })? typeArguments;
    if (typeArgumentNodes != null && typeArgumentNodes.length == 2) {
      typeArguments = (
        keyType: SharedTypeView(typeArgumentNodes[0].typeOrThrow),
        valueType: SharedTypeView(typeArgumentNodes[1].typeOrThrow),
      );
    }
    return resolverVisitor
        .analyzeMapPatternSchema(
          typeArguments: typeArguments,
          elements: elements,
        )
        .unwrapTypeSchemaView();
  }

  @override
  PatternResult<DartType> resolvePattern(
    ResolverVisitor resolverVisitor,
    SharedMatchContext context,
  ) {
    return resolverVisitor.resolveMapPattern(node: this, context: context);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    typeArguments?.accept(visitor);
    elements.accept(visitor);
  }
}

/// A method declaration.
///
///    methodDeclaration ::=
///        methodSignature [FunctionBody]
///
///    methodSignature ::=
///        'external'? ('abstract' | 'static')? [Type]? ('get' | 'set')?
///        methodName [TypeParameterList] [FormalParameterList]
///
///    methodName ::=
///        [SimpleIdentifier]
///      | 'operator' [SimpleIdentifier]
///
/// Prior to the 'extension-methods' experiment, these nodes were always
/// children of a class declaration. When the experiment is enabled, these nodes
/// can also be children of an extension declaration.
abstract final class MethodDeclaration
    implements ClassMember, FragmentDeclaration {
  /// The token for the `augment` keyword.
  Token? get augmentKeyword;

  /// The body of the method.
  FunctionBody get body;

  @override
  ExecutableElement? get declaredElement;

  @experimental
  @override
  ExecutableFragment? get declaredFragment;

  /// The token for the `external` keyword, or `null` if the constructor isn't
  /// external.
  Token? get externalKeyword;

  /// Whether this method is declared to be an abstract method.
  bool get isAbstract;

  /// Whether this method declares a getter.
  bool get isGetter;

  /// Whether this method declares an operator.
  bool get isOperator;

  /// Whether this method declares a setter.
  bool get isSetter;

  /// Whether this method is declared to be a static method.
  bool get isStatic;

  /// The token representing the `abstract` or `static` keyword, or `null` if
  /// neither modifier was specified.
  Token? get modifierKeyword;

  /// The name of the method.
  Token get name;

  /// The token representing the `operator` keyword, or `null` if this method
  /// doesn't declare an operator.
  Token? get operatorKeyword;

  /// The parameters associated with the method, or `null` if this method
  /// declares a getter.
  FormalParameterList? get parameters;

  /// The token representing the `get` or `set` keyword, or `null` if this is a
  /// method declaration rather than a property
  /// declaration.
  Token? get propertyKeyword;

  /// The return type of the method, or `null` if no return type was declared.
  TypeAnnotation? get returnType;

  /// The type parameters associated with this method, or `null` if this method
  /// isn't a generic method.
  TypeParameterList? get typeParameters;
}

final class MethodDeclarationImpl extends ClassMemberImpl
    with AstNodeWithNameScopeMixin
    implements MethodDeclaration {
  @override
  final Token? augmentKeyword;

  @override
  final Token? externalKeyword;

  @override
  final Token? modifierKeyword;

  @override
  final TypeAnnotationImpl? returnType;

  @override
  final Token? propertyKeyword;

  @override
  final Token? operatorKeyword;

  @override
  final Token name;

  @override
  final TypeParameterListImpl? typeParameters;

  @override
  final FormalParameterListImpl? parameters;

  @override
  final FunctionBodyImpl body;

  @override
  ExecutableElementImpl? declaredElement;

  MethodDeclarationImpl({
    required super.comment,
    required super.metadata,
    required this.augmentKeyword,
    required this.externalKeyword,
    required this.modifierKeyword,
    required this.returnType,
    required this.propertyKeyword,
    required this.operatorKeyword,
    required this.name,
    required this.typeParameters,
    required this.parameters,
    required this.body,
  }) {
    _becomeParentOf(returnType);
    _becomeParentOf(typeParameters);
    _becomeParentOf(parameters);
    _becomeParentOf(body);
  }

  @experimental
  @override
  ExecutableFragment? get declaredFragment =>
      declaredElement as ExecutableFragment?;

  @override
  Token get endToken => body.endToken;

  @override
  Token get firstTokenAfterCommentAndMetadata {
    return augmentKeyword ??
        Token.lexicallyFirst(externalKeyword, modifierKeyword) ??
        returnType?.beginToken ??
        Token.lexicallyFirst(propertyKeyword, operatorKeyword) ??
        name;
  }

  @override
  bool get isAbstract {
    var body = this.body;
    return externalKeyword == null &&
        (body is EmptyFunctionBodyImpl && !body.semicolon.isSynthetic);
  }

  @override
  bool get isGetter => propertyKeyword?.keyword == Keyword.GET;

  @override
  bool get isOperator => operatorKeyword != null;

  @override
  bool get isSetter => propertyKeyword?.keyword == Keyword.SET;

  @override
  bool get isStatic => modifierKeyword?.keyword == Keyword.STATIC;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('augmentKeyword', augmentKeyword)
    ..addToken('externalKeyword', externalKeyword)
    ..addToken('modifierKeyword', modifierKeyword)
    ..addNode('returnType', returnType)
    ..addToken('propertyKeyword', propertyKeyword)
    ..addToken('operatorKeyword', operatorKeyword)
    ..addToken('name', name)
    ..addNode('typeParameters', typeParameters)
    ..addNode('parameters', parameters)
    ..addNode('body', body);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitMethodDeclaration(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    returnType?.accept(visitor);
    typeParameters?.accept(visitor);
    parameters?.accept(visitor);
    body.accept(visitor);
  }
}

/// The invocation of either a function or a method.
///
/// Invocations of functions resulting from evaluating an expression are
/// represented by [FunctionExpressionInvocation] nodes. Invocations of getters
/// and setters are represented by either [PrefixedIdentifier] or
/// [PropertyAccess] nodes.
///
///    methodInvocation ::=
///        ([Expression] '.')? [SimpleIdentifier] [TypeArgumentList]?
///        [ArgumentList]
abstract final class MethodInvocation
    implements NullShortableExpression, InvocationExpression {
  /// Whether this expression is cascaded.
  ///
  /// If it is, then the target of this expression isn't stored locally but is
  /// stored in the nearest ancestor that is a [CascadeExpression].
  bool get isCascaded;

  /// Whether this method invocation is null aware (as opposed to non-null).
  bool get isNullAware;

  /// The name of the method being invoked.
  SimpleIdentifier get methodName;

  /// The operator that separates the target from the method name, or `null` if
  /// there's no target.
  ///
  /// In an ordinary method invocation this is either a period (`.`) or a
  /// null-aware opertator (`?.`). In a cascade section this is the cascade
  /// operator ('..').
  Token? get operator;

  /// The expression used to compute the receiver of the invocation.
  ///
  /// If this invocation isn't part of a cascade expression, then this is the
  /// same as [target]. If this invocation is part of a cascade expression,
  /// then the target stored with the cascade expression is returned.
  Expression? get realTarget;

  /// The expression producing the object on which the method is defined, or
  /// `null` if there's no target (that is, the target is implicitly `this`) or
  /// if this method invocation is part of a cascade expression.
  ///
  /// Use [realTarget] to get the target independent of whether this is part of
  /// a cascade expression.
  Expression? get target;
}

final class MethodInvocationImpl extends InvocationExpressionImpl
    with NullShortableExpressionImpl
    implements MethodInvocation {
  ExpressionImpl? _target;

  @override
  Token? operator;

  SimpleIdentifierImpl _methodName;

  /// The invoke type of the [methodName] if the target element is a getter,
  /// or `null` otherwise.
  DartType? _methodNameType;

  /// Initializes a newly created method invocation.
  ///
  /// The [target] and [operator] can be `null` if there's no target.
  MethodInvocationImpl({
    required ExpressionImpl? target,
    required this.operator,
    required SimpleIdentifierImpl methodName,
    required super.typeArguments,
    required super.argumentList,
  })  : _target = target,
        _methodName = methodName {
    _becomeParentOf(_target);
    _becomeParentOf(_methodName);
  }

  @override
  Token get beginToken {
    if (target case var target?) {
      return target.beginToken;
    } else if (operator case var operator?) {
      return operator;
    }
    return _methodName.beginToken;
  }

  @override
  Token get endToken => _argumentList.endToken;

  @override
  ExpressionImpl get function => methodName;

  @override
  bool get isCascaded =>
      operator != null &&
      (operator!.type == TokenType.PERIOD_PERIOD ||
          operator!.type == TokenType.QUESTION_PERIOD_PERIOD);

  @override
  bool get isNullAware {
    if (isCascaded) {
      return _ancestorCascade.isNullAware;
    }
    return operator != null &&
        (operator!.type == TokenType.QUESTION_PERIOD ||
            operator!.type == TokenType.QUESTION_PERIOD_PERIOD);
  }

  @override
  SimpleIdentifierImpl get methodName => _methodName;

  set methodName(SimpleIdentifierImpl identifier) {
    _methodName = _becomeParentOf(identifier);
  }

  /// The invoke type of the [methodName].
  ///
  /// If the target element is a [MethodElement], this is the same as the
  /// [staticInvokeType].
  ///
  /// If the target element is a getter, presumably returning an
  /// [ExecutableElement] so that it can be invoked in this [MethodInvocation],
  /// then this type is the type of the getter, and the [staticInvokeType] is
  /// the invoked type of the returned element.
  DartType? get methodNameType => _methodNameType ?? staticInvokeType;

  set methodNameType(DartType? methodNameType) {
    _methodNameType = methodNameType;
  }

  @override
  Precedence get precedence => Precedence.postfix;

  @override
  ExpressionImpl? get realTarget {
    if (isCascaded) {
      return _ancestorCascade.target;
    }
    return _target;
  }

  @override
  ExpressionImpl? get target => _target;

  set target(ExpressionImpl? expression) {
    _target = _becomeParentOf(expression);
  }

  /// The cascade that contains this [IndexExpression].
  ///
  /// We expect that [isCascaded] is `true`.
  CascadeExpressionImpl get _ancestorCascade {
    assert(isCascaded);
    for (var ancestor = parent!;; ancestor = ancestor.parent!) {
      if (ancestor is CascadeExpressionImpl) {
        return ancestor;
      }
    }
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('target', target)
    ..addToken('operator', operator)
    ..addNode('methodName', methodName)
    ..addNode('typeArguments', typeArguments)
    ..addNode('argumentList', argumentList);

  @override
  AstNode? get _nullShortingExtensionCandidate => parent;

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitMethodInvocation(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitMethodInvocation(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _target?.accept(visitor);
    _methodName.accept(visitor);
    _typeArguments?.accept(visitor);
    _argumentList.accept(visitor);
  }

  @override
  bool _extendsNullShorting(Expression descendant) =>
      identical(descendant, _target);
}

/// An expression that implicitly makes reference to a method.
abstract final class MethodReferenceExpression implements Expression {
  /// The element associated with the expression based on the static types.
  ///
  /// Returns`null` if the AST structure hasn't been resolved, or there's no
  /// meaningful element to return. The latter case can occur, for example, when
  /// this is a non-compound assignment expression, or when the method referred
  /// to couldn't be resolved.
  @experimental
  MethodElement2? get element;

  /// The element associated with the expression based on the static types, or
  /// `null` if the AST structure hasn't been resolved, or there's no meaningful
  /// static element to return. The latter case can occur, for example, when
  /// this is a non-compound assignment expression, or when the method referred
  /// to couldn't be resolved.
  MethodElement? get staticElement;
}

/// The declaration of a mixin.
///
///    mixinDeclaration ::=
///        'base'? 'mixin' name [TypeParameterList]?
///        [OnClause]? [ImplementsClause]? '{' [ClassMember]* '}'
abstract final class MixinDeclaration
    implements NamedCompilationUnitMember, FragmentDeclaration {
  /// The `augment` keyword, or `null` if the keyword was absent.
  Token? get augmentKeyword;

  /// The `base` keyword, or `null` if the keyword was absent.
  Token? get baseKeyword;

  @override
  MixinElement? get declaredElement;

  @experimental
  @override
  MixinFragment? get declaredFragment;

  /// The `implements` clause for the mixin, or `null` if the mixin doesn't
  /// implement any interfaces.
  ImplementsClause? get implementsClause;

  /// The left curly bracket.
  Token get leftBracket;

  /// The members defined by the mixin.
  NodeList<ClassMember> get members;

  /// The token representing the `mixin` keyword.
  Token get mixinKeyword;

  /// The on clause for the mixin, or `null` if the mixin doesn't have any
  /// superclass constraints.
  MixinOnClause? get onClause;

  /// The right curly bracket.
  Token get rightBracket;

  /// The type parameters for the mixin, or `null` if the mixin doesn't have any
  /// type parameters.
  TypeParameterList? get typeParameters;
}

final class MixinDeclarationImpl extends NamedCompilationUnitMemberImpl
    with AstNodeWithNameScopeMixin
    implements MixinDeclaration {
  @override
  final Token? augmentKeyword;

  @override
  final Token? baseKeyword;

  @override
  final Token mixinKeyword;

  @override
  final TypeParameterListImpl? typeParameters;

  @override
  final MixinOnClauseImpl? onClause;

  @override
  final ImplementsClauseImpl? implementsClause;

  @override
  final Token leftBracket;

  @override
  final NodeListImpl<ClassMemberImpl> members = NodeListImpl._();

  @override
  final Token rightBracket;

  @override
  MixinElementImpl? declaredElement;

  MixinDeclarationImpl({
    required super.comment,
    required super.metadata,
    required this.augmentKeyword,
    required this.baseKeyword,
    required this.mixinKeyword,
    required super.name,
    required this.typeParameters,
    required this.onClause,
    required this.implementsClause,
    required this.leftBracket,
    required List<ClassMemberImpl> members,
    required this.rightBracket,
  }) {
    _becomeParentOf(typeParameters);
    _becomeParentOf(onClause);
    _becomeParentOf(implementsClause);
    this.members._initialize(this, members);
  }

  @experimental
  @override
  MixinFragment? get declaredFragment => declaredElement as MixinFragment?;

  @override
  Token get endToken => rightBracket;

  @override
  Token get firstTokenAfterCommentAndMetadata {
    return augmentKeyword ?? baseKeyword ?? mixinKeyword;
  }

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('augmentKeyword', augmentKeyword)
    ..addToken('baseKeyword', baseKeyword)
    ..addToken('mixinKeyword', mixinKeyword)
    ..addToken('name', name)
    ..addNode('typeParameters', typeParameters)
    ..addNode('onClause', onClause)
    ..addNode('implementsClause', implementsClause)
    ..addToken('leftBracket', leftBracket)
    ..addNodeList('members', members)
    ..addToken('rightBracket', rightBracket);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitMixinDeclaration(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    typeParameters?.accept(visitor);
    onClause?.accept(visitor);
    implementsClause?.accept(visitor);
    members.accept(visitor);
  }
}

/// The "on" clause in a mixin declaration.
///
///    onClause ::=
///        'on' [NamedType] (',' [NamedType])*
abstract final class MixinOnClause implements AstNode {
  /// The token representing the `on` keyword.
  Token get onKeyword;

  /// The list of the classes are superclass constraints for the mixin.
  NodeList<NamedType> get superclassConstraints;
}

final class MixinOnClauseImpl extends AstNodeImpl implements MixinOnClause {
  @override
  final Token onKeyword;

  final NodeListImpl<NamedTypeImpl> _superclassConstraints = NodeListImpl._();

  MixinOnClauseImpl({
    required this.onKeyword,
    required List<NamedTypeImpl> superclassConstraints,
  }) {
    _superclassConstraints._initialize(this, superclassConstraints);
  }

  @override
  Token get beginToken => onKeyword;

  @override
  Token get endToken => _superclassConstraints.endToken ?? onKeyword;

  @override
  NodeListImpl<NamedTypeImpl> get superclassConstraints =>
      _superclassConstraints;

  @override
  // TODO(paulberry): add commas.
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('onKeyword', onKeyword)
    ..addNodeList('superclassConstraints', superclassConstraints);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitMixinOnClause(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _superclassConstraints.accept(visitor);
  }
}

/// A node that declares a single name within the scope of a compilation unit.
abstract final class NamedCompilationUnitMember
    implements CompilationUnitMember {
  /// The name of the member being declared.
  Token get name;
}

sealed class NamedCompilationUnitMemberImpl extends CompilationUnitMemberImpl
    implements NamedCompilationUnitMember {
  @override
  final Token name;

  /// Initializes a newly created compilation unit member with the given [name].
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the member
  /// doesn't have the corresponding attribute.
  NamedCompilationUnitMemberImpl({
    required super.comment,
    required super.metadata,
    required this.name,
  });
}

/// An expression that has a name associated with it.
///
/// They are only used in method invocations when there are named parameters.
///
///    namedExpression ::=
///        [Label] [Expression]
abstract final class NamedExpression implements Expression {
  /// The element representing the parameter being named by this expression, or
  /// `null` if the AST structure hasn't been resolved or if there's no
  /// parameter with the same name as this expression.
  ParameterElement? get element;

  /// The element representing the parameter being named by this expression.
  ///
  /// Returns `null` if the AST structure hasn't been resolved or if there's no
  /// parameter with the same name as this expression.
  @experimental
  FormalParameterElement? get element2;

  /// The expression with which the name is associated.
  Expression get expression;

  /// The name associated with the expression.
  Label get name;
}

final class NamedExpressionImpl extends ExpressionImpl
    implements NamedExpression {
  LabelImpl _name;

  ExpressionImpl _expression;

  /// Initializes a newly created named expression.
  NamedExpressionImpl({
    required LabelImpl name,
    required ExpressionImpl expression,
  })  : _name = name,
        _expression = expression {
    _becomeParentOf(_name);
    _becomeParentOf(_expression);
  }

  @override
  Token get beginToken => _name.beginToken;

  @override
  ParameterElement? get element {
    var element = _name.label.staticElement;
    if (element is ParameterElement) {
      return element;
    }
    return null;
  }

  @experimental
  @override
  FormalParameterElement? get element2 {
    if (element case FormalParameterFragment fragment) {
      return fragment.element;
    }
    return null;
  }

  @override
  Token get endToken => _expression.endToken;

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  LabelImpl get name => _name;

  set name(LabelImpl identifier) {
    _name = _becomeParentOf(identifier);
  }

  @override
  Precedence get precedence => Precedence.none;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('name', name)
    ..addNode('expression', expression);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitNamedExpression(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitNamedExpression(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _name.accept(visitor);
    _expression.accept(visitor);
  }
}

/// A named type, which can optionally include type arguments.
///
///    namedType ::=
///        [ImportPrefixReference]? name typeArguments?
abstract final class NamedType implements TypeAnnotation {
  /// The element of [name2] considering [importPrefix] for example a
  /// [ClassElement], or [TypeAliasElement], or `null` if [name2] can't be
  /// resolved, or there's no element for the type name, such as for `void`.
  Element? get element;

  /// The element of [name2] considering [importPrefix].
  ///
  /// This could be a [ClassElement], [TypeAliasElement], or other type defining
  /// element.
  ///
  /// Returns `null` if [name2] can't be resolved, or there's no element for the
  /// type name, such as for `void`.
  @experimental
  Element2? get element2;

  /// The optional import prefix before [name2].
  ImportPrefixReference? get importPrefix;

  /// Whether this type is a deferred type.
  ///
  /// A deferred type is a type that is referenced through an import prefix
  /// (such as `p.T`), where the prefix is used by a deferred import.
  ///
  /// Returns `false` if the AST structure hasn't been resolved.
  bool get isDeferred;

  /// The name of the type.
  Token get name2;

  /// The type being named, or `null` if the AST structure hasn't been resolved,
  /// or if this is part of a [ConstructorReference].
  @override
  DartType? get type;

  /// The type arguments associated with the type, or `null` if there are no
  /// type arguments.
  TypeArgumentList? get typeArguments;
}

final class NamedTypeImpl extends TypeAnnotationImpl implements NamedType {
  ImportPrefixReferenceImpl? _importPrefix;

  @override
  final Token name2;

  @experimental
  @override
  Element2? element2;

  @override
  TypeArgumentListImpl? typeArguments;

  @override
  final Token? question;

  @override
  DartType? type;

  /// Initializes a newly created type name.
  ///
  /// The [typeArguments] can be `null` if there are no type arguments.
  NamedTypeImpl({
    required ImportPrefixReferenceImpl? importPrefix,
    required this.name2,
    required this.typeArguments,
    required this.question,
  }) {
    this.importPrefix = importPrefix;
    _becomeParentOf(typeArguments);
  }

  @override
  Token get beginToken => importPrefix?.beginToken ?? name2;

  @override
  Element? get element {
    return element2.asElement;
  }

  @override
  Token get endToken => question ?? typeArguments?.endToken ?? name2;

  @override
  ImportPrefixReferenceImpl? get importPrefix {
    return _importPrefix;
  }

  set importPrefix(ImportPrefixReferenceImpl? value) {
    _importPrefix = value;
    _becomeParentOf(value);
  }

  @override
  bool get isDeferred {
    var importPrefixElement = importPrefix?.element;
    if (importPrefixElement is PrefixElement) {
      var imports = importPrefixElement.imports;
      if (imports.length != 1) {
        return false;
      }
      return imports[0].prefix is DeferredImportElementPrefix;
    }
    return false;
  }

  @override
  bool get isSynthetic => name2.isSynthetic && typeArguments == null;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('importPrefix', importPrefix)
    ..addToken('name', name2)
    ..addNode('typeArguments', typeArguments)
    ..addToken('question', question);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitNamedType(this);

  @override
  void visitChildren(AstVisitor visitor) {
    importPrefix?.accept(visitor);
    typeArguments?.accept(visitor);
  }
}

/// A node that represents a directive that impacts the namespace of a library.
///
///    directive ::=
///        [ExportDirective]
///      | [ImportDirective]
sealed class NamespaceDirective implements UriBasedDirective {
  /// The combinators used to control how names are imported or exported.
  NodeList<Combinator> get combinators;

  /// The configurations used to control which library is actually loaded at
  /// run-time.
  NodeList<Configuration> get configurations;

  /// The semicolon terminating the directive.
  Token get semicolon;
}

sealed class NamespaceDirectiveImpl extends UriBasedDirectiveImpl
    implements NamespaceDirective {
  final NodeListImpl<ConfigurationImpl> _configurations = NodeListImpl._();

  final NodeListImpl<CombinatorImpl> _combinators = NodeListImpl._();

  @override
  final Token semicolon;

  /// Initializes a newly created namespace directive.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// directive doesn't have the corresponding attribute.
  ///
  /// The list of [combinators] can be `null` if there are no combinators.
  NamespaceDirectiveImpl({
    required super.comment,
    required super.metadata,
    required super.uri,
    required List<ConfigurationImpl>? configurations,
    required List<CombinatorImpl>? combinators,
    required this.semicolon,
  }) {
    _configurations._initialize(this, configurations);
    _combinators._initialize(this, combinators);
  }

  @override
  NodeListImpl<CombinatorImpl> get combinators => _combinators;

  @override
  NodeListImpl<ConfigurationImpl> get configurations => _configurations;

  @override
  Token get endToken => semicolon;
}

/// The "native" clause in an class declaration.
///
///    nativeClause ::=
///        'native' [StringLiteral]
abstract final class NativeClause implements AstNode {
  /// The name of the native object that implements the class.
  StringLiteral? get name;

  /// The token representing the `native` keyword.
  Token get nativeKeyword;
}

final class NativeClauseImpl extends AstNodeImpl implements NativeClause {
  @override
  final Token nativeKeyword;

  @override
  final StringLiteralImpl? name;

  /// Initializes a newly created native clause.
  NativeClauseImpl({
    required this.nativeKeyword,
    required this.name,
  }) {
    _becomeParentOf(name);
  }

  @override
  Token get beginToken => nativeKeyword;

  @override
  Token get endToken {
    return name?.endToken ?? nativeKeyword;
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('nativeKeyword', nativeKeyword)
    ..addNode('name', name);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitNativeClause(this);

  @override
  void visitChildren(AstVisitor visitor) {
    name?.accept(visitor);
  }
}

/// A function body that consists of a native keyword followed by a string
/// literal.
///
///    nativeFunctionBody ::=
///        'native' [SimpleStringLiteral] ';'
abstract final class NativeFunctionBody implements FunctionBody {
  /// The token representing 'native' that marks the start of the function body.
  Token get nativeKeyword;

  /// The token representing the semicolon that marks the end of the function
  /// body.
  Token get semicolon;

  /// The string literal representing the string after the 'native' token.
  StringLiteral? get stringLiteral;
}

final class NativeFunctionBodyImpl extends FunctionBodyImpl
    implements NativeFunctionBody {
  @override
  final Token nativeKeyword;

  StringLiteralImpl? _stringLiteral;

  @override
  final Token semicolon;

  /// Initializes a newly created function body consisting of the 'native'
  /// token, a string literal, and a semicolon.
  NativeFunctionBodyImpl({
    required this.nativeKeyword,
    required StringLiteralImpl? stringLiteral,
    required this.semicolon,
  }) : _stringLiteral = stringLiteral {
    _becomeParentOf(_stringLiteral);
  }

  @override
  Token get beginToken => nativeKeyword;

  @override
  Token get endToken => semicolon;

  @override
  StringLiteralImpl? get stringLiteral => _stringLiteral;

  set stringLiteral(StringLiteralImpl? stringLiteral) {
    _stringLiteral = _becomeParentOf(stringLiteral);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('nativeKeyword', nativeKeyword)
    ..addNode('stringLiteral', stringLiteral)
    ..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitNativeFunctionBody(this);

  @override
  DartType resolve(ResolverVisitor resolver, DartType? imposedType) =>
      resolver.visitNativeFunctionBody(this, imposedType: imposedType);

  @override
  void visitChildren(AstVisitor visitor) {
    _stringLiteral?.accept(visitor);
  }
}

/// A list of AST nodes that have a common parent.
abstract final class NodeList<E extends AstNode> implements List<E> {
  /// The first token included in this node list's source range, or `null` if
  /// the list is empty.
  Token? get beginToken;

  /// The last token included in this node list's source range, or `null` if the
  /// list is empty.
  Token? get endToken;

  @Deprecated('NodeList cannot be resized')
  @override
  set length(int newLength);

  /// The node that is the parent of each of the elements in the list.
  AstNode get owner;

  /// Returns the node at the given [index] in the list or throw a [RangeError]
  /// if [index] is out of bounds.
  @override
  E operator [](int index);

  /// Use the given [visitor] to visit each of the nodes in this list.
  void accept(AstVisitor visitor);

  @Deprecated('NodeList cannot be resized')
  @override
  void add(E element);

  @Deprecated('NodeList cannot be resized')
  @override
  void addAll(Iterable<E> iterable);

  @Deprecated('NodeList cannot be resized')
  @override
  void clear();

  @Deprecated('NodeList cannot be resized')
  @override
  void insert(int index, E element);

  @Deprecated('NodeList cannot be resized')
  @override
  E removeAt(int index);
}

final class NodeListImpl<E extends AstNode>
    with ListMixin<E>
    implements NodeList<E> {
  late final AstNodeImpl _owner;

  late final List<E> _elements;

  /// Initializes a newly created list of nodes such that all of the nodes that
  /// are added to the list have their parent set to the given [owner].
  NodeListImpl(AstNodeImpl owner) : _owner = owner;

  /// Create a partially initialized instance, [_initialize] must be called.
  NodeListImpl._();

  @override
  Token? get beginToken {
    if (_elements.isEmpty) {
      return null;
    }
    return _elements[0].beginToken;
  }

  @override
  Token? get endToken {
    int length = _elements.length;
    if (length == 0) {
      return null;
    }
    return _elements[length - 1].endToken;
  }

  @override
  int get length => _elements.length;

  @Deprecated('NodeList cannot be resized')
  @override
  set length(int newLength) {
    throw UnsupportedError("Cannot resize NodeList.");
  }

  @override
  AstNodeImpl get owner => _owner;

  @override
  E operator [](int index) {
    if (index < 0 || index >= _elements.length) {
      throw RangeError("Index: $index, Size: ${_elements.length}");
    }
    return _elements[index];
  }

  @override
  void operator []=(int index, E node) {
    if (index < 0 || index >= _elements.length) {
      throw RangeError("Index: $index, Size: ${_elements.length}");
    }
    _elements[index] = node;
    _owner._becomeParentOf(node as AstNodeImpl);
  }

  @override
  void accept(AstVisitor visitor) {
    int length = _elements.length;
    for (var i = 0; i < length; i++) {
      _elements[i].accept(visitor);
    }
  }

  @Deprecated('NodeList cannot be resized')
  @override
  void add(E element) {
    throw UnsupportedError("Cannot resize NodeList.");
  }

  @Deprecated('NodeList cannot be resized')
  @override
  void addAll(Iterable<E> iterable) {
    throw UnsupportedError("Cannot resize NodeList.");
  }

  @Deprecated('NodeList cannot be resized')
  @override
  void clear() {
    throw UnsupportedError("Cannot resize NodeList.");
  }

  @Deprecated('NodeList cannot be resized')
  @override
  void insert(int index, E element) {
    throw UnsupportedError("Cannot resize NodeList.");
  }

  @Deprecated('NodeList cannot be resized')
  @override
  E removeAt(int index) {
    throw UnsupportedError("Cannot resize NodeList.");
  }

  /// Set the [owner] of this container, and populate it with [elements].
  void _initialize(AstNodeImpl owner, List<E>? elements) {
    _owner = owner;
    if (elements == null || elements.isEmpty) {
      _elements = const <Never>[];
    } else {
      _elements = elements.toList(growable: false);
      var length = elements.length;
      for (var i = 0; i < length; i++) {
        var node = elements[i];
        owner._becomeParentOf(node as AstNodeImpl);
      }
    }
  }
}

/// A formal parameter that is required (isn't optional).
///
///    normalFormalParameter ::=
///        [FunctionTypedFormalParameter]
///      | [FieldFormalParameter]
///      | [SimpleFormalParameter]
sealed class NormalFormalParameter implements FormalParameter, AnnotatedNode {}

sealed class NormalFormalParameterImpl extends FormalParameterImpl
    with _AnnotatedNodeMixin
    implements NormalFormalParameter {
  @override
  final Token? covariantKeyword;

  @override
  final Token? requiredKeyword;

  @override
  final Token? name;

  /// Initializes a newly created formal parameter.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// parameter doesn't have the corresponding attribute.
  NormalFormalParameterImpl({
    required CommentImpl? comment,
    required List<AnnotationImpl>? metadata,
    required this.covariantKeyword,
    required this.requiredKeyword,
    required this.name,
  }) {
    _initializeCommentAndAnnotations(comment, metadata);
  }

  @override
  Token get beginToken =>
      metadata.beginToken ?? firstTokenAfterCommentAndMetadata;

  @override
  ParameterKind get kind {
    var parent = this.parent;
    if (parent is DefaultFormalParameterImpl) {
      return parent.kind;
    }
    return ParameterKind.REQUIRED;
  }

  @override
  ChildEntities get _childEntities {
    return ChildEntities()
      ..addNode('documentationComment', documentationComment)
      ..addNodeList('metadata', metadata)
      ..addToken('requiredKeyword', requiredKeyword)
      ..addToken('covariantKeyword', covariantKeyword);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    //
    // Note that subclasses are responsible for visiting the identifier because
    // they often need to visit other nodes before visiting the identifier.
    //
    _visitCommentAndAnnotations(visitor);
  }
}

/// A null-assert pattern.
///
///    nullAssertPattern ::=
///        [DartPattern] '!'
abstract final class NullAssertPattern implements DartPattern {
  /// The `!` token.
  Token get operator;

  /// The sub-pattern.
  DartPattern get pattern;
}

final class NullAssertPatternImpl extends DartPatternImpl
    implements NullAssertPattern {
  @override
  final DartPatternImpl pattern;

  @override
  final Token operator;

  NullAssertPatternImpl({
    required this.pattern,
    required this.operator,
  }) {
    _becomeParentOf(pattern);
  }

  @override
  Token get beginToken => pattern.beginToken;

  @override
  Token get endToken => operator;

  @override
  PatternPrecedence get precedence => PatternPrecedence.postfix;

  @override
  VariablePatternImpl? get variablePattern => pattern.variablePattern;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addNode('pattern', pattern)
    ..addToken('operator', operator);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitNullAssertPattern(this);

  @override
  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
    return resolverVisitor
        .analyzeNullCheckOrAssertPatternSchema(
          pattern,
          isAssert: true,
        )
        .unwrapTypeSchemaView();
  }

  @override
  PatternResult<DartType> resolvePattern(
    ResolverVisitor resolverVisitor,
    SharedMatchContext context,
  ) {
    inferenceLogWriter?.enterPattern(this);
    var analysisResult = resolverVisitor.analyzeNullCheckOrAssertPattern(
        context, this, pattern,
        isAssert: true);
    inferenceLogWriter?.exitPattern(this);
    return analysisResult;
  }

  @override
  void visitChildren(AstVisitor visitor) {
    pattern.accept(visitor);
  }
}

/// A null-aware element in a list or set literal.
///
///    <nullAwareExpressionElement> ::= '?' <expression>
abstract final class NullAwareElement implements CollectionElement {
  /// The question mark before the expression.
  Token get question;

  /// The expression computing the value that is associated with the element.
  Expression get value;
}

final class NullAwareElementImpl extends CollectionElementImpl
    implements NullAwareElement {
  @override
  final Token question;

  ExpressionImpl _value;

  /// Initializes a newly created null-aware element.
  NullAwareElementImpl({
    required this.question,
    required ExpressionImpl value,
  }) : _value = value {
    _becomeParentOf(_value);
  }

  @override
  Token get beginToken => question;

  @override
  Token get endToken => _value.endToken;

  @override
  ExpressionImpl get value => _value;

  set value(ExpressionImpl expression) {
    _value = _becomeParentOf(expression);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('question', question)
    ..addNode('value', value);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitNullAwareElement(this);

  @override
  void resolveElement(
      ResolverVisitor resolver, CollectionLiteralContext? context) {
    resolver.visitNullAwareElement(this, context: context);
    resolver.pushRewrite(null);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _value.accept(visitor);
  }
}

/// A null-check pattern.
///
///    nullCheckPattern ::=
///        [DartPattern] '?'
abstract final class NullCheckPattern implements DartPattern {
  /// The `?` token.
  Token get operator;

  /// The sub-pattern.
  DartPattern get pattern;
}

final class NullCheckPatternImpl extends DartPatternImpl
    implements NullCheckPattern {
  @override
  final DartPatternImpl pattern;

  @override
  final Token operator;

  NullCheckPatternImpl({
    required this.pattern,
    required this.operator,
  }) {
    _becomeParentOf(pattern);
  }

  @override
  Token get beginToken => pattern.beginToken;

  @override
  Token get endToken => operator;

  @override
  PatternPrecedence get precedence => PatternPrecedence.postfix;

  @override
  VariablePatternImpl? get variablePattern => pattern.variablePattern;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addNode('pattern', pattern)
    ..addToken('operator', operator);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitNullCheckPattern(this);

  @override
  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
    return resolverVisitor
        .analyzeNullCheckOrAssertPatternSchema(
          pattern,
          isAssert: false,
        )
        .unwrapTypeSchemaView();
  }

  @override
  PatternResult<DartType> resolvePattern(
    ResolverVisitor resolverVisitor,
    SharedMatchContext context,
  ) {
    inferenceLogWriter?.enterPattern(this);
    var analysisResult = resolverVisitor.analyzeNullCheckOrAssertPattern(
        context, this, pattern,
        isAssert: false);
    inferenceLogWriter?.exitPattern(this);
    return analysisResult;
  }

  @override
  void visitChildren(AstVisitor visitor) {
    pattern.accept(visitor);
  }
}

/// A null literal expression.
///
///    nullLiteral ::=
///        'null'
abstract final class NullLiteral implements Literal {
  /// The token representing the literal.
  Token get literal;
}

final class NullLiteralImpl extends LiteralImpl implements NullLiteral {
  @override
  final Token literal;

  /// Initializes a newly created null literal.
  NullLiteralImpl({
    required this.literal,
  });

  @override
  Token get beginToken => literal;

  @override
  Token get endToken => literal;

  @override
  ChildEntities get _childEntities =>
      ChildEntities()..addToken('literal', literal);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitNullLiteral(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitNullLiteral(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    // There are no children to visit.
  }
}

/// Abstract interface for expressions that may participate in null-shorting.
abstract final class NullShortableExpression implements Expression {
  /// The expression that terminates any null shorting that might occur in this
  /// expression.
  ///
  /// This might be called regardless of whether this expression is itself
  /// null-aware.
  ///
  /// For example, the statement `a?.b[c] = d;` contains the following
  /// null-shortable subexpressions:
  /// - `a?.b`
  /// - `a?.b[c]`
  /// - `a?.b[c] = d`
  ///
  /// Calling [nullShortingTermination] on any of these subexpressions yields
  /// the expression `a?.b[c] = d`, indicating that the null-shorting induced by
  /// the `?.` causes the rest of the subexpression `a?.b[c] = d` to be skipped.
  Expression get nullShortingTermination;
}

base mixin NullShortableExpressionImpl implements NullShortableExpression {
  @override
  Expression get nullShortingTermination {
    var result = this;
    while (true) {
      var parent = result._nullShortingExtensionCandidate;
      if (parent is NullShortableExpressionImpl &&
          parent._extendsNullShorting(result)) {
        result = parent;
      } else {
        return result;
      }
    }
  }

  /// The ancestor of this node to which null-shorting might be extended.
  ///
  /// Usually this is just the node's parent, however if `this` is the base of
  /// a cascade section, it's the cascade expression itself, which might be a
  /// more distant ancestor.
  AstNode? get _nullShortingExtensionCandidate;

  /// Whether the effect of any null-shorting within [descendant] (which should
  /// be a descendant of `this`) should extend to include `this`.
  bool _extendsNullShorting(Expression descendant);
}

/// An object pattern.
///
///    objectPattern ::=
///        [Identifier] [TypeArgumentList]? '(' [PatternField] ')'
abstract final class ObjectPattern implements DartPattern {
  /// The patterns matching the properties of the object.
  NodeList<PatternField> get fields;

  /// The left parenthesis.
  Token get leftParenthesis;

  /// The right parenthesis.
  Token get rightParenthesis;

  /// The name of the type of object from which values are extracted.
  NamedType get type;
}

final class ObjectPatternImpl extends DartPatternImpl implements ObjectPattern {
  final NodeListImpl<PatternFieldImpl> _fields = NodeListImpl._();

  @override
  final Token leftParenthesis;

  @override
  final Token rightParenthesis;

  @override
  final NamedTypeImpl type;

  ObjectPatternImpl({
    required this.type,
    required this.leftParenthesis,
    required List<PatternFieldImpl> fields,
    required this.rightParenthesis,
  }) {
    _becomeParentOf(type);
    _fields._initialize(this, fields);
  }

  @override
  Token get beginToken => type.beginToken;

  @override
  Token get endToken => rightParenthesis;

  @override
  NodeList<PatternFieldImpl> get fields => _fields;

  @override
  PatternPrecedence get precedence => PatternPrecedence.primary;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addNode('type', type)
    ..addToken('leftParenthesis', leftParenthesis)
    ..addNodeList('fields', fields)
    ..addToken('rightParenthesis', rightParenthesis);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitObjectPattern(this);

  @override
  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
    return resolverVisitor
        .analyzeObjectPatternSchema(SharedTypeView(type.typeOrThrow))
        .unwrapTypeSchemaView();
  }

  @override
  PatternResult<DartType> resolvePattern(
    ResolverVisitor resolverVisitor,
    SharedMatchContext context,
  ) {
    inferenceLogWriter?.enterPattern(this);
    var result = resolverVisitor.analyzeObjectPattern(
      context,
      this,
      fields: resolverVisitor.buildSharedPatternFields(
        fields,
        mustBeNamed: true,
      ),
    );

    resolverVisitor.checkPatternNeverMatchesValueType(
      context: context,
      pattern: this,
      requiredType: result.requiredType.unwrapTypeView(),
      matchedValueType: result.matchedValueType.unwrapTypeView(),
    );
    inferenceLogWriter?.exitPattern(this);

    return result;
  }

  @override
  void visitChildren(AstVisitor visitor) {
    type.accept(visitor);
    fields.accept(visitor);
  }
}

/// A parenthesized expression.
///
///    parenthesizedExpression ::=
///        '(' [Expression] ')'
abstract final class ParenthesizedExpression implements Expression {
  /// The expression within the parentheses.
  Expression get expression;

  /// The left parenthesis.
  Token get leftParenthesis;

  /// The right parenthesis.
  Token get rightParenthesis;
}

final class ParenthesizedExpressionImpl extends ExpressionImpl
    implements ParenthesizedExpression {
  @override
  final Token leftParenthesis;

  ExpressionImpl _expression;

  @override
  final Token rightParenthesis;

  /// Initializes a newly created parenthesized expression.
  ParenthesizedExpressionImpl({
    required this.leftParenthesis,
    required ExpressionImpl expression,
    required this.rightParenthesis,
  }) : _expression = expression {
    _becomeParentOf(_expression);
  }

  @override
  Token get beginToken => leftParenthesis;

  @override
  Token get endToken => rightParenthesis;

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  Precedence get precedence => Precedence.primary;

  @override
  ExpressionImpl get unParenthesized {
    // This is somewhat inefficient, but it avoids a stack overflow in the
    // degenerate case.
    var expression = _expression;
    while (expression is ParenthesizedExpressionImpl) {
      expression = expression._expression;
    }
    return expression;
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('leftParenthesis', leftParenthesis)
    ..addNode('expression', expression)
    ..addToken('rightParenthesis', rightParenthesis);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitParenthesizedExpression(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitParenthesizedExpression(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _expression.accept(visitor);
  }
}

/// A parenthesized pattern.
///
///    parenthesizedPattern ::=
///        '(' [DartPattern] ')'
abstract final class ParenthesizedPattern implements DartPattern {
  /// The left parenthesis.
  Token get leftParenthesis;

  /// The pattern within the parentheses.
  DartPattern get pattern;

  /// The right parenthesis.
  Token get rightParenthesis;
}

final class ParenthesizedPatternImpl extends DartPatternImpl
    implements ParenthesizedPattern {
  @override
  final Token leftParenthesis;

  @override
  final DartPatternImpl pattern;

  @override
  final Token rightParenthesis;

  ParenthesizedPatternImpl({
    required this.leftParenthesis,
    required this.pattern,
    required this.rightParenthesis,
  }) {
    _becomeParentOf(pattern);
  }

  @override
  Token get beginToken => leftParenthesis;

  @override
  Token get endToken => rightParenthesis;

  @override
  PatternPrecedence get precedence => PatternPrecedence.primary;

  @override
  DartPattern get unParenthesized {
    var result = pattern;
    while (result is ParenthesizedPatternImpl) {
      result = result.pattern;
    }
    return result;
  }

  @override
  VariablePatternImpl? get variablePattern => pattern.variablePattern;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('leftParenthesis', leftParenthesis)
    ..addNode('pattern', pattern)
    ..addToken('rightParenthesis', rightParenthesis);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitParenthesizedPattern(this);

  @override
  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
    return resolverVisitor
        .dispatchPatternSchema(pattern)
        .unwrapTypeSchemaView();
  }

  @override
  PatternResult<DartType> resolvePattern(
    ResolverVisitor resolverVisitor,
    SharedMatchContext context,
  ) {
    inferenceLogWriter?.enterPattern(this);
    var analysisResult = resolverVisitor.dispatchPattern(context, pattern);
    inferenceLogWriter?.exitPattern(this);
    return analysisResult;
  }

  @override
  void visitChildren(AstVisitor visitor) {
    pattern.accept(visitor);
  }
}

/// A part directive.
///
///    partDirective ::=
///        [Annotation] 'part' [StringLiteral] ';'
abstract final class PartDirective implements UriBasedDirective {
  /// The configurations that control which file is actually included.
  NodeList<Configuration> get configurations;

  @override
  PartElement? get element;

  /// Information about this part directive.
  ///
  /// Returns `null` if the AST structure hasn't been resolved.
  @experimental
  LibraryFragmentInclude? get fragmentInclude;

  /// The token representing the `part` keyword.
  Token get partKeyword;

  /// The semicolon terminating the directive.
  Token get semicolon;
}

final class PartDirectiveImpl extends UriBasedDirectiveImpl
    implements PartDirective {
  @override
  final Token partKeyword;

  @override
  final NodeListImpl<ConfigurationImpl> configurations = NodeListImpl._();

  @override
  final Token semicolon;

  /// Initializes a newly created part directive.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// directive doesn't have the corresponding attribute.
  PartDirectiveImpl({
    required super.comment,
    required super.metadata,
    required this.partKeyword,
    required super.uri,
    required List<ConfigurationImpl>? configurations,
    required this.semicolon,
  }) {
    this.configurations._initialize(this, configurations);
  }

  @override
  PartElementImpl? get element {
    return super.element as PartElementImpl?;
  }

  @override
  Token get endToken => semicolon;

  @override
  Token get firstTokenAfterCommentAndMetadata => partKeyword;

  @experimental
  @override
  LibraryFragmentInclude? get fragmentInclude =>
      element as LibraryFragmentInclude?;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('partKeyword', partKeyword)
    ..addNode('uri', uri)
    ..addNodeList('configurations', configurations)
    ..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitPartDirective(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    configurations.accept(visitor);
  }
}

/// A part-of directive.
///
///    partOfDirective ::=
///        [Annotation] 'part' 'of' [Identifier] ';'
abstract final class PartOfDirective implements Directive {
  /// The name of the library that the containing compilation unit is part of,
  /// or `null` if no name was given (typically because a library URI was
  /// provided).
  LibraryIdentifier? get libraryName;

  /// The token representing the `of` keyword.
  Token get ofKeyword;

  /// The token representing the `part` keyword.
  Token get partKeyword;

  /// The semicolon terminating the directive.
  Token get semicolon;

  /// The URI of the library that the containing compilation unit is part of, or
  /// `null` if no URI was given (typically because a library name was provided).
  StringLiteral? get uri;
}

final class PartOfDirectiveImpl extends DirectiveImpl
    implements PartOfDirective {
  @override
  final Token partKeyword;

  @override
  final Token ofKeyword;

  StringLiteralImpl? _uri;

  LibraryIdentifierImpl? _libraryName;

  @override
  final Token semicolon;

  /// Initializes a newly created part-of directive.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// directive doesn't have the corresponding attribute.
  PartOfDirectiveImpl({
    required super.comment,
    required super.metadata,
    required this.partKeyword,
    required this.ofKeyword,
    required StringLiteralImpl? uri,
    required LibraryIdentifierImpl? libraryName,
    required this.semicolon,
  })  : _uri = uri,
        _libraryName = libraryName {
    _becomeParentOf(_uri);
    _becomeParentOf(_libraryName);
  }

  @override
  Token get endToken => semicolon;

  @override
  Token get firstTokenAfterCommentAndMetadata => partKeyword;

  @override
  LibraryIdentifierImpl? get libraryName => _libraryName;

  set libraryName(LibraryIdentifierImpl? libraryName) {
    _libraryName = _becomeParentOf(libraryName);
  }

  @override
  StringLiteralImpl? get uri => _uri;

  set uri(StringLiteralImpl? uri) {
    _uri = _becomeParentOf(uri);
  }

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('partKeyword', partKeyword)
    ..addToken('ofKeyword', ofKeyword)
    ..addNode('uri', uri)
    ..addNode('libraryName', libraryName)
    ..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitPartOfDirective(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _libraryName?.accept(visitor);
    _uri?.accept(visitor);
  }
}

/// A pattern assignment.
///
///    patternAssignment ::=
///        [DartPattern] '=' [Expression]
abstract final class PatternAssignment implements Expression {
  /// The equal sign separating the pattern from the expression.
  Token get equals;

  /// The expression that is matched by the pattern.
  Expression get expression;

  /// The pattern that matches the expression.
  DartPattern get pattern;
}

final class PatternAssignmentImpl extends ExpressionImpl
    implements PatternAssignment {
  @override
  final Token equals;

  ExpressionImpl _expression;

  @override
  final DartPatternImpl pattern;

  /// The pattern type schema, used for downward inference of [expression];
  /// or `null` if the node isn't resolved yet.
  DartType? patternTypeSchema;

  PatternAssignmentImpl({
    required this.pattern,
    required this.equals,
    required ExpressionImpl expression,
  }) : _expression = expression {
    _becomeParentOf(pattern);
    _becomeParentOf(_expression);
  }

  @override
  Token get beginToken => pattern.beginToken;

  @override
  Token get endToken => expression.endToken;

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  // TODO(brianwilkerson): Create a new precedence constant for pattern
  //  assignments. The proposal doesn't make the actual value clear.
  Precedence get precedence => Precedence.assignment;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addNode('pattern', pattern)
    ..addToken('equals', equals)
    ..addNode('expression', expression);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitPatternAssignment(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitPatternAssignment(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    pattern.accept(visitor);
    expression.accept(visitor);
  }
}

/// A field in an object or record pattern.
///
///    patternField ::=
///        [PatternFieldName]? [DartPattern]
abstract final class PatternField implements AstNode {
  /// The effective name of the field, or `null` if [name] is `null` and
  /// [pattern] isn't a variable pattern.
  ///
  /// The effective name can either be specified explicitly by [name], or
  /// implied by the variable pattern inside [pattern].
  String? get effectiveName;

  /// The element referenced by [effectiveName], or `null` if not resolved yet,
  /// non-`null` inside valid [ObjectPattern]s, always `null` inside
  /// [RecordPattern]s.
  Element? get element;

  /// The element referenced by [effectiveName].
  ///
  /// Returns `null` if the AST structure is not resolved yet.
  ///
  /// Returns non-`null` inside valid [ObjectPattern]s; always returns `null`
  /// inside [RecordPattern]s.
  @experimental
  Element2? get element2;

  /// The name of the field, or `null` if the field is a positional field.
  PatternFieldName? get name;

  /// The pattern used to match the corresponding record field.
  DartPattern get pattern;
}

final class PatternFieldImpl extends AstNodeImpl implements PatternField {
  @override
  Element? element;

  @override
  final PatternFieldNameImpl? name;

  @override
  final DartPatternImpl pattern;

  PatternFieldImpl({required this.name, required this.pattern}) {
    _becomeParentOf(name);
    _becomeParentOf(pattern);
  }

  @override
  Token get beginToken => name?.beginToken ?? pattern.beginToken;

  @override
  String? get effectiveName {
    var nameNode = name;
    if (nameNode != null) {
      var nameToken = nameNode.name ?? pattern.variablePattern?.name;
      return nameToken?.lexeme;
    }
    return null;
  }

  @experimental
  @override
  Element2? get element2 {
    var element = this.element;
    if (element case Fragment fragment) {
      return fragment.element;
    } else if (element case Element2 element) {
      return element;
    }
    return null;
  }

  @override
  Token get endToken => pattern.endToken;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addNode('name', name)
    ..addNode('pattern', pattern);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitPatternField(this);

  @override
  void visitChildren(AstVisitor visitor) {
    name?.accept(visitor);
    pattern.accept(visitor);
  }
}

/// A field name in an object or record pattern field.
///
///    patternFieldName ::=
///        [Token]? ':'
abstract final class PatternFieldName implements AstNode {
  /// The colon following the name.
  Token get colon;

  /// The name of the field.
  Token? get name;
}

final class PatternFieldNameImpl extends AstNodeImpl
    implements PatternFieldName {
  @override
  final Token colon;

  @override
  final Token? name;

  PatternFieldNameImpl({required this.name, required this.colon});

  @override
  Token get beginToken => name ?? colon;

  @override
  Token get endToken => colon;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('name', name)
    ..addToken('colon', colon);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitPatternFieldName(this);

  @override
  void visitChildren(AstVisitor visitor) {
    // There are no children to visit.
  }
}

/// A pattern variable declaration.
///
///    patternDeclaration ::=
///        ( 'final' | 'var' ) [DartPattern] '=' [Expression]
abstract final class PatternVariableDeclaration implements AnnotatedNode {
  /// The equal sign separating the pattern from the expression.
  Token get equals;

  /// The expression that is matched by the pattern.
  Expression get expression;

  /// The `var` or `final` keyword introducing the declaration.
  Token get keyword;

  /// The pattern that matches the expression.
  DartPattern get pattern;
}

final class PatternVariableDeclarationImpl extends AnnotatedNodeImpl
    implements PatternVariableDeclaration {
  @override
  final Token equals;

  ExpressionImpl _expression;

  @override
  final Token keyword;

  @override
  final DartPatternImpl pattern;

  /// The pattern type schema, used for downward inference of [expression];
  /// or `null` if the node isn't resolved yet.
  DartType? patternTypeSchema;

  /// Variables declared in [pattern].
  late final List<BindPatternVariableElementImpl> elements;

  PatternVariableDeclarationImpl({
    required this.keyword,
    required this.pattern,
    required this.equals,
    required ExpressionImpl expression,
    required super.comment,
    required super.metadata,
  }) : _expression = expression {
    _becomeParentOf(pattern);
    _becomeParentOf(_expression);
  }

  @override
  Token get endToken => expression.endToken;

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  /// If [keyword] is `final`, returns it.
  Token? get finalKeyword {
    if (keyword.keyword == Keyword.FINAL) {
      return keyword;
    }
    return null;
  }

  @override
  Token get firstTokenAfterCommentAndMetadata => keyword;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('keyword', keyword)
    ..addNode('pattern', pattern)
    ..addToken('equals', equals)
    ..addNode('expression', expression);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitPatternVariableDeclaration(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    pattern.accept(visitor);
    expression.accept(visitor);
  }
}

/// A pattern variable declaration statement.
///
///    patternDeclaration ::=
///        [PatternVariableDeclaration] ';'
abstract final class PatternVariableDeclarationStatement implements Statement {
  /// The pattern declaration.
  PatternVariableDeclaration get declaration;

  /// The semicolon terminating the statement.
  Token get semicolon;
}

final class PatternVariableDeclarationStatementImpl extends StatementImpl
    implements PatternVariableDeclarationStatement {
  @override
  final PatternVariableDeclarationImpl declaration;

  @override
  final Token semicolon;

  PatternVariableDeclarationStatementImpl({
    required this.declaration,
    required this.semicolon,
  }) {
    _becomeParentOf(declaration);
  }

  @override
  Token get beginToken => declaration.beginToken;

  @override
  Token get endToken => semicolon;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addNode('declaration', declaration)
    ..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitPatternVariableDeclarationStatement(this);

  @override
  void visitChildren(AstVisitor visitor) {
    declaration.accept(visitor);
  }
}

/// A postfix unary expression.
///
///    postfixExpression ::=
///        [Expression] [Token]
abstract final class PostfixExpression
    implements
        Expression,
        NullShortableExpression,
        MethodReferenceExpression,
        CompoundAssignmentExpression {
  /// The expression computing the operand for the operator.
  Expression get operand;

  /// The postfix operator being applied to the operand.
  Token get operator;

  /// The element associated with the operator based on the static type of the
  /// operand, or `null` if the AST structure hasn't been resolved, if the
  /// operator isn't user definable, or if the operator couldn't be resolved.
  @override
  MethodElement? get staticElement;
}

final class PostfixExpressionImpl extends ExpressionImpl
    with NullShortableExpressionImpl, CompoundAssignmentExpressionImpl
    implements PostfixExpression {
  ExpressionImpl _operand;

  @override
  final Token operator;

  @override
  MethodElement? staticElement;

  /// Initializes a newly created postfix expression.
  PostfixExpressionImpl({
    required ExpressionImpl operand,
    required this.operator,
  }) : _operand = operand {
    _becomeParentOf(_operand);
  }

  @override
  Token get beginToken => _operand.beginToken;

  @experimental
  @override
  MethodElement2? get element => (staticElement as MethodFragment?)?.element;

  @override
  Token get endToken => operator;

  @override
  ExpressionImpl get operand => _operand;

  set operand(ExpressionImpl expression) {
    _operand = _becomeParentOf(expression);
  }

  @override
  Precedence get precedence => Precedence.postfix;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('operand', operand)
    ..addToken('operator', operator);

  @override
  AstNode? get _nullShortingExtensionCandidate => parent;

  /// The parameter element representing the parameter to which the value of the
  /// operand is bound, or `null` ff the AST structure is not resolved or the
  /// function being invoked isn't known based on static type information.
  ParameterElement? get _staticParameterElementForOperand {
    if (staticElement == null) {
      return null;
    }
    List<ParameterElement> parameters = staticElement!.parameters;
    if (parameters.isEmpty) {
      return null;
    }
    return parameters[0];
  }

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitPostfixExpression(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitPostfixExpression(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _operand.accept(visitor);
  }

  @override
  bool _extendsNullShorting(Expression descendant) =>
      identical(descendant, operand);
}

/// An identifier that is prefixed or an access to an object property where the
/// target of the property access is a simple identifier.
///
///    prefixedIdentifier ::=
///        [SimpleIdentifier] '.' [SimpleIdentifier]
abstract final class PrefixedIdentifier implements Identifier {
  /// The identifier being prefixed.
  SimpleIdentifier get identifier;

  /// Whether this type is a deferred type.
  ///
  /// A deferred type is a type that is referenced through an import prefix
  /// (such as `p.T`), where the prefix is used by a deferred import.
  ///
  /// Returns `false` if the AST structure hasn't been resolved.
  bool get isDeferred;

  /// The period used to separate the prefix from the identifier.
  Token get period;

  /// The prefix associated with the library in which the identifier is defined.
  SimpleIdentifier get prefix;
}

final class PrefixedIdentifierImpl extends IdentifierImpl
    implements PrefixedIdentifier {
  SimpleIdentifierImpl _prefix;

  @override
  final Token period;

  SimpleIdentifierImpl _identifier;

  /// Initializes a newly created prefixed identifier.
  PrefixedIdentifierImpl({
    required SimpleIdentifierImpl prefix,
    required this.period,
    required SimpleIdentifierImpl identifier,
  })  : _prefix = prefix,
        _identifier = identifier {
    _becomeParentOf(_prefix);
    _becomeParentOf(_identifier);
  }

  @override
  Token get beginToken => _prefix.beginToken;

  @override
  Token get endToken => _identifier.endToken;

  @override
  SimpleIdentifierImpl get identifier => _identifier;

  set identifier(SimpleIdentifierImpl identifier) {
    _identifier = _becomeParentOf(identifier);
  }

  @override
  bool get isDeferred {
    Element? element = _prefix.staticElement;
    if (element is PrefixElement) {
      var imports = element.imports;
      if (imports.length != 1) {
        return false;
      }
      return imports[0].prefix is DeferredImportElementPrefix;
    }
    return false;
  }

  @override
  String get name => "${_prefix.name}.${_identifier.name}";

  @override
  Precedence get precedence => Precedence.postfix;

  @override
  SimpleIdentifierImpl get prefix => _prefix;

  set prefix(SimpleIdentifierImpl identifier) {
    _prefix = _becomeParentOf(identifier);
  }

  @override
  Element? get staticElement {
    return _identifier.staticElement;
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('prefix', prefix)
    ..addToken('period', period)
    ..addNode('identifier', identifier);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitPrefixedIdentifier(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitPrefixedIdentifier(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _prefix.accept(visitor);
    _identifier.accept(visitor);
  }
}

/// A prefix unary expression.
///
///    prefixExpression ::=
///        [Token] [Expression]
abstract final class PrefixExpression
    implements
        Expression,
        NullShortableExpression,
        MethodReferenceExpression,
        CompoundAssignmentExpression {
  /// The element associated with the operator based on the static type of the
  /// operand, or `null` if the AST structure hasn't been resolved, if the
  /// operator isn't user definable, or if the operator couldn't be resolved.
  @override
  MethodElement? staticElement;

  /// The expression computing the operand for the operator.
  Expression get operand;

  /// The prefix operator being applied to the operand.
  Token get operator;
}

final class PrefixExpressionImpl extends ExpressionImpl
    with NullShortableExpressionImpl, CompoundAssignmentExpressionImpl
    implements PrefixExpression {
  @override
  final Token operator;

  ExpressionImpl _operand;

  @override
  MethodElement? staticElement;

  /// Initializes a newly created prefix expression.
  PrefixExpressionImpl({
    required this.operator,
    required ExpressionImpl operand,
  }) : _operand = operand {
    _becomeParentOf(_operand);
  }

  @override
  Token get beginToken => operator;

  @experimental
  @override
  MethodElement2? get element => (staticElement as MethodFragment?)?.element;

  @override
  Token get endToken => _operand.endToken;

  @override
  ExpressionImpl get operand => _operand;

  set operand(ExpressionImpl expression) {
    _operand = _becomeParentOf(expression);
  }

  @override
  Precedence get precedence => Precedence.prefix;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('operator', operator)
    ..addNode('operand', operand);

  @override
  AstNode? get _nullShortingExtensionCandidate => parent;

  /// The parameter element representing the parameter to which the value of the
  /// operand is bound, or `null` if the AST structure is not resolved or the
  /// function being invoked isn't known based on static type information.
  ParameterElement? get _staticParameterElementForOperand {
    if (staticElement == null) {
      return null;
    }
    List<ParameterElement> parameters = staticElement!.parameters;
    if (parameters.isEmpty) {
      return null;
    }
    return parameters[0];
  }

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitPrefixExpression(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitPrefixExpression(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _operand.accept(visitor);
  }

  @override
  bool _extendsNullShorting(Expression descendant) =>
      identical(descendant, operand) && operator.type.isIncrementOperator;
}

/// The access of a property of an object.
///
/// Note, however, that accesses to properties of objects can also be
/// represented as [PrefixedIdentifier] nodes in cases where the target is also
/// a simple identifier.
///
///    propertyAccess ::=
///        [Expression] '.' [SimpleIdentifier]
abstract final class PropertyAccess
    implements NullShortableExpression, CommentReferableExpression {
  /// Whether this expression is cascaded.
  ///
  /// If it is, then the target of this expression isn't stored locally but is
  /// stored in the nearest ancestor that is a [CascadeExpression].
  bool get isCascaded;

  /// Whether this property access is null aware (as opposed to non-null).
  bool get isNullAware;

  /// The property access operator.
  Token get operator;

  /// The name of the property being accessed.
  SimpleIdentifier get propertyName;

  /// The expression used to compute the receiver of the invocation.
  ///
  /// If this invocation isn't part of a cascade expression, then this is the
  /// same as [target]. If this invocation is part of a cascade expression,
  /// then the target stored with the cascade expression is returned.
  Expression get realTarget;

  /// The expression computing the object defining the property being accessed,
  /// or `null` if this property access is part of a cascade expression.
  ///
  /// Use [realTarget] to get the target independent of whether this is part of
  /// a cascade expression.
  Expression? get target;
}

final class PropertyAccessImpl extends CommentReferableExpressionImpl
    with NullShortableExpressionImpl
    implements PropertyAccess {
  ExpressionImpl? _target;

  @override
  final Token operator;

  SimpleIdentifierImpl _propertyName;

  /// Initializes a newly created property access expression.
  PropertyAccessImpl({
    required ExpressionImpl? target,
    required this.operator,
    required SimpleIdentifierImpl propertyName,
  })  : _target = target,
        _propertyName = propertyName {
    _becomeParentOf(_target);
    _becomeParentOf(_propertyName);
  }

  @override
  Token get beginToken {
    if (target case var target?) {
      return target.beginToken;
    }
    return operator;
  }

  @override
  Token get endToken => _propertyName.endToken;

  @override
  bool get isAssignable => true;

  @override
  bool get isCascaded =>
      operator.type == TokenType.PERIOD_PERIOD ||
      operator.type == TokenType.QUESTION_PERIOD_PERIOD;

  @override
  bool get isNullAware {
    if (isCascaded) {
      return _ancestorCascade.isNullAware;
    }
    return operator.type == TokenType.QUESTION_PERIOD ||
        operator.type == TokenType.QUESTION_PERIOD_PERIOD;
  }

  @override
  Precedence get precedence => Precedence.postfix;

  @override
  SimpleIdentifierImpl get propertyName => _propertyName;

  set propertyName(SimpleIdentifierImpl identifier) {
    _propertyName = _becomeParentOf(identifier);
  }

  @override
  ExpressionImpl get realTarget {
    if (isCascaded) {
      return _ancestorCascade.target;
    }
    return _target!;
  }

  @override
  ExpressionImpl? get target => _target;

  set target(ExpressionImpl? expression) {
    _target = _becomeParentOf(expression);
  }

  /// The cascade that contains this [IndexExpression].
  ///
  /// This method assumes that [isCascaded] is `true`.
  CascadeExpressionImpl get _ancestorCascade {
    assert(isCascaded);
    for (var ancestor = parent!;; ancestor = ancestor.parent!) {
      if (ancestor is CascadeExpressionImpl) {
        return ancestor;
      }
    }
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('target', target)
    ..addToken('operator', operator)
    ..addNode('propertyName', propertyName);

  @override
  AstNode? get _nullShortingExtensionCandidate => parent;

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitPropertyAccess(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitPropertyAccess(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _target?.accept(visitor);
    _propertyName.accept(visitor);
  }

  @override
  bool _extendsNullShorting(Expression descendant) =>
      identical(descendant, _target);
}

/// A record literal.
///
///    recordLiteral ::= '(' recordField (',' recordField)* ','? ')'
///
///    recordField  ::= (identifier ':')? [Expression]
abstract final class RecordLiteral implements Literal {
  /// The token representing the `const` keyword, or `null` if the literal isn't
  /// a constant.
  Token? get constKeyword;

  /// The syntactic elements used to compute the fields of the record.
  NodeList<Expression> get fields;

  /// Whether this literal is a constant expression.
  ///
  /// It is a constant expression if either the keyword `const` was explicitly
  /// provided or because no keyword was provided and this expression occurs in
  /// a constant context.
  bool get isConst;

  /// The left parenthesis.
  Token get leftParenthesis;

  /// The right parenthesis.
  Token get rightParenthesis;
}

final class RecordLiteralImpl extends LiteralImpl implements RecordLiteral {
  @override
  final Token? constKeyword;

  @override
  final Token leftParenthesis;

  final NodeListImpl<ExpressionImpl> _fields = NodeListImpl._();

  @override
  final Token rightParenthesis;

  /// Initializes a newly created record literal.
  RecordLiteralImpl({
    required this.constKeyword,
    required this.leftParenthesis,
    required List<ExpressionImpl> fields,
    required this.rightParenthesis,
  }) {
    _fields._initialize(this, fields);
  }

  @override
  Token get beginToken => constKeyword ?? leftParenthesis;

  @override
  Token get endToken => rightParenthesis;

  @override
  NodeList<ExpressionImpl> get fields => _fields;

  @override
  bool get isConst => constKeyword != null || inConstantContext;

  @override
  // TODO(paulberry): add commas.
  ChildEntities get _childEntities => super._childEntities
    ..addToken('constKeyword', constKeyword)
    ..addToken('leftParenthesis', leftParenthesis)
    ..addNodeList('fields', fields)
    ..addToken('rightParenthesis', rightParenthesis);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitRecordLiteral(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitRecordLiteral(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _fields.accept(visitor);
  }
}

/// A record pattern.
///
///    recordPattern ::=
///        '(' [PatternField] (',' [PatternField])* ')'
abstract final class RecordPattern implements DartPattern {
  /// The fields of the record pattern.
  NodeList<PatternField> get fields;

  /// The left parenthesis.
  Token get leftParenthesis;

  /// The right parenthesis.
  Token get rightParenthesis;
}

final class RecordPatternImpl extends DartPatternImpl implements RecordPattern {
  final NodeListImpl<PatternFieldImpl> _fields = NodeListImpl._();

  @override
  final Token leftParenthesis;

  @override
  final Token rightParenthesis;

  bool hasDuplicateNamedField = false;

  RecordPatternImpl({
    required this.leftParenthesis,
    required List<PatternFieldImpl> fields,
    required this.rightParenthesis,
  }) {
    _fields._initialize(this, fields);
  }

  @override
  Token get beginToken => leftParenthesis;

  @override
  Token get endToken => rightParenthesis;

  @override
  NodeList<PatternFieldImpl> get fields => _fields;

  @override
  PatternPrecedence get precedence => PatternPrecedence.primary;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('leftParenthesis', leftParenthesis)
    ..addNodeList('fields', fields)
    ..addToken('rightParenthesis', rightParenthesis);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitRecordPattern(this);

  @override
  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
    return resolverVisitor
        .analyzeRecordPatternSchema(
          fields: resolverVisitor.buildSharedPatternFields(
            fields,
            mustBeNamed: false,
          ),
        )
        .unwrapTypeSchemaView();
  }

  @override
  PatternResult<DartType> resolvePattern(
    ResolverVisitor resolverVisitor,
    SharedMatchContext context,
  ) {
    inferenceLogWriter?.enterPattern(this);
    var result = resolverVisitor.analyzeRecordPattern(
      context,
      this,
      fields: resolverVisitor.buildSharedPatternFields(
        fields,
        mustBeNamed: false,
      ),
    );

    if (!hasDuplicateNamedField) {
      resolverVisitor.checkPatternNeverMatchesValueType(
        context: context,
        pattern: this,
        requiredType: result.requiredType.unwrapTypeView(),
        matchedValueType: result.matchedValueType.unwrapTypeView(),
      );
    }
    inferenceLogWriter?.exitPattern(this);

    return result;
  }

  @override
  void visitChildren(AstVisitor visitor) {
    fields.accept(visitor);
  }
}

/// A record type.
///
/// recordType ::=
///     '(' recordTypeFields ',' recordTypeNamedFields ')'
///   | '(' recordTypeFields ','? ')'
///   | '(' recordTypeNamedFields ')'
///
/// recordTypeFields ::= recordTypeField ( ',' recordTypeField )*
///
/// recordTypeField ::= metadata type identifier?
///
/// recordTypeNamedFields ::=
///     '{' recordTypeNamedField
///     ( ',' recordTypeNamedField )* ','? '}'
///
/// recordTypeNamedField ::= metadata type identifier
abstract final class RecordTypeAnnotation implements TypeAnnotation {
  /// The left parenthesis.
  Token get leftParenthesis;

  /// The optional named fields.
  RecordTypeAnnotationNamedFields? get namedFields;

  /// The positional fields (might be empty).
  NodeList<RecordTypeAnnotationPositionalField> get positionalFields;

  /// The right parenthesis.
  Token get rightParenthesis;
}

/// A field in a [RecordTypeAnnotation].
sealed class RecordTypeAnnotationField implements AstNode {
  /// The annotations associated with the field.
  NodeList<Annotation> get metadata;

  /// The name of the field.
  Token? get name;

  /// The type of the field.
  TypeAnnotation get type;
}

sealed class RecordTypeAnnotationFieldImpl extends AstNodeImpl
    implements RecordTypeAnnotationField {
  @override
  final NodeListImpl<AnnotationImpl> metadata = NodeListImpl._();

  @override
  final TypeAnnotationImpl type;

  RecordTypeAnnotationFieldImpl({
    required List<AnnotationImpl>? metadata,
    required this.type,
  }) {
    this.metadata._initialize(this, metadata);
    _becomeParentOf(type);
  }

  @override
  Token get beginToken => metadata.beginToken ?? type.beginToken;

  @override
  Token get endToken => name ?? type.endToken;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addNodeList('metadata', metadata)
    ..addNode('type', type)
    ..addToken('name', name);

  @override
  void visitChildren(AstVisitor visitor) {
    metadata.accept(visitor);
    type.accept(visitor);
  }
}

final class RecordTypeAnnotationImpl extends TypeAnnotationImpl
    implements RecordTypeAnnotation {
  @override
  final Token leftParenthesis;

  @override
  final NodeListImpl<RecordTypeAnnotationPositionalFieldImpl> positionalFields =
      NodeListImpl._();

  @override
  final RecordTypeAnnotationNamedFieldsImpl? namedFields;

  @override
  final Token rightParenthesis;

  @override
  final Token? question;

  @override
  DartType? type;

  RecordTypeAnnotationImpl({
    required this.leftParenthesis,
    required List<RecordTypeAnnotationPositionalFieldImpl> positionalFields,
    required this.namedFields,
    required this.rightParenthesis,
    required this.question,
  }) {
    _becomeParentOf(namedFields);
    this.positionalFields._initialize(this, positionalFields);
  }

  @override
  Token get beginToken => leftParenthesis;

  @override
  Token get endToken => question ?? rightParenthesis;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('leftParenthesis', leftParenthesis)
    ..addNodeList('positionalFields', positionalFields)
    ..addNode('namedFields', namedFields)
    ..addToken('rightParenthesis', rightParenthesis)
    ..addToken('question', question);

  @override
  E? accept<E>(AstVisitor<E> visitor) {
    return visitor.visitRecordTypeAnnotation(this);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    positionalFields.accept(visitor);
    namedFields?.accept(visitor);
  }
}

/// A named field in a [RecordTypeAnnotation].
abstract final class RecordTypeAnnotationNamedField
    implements RecordTypeAnnotationField {
  @override
  Token get name;
}

final class RecordTypeAnnotationNamedFieldImpl
    extends RecordTypeAnnotationFieldImpl
    implements RecordTypeAnnotationNamedField {
  @override
  final Token name;

  RecordTypeAnnotationNamedFieldImpl({
    required super.metadata,
    required super.type,
    required this.name,
  });

  @override
  E? accept<E>(AstVisitor<E> visitor) {
    return visitor.visitRecordTypeAnnotationNamedField(this);
  }
}

/// The portion of a [RecordTypeAnnotation] with named fields.
abstract final class RecordTypeAnnotationNamedFields implements AstNode {
  /// The fields contained in the block.
  NodeList<RecordTypeAnnotationNamedField> get fields;

  /// The left curly bracket.
  Token get leftBracket;

  /// The right curly bracket.
  Token get rightBracket;
}

final class RecordTypeAnnotationNamedFieldsImpl extends AstNodeImpl
    implements RecordTypeAnnotationNamedFields {
  @override
  final Token leftBracket;

  @override
  final NodeListImpl<RecordTypeAnnotationNamedFieldImpl> fields =
      NodeListImpl._();

  @override
  final Token rightBracket;

  RecordTypeAnnotationNamedFieldsImpl({
    required this.leftBracket,
    required List<RecordTypeAnnotationNamedFieldImpl> fields,
    required this.rightBracket,
  }) {
    this.fields._initialize(this, fields);
  }

  @override
  Token get beginToken => leftBracket;

  @override
  Token get endToken => rightBracket;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('leftBracket', leftBracket)
    ..addNodeList('fields', fields)
    ..addToken('rightBracket', rightBracket);

  @override
  E? accept<E>(AstVisitor<E> visitor) {
    return visitor.visitRecordTypeAnnotationNamedFields(this);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    fields.accept(visitor);
  }
}

/// A positional field in a [RecordTypeAnnotation].
abstract final class RecordTypeAnnotationPositionalField
    implements RecordTypeAnnotationField {}

final class RecordTypeAnnotationPositionalFieldImpl
    extends RecordTypeAnnotationFieldImpl
    implements RecordTypeAnnotationPositionalField {
  @override
  final Token? name;

  RecordTypeAnnotationPositionalFieldImpl({
    required super.metadata,
    required super.type,
    required this.name,
  });

  @override
  E? accept<E>(AstVisitor<E> visitor) {
    return visitor.visitRecordTypeAnnotationPositionalField(this);
  }
}

/// The invocation of a constructor in the same class from within a
/// constructor's initialization list.
///
///    redirectingConstructorInvocation ::=
///        'this' ('.' identifier)? arguments
abstract final class RedirectingConstructorInvocation
    implements ConstructorInitializer, ConstructorReferenceNode {
  /// The list of arguments to the constructor.
  ArgumentList get argumentList;

  /// The name of the constructor that is being invoked, or `null` if the
  /// unnamed constructor is being invoked.
  SimpleIdentifier? get constructorName;

  /// The token for the period before the name of the constructor that is being
  /// invoked, or `null` if the unnamed constructor is being invoked.
  Token? get period;

  /// The element associated with the constructor based on static type
  /// information, or `null` if the AST structure hasn't been resolved or if the
  /// constructor couldn't be resolved.
  @override
  ConstructorElement? get staticElement;

  /// The token for the `this` keyword.
  Token get thisKeyword;
}

final class RedirectingConstructorInvocationImpl
    extends ConstructorInitializerImpl
    implements RedirectingConstructorInvocation {
  @override
  final Token thisKeyword;

  @override
  final Token? period;

  SimpleIdentifierImpl? _constructorName;

  ArgumentListImpl _argumentList;

  @override
  ConstructorElement? staticElement;

  /// Initializes a newly created redirecting invocation to invoke the
  /// constructor with the given name with the given arguments.
  ///
  /// The [constructorName] can be `null` if the constructor being invoked is
  /// the unnamed constructor.
  RedirectingConstructorInvocationImpl({
    required this.thisKeyword,
    required this.period,
    required SimpleIdentifierImpl? constructorName,
    required ArgumentListImpl argumentList,
  })  : _constructorName = constructorName,
        _argumentList = argumentList {
    _becomeParentOf(_constructorName);
    _becomeParentOf(_argumentList);
  }

  @override
  ArgumentListImpl get argumentList => _argumentList;

  set argumentList(ArgumentListImpl argumentList) {
    _argumentList = _becomeParentOf(argumentList);
  }

  @override
  Token get beginToken => thisKeyword;

  @override
  SimpleIdentifierImpl? get constructorName => _constructorName;

  set constructorName(SimpleIdentifierImpl? identifier) {
    _constructorName = _becomeParentOf(identifier);
  }

  @experimental
  @override
  ConstructorElement2? get element =>
      staticElement?.asElement2 as ConstructorElement2?;

  @override
  Token get endToken => _argumentList.endToken;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('thisKeyword', thisKeyword)
    ..addToken('period', period)
    ..addNode('constructorName', constructorName)
    ..addNode('argumentList', argumentList);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitRedirectingConstructorInvocation(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _constructorName?.accept(visitor);
    _argumentList.accept(visitor);
  }
}

/// A relational pattern.
///
///    relationalPattern ::=
///        (equalityOperator | relationalOperator) [Expression]
abstract final class RelationalPattern implements DartPattern {
  /// The element of the [operator] for the matched type.
  MethodElement? get element;

  /// The element of the [operator] for the matched type.
  ///
  /// Returns `null` if the AST structure hasn't been resolved or if the
  /// operator couldn't be resolved.
  @experimental
  MethodElement2? get element2;

  /// The expression used to compute the operand.
  Expression get operand;

  /// The relational operator being applied.
  Token get operator;
}

final class RelationalPatternImpl extends DartPatternImpl
    implements RelationalPattern {
  ExpressionImpl _operand;

  @override
  final Token operator;

  @override
  MethodElement? element;

  RelationalPatternImpl({
    required this.operator,
    required ExpressionImpl operand,
  }) : _operand = operand {
    _becomeParentOf(operand);
  }

  @override
  Token get beginToken => operator;

  @experimental
  @override
  MethodElement2? get element2 {
    if (element case MethodFragment fragment) {
      return fragment.element;
    }
    return null;
  }

  @override
  Token get endToken => operand.endToken;

  @override
  ExpressionImpl get operand => _operand;

  set operand(ExpressionImpl operand) {
    _operand = _becomeParentOf(operand);
  }

  @override
  PatternPrecedence get precedence => PatternPrecedence.relational;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('operator', operator)
    ..addNode('operand', operand);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitRelationalPattern(this);

  @override
  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
    return resolverVisitor
        .analyzeRelationalPatternSchema()
        .unwrapTypeSchemaView();
  }

  @override
  PatternResult<DartType> resolvePattern(
    ResolverVisitor resolverVisitor,
    SharedMatchContext context,
  ) {
    inferenceLogWriter?.enterPattern(this);
    var analysisResult =
        resolverVisitor.analyzeRelationalPattern(context, this, operand);
    resolverVisitor.popRewrite();
    inferenceLogWriter?.exitPattern(this);
    return analysisResult;
  }

  @override
  void visitChildren(AstVisitor visitor) {
    operand.accept(visitor);
  }
}

/// The name of the primary constructor of an extension type.
@experimental
abstract final class RepresentationConstructorName implements AstNode {
  /// The name of the primary constructor.
  Token get name;

  /// The period separating [name] from the previous token.
  Token get period;
}

final class RepresentationConstructorNameImpl extends AstNodeImpl
    implements RepresentationConstructorName {
  @override
  final Token period;

  @override
  final Token name;

  RepresentationConstructorNameImpl({
    required this.period,
    required this.name,
  });

  @override
  Token get beginToken => period;

  @override
  Token get endToken => name;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('period', period)
    ..addToken('name', name);

  @override
  E? accept<E>(AstVisitor<E> visitor) {
    return visitor.visitRepresentationConstructorName(this);
  }

  @override
  void visitChildren(AstVisitor visitor) {}
}

/// The declaration of an extension type representation.
///
/// It declares both the representation field and the primary constructor.
///
///    <representationDeclaration> ::=
///        ('.' <identifierOrNew>)? '(' <metadata> <type> <identifier> ')'
@experimental
abstract final class RepresentationDeclaration implements AstNode {
  /// The element of the primary constructor.
  ConstructorElement? get constructorElement;

  /// The fragment of the primary constructor contained in this declaration.
  @experimental
  ConstructorFragment? get constructorFragment;

  /// The optional name of the primary constructor.
  RepresentationConstructorName? get constructorName;

  /// The element for [fieldName] with [fieldType].
  FieldElement? get fieldElement;

  /// The fragment for [fieldName] with [fieldType] contained in this
  /// declaration.
  @experimental
  FieldFragment? get fieldFragment;

  /// The annotations associated with the field.
  NodeList<Annotation> get fieldMetadata;

  /// The representation name.
  Token get fieldName;

  /// The representation type.
  TypeAnnotation get fieldType;

  /// The left parenthesis.
  Token get leftParenthesis;

  /// The right parenthesis.
  Token get rightParenthesis;
}

final class RepresentationDeclarationImpl extends AstNodeImpl
    implements RepresentationDeclaration {
  @override
  final RepresentationConstructorNameImpl? constructorName;

  @override
  ConstructorElementImpl? constructorElement;

  @override
  final Token leftParenthesis;

  @override
  final NodeListImpl<AnnotationImpl> fieldMetadata = NodeListImpl._();

  @override
  final TypeAnnotationImpl fieldType;

  @override
  final Token fieldName;

  @override
  FieldElementImpl? fieldElement;

  @override
  final Token rightParenthesis;

  RepresentationDeclarationImpl({
    required this.constructorName,
    required this.leftParenthesis,
    required List<AnnotationImpl> fieldMetadata,
    required this.fieldType,
    required this.fieldName,
    required this.rightParenthesis,
  }) {
    this.fieldMetadata._initialize(this, fieldMetadata);
    _becomeParentOf(constructorName);
    _becomeParentOf(fieldType);
  }

  @override
  Token get beginToken => constructorName?.beginToken ?? leftParenthesis;

  @experimental
  @override
  ConstructorFragment? get constructorFragment =>
      constructorElement as ConstructorFragment?;

  @override
  Token get endToken => rightParenthesis;

  @experimental
  @override
  FieldFragment? get fieldFragment => fieldElement as FieldFragment?;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addNode('constructorName', constructorName)
    ..addToken('leftParenthesis', leftParenthesis)
    ..addNodeList('fieldMetadata', fieldMetadata)
    ..addNode('fieldType', fieldType)
    ..addToken('fieldName', fieldName)
    ..addToken('rightParenthesis', rightParenthesis);

  @override
  E? accept<E>(AstVisitor<E> visitor) {
    return visitor.visitRepresentationDeclaration(this);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    constructorName?.accept(visitor);
    fieldMetadata.accept(visitor);
    fieldType.accept(visitor);
  }
}

/// A rest pattern element.
///
///    restPatternElement ::= '...' [DartPattern]?
abstract final class RestPatternElement
    implements ListPatternElement, MapPatternElement {
  /// The operator token '...'.
  Token get operator;

  /// The optional pattern.
  DartPattern? get pattern;
}

final class RestPatternElementImpl extends AstNodeImpl
    implements
        RestPatternElement,
        ListPatternElementImpl,
        MapPatternElementImpl {
  @override
  final Token operator;

  @override
  final DartPatternImpl? pattern;

  RestPatternElementImpl({
    required this.operator,
    required this.pattern,
  }) {
    _becomeParentOf(pattern);
  }

  @override
  Token get beginToken => operator;

  @override
  Token get endToken => pattern?.endToken ?? operator;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('operator', operator)
    ..addNode('pattern', pattern);

  @override
  E? accept<E>(AstVisitor<E> visitor) {
    return visitor.visitRestPatternElement(this);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    pattern?.accept(visitor);
  }
}

/// A rethrow expression.
///
///    rethrowExpression ::=
///        'rethrow'
abstract final class RethrowExpression implements Expression {
  /// The token representing the `rethrow` keyword.
  Token get rethrowKeyword;
}

final class RethrowExpressionImpl extends ExpressionImpl
    implements RethrowExpression {
  @override
  final Token rethrowKeyword;

  /// Initializes a newly created rethrow expression.
  RethrowExpressionImpl({
    required this.rethrowKeyword,
  });

  @override
  Token get beginToken => rethrowKeyword;

  @override
  Token get endToken => rethrowKeyword;

  @override
  Precedence get precedence => Precedence.assignment;

  @override
  ChildEntities get _childEntities =>
      ChildEntities()..addToken('rethrowKeyword', rethrowKeyword);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitRethrowExpression(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitRethrowExpression(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    // There are no children to visit.
  }
}

/// A return statement.
///
///    returnStatement ::=
///        'return' [Expression]? ';'
abstract final class ReturnStatement implements Statement {
  /// The expression computing the value to be returned, or `null` if no
  /// explicit value was provided.
  Expression? get expression;

  /// The token representing the `return` keyword.
  Token get returnKeyword;

  /// The semicolon terminating the statement.
  Token get semicolon;
}

final class ReturnStatementImpl extends StatementImpl
    implements ReturnStatement {
  @override
  final Token returnKeyword;

  ExpressionImpl? _expression;

  @override
  final Token semicolon;

  /// Initializes a newly created return statement.
  ///
  /// The [expression] can be `null` if no explicit value was provided.
  ReturnStatementImpl({
    required this.returnKeyword,
    required ExpressionImpl? expression,
    required this.semicolon,
  }) : _expression = expression {
    _becomeParentOf(_expression);
  }

  @override
  Token get beginToken => returnKeyword;

  @override
  Token get endToken => semicolon;

  @override
  ExpressionImpl? get expression => _expression;

  set expression(ExpressionImpl? expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('returnKeyword', returnKeyword)
    ..addNode('expression', expression)
    ..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitReturnStatement(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _expression?.accept(visitor);
  }
}

/// A script tag that can optionally occur at the beginning of a compilation
/// unit.
///
///    scriptTag ::=
///        '#!' (~NEWLINE)* NEWLINE
abstract final class ScriptTag implements AstNode {
  /// The token representing this script tag.
  Token get scriptTag;
}

final class ScriptTagImpl extends AstNodeImpl implements ScriptTag {
  @override
  final Token scriptTag;

  /// Initializes a newly created script tag.
  ScriptTagImpl({
    required this.scriptTag,
  });

  @override
  Token get beginToken => scriptTag;

  @override
  Token get endToken => scriptTag;

  @override
  ChildEntities get _childEntities =>
      ChildEntities()..addToken('scriptTag', scriptTag);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitScriptTag(this);

  @override
  void visitChildren(AstVisitor visitor) {
    // There are no children to visit.
  }
}

/// A set or map literal.
///
///    setOrMapLiteral ::=
///        'const'? [TypeArgumentList]? '{' elements? '}'
///
///    elements ::=
///        [CollectionElement] ( ',' [CollectionElement] )* ','?
///
/// This is the class that is used to represent either a map or set literal when
/// either the 'control-flow-collections' or 'spread-collections' experiments
/// are enabled. If neither of those experiments are enabled, then `MapLiteral`
/// is used to represent a map literal and `SetLiteral` is used for set
/// literals.
abstract final class SetOrMapLiteral implements TypedLiteral {
  /// The syntactic elements used to compute the elements of the set or map.
  NodeList<CollectionElement> get elements;

  /// Whether this literal represents a map literal.
  ///
  /// This getter always returns `false` if [isSet] returns `true`.
  ///
  /// However, this getter is _not_ the inverse of [isSet]. It's possible for
  /// both getters to return `false` if
  ///
  /// - the AST hasn't been resolved (because determining the kind of the
  ///   literal is done during resolution),
  /// - the literal is ambiguous (contains one or more spread elements and none
  ///   of those elements can be used to determine the kind of the literal), or
  /// - the literal is invalid because it contains both expressions (for sets)
  ///   and map entries (for maps).
  ///
  /// In both of the latter two cases there are compilation errors associated
  /// with the literal.
  bool get isMap;

  /// Whether this literal represents a set literal.
  ///
  /// This getter always returns `false` if [isMap] returns `true`.
  ///
  /// However, this getter is _not_ the inverse of [isMap]. It's possible for
  /// both getters to return `false` if
  ///
  /// - the AST hasn't been resolved (because determining the kind of the
  ///   literal is done during resolution),
  /// - the literal is ambiguous (contains one or more spread elements and none
  ///   of those elements can be used to determine the kind of the literal), or
  /// - the literal is invalid because it contains both expressions (for sets)
  ///   and map entries (for maps).
  ///
  /// In both of the latter two cases there are compilation errors associated
  /// with the literal.
  bool get isSet;

  /// The left curly bracket.
  Token get leftBracket;

  /// The right curly bracket.
  Token get rightBracket;
}

final class SetOrMapLiteralImpl extends TypedLiteralImpl
    implements SetOrMapLiteral {
  @override
  final Token leftBracket;

  final NodeListImpl<CollectionElementImpl> _elements = NodeListImpl._();

  @override
  final Token rightBracket;

  /// A representation of whether this literal represents a map or a set, or
  /// whether the kind hasn't or can't be determined.
  _SetOrMapKind _resolvedKind = _SetOrMapKind.unresolved;

  /// The context type computed by
  /// [ResolverVisitor._computeSetOrMapContextType].
  ///
  /// Note that this isn't the same as the context pushed down by type
  /// inference (which can be obtained via [InferenceContext.getContext]). For
  /// example, in the following code:
  ///
  ///     var m = {};
  ///
  /// The context pushed down by type inference is null, whereas the
  /// `contextType` is `Map<dynamic, dynamic>`.
  InterfaceType? contextType;

  /// Initializes a newly created set or map literal.
  ///
  /// The [constKeyword] can be `null` if the literal isn't a constant.
  ///
  /// The [typeArguments] can be `null` if no type arguments were declared.
  ///
  /// The [elements] can be `null` if the set is empty.
  SetOrMapLiteralImpl({
    required super.constKeyword,
    required super.typeArguments,
    required this.leftBracket,
    required List<CollectionElementImpl> elements,
    required this.rightBracket,
  }) {
    _elements._initialize(this, elements);
  }

  @override
  Token get beginToken {
    if (constKeyword case var constKeyword?) {
      return constKeyword;
    }
    var typeArguments = this.typeArguments;
    if (typeArguments != null) {
      return typeArguments.beginToken;
    }
    return leftBracket;
  }

  @override
  NodeListImpl<CollectionElementImpl> get elements => _elements;

  @override
  Token get endToken => rightBracket;

  @override
  bool get isMap => _resolvedKind == _SetOrMapKind.map;

  @override
  bool get isSet => _resolvedKind == _SetOrMapKind.set;

  @override
  // TODO(paulberry): add commas.
  ChildEntities get _childEntities => super._childEntities
    ..addToken('leftBracket', leftBracket)
    ..addNodeList('elements', elements)
    ..addToken('rightBracket', rightBracket);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitSetOrMapLiteral(this);

  void becomeMap() {
    assert(_resolvedKind == _SetOrMapKind.unresolved ||
        _resolvedKind == _SetOrMapKind.map);
    _resolvedKind = _SetOrMapKind.map;
  }

  void becomeSet() {
    assert(_resolvedKind == _SetOrMapKind.unresolved ||
        _resolvedKind == _SetOrMapKind.set);
    _resolvedKind = _SetOrMapKind.set;
  }

  void becomeUnresolved() {
    _resolvedKind = _SetOrMapKind.unresolved;
  }

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitSetOrMapLiteral(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _elements.accept(visitor);
  }
}

/// A combinator that restricts the names being imported to those in a given
/// list.
///
///    showCombinator ::=
///        'show' [SimpleIdentifier] (',' [SimpleIdentifier])*
abstract final class ShowCombinator implements Combinator {
  /// The list of names from the library that are made visible by this
  /// combinator.
  NodeList<SimpleIdentifier> get shownNames;
}

final class ShowCombinatorImpl extends CombinatorImpl
    implements ShowCombinator {
  final NodeListImpl<SimpleIdentifierImpl> _shownNames = NodeListImpl._();

  /// Initializes a newly created import show combinator.
  ShowCombinatorImpl({
    required super.keyword,
    required List<SimpleIdentifierImpl> shownNames,
  }) {
    _shownNames._initialize(this, shownNames);
  }

  @override
  Token get endToken => _shownNames.endToken!;

  @override
  NodeListImpl<SimpleIdentifierImpl> get shownNames => _shownNames;

  @override
  // TODO(paulberry): add commas.
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('keyword', keyword)
    ..addNodeList('shownNames', shownNames);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitShowCombinator(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _shownNames.accept(visitor);
  }
}

/// A simple formal parameter.
///
///    simpleFormalParameter ::=
///        ('final' [TypeAnnotation] | 'var' | [TypeAnnotation])?
///        [SimpleIdentifier]
abstract final class SimpleFormalParameter implements NormalFormalParameter {
  /// The token representing either the `final`, `const` or `var` keyword, or
  /// `null` if no keyword was used.
  Token? get keyword;

  /// The declared type of the parameter, or `null` if the parameter doesn't
  /// have a declared type.
  TypeAnnotation? get type;
}

final class SimpleFormalParameterImpl extends NormalFormalParameterImpl
    implements SimpleFormalParameter {
  @override
  final Token? keyword;

  TypeAnnotationImpl? _type;

  /// Initializes a newly created formal parameter.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// parameter doesn't have the corresponding attribute.
  ///
  /// The [keyword] can be `null` if a type was specified.
  ///
  /// The [type] must be `null` if the keyword is `var`.
  SimpleFormalParameterImpl({
    required super.comment,
    required super.metadata,
    required super.covariantKeyword,
    required super.requiredKeyword,
    required this.keyword,
    required TypeAnnotationImpl? type,
    required super.name,
  }) : _type = type {
    _becomeParentOf(_type);
  }

  @override
  Token get endToken => name ?? type!.endToken;

  @override
  Token get firstTokenAfterCommentAndMetadata =>
      requiredKeyword ??
      covariantKeyword ??
      keyword ??
      type?.beginToken ??
      name!;

  @override
  bool get isConst => keyword?.keyword == Keyword.CONST;

  @override
  bool get isExplicitlyTyped => _type != null;

  @override
  bool get isFinal => keyword?.keyword == Keyword.FINAL;

  @override
  TypeAnnotationImpl? get type => _type;

  set type(TypeAnnotationImpl? type) {
    _type = _becomeParentOf(type);
  }

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('keyword', keyword)
    ..addNode('type', type)
    ..addToken('name', name);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitSimpleFormalParameter(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _type?.accept(visitor);
  }
}

/// A simple identifier.
///
///    simpleIdentifier ::=
///        initialCharacter internalCharacter*
///
///    initialCharacter ::= '_' | '$' | letter
///
///    internalCharacter ::= '_' | '$' | letter | digit
abstract final class SimpleIdentifier implements Identifier {
  /// Whether this identifier is the "name" part of a prefixed identifier or a
  /// method invocation.
  bool get isQualified;

  /// If the identifier is a tear-off, return the inferred type arguments
  /// applied to the function type of the element to produce its `[staticType]`.
  ///
  /// An empty list if the function type doesn't have type parameters or if the
  /// context type has type parameters, or `null` if this node isn't a tear-off
  /// or if the AST structure hasn't been resolved.
  List<DartType>? get tearOffTypeArgumentTypes;

  /// The token representing the identifier.
  Token get token;

  /// Whether this identifier is the name being declared in a declaration.
  // TODO(brianwilkerson): Convert this to a getter.
  bool inDeclarationContext();

  /// Whether this expression is computing a right-hand value.
  ///
  /// Note that [inGetterContext] and [inSetterContext] aren't opposites, nor
  /// are they mutually exclusive. In other words, it's possible for both
  /// methods to return `true` when invoked on the same node.
  // TODO(brianwilkerson): Convert this to a getter.
  bool inGetterContext();

  /// Whether this expression is computing a left-hand value.
  ///
  /// Note that [inGetterContext] and [inSetterContext] aren't opposites, nor
  /// are they mutually exclusive. In other words, it's possible for both
  /// methods to return `true` when invoked on the same node.
  // TODO(brianwilkerson): Convert this to a getter.
  bool inSetterContext();
}

final class SimpleIdentifierImpl extends IdentifierImpl
    implements SimpleIdentifier {
  @override
  Token token;

  /// The element associated with this identifier based on static type
  /// information, or `null` if the AST structure hasn't been resolved or if
  /// this identifier couldn't be resolved.
  Element? _staticElement;

  @override
  List<DartType>? tearOffTypeArgumentTypes;

  /// If this identifier is meant to be looked up in the enclosing scope, the
  /// raw result the scope lookup, prior to figuring out whether a write or a
  /// read context is intended, and prior to falling back on implicit `this` (if
  /// appropriate).
  ///
  /// Or `null` if this identifier isn't meant to be looked up in the enclosing
  /// scope.
  ScopeLookupResult? scopeLookupResult;

  /// Initializes a newly created identifier.
  SimpleIdentifierImpl(this.token);

  /// The cascade that contains this [SimpleIdentifier].
  CascadeExpressionImpl? get ancestorCascade {
    var operatorType = token.previous?.type;
    if (operatorType == TokenType.PERIOD_PERIOD ||
        operatorType == TokenType.QUESTION_PERIOD_PERIOD) {
      return thisOrAncestorOfType<CascadeExpressionImpl>();
    }
    return null;
  }

  @override
  Token get beginToken => token;

  @override
  Token get endToken => token;

  @override
  bool get isQualified {
    var parent = this.parent!;
    if (parent is PrefixedIdentifier) {
      return identical(parent.identifier, this);
    } else if (parent is PropertyAccess) {
      return identical(parent.propertyName, this);
    } else if (parent is ConstructorName) {
      return identical(parent.name, this);
    } else if (parent is MethodInvocation) {
      MethodInvocation invocation = parent;
      return identical(invocation.methodName, this) &&
          invocation.realTarget != null;
    }
    return false;
  }

  @override
  bool get isSynthetic => token.isSynthetic;

  @override
  String get name => token.lexeme;

  @override
  Precedence get precedence => Precedence.primary;

  /// The element being referenced by this identifier, or `null` if this
  /// identifier is used to either read or write a value, the AST structure
  /// hasn't been resolved, or if this identifier couldn't be resolved.
  ///
  /// This element is set when this identifier is used not as an expression,
  /// but just to reference some element.
  ///
  /// Examples are the name of the type in a [NamedType], the name of the method
  /// in a [MethodInvocation], the name of the constructor in a
  /// [ConstructorName], the name of the property in a [PropertyAccess], the
  /// prefix and the identifier in a [PrefixedIdentifier] (which then can be
  /// used to read or write a value).
  ///
  /// In invalid code, for recovery, any element could be used. For example, in
  /// `set mySetter(_) {} mySetter topVar;` a setter is used as a type name. We
  /// do this to help the user to navigate to this element, and maybe change its
  /// name, add a new declaration, etc.
  ///
  /// If either [readElement] or [writeElement] aren't `null`, the
  /// [referenceElement] is `null`, because the identifier is being used to
  /// read or write a value.
  ///
  /// All three of [readElement], [writeElement], and [referenceElement] can be
  /// `null` when the AST structure hasn't been resolved, or this identifier
  /// couldn't be resolved.
  Element? get referenceElement => null;

  @override
  Element? get staticElement => _staticElement;

  set staticElement(Element? element) {
    _staticElement = element;
  }

  @override
  ChildEntities get _childEntities => ChildEntities()..addToken('token', token);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitSimpleIdentifier(this);

  @override
  bool inDeclarationContext() {
    var parent = this.parent;
    switch (parent) {
      case ImportDirective():
        return parent.prefix == this;
      case Label():
        var parent2 = parent.parent;
        return parent2 is Statement || parent2 is SwitchMember;
    }
    return false;
  }

  @override
  bool inGetterContext() {
    AstNode initialParent = this.parent!;
    AstNode parent = initialParent;
    AstNode target = this;
    // skip prefix
    if (initialParent is PrefixedIdentifier) {
      if (identical(initialParent.prefix, this)) {
        return true;
      }
      parent = initialParent.parent!;
      target = initialParent;
    } else if (initialParent is PropertyAccess) {
      if (identical(initialParent.target, this)) {
        return true;
      }
      parent = initialParent.parent!;
      target = initialParent;
    }
    // skip label
    if (parent is Label) {
      return false;
    }
    // analyze usage
    if (parent is AssignmentExpression) {
      if (identical(parent.leftHandSide, target) &&
          parent.operator.type == TokenType.EQ) {
        return false;
      }
    }
    if (parent is ConstructorFieldInitializer &&
        identical(parent.fieldName, target)) {
      return false;
    }
    if (parent is ForEachPartsWithIdentifier) {
      if (identical(parent.identifier, target)) {
        return false;
      }
    }
    return true;
  }

  @override
  bool inSetterContext() {
    AstNode initialParent = this.parent!;
    AstNode parent = initialParent;
    AstNode target = this;
    // skip prefix
    if (initialParent is PrefixedIdentifier) {
      // if this is the prefix, then return false
      if (identical(initialParent.prefix, this)) {
        return false;
      }
      parent = initialParent.parent!;
      target = initialParent;
    } else if (initialParent is PropertyAccess) {
      if (identical(initialParent.target, this)) {
        return false;
      }
      parent = initialParent.parent!;
      target = initialParent;
    }
    // analyze usage
    if (parent is PrefixExpression) {
      return parent.operator.type.isIncrementOperator;
    } else if (parent is PostfixExpression) {
      return parent.operator.type.isIncrementOperator;
    } else if (parent is AssignmentExpression) {
      return identical(parent.leftHandSide, target);
    } else if (parent is ForEachPartsWithIdentifier) {
      return identical(parent.identifier, target);
    }
    return false;
  }

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitSimpleIdentifier(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    // There are no children to visit.
  }
}

/// A string literal expression that doesn't contain any interpolations.
///
///    simpleStringLiteral ::=
///        rawStringLiteral
///      | basicStringLiteral
///
///    rawStringLiteral ::=
///        'r' basicStringLiteral
///
///    basicStringLiteral ::=
///        multiLineStringLiteral
///      | singleLineStringLiteral
///
///    multiLineStringLiteral ::=
///        "'''" characters "'''"
///      | '"""' characters '"""'
///
///    singleLineStringLiteral ::=
///        "'" characters "'"
///      | '"' characters '"'
abstract final class SimpleStringLiteral implements SingleStringLiteral {
  /// The token representing the literal.
  Token get literal;

  /// The value of the literal.
  String get value;
}

final class SimpleStringLiteralImpl extends SingleStringLiteralImpl
    implements SimpleStringLiteral {
  @override
  final Token literal;

  @override
  String value;

  /// Initializes a newly created simple string literal.
  SimpleStringLiteralImpl({
    required this.literal,
    required this.value,
  });

  @override
  Token get beginToken => literal;

  @override
  int get contentsEnd => offset + _helper.end;

  @override
  int get contentsOffset => offset + _helper.start;

  @override
  Token get endToken => literal;

  @override
  bool get isMultiline => _helper.isMultiline;

  @override
  bool get isRaw => _helper.isRaw;

  @override
  bool get isSingleQuoted => _helper.isSingleQuoted;

  @override
  bool get isSynthetic => literal.isSynthetic;

  @override
  ChildEntities get _childEntities =>
      ChildEntities()..addToken('literal', literal);

  StringLexemeHelper get _helper {
    return StringLexemeHelper(literal.lexeme, true, true);
  }

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitSimpleStringLiteral(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitSimpleStringLiteral(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    // There are no children to visit.
  }

  @override
  void _appendStringValue(StringBuffer buffer) {
    buffer.write(value);
  }
}

/// A single string literal expression.
///
///    singleStringLiteral ::=
///        [SimpleStringLiteral]
///      | [StringInterpolation]
sealed class SingleStringLiteral implements StringLiteral {
  /// The offset of the after-last contents character.
  int get contentsEnd;

  /// The offset of the first contents character.
  ///
  /// If the string is multiline, then leading whitespaces are skipped.
  int get contentsOffset;

  /// Whether this string literal is a multi-line string.
  bool get isMultiline;

  /// Whether this string literal is a raw string.
  bool get isRaw;

  /// Whether this string literal uses single quotes (' or ''').
  ///
  /// If `false` is returned then the string literal uses double quotes
  /// (" or """).
  bool get isSingleQuoted;
}

sealed class SingleStringLiteralImpl extends StringLiteralImpl
    implements SingleStringLiteral {}

/// A spread element.
///
///    spreadElement:
///        ( '...' | '...?' ) [Expression]
abstract final class SpreadElement implements CollectionElement {
  /// The expression used to compute the collection being spread.
  Expression get expression;

  /// Whether this is a null-aware spread, as opposed to a non-null spread.
  bool get isNullAware;

  /// The spread operator, either '...' or '...?'.
  Token get spreadOperator;
}

final class SpreadElementImpl extends AstNodeImpl
    implements CollectionElementImpl, SpreadElement {
  @override
  final Token spreadOperator;

  ExpressionImpl _expression;

  SpreadElementImpl({
    required this.spreadOperator,
    required ExpressionImpl expression,
  }) : _expression = expression {
    _becomeParentOf(_expression);
  }

  @override
  Token get beginToken => spreadOperator;

  @override
  Token get endToken => _expression.endToken;

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  bool get isNullAware =>
      spreadOperator.type == TokenType.PERIOD_PERIOD_PERIOD_QUESTION;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('spreadOperator', spreadOperator)
    ..addNode('expression', expression);

  @override
  E? accept<E>(AstVisitor<E> visitor) {
    return visitor.visitSpreadElement(this);
  }

  @override
  void resolveElement(
      ResolverVisitor resolver, CollectionLiteralContext? context) {
    resolver.visitSpreadElement(this, context: context);
    resolver.pushRewrite(null);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _expression.accept(visitor);
  }
}

/// A node that represents a statement.
///
///    statement ::=
///        [Block]
///      | [VariableDeclarationStatement]
///      | [ForStatement]
///      | [ForEachStatement]
///      | [WhileStatement]
///      | [DoStatement]
///      | [SwitchStatement]
///      | [IfStatement]
///      | [TryStatement]
///      | [BreakStatement]
///      | [ContinueStatement]
///      | [ReturnStatement]
///      | [ExpressionStatement]
///      | [FunctionDeclarationStatement]
abstract final class Statement implements AstNode {
  /// If this is a labeled statement, returns the statement being labeled,
  /// otherwise returns the statement itself.
  Statement get unlabeled;
}

sealed class StatementImpl extends AstNodeImpl implements Statement {
  @override
  StatementImpl get unlabeled => this;
}

/// A string interpolation literal.
///
///    stringInterpolation ::=
///        ''' [InterpolationElement]* '''
///      | '"' [InterpolationElement]* '"'
abstract final class StringInterpolation implements SingleStringLiteral {
  /// The elements that are composed to produce the resulting string.
  ///
  /// The list includes [firstString] and [lastString].
  NodeList<InterpolationElement> get elements;

  /// The first element in this interpolation, which is always a string.
  ///
  /// The string might be empty if there's no text before the first
  /// interpolation expression (such as in `'$foo bar'`).
  InterpolationString get firstString;

  /// The last element in this interpolation, which is always a string.
  ///
  /// The string might be empty if there's no text after the last
  /// interpolation expression (such as in `'foo $bar'`).
  InterpolationString get lastString;
}

final class StringInterpolationImpl extends SingleStringLiteralImpl
    implements StringInterpolation {
  /// The elements that are composed to produce the resulting string.
  final NodeListImpl<InterpolationElementImpl> _elements = NodeListImpl._();

  /// Initializes a newly created string interpolation expression.
  StringInterpolationImpl({
    required List<InterpolationElementImpl> elements,
  }) {
    // TODO(scheglov): Replace asserts with appropriately typed parameters.
    assert(elements.length > 2, 'Expected at last three elements.');
    assert(
      elements.first is InterpolationStringImpl,
      'The first element must be a string.',
    );
    assert(
      elements[1] is InterpolationExpressionImpl,
      'The second element must be an expression.',
    );
    assert(
      elements.last is InterpolationStringImpl,
      'The last element must be a string.',
    );
    _elements._initialize(this, elements);
  }

  @override
  Token get beginToken => _elements.beginToken!;

  @override
  int get contentsEnd {
    var element = _elements.last as InterpolationString;
    return element.contentsEnd;
  }

  @override
  int get contentsOffset {
    var element = _elements.first as InterpolationString;
    return element.contentsOffset;
  }

  @override
  NodeListImpl<InterpolationElementImpl> get elements => _elements;

  @override
  Token get endToken => _elements.endToken!;

  @override
  InterpolationStringImpl get firstString =>
      elements.first as InterpolationStringImpl;

  @override
  bool get isMultiline => _firstHelper.isMultiline;

  @override
  bool get isRaw => false;

  @override
  bool get isSingleQuoted => _firstHelper.isSingleQuoted;

  @override
  InterpolationStringImpl get lastString =>
      elements.last as InterpolationStringImpl;

  @override
  ChildEntities get _childEntities =>
      ChildEntities()..addNodeList('elements', elements);

  StringLexemeHelper get _firstHelper {
    var lastString = _elements.first as InterpolationString;
    String lexeme = lastString.contents.lexeme;
    return StringLexemeHelper(lexeme, true, false);
  }

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitStringInterpolation(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitStringInterpolation(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _elements.accept(visitor);
  }

  @override
  void _appendStringValue(StringBuffer buffer) {
    throw ArgumentError();
  }
}

/// A helper for analyzing string lexemes.
class StringLexemeHelper {
  final String lexeme;
  final bool isFirst;
  final bool isLast;

  bool isRaw = false;
  bool isSingleQuoted = false;
  bool isMultiline = false;
  int start = 0;
  int end = 0;

  StringLexemeHelper(this.lexeme, this.isFirst, this.isLast) {
    if (isFirst) {
      isRaw = lexeme.startsWith('r');
      if (isRaw) {
        start++;
      }
      if (lexeme.startsWith("'''", start)) {
        isSingleQuoted = true;
        isMultiline = true;
        start += 3;
        start = _trimInitialWhitespace(start);
      } else if (lexeme.startsWith('"""', start)) {
        isSingleQuoted = false;
        isMultiline = true;
        start += 3;
        start = _trimInitialWhitespace(start);
      } else if (start < lexeme.length && lexeme.codeUnitAt(start) == 0x27) {
        isSingleQuoted = true;
        isMultiline = false;
        start++;
      } else if (start < lexeme.length && lexeme.codeUnitAt(start) == 0x22) {
        isSingleQuoted = false;
        isMultiline = false;
        start++;
      }
    }
    end = lexeme.length;
    if (isLast) {
      if (start + 3 <= end &&
          (lexeme.endsWith("'''") || lexeme.endsWith('"""'))) {
        end -= 3;
      } else if (start + 1 <= end &&
          (lexeme.endsWith("'") || lexeme.endsWith('"'))) {
        end -= 1;
      }
    }
  }

  /// Given the [lexeme] for a multi-line string whose content begins at the
  /// given [start] index, returns the index of the first character that is
  /// included in the value of the string.
  ///
  /// According to the specification:
  ///
  /// If the first line of a multiline string consists solely of the whitespace
  /// characters defined by the production WHITESPACE 20.1), possibly prefixed
  /// by \, then that line is ignored, including the new line at its end.
  int _trimInitialWhitespace(int start) {
    int length = lexeme.length;
    int index = start;
    while (index < length) {
      int currentChar = lexeme.codeUnitAt(index);
      if (currentChar == 0x0D) {
        if (index + 1 < length && lexeme.codeUnitAt(index + 1) == 0x0A) {
          return index + 2;
        }
        return index + 1;
      } else if (currentChar == 0x0A) {
        return index + 1;
      } else if (currentChar == 0x5C) {
        if (index + 1 >= length) {
          return start;
        }
        currentChar = lexeme.codeUnitAt(index + 1);
        if (currentChar != 0x0D &&
            currentChar != 0x0A &&
            currentChar != 0x09 &&
            currentChar != 0x20) {
          return start;
        }
      } else if (currentChar != 0x09 && currentChar != 0x20) {
        return start;
      }
      index++;
    }
    return start;
  }
}

/// A string literal expression.
///
///    stringLiteral ::=
///        [SimpleStringLiteral]
///      | [AdjacentStrings]
///      | [StringInterpolation]
sealed class StringLiteral implements Literal {
  /// The value of the string literal, or `null` if the string isn't a constant
  /// string without any string interpolation.
  String? get stringValue;
}

sealed class StringLiteralImpl extends LiteralImpl implements StringLiteral {
  @override
  String? get stringValue {
    StringBuffer buffer = StringBuffer();
    try {
      _appendStringValue(buffer);
    } on ArgumentError {
      return null;
    }
    return buffer.toString();
  }

  /// Append the value of this string literal to the given [buffer].
  ///
  /// Throw an [ArgumentError] if the string isn't a constant string without any
  /// string interpolation.
  void _appendStringValue(StringBuffer buffer);
}

/// The invocation of a superclass' constructor from within a constructor's
/// initialization list.
///
///    superInvocation ::=
///        'super' ('.' [SimpleIdentifier])? [ArgumentList]
abstract final class SuperConstructorInvocation
    implements ConstructorInitializer, ConstructorReferenceNode {
  /// The list of arguments to the constructor.
  ArgumentList get argumentList;

  /// The name of the constructor that is being invoked, or `null` if the
  /// unnamed constructor is being invoked.
  SimpleIdentifier? get constructorName;

  /// The token for the period before the name of the constructor that is being
  /// invoked, or `null` if the unnamed constructor is being invoked.
  Token? get period;

  /// The token for the `super` keyword.
  Token get superKeyword;
}

final class SuperConstructorInvocationImpl extends ConstructorInitializerImpl
    implements SuperConstructorInvocation {
  @override
  final Token superKeyword;

  @override
  final Token? period;

  SimpleIdentifierImpl? _constructorName;

  ArgumentListImpl _argumentList;

  @override
  ConstructorElement? staticElement;

  /// Initializes a newly created super invocation to invoke the inherited
  /// constructor with the given name with the given arguments.
  ///
  /// The [period] and [constructorName] can be `null` if the constructor being
  /// invoked is the unnamed constructor.
  SuperConstructorInvocationImpl({
    required this.superKeyword,
    required this.period,
    required SimpleIdentifierImpl? constructorName,
    required ArgumentListImpl argumentList,
  })  : _constructorName = constructorName,
        _argumentList = argumentList {
    _becomeParentOf(_constructorName);
    _becomeParentOf(_argumentList);
  }

  @override
  ArgumentListImpl get argumentList => _argumentList;

  set argumentList(ArgumentListImpl argumentList) {
    _argumentList = _becomeParentOf(argumentList);
  }

  @override
  Token get beginToken => superKeyword;

  @override
  SimpleIdentifierImpl? get constructorName => _constructorName;

  set constructorName(SimpleIdentifierImpl? identifier) {
    _constructorName = _becomeParentOf(identifier);
  }

  @experimental
  @override
  ConstructorElement2? get element =>
      staticElement?.asElement2 as ConstructorElement2?;

  @override
  Token get endToken => _argumentList.endToken;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('superKeyword', superKeyword)
    ..addToken('period', period)
    ..addNode('constructorName', constructorName)
    ..addNode('argumentList', argumentList);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitSuperConstructorInvocation(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _constructorName?.accept(visitor);
    _argumentList.accept(visitor);
  }
}

/// A super expression.
///
///    superExpression ::=
///        'super'
abstract final class SuperExpression implements Expression {
  /// The token representing the `super` keyword.
  Token get superKeyword;
}

final class SuperExpressionImpl extends ExpressionImpl
    implements SuperExpression {
  @override
  final Token superKeyword;

  /// Initializes a newly created super expression.
  SuperExpressionImpl({
    required this.superKeyword,
  });

  @override
  Token get beginToken => superKeyword;

  @override
  Token get endToken => superKeyword;

  @override
  Precedence get precedence => Precedence.primary;

  @override
  ChildEntities get _childEntities =>
      ChildEntities()..addToken('superKeyword', superKeyword);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitSuperExpression(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitSuperExpression(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    // There are no children to visit.
  }
}

/// A super-initializer formal parameter.
///
///    superFormalParameter ::=
///        ('final' [TypeAnnotation] | 'const' [TypeAnnotation] | 'var' |
///        [TypeAnnotation])?
///        'super' '.' name ([TypeParameterList]? [FormalParameterList])?
abstract final class SuperFormalParameter implements NormalFormalParameter {
  /// The token representing either the `final`, `const` or `var` keyword, or
  /// `null` if no keyword was used.
  Token? get keyword;

  /// The name of the parameter being declared.
  @override
  Token get name;

  /// The parameters of the function-typed parameter, or `null` if this isn't a
  /// function-typed field formal parameter.
  FormalParameterList? get parameters;

  /// The token representing the period.
  Token get period;

  /// The question mark indicating that the function type is nullable, or `null`
  /// if there's no question mark, which will always be the case when the
  /// parameter doesn't use the older style for denoting a function typed
  /// parameter.
  ///
  /// If the parameter is function-typed, and has the question mark, then its
  /// function type is nullable. Having a nullable function type means that the
  /// parameter can be `null`.
  Token? get question;

  /// The token representing the `super` keyword.
  Token get superKeyword;

  /// The declared type of the parameter, or `null` if the parameter doesn't
  /// have a declared type.
  ///
  /// If this is a function-typed field formal parameter this is the return type
  /// of the function.
  TypeAnnotation? get type;

  /// The type parameters associated with this method, or `null` if this method
  /// isn't a generic method.
  TypeParameterList? get typeParameters;
}

final class SuperFormalParameterImpl extends NormalFormalParameterImpl
    implements SuperFormalParameter {
  @override
  final Token? keyword;

  TypeAnnotationImpl? _type;

  @override
  final Token superKeyword;

  @override
  final Token period;

  TypeParameterListImpl? _typeParameters;

  FormalParameterListImpl? _parameters;

  @override
  final Token? question;

  /// Initializes a newly created formal parameter.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// parameter doesn't have the corresponding attribute.
  ///
  /// The [keyword] can be `null` if there's a type.
  ///
  /// The [type] must be `null` if the keyword is `var`.
  ///
  /// The [thisKeyword] and [period] can be `null` if the keyword `this` isn't
  /// provided.
  ///
  /// The[parameters] can be `null` if this isn't a function-typed field formal
  /// parameter.
  SuperFormalParameterImpl({
    required super.comment,
    required super.metadata,
    required super.covariantKeyword,
    required super.requiredKeyword,
    required this.keyword,
    required TypeAnnotationImpl? type,
    required this.superKeyword,
    required this.period,
    required super.name,
    required TypeParameterListImpl? typeParameters,
    required FormalParameterListImpl? parameters,
    required this.question,
  })  : _type = type,
        _typeParameters = typeParameters,
        _parameters = parameters {
    _becomeParentOf(_type);
    _becomeParentOf(_typeParameters);
    _becomeParentOf(_parameters);
  }

  @override
  Token get endToken {
    return question ?? _parameters?.endToken ?? name;
  }

  @override
  Token get firstTokenAfterCommentAndMetadata =>
      requiredKeyword ??
      covariantKeyword ??
      keyword ??
      type?.beginToken ??
      superKeyword;

  @override
  bool get isConst => keyword?.keyword == Keyword.CONST;

  @override
  bool get isExplicitlyTyped => _parameters != null || _type != null;

  @override
  bool get isFinal => keyword?.keyword == Keyword.FINAL;

  @override
  Token get name => super.name!;

  @override
  FormalParameterListImpl? get parameters => _parameters;

  set parameters(FormalParameterListImpl? parameters) {
    _parameters = _becomeParentOf(parameters);
  }

  @override
  TypeAnnotationImpl? get type => _type;

  set type(TypeAnnotationImpl? type) {
    _type = _becomeParentOf(type as TypeAnnotationImpl);
  }

  @override
  TypeParameterListImpl? get typeParameters => _typeParameters;

  set typeParameters(TypeParameterListImpl? typeParameters) {
    _typeParameters = _becomeParentOf(typeParameters);
  }

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('keyword', keyword)
    ..addNode('type', type)
    ..addToken('superKeyword', superKeyword)
    ..addToken('period', period)
    ..addToken('name', name)
    ..addNode('typeParameters', typeParameters)
    ..addNode('parameters', parameters);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitSuperFormalParameter(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _type?.accept(visitor);
    _typeParameters?.accept(visitor);
    _parameters?.accept(visitor);
  }
}

/// A case in a switch statement.
///
///    switchCase ::=
///        [SimpleIdentifier]* 'case' [Expression] ':' [Statement]*
abstract final class SwitchCase implements SwitchMember {
  /// The expression controlling whether the statements are executed.
  Expression get expression;
}

final class SwitchCaseImpl extends SwitchMemberImpl implements SwitchCase {
  ExpressionImpl _expression;

  /// Initializes a newly created switch case.
  ///
  /// The list of [labels] can be `null` if there are no labels.
  SwitchCaseImpl({
    required super.labels,
    required super.keyword,
    required ExpressionImpl expression,
    required super.colon,
    required super.statements,
  }) : _expression = expression {
    _becomeParentOf(_expression);
  }

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNodeList('labels', labels)
    ..addToken('keyword', keyword)
    ..addNode('expression', expression)
    ..addToken('colon', colon)
    ..addNodeList('statements', statements);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitSwitchCase(this);

  @override
  void visitChildren(AstVisitor visitor) {
    labels.accept(visitor);
    _expression.accept(visitor);
    statements.accept(visitor);
  }
}

/// The default case in a switch statement.
///
///    switchDefault ::=
///        [SimpleIdentifier]* 'default' ':' [Statement]*
abstract final class SwitchDefault implements SwitchMember {}

final class SwitchDefaultImpl extends SwitchMemberImpl
    implements SwitchDefault {
  /// Initializes a newly created switch default.
  ///
  /// The list of [labels] can be `null` if there are no labels.
  SwitchDefaultImpl({
    required super.labels,
    required super.keyword,
    required super.colon,
    required super.statements,
  });

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNodeList('labels', labels)
    ..addToken('keyword', keyword)
    ..addToken('colon', colon)
    ..addNodeList('statements', statements);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitSwitchDefault(this);

  @override
  void visitChildren(AstVisitor visitor) {
    labels.accept(visitor);
    statements.accept(visitor);
  }
}

/// A switch expression.
///
///    switchExpression ::=
///        'switch' '(' [Expression] ')' '{' [SwitchExpressionCase]
///        (',' [SwitchExpressionCase])* ','? '}'
abstract final class SwitchExpression implements Expression {
  /// The cases that can be selected by the expression.
  NodeList<SwitchExpressionCase> get cases;

  /// The expression used to determine which of the switch cases is selected.
  Expression get expression;

  /// The left curly bracket.
  Token get leftBracket;

  /// The left parenthesis.
  Token get leftParenthesis;

  /// The right curly bracket.
  Token get rightBracket;

  /// The right parenthesis.
  Token get rightParenthesis;

  /// The token representing the `switch` keyword.
  Token get switchKeyword;
}

/// A case in a switch expression.
///
///    switchExpressionCase ::=
///        [GuardedPattern] '=>' [Expression]
abstract final class SwitchExpressionCase implements AstNode {
  /// The arrow separating the pattern from the expression.
  Token get arrow;

  /// The expression whose value is returned from the switch expression if the
  /// pattern matches.
  Expression get expression;

  /// The refutable pattern that must match for the [expression] to be executed.
  GuardedPattern get guardedPattern;
}

final class SwitchExpressionCaseImpl extends AstNodeImpl
    with AstNodeWithNameScopeMixin
    implements SwitchExpressionCase, CaseNodeImpl {
  @override
  final GuardedPatternImpl guardedPattern;

  @override
  final Token arrow;

  ExpressionImpl _expression;

  SwitchExpressionCaseImpl({
    required this.guardedPattern,
    required this.arrow,
    required ExpressionImpl expression,
  }) : _expression = expression {
    _becomeParentOf(guardedPattern);
    _becomeParentOf(_expression);
  }

  @override
  Token get beginToken => guardedPattern.beginToken;

  @override
  Token get endToken => expression.endToken;

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addNode('guardedPattern', guardedPattern)
    ..addToken('arrow', arrow)
    ..addNode('expression', expression);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitSwitchExpressionCase(this);

  @override
  void visitChildren(AstVisitor visitor) {
    guardedPattern.accept(visitor);
    expression.accept(visitor);
  }
}

final class SwitchExpressionImpl extends ExpressionImpl
    implements SwitchExpression {
  @override
  final Token switchKeyword;

  @override
  final Token leftParenthesis;

  ExpressionImpl _expression;

  @override
  final Token rightParenthesis;

  @override
  final Token leftBracket;

  @override
  final NodeListImpl<SwitchExpressionCaseImpl> cases = NodeListImpl._();

  @override
  final Token rightBracket;

  SwitchExpressionImpl({
    required this.switchKeyword,
    required this.leftParenthesis,
    required ExpressionImpl expression,
    required this.rightParenthesis,
    required this.leftBracket,
    required List<SwitchExpressionCaseImpl> cases,
    required this.rightBracket,
  }) : _expression = expression {
    _becomeParentOf(_expression);
    this.cases._initialize(this, cases);
  }

  @override
  Token get beginToken => switchKeyword;

  @override
  Token get endToken => rightBracket;

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  Precedence get precedence => Precedence.primary;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('switchKeyword', switchKeyword)
    ..addToken('leftParenthesis', leftParenthesis)
    ..addNode('expression', expression)
    ..addToken('rightParenthesis', rightParenthesis)
    ..addToken('leftBracket', leftBracket)
    ..addNodeList('cases', cases)
    ..addToken('rightBracket', rightBracket);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitSwitchExpression(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    inferenceLogWriter?.enterExpression(this, contextType);
    var previousExhaustiveness = resolver.legacySwitchExhaustiveness;
    var staticType = resolver
        .analyzeSwitchExpression(
            this, expression, cases.length, SharedTypeSchemaView(contextType))
        .type
        .unwrapTypeView();
    recordStaticType(staticType, resolver: resolver);
    resolver.popRewrite();
    resolver.legacySwitchExhaustiveness = previousExhaustiveness;
    inferenceLogWriter?.exitExpression(this);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    expression.accept(visitor);
    cases.accept(visitor);
  }
}

/// An element within a switch statement.
///
///    switchMember ::=
///        [SwitchCase]
///      | [SwitchDefault]
///      | [SwitchPatternCase]
///
/// The class [SwitchPatternCase] exists only to support the 'patterns' feature.
///
/// Note that when the patterns feature is enabled by default, the class
/// [SwitchPatternCase] might replace [SwitchCase] entirely. If we do that, then
/// legacy code (code opted into a version prior to the release of patterns)
/// will likely wrap the expression in a [ConstantPattern] with synthetic
/// tokens.
// TODO(brianwilkerson): Consider renaming `SwitchMember`, `SwitchCase`, and
//  `SwitchDefault` to start with `SwitchStatement` for consistency.
sealed class SwitchMember implements AstNode {
  /// The colon separating the keyword or the expression from the statements.
  Token get colon;

  /// The token representing the `case` or `default` keyword.
  Token get keyword;

  /// The labels associated with the switch member.
  NodeList<Label> get labels;

  /// The statements that are executed if this switch member is selected.
  NodeList<Statement> get statements;
}

sealed class SwitchMemberImpl extends AstNodeImpl
    with AstNodeWithNameScopeMixin
    implements SwitchMember {
  final NodeListImpl<LabelImpl> _labels = NodeListImpl._();

  @override
  final Token keyword;

  @override
  final Token colon;

  final NodeListImpl<StatementImpl> _statements = NodeListImpl._();

  /// Initializes a newly created switch member.
  ///
  /// The list of [labels] can be `null` if there are no labels.
  SwitchMemberImpl({
    required List<LabelImpl> labels,
    required this.keyword,
    required this.colon,
    required List<StatementImpl> statements,
  }) {
    _labels._initialize(this, labels);
    _statements._initialize(this, statements);
  }

  @override
  Token get beginToken {
    if (_labels.isNotEmpty) {
      return _labels.beginToken!;
    }
    return keyword;
  }

  @override
  Token get endToken {
    if (_statements.isNotEmpty) {
      return _statements.endToken!;
    }
    return colon;
  }

  @override
  NodeListImpl<LabelImpl> get labels => _labels;

  @override
  NodeListImpl<StatementImpl> get statements => _statements;
}

/// A pattern-based case in a switch statement.
///
///    switchPatternCase ::=
///        [Label]* 'case' [DartPattern] [WhenClause]? ':' [Statement]*
abstract final class SwitchPatternCase implements SwitchMember {
  /// The pattern controlling whether the statements is executed.
  GuardedPattern get guardedPattern;
}

final class SwitchPatternCaseImpl extends SwitchMemberImpl
    implements SwitchPatternCase, CaseNodeImpl {
  @override
  final GuardedPatternImpl guardedPattern;

  SwitchPatternCaseImpl({
    required super.labels,
    required super.keyword,
    required this.guardedPattern,
    required super.colon,
    required super.statements,
  }) {
    _becomeParentOf(guardedPattern);
  }

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addNodeList('labels', labels)
    ..addToken('keyword', keyword)
    ..addNode('guardedPattern', guardedPattern)
    ..addToken('colon', colon)
    ..addNodeList('statements', statements);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitSwitchPatternCase(this);

  @override
  void visitChildren(AstVisitor visitor) {
    labels.accept(visitor);
    guardedPattern.accept(visitor);
    statements.accept(visitor);
  }
}

/// A switch statement.
///
///    switchStatement ::=
///        'switch' '(' [Expression] ')' '{' [SwitchCase]* [SwitchDefault]? '}'
abstract final class SwitchStatement implements Statement {
  /// The expression used to determine which of the switch members is selected.
  Expression get expression;

  /// The left curly bracket.
  Token get leftBracket;

  /// The left parenthesis.
  Token get leftParenthesis;

  /// The switch members that can be selected by the expression.
  NodeList<SwitchMember> get members;

  /// The right curly bracket.
  Token get rightBracket;

  /// The right parenthesis.
  Token get rightParenthesis;

  /// The token representing the `switch` keyword.
  Token get switchKeyword;
}

class SwitchStatementCaseGroup {
  final List<SwitchMemberImpl> members;
  final bool hasLabels;

  /// Joined variables declared in [members], available in [statements].
  late Map<String, PromotableElement> variables;

  SwitchStatementCaseGroup(this.members, this.hasLabels);

  NodeListImpl<StatementImpl> get statements {
    return members.last.statements;
  }
}

final class SwitchStatementImpl extends StatementImpl
    implements SwitchStatement {
  @override
  final Token switchKeyword;

  @override
  final Token leftParenthesis;

  ExpressionImpl _expression;

  @override
  final Token rightParenthesis;

  @override
  final Token leftBracket;

  final NodeListImpl<SwitchMemberImpl> _members = NodeListImpl._();

  late final List<SwitchStatementCaseGroup> memberGroups =
      _computeMemberGroups();

  @override
  final Token rightBracket;

  /// Initializes a newly created switch statement.
  ///
  /// The list of [members] can be `null` if there are no switch members.
  SwitchStatementImpl({
    required this.switchKeyword,
    required this.leftParenthesis,
    required ExpressionImpl expression,
    required this.rightParenthesis,
    required this.leftBracket,
    required List<SwitchMemberImpl> members,
    required this.rightBracket,
  }) : _expression = expression {
    _becomeParentOf(_expression);
    _members._initialize(this, members);
  }

  @override
  Token get beginToken => switchKeyword;

  @override
  Token get endToken => rightBracket;

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  NodeListImpl<SwitchMemberImpl> get members => _members;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('switchKeyword', switchKeyword)
    ..addToken('leftParenthesis', leftParenthesis)
    ..addNode('expression', expression)
    ..addToken('rightParenthesis', rightParenthesis)
    ..addToken('leftBracket', leftBracket)
    ..addNodeList('members', members)
    ..addToken('rightBracket', rightBracket);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitSwitchStatement(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _expression.accept(visitor);
    _members.accept(visitor);
  }

  List<SwitchStatementCaseGroup> _computeMemberGroups() {
    var groups = <SwitchStatementCaseGroup>[];
    var groupMembers = <SwitchMemberImpl>[];
    var groupHasLabels = false;
    for (var member in members) {
      groupMembers.add(member);
      groupHasLabels |= member.labels.isNotEmpty;
      if (member.statements.isNotEmpty) {
        groups.add(
          SwitchStatementCaseGroup(groupMembers, groupHasLabels),
        );
        groupMembers = [];
        groupHasLabels = false;
      }
    }
    if (groupMembers.isNotEmpty) {
      groups.add(
        SwitchStatementCaseGroup(groupMembers, groupHasLabels),
      );
    }
    return groups;
  }
}

/// A symbol literal expression.
///
///    symbolLiteral ::=
///        '#' (operator | (identifier ('.' identifier)*))
abstract final class SymbolLiteral implements Literal {
  /// The components of the literal.
  List<Token> get components;

  /// The token introducing the literal.
  Token get poundSign;
}

final class SymbolLiteralImpl extends LiteralImpl implements SymbolLiteral {
  @override
  final Token poundSign;

  @override
  final List<Token> components;

  /// Initializes a newly created symbol literal.
  SymbolLiteralImpl({
    required this.poundSign,
    required this.components,
  });

  @override
  Token get beginToken => poundSign;

  @override
  Token get endToken => components[components.length - 1];

  @override
  // TODO(paulberry): add "." tokens.
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('poundSign', poundSign)
    ..addTokenList('components', components);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitSymbolLiteral(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitSymbolLiteral(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    // There are no children to visit.
  }
}

/// An identifier that can be used to look up names in the lexical scope when
/// there's no identifier in the AST structure.
///
/// For example, there's no identifier in the AST when the parser can't
/// distinguish between a method invocation and an invocation of a top-level
/// function imported with a prefix.
final class SyntheticIdentifier implements SimpleIdentifier {
  @override
  final String name;

  SyntheticIdentifier(this.name);

  @override
  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}

/// A this expression.
///
///    thisExpression ::=
///        'this'
abstract final class ThisExpression implements Expression {
  /// The token representing the `this` keyword.
  Token get thisKeyword;
}

final class ThisExpressionImpl extends ExpressionImpl
    implements ThisExpression {
  @override
  final Token thisKeyword;

  /// Initializes a newly created this expression.
  ThisExpressionImpl({
    required this.thisKeyword,
  });

  @override
  Token get beginToken => thisKeyword;

  @override
  Token get endToken => thisKeyword;

  @override
  Precedence get precedence => Precedence.primary;

  @override
  ChildEntities get _childEntities =>
      ChildEntities()..addToken('thisKeyword', thisKeyword);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitThisExpression(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitThisExpression(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    // There are no children to visit.
  }
}

/// A throw expression.
///
///    throwExpression ::=
///        'throw' [Expression]
abstract final class ThrowExpression implements Expression {
  /// The expression computing the exception to be thrown.
  Expression get expression;

  /// The token representing the `throw` keyword.
  Token get throwKeyword;
}

final class ThrowExpressionImpl extends ExpressionImpl
    implements ThrowExpression {
  @override
  final Token throwKeyword;

  ExpressionImpl _expression;

  /// Initializes a newly created throw expression.
  ThrowExpressionImpl({
    required this.throwKeyword,
    required ExpressionImpl expression,
  }) : _expression = expression {
    _becomeParentOf(_expression);
  }

  @override
  Token get beginToken => throwKeyword;

  @override
  Token get endToken {
    return _expression.endToken;
  }

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  Precedence get precedence => Precedence.assignment;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('throwKeyword', throwKeyword)
    ..addNode('expression', expression);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitThrowExpression(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitThrowExpression(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _expression.accept(visitor);
  }
}

/// The declaration of one or more top-level variables of the same type.
///
///    topLevelVariableDeclaration ::=
///        ('final' | 'const') <type>? <staticFinalDeclarationList> ';'
///      | 'late' 'final' <type>? <initializedIdentifierList> ';'
///      | 'late'? <varOrType> <initializedIdentifierList> ';'
///      | 'external' <finalVarOrType> <identifierList> ';'
///
/// (Note: there's no `<topLevelVariableDeclaration>` production in the grammar;
/// this is a subset of the grammar production `<topLevelDeclaration>`, which
/// encompasses everything that can appear inside a Dart file after part
/// directives).
abstract final class TopLevelVariableDeclaration
    implements CompilationUnitMember {
  /// The `augment` keyword, or `null` if the keyword was absent.
  @experimental
  Token? get augmentKeyword;

  /// The `external` keyword, or `null` if the keyword isn't used.
  Token? get externalKeyword;

  /// The semicolon terminating the declaration.
  Token get semicolon;

  /// The top-level variables being declared.
  VariableDeclarationList get variables;
}

final class TopLevelVariableDeclarationImpl extends CompilationUnitMemberImpl
    implements TopLevelVariableDeclaration {
  VariableDeclarationListImpl _variableList;

  @override
  final Token? augmentKeyword;

  @override
  final Token? externalKeyword;

  @override
  final Token semicolon;

  /// Initializes a newly created top-level variable declaration.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// variable doesn't have the corresponding attribute.
  TopLevelVariableDeclarationImpl({
    required super.comment,
    required super.metadata,
    required this.augmentKeyword,
    required this.externalKeyword,
    required VariableDeclarationListImpl variableList,
    required this.semicolon,
  }) : _variableList = variableList {
    _becomeParentOf(_variableList);
  }

  @override
  Element? get declaredElement => null;

  @override
  Token get endToken => semicolon;

  @override
  Token get firstTokenAfterCommentAndMetadata =>
      augmentKeyword ?? externalKeyword ?? _variableList.beginToken;

  @override
  VariableDeclarationListImpl get variables => _variableList;

  set variables(VariableDeclarationListImpl variables) {
    _variableList = _becomeParentOf(variables);
  }

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('augmentKeyword', augmentKeyword)
    ..addToken('externalKeyword', externalKeyword)
    ..addNode('variables', variables)
    ..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitTopLevelVariableDeclaration(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _variableList.accept(visitor);
  }
}

/// A try statement.
///
///    tryStatement ::=
///        'try' [Block] ([CatchClause]+ finallyClause? | finallyClause)
///
///    finallyClause ::=
///        'finally' [Block]
abstract final class TryStatement implements Statement {
  /// The body of the statement.
  Block get body;

  /// The catch clauses contained in the try statement.
  NodeList<CatchClause> get catchClauses;

  /// The finally block contained in the try statement, or `null` if the
  /// statement doesn't contain a finally clause.
  Block? get finallyBlock;

  /// The token representing the `finally` keyword, or `null` if the statement
  /// doesn't contain a finally clause.
  Token? get finallyKeyword;

  /// The token representing the `try` keyword.
  Token get tryKeyword;
}

final class TryStatementImpl extends StatementImpl implements TryStatement {
  @override
  final Token tryKeyword;

  BlockImpl _body;

  final NodeListImpl<CatchClauseImpl> _catchClauses = NodeListImpl._();

  @override
  final Token? finallyKeyword;

  BlockImpl? _finallyBlock;

  /// Initializes a newly created try statement.
  ///
  /// The [finallyKeyword] and [finallyBlock] can be `null` if there's no
  /// finally clause.
  TryStatementImpl({
    required this.tryKeyword,
    required BlockImpl body,
    required List<CatchClauseImpl> catchClauses,
    required this.finallyKeyword,
    required BlockImpl? finallyBlock,
  })  : _body = body,
        _finallyBlock = finallyBlock {
    _becomeParentOf(_body);
    _catchClauses._initialize(this, catchClauses);
    _becomeParentOf(_finallyBlock);
  }

  @override
  Token get beginToken => tryKeyword;

  @override
  BlockImpl get body => _body;

  set body(BlockImpl block) {
    _body = _becomeParentOf(block);
  }

  @override
  NodeListImpl<CatchClauseImpl> get catchClauses => _catchClauses;

  @override
  Token get endToken {
    if (finallyBlock case var finallyBlock?) {
      return finallyBlock.endToken;
    } else if (finallyKeyword case var finallyKeyword?) {
      return finallyKeyword;
    } else if (_catchClauses case [..., var last]) {
      return last.endToken;
    }
    return _body.endToken;
  }

  @override
  BlockImpl? get finallyBlock => _finallyBlock;

  set finallyBlock(BlockImpl? block) {
    _finallyBlock = _becomeParentOf(block);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('tryKeyword', tryKeyword)
    ..addNode('body', body)
    ..addNodeList('catchClauses', catchClauses)
    ..addToken('finallyKeyword', finallyKeyword)
    ..addNode('finallyBlock', finallyBlock);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitTryStatement(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _body.accept(visitor);
    _catchClauses.accept(visitor);
    _finallyBlock?.accept(visitor);
  }
}

/// The declaration of a type alias.
///
///    typeAlias ::=
///        [ClassTypeAlias]
///      | [FunctionTypeAlias]
///      | [GenericTypeAlias]
abstract final class TypeAlias implements NamedCompilationUnitMember {
  /// The `augment` keyword, or `null` if the keyword was absent.
  @experimental
  Token? get augmentKeyword;

  /// The semicolon terminating the declaration.
  Token get semicolon;

  /// The token representing the `typedef` or `class` keyword.
  Token get typedefKeyword;
}

sealed class TypeAliasImpl extends NamedCompilationUnitMemberImpl
    implements TypeAlias {
  @override
  final Token? augmentKeyword;

  @override
  final Token typedefKeyword;

  @override
  final Token semicolon;

  /// Initializes a newly created type alias.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// declaration doesn't have the corresponding attribute.
  TypeAliasImpl({
    required super.comment,
    required super.metadata,
    required this.augmentKeyword,
    required this.typedefKeyword,
    required super.name,
    required this.semicolon,
  });

  @override
  Token get endToken => semicolon;

  @override
  Token get firstTokenAfterCommentAndMetadata {
    return augmentKeyword ?? typedefKeyword;
  }
}

/// A type annotation.
///
///    type ::=
///        [NamedType]
///      | [GenericFunctionType]
///      | [RecordTypeAnnotation]
sealed class TypeAnnotation implements AstNode {
  /// The question mark indicating that the type is nullable, or `null` if
  /// there's no question mark.
  Token? get question;

  /// The type being named, or `null` if the AST structure hasn't been resolved.
  DartType? get type;
}

sealed class TypeAnnotationImpl extends AstNodeImpl implements TypeAnnotation {}

/// A list of type arguments.
///
///    typeArguments ::=
///        '<' typeName (',' typeName)* '>'
abstract final class TypeArgumentList implements AstNode {
  /// The type arguments associated with the type.
  NodeList<TypeAnnotation> get arguments;

  /// The left bracket.
  Token get leftBracket;

  /// The right bracket.
  Token get rightBracket;
}

final class TypeArgumentListImpl extends AstNodeImpl
    implements TypeArgumentList {
  @override
  final Token leftBracket;

  final NodeListImpl<TypeAnnotationImpl> _arguments = NodeListImpl._();

  @override
  final Token rightBracket;

  /// Initializes a newly created list of type arguments.
  TypeArgumentListImpl({
    required this.leftBracket,
    required List<TypeAnnotationImpl> arguments,
    required this.rightBracket,
  }) {
    _arguments._initialize(this, arguments);
  }

  @override
  NodeListImpl<TypeAnnotationImpl> get arguments => _arguments;

  @override
  Token get beginToken => leftBracket;

  @override
  Token get endToken => rightBracket;

  @override
  // TODO(paulberry): Add commas.
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('leftBracket', leftBracket)
    ..addNodeList('arguments', arguments)
    ..addToken('rightBracket', rightBracket);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitTypeArgumentList(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _arguments.accept(visitor);
  }
}

/// A literal that has a type associated with it.
///
///    typedLiteral ::=
///        [ListLiteral]
///      | [SetOrMapLiteral]
sealed class TypedLiteral implements Literal {
  /// The token representing the `const` keyword, or `null` if the literal isn't
  /// a constant.
  Token? get constKeyword;

  /// Whether this literal is a constant expression.
  ///
  /// It is a constant expression if either the keyword `const` was explicitly
  /// provided or because no keyword was provided and this expression occurs in
  /// a constant context.
  bool get isConst;

  /// The type argument associated with this literal, or `null` if no type
  /// arguments were declared.
  TypeArgumentList? get typeArguments;
}

sealed class TypedLiteralImpl extends LiteralImpl implements TypedLiteral {
  @override
  Token? constKeyword;

  TypeArgumentListImpl? _typeArguments;

  /// Initializes a newly created typed literal.
  ///
  /// The [constKeyword] can be `null` if the literal isn't a constant.
  ///
  /// The [typeArguments] can be `null` if no type arguments were declared.
  TypedLiteralImpl({
    required this.constKeyword,
    required TypeArgumentListImpl? typeArguments,
  }) : _typeArguments = typeArguments {
    _becomeParentOf(_typeArguments);
  }

  @override
  bool get isConst {
    return constKeyword != null || inConstantContext;
  }

  @override
  TypeArgumentListImpl? get typeArguments => _typeArguments;

  set typeArguments(TypeArgumentListImpl? typeArguments) {
    _typeArguments = _becomeParentOf(typeArguments);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('constKeyword', constKeyword)
    ..addNode('typeArguments', typeArguments);

  @override
  void visitChildren(AstVisitor visitor) {
    _typeArguments?.accept(visitor);
  }
}

/// An expression representing a type, such as the expression `int` in
/// `var x = int;`.
///
/// Objects of this type aren't produced directly by the parser (because the
/// parser can't tell whether an identifier refers to a type); they are
/// produced at resolution time.
///
/// The `.staticType` getter returns the type of the expression (which is
/// always the type `Type`). To get the type represented by the type literal
/// use `.typeName.type`.
abstract final class TypeLiteral
    implements Expression, CommentReferableExpression {
  /// The type represented by this literal.
  NamedType get type;
}

final class TypeLiteralImpl extends CommentReferableExpressionImpl
    implements TypeLiteral {
  NamedTypeImpl _typeName;

  TypeLiteralImpl({
    required NamedTypeImpl typeName,
  }) : _typeName = typeName {
    _becomeParentOf(_typeName);
  }

  @override
  Token get beginToken => _typeName.beginToken;

  @override
  Token get endToken => _typeName.endToken;

  @override
  Precedence get precedence {
    if (_typeName.typeArguments != null) {
      return Precedence.postfix;
    } else if (_typeName.importPrefix != null) {
      return Precedence.postfix;
    } else {
      return Precedence.primary;
    }
  }

  @override
  NamedTypeImpl get type => _typeName;

  set typeName(NamedTypeImpl value) {
    _typeName = _becomeParentOf(value);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()..addNode('type', type);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitTypeLiteral(this);

  @override
  void resolveExpression(ResolverVisitor resolver, DartType contextType) {
    resolver.visitTypeLiteral(this, contextType: contextType);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    _typeName.accept(visitor);
  }
}

/// A type parameter.
///
///    typeParameter ::=
///        name ('extends' [TypeAnnotation])?
abstract final class TypeParameter implements Declaration, FragmentDeclaration {
  /// The upper bound for legal arguments, or `null` if there's no explicit
  /// upper bound.
  TypeAnnotation? get bound;

  @override
  TypeParameterElement? get declaredElement;

  @experimental
  @override
  TypeParameterFragment? get declaredFragment;

  /// The token representing the `extends` keyword, or `null` if there's no
  /// explicit upper bound.
  Token? get extendsKeyword;

  /// The name of the type parameter.
  Token get name;
}

final class TypeParameterImpl extends DeclarationImpl implements TypeParameter {
  @override
  final Token name;

  /// The token representing the variance modifier keyword, or `null` if there's
  /// no explicit variance modifier, meaning legacy covariance.
  Token? varianceKeyword;

  @override
  Token? extendsKeyword;

  TypeAnnotationImpl? _bound;

  @override
  TypeParameterElementImpl? declaredElement;

  /// Initializes a newly created type parameter.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// parameter doesn't have the corresponding attribute.
  ///
  /// The [extendsKeyword] and [bound] can be `null` if the parameter doesn't
  /// have a bound.
  TypeParameterImpl({
    required super.comment,
    required super.metadata,
    required this.name,
    required this.extendsKeyword,
    required TypeAnnotationImpl? bound,
    this.varianceKeyword,
  }) : _bound = bound {
    _becomeParentOf(_bound);
  }

  @override
  TypeAnnotationImpl? get bound => _bound;

  set bound(TypeAnnotationImpl? type) {
    _bound = _becomeParentOf(type);
  }

  @experimental
  @override
  TypeParameterFragment? get declaredFragment =>
      declaredElement as TypeParameterFragment?;

  @override
  Token get endToken {
    return _bound?.endToken ?? name;
  }

  @override
  Token get firstTokenAfterCommentAndMetadata => varianceKeyword ?? name;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('name', name)
    ..addToken('extendsKeyword', extendsKeyword)
    ..addNode('bound', bound);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitTypeParameter(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _bound?.accept(visitor);
  }
}

/// Type parameters within a declaration.
///
///    typeParameterList ::=
///        '<' [TypeParameter] (',' [TypeParameter])* '>'
abstract final class TypeParameterList implements AstNode {
  /// The left angle bracket.
  Token get leftBracket;

  /// The right angle bracket.
  Token get rightBracket;

  /// The type parameters for the type.
  NodeList<TypeParameter> get typeParameters;
}

final class TypeParameterListImpl extends AstNodeImpl
    implements TypeParameterList {
  @override
  final Token leftBracket;

  final NodeListImpl<TypeParameterImpl> _typeParameters = NodeListImpl._();

  @override
  final Token rightBracket;

  /// Initializes a newly created list of type parameters.
  TypeParameterListImpl({
    required this.leftBracket,
    required List<TypeParameterImpl> typeParameters,
    required this.rightBracket,
  }) {
    _typeParameters._initialize(this, typeParameters);
  }

  @override
  Token get beginToken => leftBracket;

  @override
  Token get endToken => rightBracket;

  @override
  NodeListImpl<TypeParameterImpl> get typeParameters => _typeParameters;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('leftBracket', leftBracket)
    ..addNodeList('typeParameters', typeParameters)
    ..addToken('rightBracket', rightBracket);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitTypeParameterList(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _typeParameters.accept(visitor);
  }
}

/// A directive that references a URI.
///
///    uriBasedDirective ::=
///        [LibraryAugmentationDirective]
///        [ExportDirective]
///      | [ImportDirective]
///      | [PartDirective]
sealed class UriBasedDirective implements Directive {
  /// The URI referenced by this directive.
  StringLiteral get uri;
}

sealed class UriBasedDirectiveImpl extends DirectiveImpl
    implements UriBasedDirective {
  StringLiteralImpl _uri;

  /// Initializes a newly create URI-based directive.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// directive doesn't have the corresponding attribute.
  UriBasedDirectiveImpl({
    required super.comment,
    required super.metadata,
    required StringLiteralImpl uri,
  }) : _uri = uri {
    _becomeParentOf(_uri);
  }

  @override
  StringLiteralImpl get uri => _uri;

  set uri(StringLiteralImpl uri) {
    _uri = _becomeParentOf(uri);
  }

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _uri.accept(visitor);
  }

  /// Validate this directive, but don't check for existence.
  ///
  /// Returns a code indicating the problem if a problem was found, or `null` if
  /// there's no problem.
  static UriValidationCode? validateUri(
      bool isImport, StringLiteral uriLiteral, String? uriContent) {
    if (uriLiteral is StringInterpolation) {
      return UriValidationCode.URI_WITH_INTERPOLATION;
    }
    if (uriContent == null) {
      return UriValidationCode.INVALID_URI;
    }
    if (uriContent.isEmpty) {
      return null;
    }
    Uri uri;
    try {
      uri = Uri.parse(Uri.encodeFull(uriContent));
    } on FormatException {
      return UriValidationCode.INVALID_URI;
    }
    if (uri.path.isEmpty) {
      return UriValidationCode.INVALID_URI;
    }
    return null;
  }
}

/// Validation codes returned by [UriBasedDirective.validate].
class UriValidationCode {
  static const UriValidationCode INVALID_URI = UriValidationCode('INVALID_URI');

  static const UriValidationCode URI_WITH_INTERPOLATION =
      UriValidationCode('URI_WITH_INTERPOLATION');

  /// The name of the validation code.
  final String name;

  /// Initializes a newly created validation code to have the given [name].
  const UriValidationCode(this.name);

  @override
  String toString() => name;
}

/// An identifier that has an initial value associated with it.
///
/// Instances of this class are always children of the class
/// [VariableDeclarationList].
///
///    variableDeclaration ::=
///        name ('=' [Expression])?
// TODO(paulberry): The grammar doesn't allow metadata to be associated with a
//  VariableDeclaration, and currently we don't record comments for it either.
//  Consider changing the class hierarchy so that [VariableDeclaration] doesn't
//  extend [Declaration].
//
// TODO(brianwilkerson): This class represents both declarations that can be
//  augmented and declarations that can't be augmented. This results in getters
//  that are only sometimes applicable. Consider changing the class hierarchy so
//  that these two kinds of variables can be distinguished.
abstract final class VariableDeclaration
    implements Declaration, FragmentDeclaration {
  /// The element declared by this declaration.
  ///
  /// Returns `null` if the AST structure hasn't been resolved or if this node
  /// represents the declaration of a top-level variable or a field.
  @override
  VariableElement? get declaredElement;

  /// The element declared by this declaration.
  ///
  /// Returns `null` if the AST structure hasn't been resolved or if this node
  /// represents the declaration of a top-level variable or a field.
  @experimental
  LocalVariableElement2? get declaredElement2;

  /// The fragment declared by this declaration.
  ///
  /// Returns `null` if the AST structure hasn't been resolved or if this node
  /// represents the declaration of a local variable.
  @experimental
  @override
  VariableFragment? get declaredFragment;

  /// The equal sign separating the variable name from the initial value, or
  /// `null` if the initial value isn't specified.
  Token? get equals;

  /// The expression used to compute the initial value for the variable, or
  /// `null` if the initial value isn't specified.
  Expression? get initializer;

  /// Whether this variable was declared with the 'const' modifier.
  bool get isConst;

  /// Whether this variable was declared with the 'final' modifier.
  ///
  /// Variables that are declared with the 'const' modifier return `false` even
  /// though they are implicitly final.
  bool get isFinal;

  /// Whether this variable was declared with the 'late' modifier.
  bool get isLate;

  /// The name of the variable being declared.
  Token get name;
}

final class VariableDeclarationImpl extends DeclarationImpl
    implements VariableDeclaration {
  @override
  final Token name;

  @override
  VariableElementImpl? declaredElement;

  @override
  final Token? equals;

  ExpressionImpl? _initializer;

  /// When this node is read as a part of summaries, we usually don't want
  /// to read the [initializer], but we need to know if there is one in
  /// the code. So, this flag might be set to `true` even though
  /// [initializer] is `null`.
  bool hasInitializer = false;

  /// Initializes a newly created variable declaration.
  ///
  /// The [equals] and [initializer] can be `null` if there's no initializer.
  VariableDeclarationImpl({
    required this.name,
    required this.equals,
    required ExpressionImpl? initializer,
  })  : _initializer = initializer,
        super(comment: null, metadata: null) {
    _becomeParentOf(_initializer);
  }

  @experimental
  @override
  LocalVariableElement2? get declaredElement2 {
    return declaredElement.asElement2.ifTypeOrNull<LocalVariableElement2>();
  }

  @experimental
  @override
  VariableFragment? get declaredFragment {
    if (declaredElement case VariableFragment fragment) {
      return fragment;
    }
    return null;
  }

  /// This overridden implementation of [documentationComment] looks in the
  /// grandparent node for Dartdoc comments if no documentation is specifically
  /// available on the node.
  @override
  CommentImpl? get documentationComment {
    var comment = super.documentationComment;
    if (comment == null) {
      var node = parent?.parent;
      if (node is AnnotatedNodeImpl) {
        return node.documentationComment;
      }
    }
    return comment;
  }

  @override
  Token get endToken {
    if (initializer case var initializer?) {
      return initializer.endToken;
    }
    return name;
  }

  @override
  Token get firstTokenAfterCommentAndMetadata => name;

  @override
  ExpressionImpl? get initializer => _initializer;

  set initializer(ExpressionImpl? expression) {
    _initializer = _becomeParentOf(expression);
  }

  @override
  bool get isConst {
    var parent = this.parent;
    return parent is VariableDeclarationList && parent.isConst;
  }

  @override
  bool get isFinal {
    var parent = this.parent;
    return parent is VariableDeclarationList && parent.isFinal;
  }

  @override
  bool get isLate {
    var parent = this.parent;
    return parent is VariableDeclarationList && parent.isLate;
  }

  DartType get type {
    if (declaredElement2 case var declaredElement?) {
      return declaredElement.type;
    }
    // SAFETY: The variable declaration is either a local variable,
    // of a fragment of: top-level, field, formal parameter.
    return declaredFragment!.element.type;
  }

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('name', name)
    ..addToken('equals', equals)
    ..addNode('initializer', initializer);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitVariableDeclaration(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _initializer?.accept(visitor);
  }
}

/// The declaration of one or more variables of the same type.
///
///    variableDeclarationList ::=
///        finalConstVarOrType [VariableDeclaration]
///        (',' [VariableDeclaration])*
///
///    finalConstVarOrType ::=
///      'final' 'late'? [TypeAnnotation]?
///      | 'const' [TypeAnnotation]?
///      | 'var'
///      | 'late'? [TypeAnnotation]
abstract final class VariableDeclarationList implements AnnotatedNode {
  /// Whether the variables in this list were declared with the 'const'
  /// modifier.
  bool get isConst;

  /// Whether the variables in this list were declared with the 'final'
  /// modifier.
  ///
  /// Variables that are declared with the 'const' modifier return `false` even
  /// though they are implicitly final. (In other words, this is a syntactic
  /// check rather than a semantic check.)
  bool get isFinal;

  /// Whether the variables in this list were declared with the 'late' modifier.
  bool get isLate;

  /// The token representing the `final`, `const` or `var` keyword, or `null` if
  /// no keyword was included.
  Token? get keyword;

  /// The token representing the `late` keyword, or `null` if the late modifier
  /// isn't included.
  Token? get lateKeyword;

  /// The type of the variables being declared, or `null` if no type was
  /// provided.
  TypeAnnotation? get type;

  /// A list containing the individual variables being declared.
  NodeList<VariableDeclaration> get variables;
}

final class VariableDeclarationListImpl extends AnnotatedNodeImpl
    implements VariableDeclarationList {
  @override
  final Token? keyword;

  @override
  final Token? lateKeyword;

  TypeAnnotationImpl? _type;

  final NodeListImpl<VariableDeclarationImpl> _variables = NodeListImpl._();

  /// Initializes a newly created variable declaration list.
  ///
  /// Either or both of the [comment] and [metadata] can be `null` if the
  /// variable list doesn't have the corresponding attribute.
  ///
  /// The [keyword] can be `null` if a type was specified.
  ///
  /// The [type] must be `null` if the keyword is `var`.
  VariableDeclarationListImpl({
    required super.comment,
    required super.metadata,
    required this.lateKeyword,
    required this.keyword,
    required TypeAnnotationImpl? type,
    required List<VariableDeclarationImpl> variables,
  }) : _type = type {
    _becomeParentOf(_type);
    _variables._initialize(this, variables);
  }

  @override
  Token get endToken => _variables.endToken!;

  @override
  Token get firstTokenAfterCommentAndMetadata {
    return Token.lexicallyFirst(lateKeyword, keyword) ??
        _type?.beginToken ??
        _variables.beginToken!;
  }

  @override
  bool get isConst => keyword?.keyword == Keyword.CONST;

  @override
  bool get isFinal => keyword?.keyword == Keyword.FINAL;

  @override
  bool get isLate => lateKeyword != null;

  @override
  TypeAnnotationImpl? get type => _type;

  set type(TypeAnnotationImpl? type) {
    _type = _becomeParentOf(type);
  }

  @override
  NodeListImpl<VariableDeclarationImpl> get variables => _variables;

  @override
  // TODO(paulberry): include commas.
  ChildEntities get _childEntities => super._childEntities
    ..addToken('lateKeyword', lateKeyword)
    ..addToken('keyword', keyword)
    ..addNode('type', type)
    ..addNodeList('variables', variables);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitVariableDeclarationList(this);

  @override
  void visitChildren(AstVisitor visitor) {
    super.visitChildren(visitor);
    _type?.accept(visitor);
    _variables.accept(visitor);
  }
}

/// A list of variables that are being declared in a context where a statement
/// is required.
///
///    variableDeclarationStatement ::=
///        [VariableDeclarationList] ';'
abstract final class VariableDeclarationStatement implements Statement {
  /// The semicolon terminating the statement.
  Token get semicolon;

  /// The variables being declared.
  VariableDeclarationList get variables;
}

final class VariableDeclarationStatementImpl extends StatementImpl
    implements VariableDeclarationStatement {
  VariableDeclarationListImpl _variableList;

  @override
  final Token semicolon;

  /// Initializes a newly created variable declaration statement.
  VariableDeclarationStatementImpl({
    required VariableDeclarationListImpl variableList,
    required this.semicolon,
  }) : _variableList = variableList {
    _becomeParentOf(_variableList);
  }

  @override
  Token get beginToken => _variableList.beginToken;

  @override
  Token get endToken => semicolon;

  @override
  VariableDeclarationListImpl get variables => _variableList;

  set variables(VariableDeclarationListImpl variables) {
    _variableList = _becomeParentOf(variables);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addNode('variables', variables)
    ..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) =>
      visitor.visitVariableDeclarationStatement(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _variableList.accept(visitor);
  }
}

/// The shared interface of [AssignedVariablePattern] and
/// [DeclaredVariablePattern].
sealed class VariablePattern implements DartPattern {
  /// The name of the variable declared or referenced by the pattern.
  Token get name;
}

sealed class VariablePatternImpl extends DartPatternImpl
    implements VariablePattern {
  @override
  final Token name;

  /// If this variable was used to resolve an implicitly named field, the
  /// implicit name node is recorded here for a future use.
  PatternFieldNameImpl? fieldNameWithImplicitName;

  VariablePatternImpl({
    required this.name,
  });

  @override
  VariablePatternImpl? get variablePattern => this;
}

/// A guard in a pattern-based `case` in a `switch` statement, `switch`
/// expression, `if` statement, or `if` element.
///
///    switchCase ::=
///        'when' [Expression]
abstract final class WhenClause implements AstNode {
  /// The condition that is evaluated when the [pattern] matches, that must
  /// evaluate to `true` in order for the [expression] to be executed.
  Expression get expression;

  /// The `when` keyword.
  Token get whenKeyword;
}

final class WhenClauseImpl extends AstNodeImpl implements WhenClause {
  ExpressionImpl _expression;

  @override
  final Token whenKeyword;

  WhenClauseImpl({
    required this.whenKeyword,
    required ExpressionImpl expression,
  }) : _expression = expression {
    _becomeParentOf(expression);
  }

  @override
  Token get beginToken => whenKeyword;

  @override
  Token get endToken => expression.endToken;

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('whenKeyword', whenKeyword)
    ..addNode('expression', expression);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitWhenClause(this);

  @override
  void visitChildren(AstVisitor visitor) {
    expression.accept(visitor);
  }
}

/// A while statement.
///
///    whileStatement ::=
///        'while' '(' [Expression] ')' [Statement]
abstract final class WhileStatement implements Statement {
  /// The body of the loop.
  Statement get body;

  /// The expression used to determine whether to execute the body of the loop.
  Expression get condition;

  /// The left parenthesis.
  Token get leftParenthesis;

  /// The right parenthesis.
  Token get rightParenthesis;

  /// The token representing the `while` keyword.
  Token get whileKeyword;
}

final class WhileStatementImpl extends StatementImpl implements WhileStatement {
  @override
  final Token whileKeyword;

  @override
  final Token leftParenthesis;

  ExpressionImpl _condition;

  @override
  final Token rightParenthesis;

  StatementImpl _body;

  /// Initializes a newly created while statement.
  WhileStatementImpl({
    required this.whileKeyword,
    required this.leftParenthesis,
    required ExpressionImpl condition,
    required this.rightParenthesis,
    required StatementImpl body,
  })  : _condition = condition,
        _body = body {
    _becomeParentOf(_condition);
    _becomeParentOf(_body);
  }

  @override
  Token get beginToken => whileKeyword;

  @override
  StatementImpl get body => _body;

  set body(StatementImpl statement) {
    _body = _becomeParentOf(statement);
  }

  @override
  ExpressionImpl get condition => _condition;

  set condition(ExpressionImpl expression) {
    _condition = _becomeParentOf(expression);
  }

  @override
  Token get endToken => _body.endToken;

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('whileKeyword', whileKeyword)
    ..addToken('leftParenthesis', leftParenthesis)
    ..addNode('condition', condition)
    ..addToken('rightParenthesis', rightParenthesis)
    ..addNode('body', body);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitWhileStatement(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _condition.accept(visitor);
    _body.accept(visitor);
  }
}

/// A wildcard pattern.
///
///    wildcardPattern ::=
///        ( 'var' | 'final' | 'final'? [TypeAnnotation])? '_'
abstract final class WildcardPattern implements DartPattern {
  /// The `var` or `final` keyword.
  Token? get keyword;

  /// The `_` token.
  Token get name;

  /// The type that the pattern is required to match, or `null` if any type is
  /// matched.
  TypeAnnotation? get type;
}

final class WildcardPatternImpl extends DartPatternImpl
    implements WildcardPattern {
  @override
  final Token? keyword;

  @override
  final Token name;

  @override
  final TypeAnnotationImpl? type;

  WildcardPatternImpl({
    required this.name,
    required this.keyword,
    required this.type,
  }) {
    _becomeParentOf(type);
  }

  @override
  Token get beginToken => type?.beginToken ?? name;

  @override
  Token get endToken => name;

  /// If [keyword] is `final`, returns it.
  Token? get finalKeyword {
    var keyword = this.keyword;
    if (keyword != null && keyword.keyword == Keyword.FINAL) {
      return keyword;
    }
    return null;
  }

  @override
  PatternPrecedence get precedence => PatternPrecedence.primary;

  @override
  ChildEntities get _childEntities => super._childEntities
    ..addToken('keyword', keyword)
    ..addNode('type', type)
    ..addToken('name', name);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitWildcardPattern(this);

  @override
  DartType computePatternSchema(ResolverVisitor resolverVisitor) {
    return resolverVisitor
        .analyzeDeclaredVariablePatternSchema(
            type?.typeOrThrow.wrapSharedTypeView())
        .unwrapTypeSchemaView();
  }

  @override
  PatternResult<DartType> resolvePattern(
    ResolverVisitor resolverVisitor,
    SharedMatchContext context,
  ) {
    var declaredType = type?.typeOrThrow;
    var analysisResult = resolverVisitor.analyzeWildcardPattern(
      context: context,
      node: this,
      declaredType: declaredType?.wrapSharedTypeView(),
    );

    if (declaredType != null) {
      resolverVisitor.checkPatternNeverMatchesValueType(
        context: context,
        pattern: this,
        requiredType: declaredType,
        matchedValueType: analysisResult.matchedValueType.unwrapTypeView(),
      );
    }

    return analysisResult;
  }

  @override
  void visitChildren(AstVisitor visitor) {
    type?.accept(visitor);
  }
}

/// The with clause in a class declaration.
///
///    withClause ::=
///        'with' [NamedType] (',' [NamedType])*
abstract final class WithClause implements AstNode {
  /// The names of the mixins that were specified.
  NodeList<NamedType> get mixinTypes;

  /// The token representing the `with` keyword.
  Token get withKeyword;
}

final class WithClauseImpl extends AstNodeImpl implements WithClause {
  @override
  final Token withKeyword;

  final NodeListImpl<NamedTypeImpl> _mixinTypes = NodeListImpl._();

  /// Initializes a newly created with clause.
  WithClauseImpl({
    required this.withKeyword,
    required List<NamedTypeImpl> mixinTypes,
  }) {
    _mixinTypes._initialize(this, mixinTypes);
  }

  @override
  Token get beginToken => withKeyword;

  @override
  Token get endToken => _mixinTypes.endToken ?? withKeyword;

  @override
  NodeListImpl<NamedTypeImpl> get mixinTypes => _mixinTypes;

  @override
  // TODO(paulberry): add commas.
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('withKeyword', withKeyword)
    ..addNodeList('mixinTypes', mixinTypes);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitWithClause(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _mixinTypes.accept(visitor);
  }
}

/// A yield statement.
///
///    yieldStatement ::=
///        'yield' '*'? [Expression] ‘;’
abstract final class YieldStatement implements Statement {
  /// The expression whose value is yielded.
  Expression get expression;

  /// The semicolon following the expression.
  Token get semicolon;

  /// The star optionally following the `yield` keyword.
  Token? get star;

  /// The `yield` keyword.
  Token get yieldKeyword;
}

final class YieldStatementImpl extends StatementImpl implements YieldStatement {
  @override
  final Token yieldKeyword;

  @override
  final Token? star;

  ExpressionImpl _expression;

  @override
  final Token semicolon;

  /// Initializes a newly created yield expression.
  ///
  /// The [star] can be `null` if no star was provided.
  YieldStatementImpl({
    required this.yieldKeyword,
    required this.star,
    required ExpressionImpl expression,
    required this.semicolon,
  }) : _expression = expression {
    _becomeParentOf(_expression);
  }

  @override
  Token get beginToken {
    return yieldKeyword;
  }

  @override
  Token get endToken {
    return semicolon;
  }

  @override
  ExpressionImpl get expression => _expression;

  set expression(ExpressionImpl expression) {
    _expression = _becomeParentOf(expression);
  }

  @override
  ChildEntities get _childEntities => ChildEntities()
    ..addToken('yieldKeyword', yieldKeyword)
    ..addToken('star', star)
    ..addNode('expression', expression)
    ..addToken('semicolon', semicolon);

  @override
  E? accept<E>(AstVisitor<E> visitor) => visitor.visitYieldStatement(this);

  @override
  void visitChildren(AstVisitor visitor) {
    _expression.accept(visitor);
  }
}

/// Mixin implementing shared functionality for AST nodes that can have optional
/// annotations and an optional documentation comment.
base mixin _AnnotatedNodeMixin on AstNodeImpl implements AnnotatedNode {
  CommentImpl? _comment;

  final NodeListImpl<AnnotationImpl> _metadata = NodeListImpl._();

  @override
  CommentImpl? get documentationComment => _comment;

  set documentationComment(CommentImpl? comment) {
    _comment = _becomeParentOf(comment);
  }

  /// The first token following the comment and metadata.
  @override
  Token get firstTokenAfterCommentAndMetadata;

  @override
  NodeListImpl<AnnotationImpl> get metadata => _metadata;

  @override
  List<AstNode> get sortedCommentAndAnnotations {
    var comment = _comment;
    return <AstNode>[
      if (comment != null) comment,
      ..._metadata,
    ]..sort(AstNode.LEXICAL_ORDER);
  }

  /// Returns `true` if there are no annotations before the comment.
  ///
  /// Note that a result of `true` doesn't imply that there's a comment, nor
  /// that there are annotations associated with this node.
  bool _commentIsBeforeAnnotations() {
    if (_comment == null || _metadata.isEmpty) {
      return true;
    }
    Annotation firstAnnotation = _metadata[0];
    return _comment!.offset < firstAnnotation.offset;
  }

  /// Initializes the comment and metadata pointed to by this node.
  ///
  /// Intended to be called from the constructor.
  void _initializeCommentAndAnnotations(
      CommentImpl? comment, List<AnnotationImpl>? metadata) {
    _comment = _becomeParentOf(comment);
    _metadata._initialize(this, metadata);
  }

  /// Visits the AST nodes associated with [documentationComment] and
  /// [metadata] (if any).
  ///
  /// Intended to be called from the [AstNode.visitChildren] method.
  void _visitCommentAndAnnotations(AstVisitor<dynamic> visitor) {
    if (_commentIsBeforeAnnotations()) {
      _comment?.accept(visitor);
      _metadata.accept(visitor);
    } else {
      List<AstNode> children = sortedCommentAndAnnotations;
      int length = children.length;
      for (int i = 0; i < length; i++) {
        children[i].accept(visitor);
      }
    }
  }
}

/// An indication of the resolved kind of a [SetOrMapLiteral].
enum _SetOrMapKind {
  /// Indicates that the literal represents a map.
  map,

  /// Indicates that the literal represents a set.
  set,

  /// Indicates that either
  /// - the literal is syntactically ambiguous and resolution hasn't yet been
  ///   performed, or
  /// - the literal is invalid because resolution isn't able to resolve the
  ///   ambiguity.
  unresolved
}
