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

import 'package:_fe_analyzer_shared/src/messages/severity.dart'
    show CfeSeverity;
import 'package:_fe_analyzer_shared/src/parser/parser.dart'
    show
        Assert,
        BlockKind,
        ConstructorReferenceContext,
        FormalParameterKind,
        IdentifierContext,
        MemberKind,
        Parser,
        boolFromToken,
        doubleFromToken,
        intFromToken,
        lengthForToken,
        lengthOfSpan,
        stripSeparators;
import 'package:_fe_analyzer_shared/src/parser/quote.dart'
    show
        Quote,
        analyzeQuote,
        unescape,
        unescapeFirstStringPart,
        unescapeLastStringPart,
        unescapeString;
import 'package:_fe_analyzer_shared/src/parser/stack_listener.dart'
    show FixedNullableList, GrowableList, NullValues, ParserRecovery;
import 'package:_fe_analyzer_shared/src/scanner/token.dart'
    show Keyword, Token, TokenIsAExtension, TokenType;
import 'package:_fe_analyzer_shared/src/scanner/token_impl.dart'
    show isBinaryOperator, isMinusOperator, isUserDefinableOperator;
import 'package:_fe_analyzer_shared/src/type_inference/assigned_variables.dart';
import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
import 'package:_fe_analyzer_shared/src/util/link.dart';
import 'package:_fe_analyzer_shared/src/util/value_kind.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/clone.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/names.dart' show minusName, plusName;
import 'package:kernel/src/bounds_checks.dart' hide calculateBounds;
import 'package:kernel/type_environment.dart';

import '../api_prototype/experimental_flags.dart';
import '../api_prototype/lowering_predicates.dart';
import '../base/constant_context.dart' show ConstantContext;
import '../base/identifiers.dart'
    show
        Identifier,
        InitializedIdentifier,
        QualifiedName,
        QualifiedNameBuilder,
        QualifiedNameGenerator,
        QualifiedNameIdentifier,
        SimpleIdentifier;
import '../base/label_scope.dart';
import '../base/local_scope.dart';
import '../base/lookup_result.dart';
import '../base/modifiers.dart' show Modifiers;
import '../base/problems.dart' show internalProblem, unhandled, unsupported;
import '../base/scope.dart';
import '../builder/builder.dart';
import '../builder/constructor_builder.dart';
import '../builder/declaration_builders.dart';
import '../builder/factory_builder.dart';
import '../builder/formal_parameter_builder.dart';
import '../builder/function_type_builder.dart';
import '../builder/invalid_type_builder.dart';
import '../builder/library_builder.dart';
import '../builder/member_builder.dart';
import '../builder/method_builder.dart';
import '../builder/named_type_builder.dart';
import '../builder/nullability_builder.dart';
import '../builder/omitted_type_builder.dart';
import '../builder/prefix_builder.dart';
import '../builder/property_builder.dart';
import '../builder/record_type_builder.dart';
import '../builder/type_builder.dart';
import '../builder/variable_builder.dart';
import '../builder/void_type_builder.dart';
import '../codes/cfe_codes.dart'
    show
        LocatedMessage,
        Message,
        Template,
        codeNamedFieldClashesWithPositionalFieldInRecord,
        noLength,
        codeDuplicatedRecordLiteralFieldName,
        codeDuplicatedRecordLiteralFieldNameContext,
        codeExperimentNotEnabledOffByDefault,
        codeLocalVariableUsedBeforeDeclared,
        codeLocalVariableUsedBeforeDeclaredContext;
import '../codes/cfe_codes.dart' as cfe;
import '../dill/dill_library_builder.dart' show DillLibraryBuilder;
import '../dill/dill_type_parameter_builder.dart';
import '../fragment/fragment.dart';
import '../source/diet_parser.dart';
import '../source/offset_map.dart';
import '../source/source_constructor_builder.dart';
import '../source/source_library_builder.dart';
import '../source/source_member_builder.dart';
import '../source/source_property_builder.dart';
import '../source/source_type_parameter_builder.dart';
import '../source/stack_listener_impl.dart'
    show StackListenerImpl, offsetForToken;
import '../source/type_parameter_factory.dart';
import '../source/value_kinds.dart';
import '../type_inference/inference_results.dart'
    show InitializerInferenceResult;
import '../type_inference/inference_visitor.dart'
    show ExpressionEvaluationHelper;
import '../type_inference/type_inferrer.dart'
    show TypeInferrer, InferredFunctionBody;
import '../util/helpers.dart';
import '../util/local_stack.dart';
import 'benchmarker.dart' show Benchmarker;
import 'body_builder_context.dart';
import 'collections.dart';
import 'constness.dart' show Constness;
import 'expression_generator.dart';
import 'expression_generator_helper.dart';
import 'forest.dart' show Forest;
import 'implicit_type_argument.dart' show ImplicitTypeArgument;
import 'internal_ast.dart';
import 'kernel_variable_builder.dart';
import 'load_library_builder.dart';
import 'type_algorithms.dart' show calculateBounds;
import 'utils.dart';

part 'body_builder_helpers.dart';

class BodyBuilder extends StackListenerImpl
    implements ExpressionGeneratorHelper {
  @override
  final Forest forest;

  @override
  final SourceLibraryBuilder libraryBuilder;

  final BodyBuilderContext _context;

  final ClassHierarchy hierarchy;

  final CoreTypes coreTypes;

  final LocalScope enclosingScope;

  final bool enableNative;

  // TODO(ahe): Consider renaming [uri] to 'partUri'.
  @override
  final Uri uri;

  final TypeInferrer typeInferrer;

  final Benchmarker? benchmarker;

  /// Only used when [member] is a constructor. It tracks if an implicit super
  /// initializer is needed.
  ///
  /// An implicit super initializer isn't needed
  ///
  /// 1. if the current class is Object,
  /// 2. if there is an explicit super initializer,
  /// 3. if there is a redirecting (this) initializer, or
  /// 4. if a compile-time error prevented us from generating code for an
  ///    initializer. This avoids cascading errors.
  bool needsImplicitSuperInitializer;

  LocalScope? formalParameterScope;

  /// This is set to true when we start parsing an initializer. We use this to
  /// find the correct scope for initializers like in this example:
  ///
  ///     class C {
  ///       final x;
  ///       C(x) : x = x;
  ///     }
  ///
  /// When parsing this initializer `x = x`, `x` must be resolved in two
  /// different scopes. The first `x` must be resolved in the class' scope, the
  /// second in the formal parameter scope.
  bool inInitializerLeftHandSide = false;

  /// This is set to true when we are parsing constructor initializers.
  bool inConstructorInitializer = false;

  /// This is set to `true` when we are parsing formals.
  bool inFormals = false;

  /// Set to `true` when we are parsing a field initializer either directly
  /// or within an initializer list.
  ///
  /// For instance in `<init>` in
  ///
  ///    var foo = <init>;
  ///    class Class {
  ///      var bar = <init>;
  ///      Class() : <init>;
  ///    }
  ///
  /// This is used to determine whether instance properties are available.
  bool inFieldInitializer = false;

  /// `true` if we are directly in a field initializer of a late field.
  ///
  /// For instance in `<init>` in
  ///
  ///    late var foo = <init>;
  ///    class Class {
  ///      late var bar = <init>;
  ///      Class() : bar = 42;
  ///    }
  ///
  bool inLateFieldInitializer = false;

  /// `true` if we are directly in the initializer of a late local.
  ///
  /// For instance in `<init>` in
  ///
  ///    method() {
  ///      late var foo = <init>;
  ///    }
  ///    class Class {
  ///      method() {
  ///        late var bar = <init>;
  ///      }
  ///    }
  ///
  bool get inLateLocalInitializer => _localInitializerState.head;

  /// Level of nesting of function-type type parameters.
  ///
  /// For instance, `X` is at nesting level 1, and `Y` is at nesting level 2 in
  /// the following:
  ///
  ///    method() {
  ///      Function<X>(Function<Y extends X>(Y))? f;
  ///    }
  ///
  /// For simplicity, non-generic functions are considered generic functions
  /// with 0 type parameters.
  int _structuralParameterDepthLevel = 0;

  /// True if a type of a formal parameter is currently compiled.
  ///
  /// This variable is needed to distinguish between the type of a formal
  /// parameter and its initializer because in those two regions of code the
  /// type parameters should be interpreted differently: as structural and
  /// nominal correspondingly.
  bool _insideOfFormalParameterType = false;

  bool get inFunctionType =>
      _structuralParameterDepthLevel > 0 || _insideOfFormalParameterType;

  Link<bool> _isOrAsOperatorTypeState = const Link<bool>().prepend(false);

  bool get inIsOrAsOperatorType => _isOrAsOperatorTypeState.head;

  Link<bool> _localInitializerState = const Link<bool>().prepend(false);

  List<Initializer>? _initializers;

  bool inCatchClause = false;

  bool inCatchBlock = false;

  int functionNestingLevel = 0;

  Statement? problemInLoopOrSwitch;

  final LocalStack<LabelScope> _labelScopes;

  final LocalStack<LabelScope?> _switchScopes = new LocalStack([]);

  late CloneVisitorNotMembers _simpleCloner = new CloneVisitorNotMembers();

  @override
  ConstantContext constantContext = ConstantContext.none;

  DartType? currentLocalVariableType;

  static const Modifiers noCurrentLocalVariableModifiers = const Modifiers(-1);

  Modifiers currentLocalVariableModifiers = noCurrentLocalVariableModifiers;

  /// If non-null, records instance fields which have already been initialized
  /// and where that was.
  Map<String, int>? initializedFields;

  /// Variables with metadata.  Their types need to be inferred late, for
  /// example, in [finishFunction].
  List<VariableDeclaration>? variablesWithMetadata;

  /// More than one variable declared in a single statement that has metadata.
  /// Their types need to be inferred late, for example, in [finishFunction].
  List<List<VariableDeclaration>>? multiVariablesWithMetadata;

  /// If the current member is an instance member in an extension declaration or
  /// an instance member or constructor in and extension type declaration,
  /// [thisVariable] holds the synthetically added variable holding the value
  /// for `this`.
  final VariableDeclaration? thisVariable;

  final List<TypeParameter>? thisTypeParameters;

  final LocalStack<LocalScope> _localScopes;

  Set<VariableDeclaration>? declaredInCurrentGuard;

  JumpTarget? breakTarget;

  JumpTarget? continueTarget;

  /// Index for building unique lowered names for wildcard variables.
  int wildcardVariableIndex = 0;

  BodyBuilder({
    required this.libraryBuilder,
    required BodyBuilderContext context,
    required this.enclosingScope,
    this.formalParameterScope,
    required this.hierarchy,
    required this.coreTypes,
    this.thisVariable,
    this.thisTypeParameters,
    required this.uri,
    required this.typeInferrer,
  }) : _context = context,
       forest = const Forest(),
       enableNative = libraryBuilder.loader.target.backendTarget.enableNative(
         libraryBuilder.importUri,
       ),
       needsImplicitSuperInitializer = context.needsImplicitSuperInitializer(
         coreTypes,
       ),
       benchmarker = libraryBuilder.loader.target.benchmarker,
       _localScopes = new LocalStack([enclosingScope]),
       _labelScopes = new LocalStack([new LabelScopeImpl()]) {
    if (formalParameterScope != null) {
      for (VariableBuilder builder in formalParameterScope!.localVariables) {
        typeInferrer.assignedVariables.declare(builder.variable!);
      }
    }
    if (thisVariable != null && context.isConstructor) {
      // The this variable is not part of the [formalParameterScope] in
      // constructors.
      typeInferrer.assignedVariables.declare(thisVariable!);
    }
  }

  BodyBuilder.forField(
    SourceLibraryBuilder libraryBuilder,
    BodyBuilderContext bodyBuilderContext,
    LookupScope enclosingScope,
    TypeInferrer typeInferrer,
    Uri uri,
  ) : this(
        libraryBuilder: libraryBuilder,
        context: bodyBuilderContext,
        enclosingScope: new EnclosingLocalScope(enclosingScope),
        formalParameterScope: null,
        hierarchy: libraryBuilder.loader.hierarchy,
        coreTypes: libraryBuilder.loader.coreTypes,
        thisVariable: null,
        uri: uri,
        typeInferrer: typeInferrer,
      );

  BodyBuilder.forOutlineExpression(
    SourceLibraryBuilder libraryBuilder,
    BodyBuilderContext bodyBuilderContext,
    LookupScope scope,
    Uri fileUri, {
    LocalScope? formalParameterScope,
  }) : this(
         libraryBuilder: libraryBuilder,
         context: bodyBuilderContext,
         enclosingScope: new EnclosingLocalScope(scope),
         formalParameterScope: formalParameterScope,
         hierarchy: libraryBuilder.loader.hierarchy,
         coreTypes: libraryBuilder.loader.coreTypes,
         thisVariable: null,
         uri: fileUri,
         typeInferrer: libraryBuilder.loader.typeInferenceEngine
             .createLocalTypeInferrer(
               fileUri,
               bodyBuilderContext.thisType,
               libraryBuilder,
               scope,
               null,
             ),
       );

  LocalScope get _localScope => _localScopes.current;

  LabelScope get _labelScope => _labelScopes.current;

  LabelScope? get _switchScope =>
      _switchScopes.hasCurrent ? _switchScopes.current : null;

  @override
  LibraryFeatures get libraryFeatures => libraryBuilder.libraryFeatures;

  @override
  bool get isDartLibrary =>
      libraryBuilder.importUri.isScheme("dart") ||
      uri.isScheme("org-dartlang-sdk");

  @override
  Message reportFeatureNotEnabled(
    LibraryFeature feature,
    int charOffset,
    int length,
  ) {
    return libraryBuilder.reportFeatureNotEnabled(
      feature,
      uri,
      charOffset,
      length,
    );
  }

  JumpTarget createBreakTarget(int charOffset) {
    return createJumpTarget(JumpTargetKind.Break, charOffset);
  }

  JumpTarget createContinueTarget(int charOffset) {
    return createJumpTarget(JumpTargetKind.Continue, charOffset);
  }

  JumpTarget createGotoTarget(int charOffset) {
    return createJumpTarget(JumpTargetKind.Goto, charOffset);
  }

  void enterLocalScope(LocalScope localScope) {
    _localScopes.push(localScope);
    _labelScopes.push(new LabelScopeImpl(_labelScope));
  }

  void createAndEnterLocalScope({
    required String debugName,
    required ScopeKind kind,
  }) {
    _localScopes.push(
      _localScope.createNestedScope(debugName: debugName, kind: kind),
    );
    _labelScopes.push(new LabelScopeImpl(_labelScope));
  }

  void exitLocalScope({List<ScopeKind>? expectedScopeKinds}) {
    assert(
      expectedScopeKinds == null ||
          expectedScopeKinds.contains(_localScope.kind),
      "Expected the current scope to be one of the kinds "
      "${expectedScopeKinds.map((k) => "'${k}'").join(", ")}, "
      "but got '${_localScope.kind}'.",
    );
    if (isGuardScope(_localScope) && declaredInCurrentGuard != null) {
      for (VariableBuilder builder in _localScope.localVariables) {
        declaredInCurrentGuard!.remove(builder.variable);
      }
      if (declaredInCurrentGuard!.isEmpty) {
        declaredInCurrentGuard = null;
      }
    }
    _labelScopes.pop();
    _localScopes.pop();
  }

  void enterBreakTarget(int charOffset, [JumpTarget? target]) {
    push(breakTarget ?? NullValues.BreakTarget);
    breakTarget = target ?? createBreakTarget(charOffset);
  }

  void enterContinueTarget(int charOffset, [JumpTarget? target]) {
    push(continueTarget ?? NullValues.ContinueTarget);
    continueTarget = target ?? createContinueTarget(charOffset);
  }

  JumpTarget? exitBreakTarget() {
    JumpTarget? current = breakTarget;
    breakTarget = pop() as JumpTarget?;
    return current;
  }

  JumpTarget? exitContinueTarget() {
    JumpTarget? current = continueTarget;
    continueTarget = pop() as JumpTarget?;
    return current;
  }

  @override
  void beginBlockFunctionBody(Token begin) {
    debugEvent("beginBlockFunctionBody");
    createAndEnterLocalScope(
      debugName: "block function body",
      kind: ScopeKind.functionBody,
    );
  }

  @override
  void beginForStatement(Token token) {
    debugEvent("beginForStatement");
    enterLoop(token.charOffset);
    createAndEnterLocalScope(
      debugName: "for statement",
      kind: ScopeKind.forStatement,
    );
  }

  @override
  void beginForControlFlow(Token? awaitToken, Token forToken) {
    debugEvent("beginForControlFlow");
    createAndEnterLocalScope(
      debugName: "for in a collection",
      kind: ScopeKind.forStatement,
    );
  }

  @override
  void beginDoWhileStatementBody(Token token) {
    debugEvent("beginDoWhileStatementBody");
    createAndEnterLocalScope(
      debugName: "do-while statement body",
      kind: ScopeKind.statementLocalScope,
    );
  }

  @override
  void endDoWhileStatementBody(Token token) {
    debugEvent("endDoWhileStatementBody");
    Object? body = pop();
    exitLocalScope();
    push(body);
  }

  @override
  void beginWhileStatementBody(Token token) {
    debugEvent("beginWhileStatementBody");
    createAndEnterLocalScope(
      debugName: "while statement body",
      kind: ScopeKind.statementLocalScope,
    );
  }

  @override
  void endWhileStatementBody(Token endToken) {
    debugEvent("endWhileStatementBody");
    Object? body = pop();
    exitLocalScope();
    push(body);
  }

  @override
  void beginForStatementBody(Token token) {
    debugEvent("beginForStatementBody");
    createAndEnterLocalScope(
      debugName: "for statement body",
      kind: ScopeKind.statementLocalScope,
    );
  }

  @override
  void endForStatementBody(Token endToken) {
    debugEvent("endForStatementBody");
    Object? body = pop();
    exitLocalScope();
    push(body);
  }

  @override
  void beginForInBody(Token token) {
    debugEvent("beginForInBody");
    createAndEnterLocalScope(
      debugName: "for-in body",
      kind: ScopeKind.statementLocalScope,
    );
  }

  @override
  void endForInBody(Token endToken) {
    debugEvent("endForInBody");
    Object? body = pop();
    exitLocalScope();
    push(body);
  }

  @override
  void beginElseStatement(Token token) {
    debugEvent("beginElseStatement");
    createAndEnterLocalScope(
      debugName: "else",
      kind: ScopeKind.statementLocalScope,
    );
  }

  @override
  void endElseStatement(Token beginToken, Token endToken) {
    debugEvent("endElseStatement");
    Object? body = pop();
    exitLocalScope();
    push(body);
  }

  bool get inConstructor {
    return functionNestingLevel == 0 && _context.isConstructor;
  }

  bool get isDeclarationInstanceContext {
    return _context.isDeclarationInstanceContext;
  }

  @override
  InstanceTypeParameterAccessState get instanceTypeParameterAccessState {
    return _context.instanceTypeParameterAccessState;
  }

  @override
  TypeEnvironment get typeEnvironment => typeInferrer.typeSchemaEnvironment;

  DartType get implicitTypeArgument => const ImplicitTypeArgument();

  void _enterLocalState({bool inLateLocalInitializer = false}) {
    _localInitializerState = _localInitializerState.prepend(
      inLateLocalInitializer,
    );
  }

  void _exitLocalState() {
    _localInitializerState = _localInitializerState.tail!;
  }

  @override
  void registerVariableAssignment(VariableDeclaration variable) {
    typeInferrer.assignedVariables.write(variable);
  }

  @override
  VariableDeclarationImpl createVariableDeclarationForValue(
    Expression expression,
  ) {
    VariableDeclarationImpl variable = forest.createVariableDeclarationForValue(
      expression,
    );
    typeInferrer.assignedVariables.declare(variable);
    return variable;
  }

  @override
  void push(Object? node) {
    if (node is DartType) {
      unhandled("DartType", "push", -1, uri);
    }
    inInitializerLeftHandSide = false;
    super.push(node);
  }

  Expression popForValue() => toValue(pop());

  Expression popForEffect() => toEffect(pop());

  Expression? popForValueIfNotNull(Object? value) {
    return value == null ? null : popForValue();
  }

  @override
  Expression toValue(Object? node) {
    if (node is Generator) {
      return node.buildSimpleRead();
    } else if (node is Expression) {
      return node;
    } else if (node is SuperInitializer) {
      return buildProblem(cfe.codeSuperAsExpression, node.fileOffset, noLength);
    } else {
      return unhandled("${node.runtimeType}", "toValue", -1, uri);
    }
  }

  Expression toEffect(Object? node) {
    if (node is Generator) return node.buildForEffect();
    return toValue(node);
  }

  Pattern toPattern(Object? node) {
    if (node is Pattern) {
      return node;
    } else if (node is Generator) {
      return forest.createConstantPattern(node.buildSimpleRead());
    } else if (node is Expression) {
      return forest.createConstantPattern(node);
    } else {
      return unhandled("${node.runtimeType}", "toPattern", -1, uri);
    }
  }

  List<Expression> popListForValue(int n) {
    List<Expression> list = new List<Expression>.filled(
      n,
      dummyExpression,
      growable: true,
    );
    for (int i = n - 1; i >= 0; i--) {
      list[i] = popForValue();
    }
    return list;
  }

  List<Expression> popListForEffect(int n) {
    List<Expression> list = new List<Expression>.filled(
      n,
      dummyExpression,
      growable: true,
    );
    for (int i = n - 1; i >= 0; i--) {
      list[i] = popForEffect();
    }
    return list;
  }

  Statement popBlock(int count, Token openBrace, Token? closeBrace) {
    return forest.createBlock(
      offsetForToken(openBrace),
      offsetForToken(closeBrace),
      const GrowableList<Statement>().popNonNullable(
            stack,
            count,
            dummyStatement,
          ) ??
          <Statement>[],
    );
  }

  Statement? popStatementIfNotNull(Token? token) {
    return token == null ? null : popStatement(token);
  }

  Statement popStatement(Token token) {
    Object? element = pop();
    if (element is Statement) {
      return forest.wrapVariables(element);
    } else {
      return _handleStatementNotStatement(element, token);
    }
  }

  Statement _handleStatementNotStatement(Object? element, Token? token) {
    if (element is ParserRecovery) {
      return new Block(<Statement>[
        forest.createExpressionStatement(
          element.charOffset,
          ParserErrorGenerator.buildProblemExpression(
            this,
            cfe.codeSyntheticToken,
            element.charOffset,
          ),
        ),
      ])..fileOffset = element.charOffset;
    } else {
      unhandled(
        "expected statement is ${element.runtimeType}: $element",
        "popStatement",
        token?.charOffset ?? -1,
        uri,
      );
    }
  }

  Statement popStatementNoWrap([Token? token]) {
    Object? element = pop();
    if (element is Statement) {
      return element;
    } else {
      return _handleStatementNotStatement(element, token);
    }
  }

  Statement? popNullableStatement() {
    Statement? statement = pop(NullValues.Block) as Statement?;
    if (statement != null) {
      statement = forest.wrapVariables(statement);
    }
    return statement;
  }

  void enterSwitchScope() {
    _switchScopes.push(_labelScope);
  }

  void exitSwitchScope() {
    LabelScope switchScope = _switchScope!;
    LabelScope? outerSwitchScope = _switchScopes.hasPrevious
        ? _switchScopes.previous
        : null;
    if (switchScope.unclaimedForwardDeclarations != null) {
      switchScope.unclaimedForwardDeclarations!.forEach((
        String name,
        JumpTarget declaration,
      ) {
        if (outerSwitchScope == null) {
          for (Statement statement in declaration.users) {
            statement.parent!.replaceChild(
              statement,
              wrapInProblemStatement(
                statement,
                cfe.codeLabelNotFound.withArgumentsOld(name),
              ),
            );
          }
        } else {
          outerSwitchScope.forwardDeclareLabel(name, declaration);
        }
      });
    }
    _switchScopes.pop();
  }

  void wrapVariableInitializerInError(
    VariableDeclaration variable,
    Template<Message Function(String name), Function> template,
    List<LocatedMessage> context,
  ) {
    String name = variable.name!;
    int offset = variable.fileOffset;
    Message message = template.withArgumentsOld(name);
    if (variable.initializer == null) {
      variable.initializer = buildProblem(
        message,
        offset,
        name.length,
        context: context,
      )..parent = variable;
    } else {
      variable.initializer = wrapInLocatedProblem(
        variable.initializer!,
        message.withLocation(uri, offset, name.length),
        context: context,
      )..parent = variable;
    }
  }

  void declareVariable(VariableDeclaration variable, LocalScope scope) {
    String name = variable.name!;
    Builder? existing = scope.lookupLocalVariable(name);
    if (existing != null) {
      // This reports an error for duplicated declarations in the same scope:
      // `{ var x; var x; }`
      wrapVariableInitializerInError(
        variable,
        cfe.codeDuplicatedDeclaration,
        <LocatedMessage>[
          cfe.codeDuplicatedDeclarationCause
              .withArgumentsOld(name)
              .withLocation(uri, existing.fileOffset, name.length),
        ],
      );
      return;
    }
    if (isGuardScope(scope)) {
      (declaredInCurrentGuard ??= {}).add(variable);
    }
    String variableName = variable.name!;
    List<int>? previousOffsets = scope.declare(
      variableName,
      new VariableBuilderImpl(variableName, variable, uri),
    );
    if (previousOffsets != null && previousOffsets.isNotEmpty) {
      // This case is different from the above error. In this case, the problem
      // is using `x` before it's declared: `{ var x; { print(x); var x;
      // }}`. In this case, we want two errors, the `x` in `print(x)` and the
      // second (or innermost declaration) of `x`.
      for (int previousOffset in previousOffsets) {
        addProblem(
          codeLocalVariableUsedBeforeDeclared.withArgumentsOld(variableName),
          previousOffset,
          variableName.length,
          context: <LocatedMessage>[
            codeLocalVariableUsedBeforeDeclaredContext
                .withArgumentsOld(variableName)
                .withLocation(uri, variable.fileOffset, variableName.length),
          ],
        );
      }
    }
  }

  JumpTarget createJumpTarget(JumpTargetKind kind, int charOffset) {
    return new JumpTarget(kind, functionNestingLevel, uri, charOffset);
  }

  /// Infers the [annotations].
  ///
  /// If [indices] is provided, only the annotations at the given indices are
  /// inferred. Otherwise all annotations are inferred.
  void inferAnnotations(
    TreeNode? parent,
    List<Expression>? annotations, {
    List<int>? indices,
  }) {
    if (annotations != null) {
      typeInferrer.inferMetadata(this, parent, annotations, indices);
    }
  }

  @override
  void beginMetadata(Token token) {
    debugEvent("beginMetadata");
    super.push(constantContext);
    constantContext = ConstantContext.inferred;
    assert(checkState(token, [ValueKinds.ConstantContext]));
  }

  @override
  void endMetadata(Token beginToken, Token? periodBeforeName, Token endToken) {
    assert(
      checkState(beginToken, [
        /*arguments*/ ValueKinds.ArgumentsOrNull,
        /*suffix*/ if (periodBeforeName != null)
          unionOfKinds([ValueKinds.Identifier, ValueKinds.ParserRecovery]),
        /*type arguments*/ ValueKinds.TypeArgumentsOrNull,
        /*type*/ unionOfKinds([
          ValueKinds.Generator,
          ValueKinds.QualifiedName,
          ValueKinds.ParserRecovery,
        ]),
      ]),
    );
    debugEvent("Metadata");
    Arguments? arguments = pop() as Arguments?;
    pushQualifiedReference(
      beginToken.next!,
      periodBeforeName,
      ConstructorReferenceContext.Const,
    );
    assert(
      checkState(beginToken, [
        /*constructor name identifier*/ ValueKinds.IdentifierOrNull,
        /*constructor name*/ ValueKinds.Name,
        /*type arguments*/ ValueKinds.TypeArgumentsOrNull,
        /*class*/ unionOfKinds([
          ValueKinds.Generator,
          ValueKinds.ParserRecovery,
        ]),
      ]),
    );
    if (arguments != null) {
      push(arguments);
      _buildConstructorReferenceInvocation(
        beginToken.next!,
        beginToken.offset,
        Constness.explicitConst,
        inMetadata: true,
        inImplicitCreationContext: false,
      );
      push(popForValue());
    } else {
      pop(); // Name last identifier
      String? name = pop() as String?;
      pop(); // Type arguments (ignored, already reported by parser).
      Object? expression = pop();
      if (expression is Identifier) {
        // Coverage-ignore-block(suite): Not run.
        Identifier identifier = expression;
        expression = new UnresolvedNameGenerator(
          this,
          identifier.token,
          new Name(identifier.name, libraryBuilder.nameOrigin),
          unresolvedReadKind: UnresolvedKind.Unknown,
        );
      }

      if ((name?.isNotEmpty ?? false) && expression is Generator) {
        Token period = periodBeforeName ?? beginToken.next!.next!;
        Generator generator = expression;
        expression = generator.buildSelectorAccess(
          new PropertySelector(
            this,
            period.next!,
            new Name(name!, libraryBuilder.nameOrigin),
          ),
          period.next!.offset,
          false,
        );
      }

      ConstantContext savedConstantContext = pop() as ConstantContext;
      if (!(expression is StaticAccessGenerator &&
              expression.readTarget is Field) &&
          expression is! VariableUseGenerator &&
          // TODO(johnniwinther): Stop using the type of the generator here.
          // Ask a property instead.
          (expression is! ReadOnlyAccessGenerator ||
              // Coverage-ignore(suite): Not run.
              expression is TypeUseGenerator ||
              // Coverage-ignore(suite): Not run.
              expression is ParenthesizedExpressionGenerator)) {
        Expression value = toValue(expression);
        push(
          wrapInProblem(
            value,
            cfe.codeExpressionNotMetadata,
            value.fileOffset,
            noLength,
          ),
        );
      } else {
        push(toValue(expression));
      }
      constantContext = savedConstantContext;
    }
    assert(checkState(beginToken, [ValueKinds.Expression]));
  }

  @override
  void endMetadataStar(int count) {
    assert(checkState(null, repeatedKind(ValueKinds.Expression, count)));
    debugEvent("MetadataStar");
    if (count == 0) {
      push(NullValues.Metadata);
    } else {
      push(
        const GrowableList<Expression>().popNonNullable(
              stack,
              count,
              dummyExpression,
            ) ??
            NullValues.Metadata /* Ignore parser recovery */,
      );
    }
    assert(checkState(null, [ValueKinds.AnnotationListOrNull]));
  }

  @override
  void endTopLevelFields(
    Token? augmentToken,
    Token? externalToken,
    Token? staticToken,
    Token? covariantToken,
    Token? lateToken,
    Token? varFinalOrConst,
    int count,
    Token beginToken,
    Token endToken,
  ) {
    debugEvent("TopLevelFields");
    push(count);
    assert(checkState(beginToken, [ValueKinds.Integer]));
  }

  @override
  void endClassFields(
    Token? abstractToken,
    Token? augmentToken,
    Token? externalToken,
    Token? staticToken,
    Token? covariantToken,
    Token? lateToken,
    Token? varFinalOrConst,
    int count,
    Token beginToken,
    Token endToken,
  ) {
    debugEvent("Fields");
    push(count);
    assert(checkState(beginToken, [ValueKinds.Integer]));
  }

  void finishFields(OffsetMap offsetMap) {
    debugEvent("finishFields");
    assert(checkState(null, [/*field count*/ ValueKinds.Integer]));
    int count = pop() as int;
    for (int i = 0; i < count; i++) {
      assert(
        checkState(null, [
          ValueKinds.FieldInitializerOrNull,
          ValueKinds.Identifier,
        ]),
      );
      Expression? initializer = pop() as Expression?;
      Identifier identifier = pop() as Identifier;
      FieldFragment fieldFragment = offsetMap.lookupField(identifier);
      fieldFragment.declaration.buildFieldInitializer(
        this,
        typeInferrer,
        coreTypes,
        initializer,
      );
    }
    assert(
      checkState(null, [
        ValueKinds.TypeOrNull,
        ValueKinds.AnnotationListOrNull,
      ]),
    );
    {
      // TODO(ahe): The type we compute here may be different from what is
      // computed in the outline phase. We should make sure that the outline
      // phase computes the same type. See
      // pkg/front_end/testcases/regress/issue_32200.dart for an example where
      // not calling [buildDartType] leads to a missing compile-time
      // error. Also, notice that the type of the problematic field isn't
      // `invalid-type`.
      TypeBuilder? type = pop() as TypeBuilder?;
      if (type != null) {
        buildDartType(
          type,
          TypeUse.fieldType,
          allowPotentiallyConstantType: false,
        );
      }
    }
    pop(); // Annotations.

    performBacklogComputations();
    assert(stack.length == 0);
  }

  /// Perform delayed computations that were put on back log during body
  /// building.
  ///
  /// Back logged computations include resolution of redirecting factory
  /// invocations and checking of typedef types.
  void performBacklogComputations() {
    _finishVariableMetadata();
    libraryBuilder.checkPendingBoundsChecks(typeEnvironment);
  }

  void finishRedirectingFactoryBody() {
    performBacklogComputations();
  }

  @override
  void endMember() {
    debugEvent("Member");
  }

  @override
  void endBlockFunctionBody(int count, Token? openBrace, Token closeBrace) {
    debugEvent("BlockFunctionBody");
    if (openBrace == null) {
      assert(count == 0);
      push(NullValues.Block);
    } else {
      Statement block = popBlock(count, openBrace, closeBrace);
      exitLocalScope();
      push(block);
    }
    assert(checkState(closeBrace, [ValueKinds.StatementOrNull]));
  }

  void prepareInitializers() {
    _localScopes.push(
      _context.computeFormalParameterInitializerScope(_localScope),
    );
    if (_context.isConstructor) {
      _context.prepareInitializers();
      if (_context.formals != null) {
        for (FormalParameterBuilder formal in _context.formals!) {
          if (formal.isInitializingFormal) {
            List<Initializer> initializers;
            if (_context.isExternalConstructor) {
              initializers = <Initializer>[
                buildInvalidInitializer(
                  buildProblem(
                    cfe.codeExternalConstructorWithFieldInitializers,
                    formal.fileOffset,
                    formal.name.length,
                  ),
                  formal.fileOffset,
                ),
              ];
            } else {
              initializers = buildFieldInitializer(
                formal.name,
                formal.fileOffset,
                formal.fileOffset,
                new VariableGet(formal.variable!),
                formal: formal,
              );
            }
            for (Initializer initializer in initializers) {
              _context.addInitializer(initializer, this, inferenceResult: null);
            }
          }
        }
      }
    }
  }

  @override
  void handleNoInitializers() {
    debugEvent("NoInitializers");
    if (functionNestingLevel == 0) {
      prepareInitializers();
      _localScopes.push(
        formalParameterScope ??
            new FixedLocalScope(
              kind: ScopeKind.initializers,
              debugName: "initializers",
            ),
      );
    }
  }

  @override
  void beginInitializers(Token token) {
    debugEvent("beginInitializers");
    if (functionNestingLevel == 0) {
      prepareInitializers();
    }
    inConstructorInitializer = true;
  }

  @override
  void endInitializers(int count, Token beginToken, Token endToken) {
    debugEvent("Initializers");
    if (functionNestingLevel == 0) {
      _localScopes.push(
        formalParameterScope ??
            new FixedLocalScope(
              kind: ScopeKind.initializers,
              debugName: "initializers",
            ),
      );
    }
    inConstructorInitializer = false;
  }

  @override
  void beginInitializer(Token token) {
    debugEvent("beginInitializer");
    inInitializerLeftHandSide = true;
    inFieldInitializer = true;
  }

  @override
  void endInitializer(Token endToken) {
    assert(
      checkState(endToken, [
        unionOfKinds([
          ValueKinds.Initializer,
          ValueKinds.Generator,
          ValueKinds.Expression,
        ]),
      ]),
    );

    debugEvent("endInitializer");
    inFieldInitializer = false;
    assert(!inInitializerLeftHandSide);
    Object? node = pop();
    List<Initializer> initializers;

    if (!(_context.isConstructor && !_context.isExternalConstructor)) {
      // An error has been reported by the parser.
      initializers = <Initializer>[];
    } else if (node is Initializer) {
      initializers = <Initializer>[node];
    } else if (node is Generator) {
      initializers = node.buildFieldInitializer(initializedFields);
    } else if (node is ConstructorInvocation) {
      // Coverage-ignore-block(suite): Not run.
      initializers = <Initializer>[
        // TODO(jensj): Does this offset make sense?
        buildSuperInitializer(
          false,
          node.target,
          node.arguments,
          endToken.next!.charOffset,
        ),
      ];
    } else {
      Expression value = toValue(node);
      if (!forest.isThrow(node)) {
        // TODO(johnniwinther): Derive the message position from the [node]
        // and not the [value].  For instance this occurs for `super()?.foo()`
        // in an initializer list, pointing to `foo` as expecting an
        // initializer.
        value = wrapInProblem(
          value,
          cfe.codeExpectedAnInitializer,
          value.fileOffset,
          noLength,
        );
      }
      initializers = <Initializer>[
        // TODO(johnniwinther): This should probably be [value] instead of
        //  [node].
        // TODO(jensj): Does this offset make sense?
        buildInvalidInitializer(node as Expression, endToken.next!.charOffset),
      ];
    }

    _initializers ??= <Initializer>[];
    _initializers!.addAll(initializers);
  }

  List<Object>? createSuperParametersAsArguments(
    List<FormalParameterBuilder> formals,
  ) {
    List<Object>? superParametersAsArguments;
    for (int i = 0; i < formals.length; i++) {
      FormalParameterBuilder formal = formals[i];
      if (formal.isSuperInitializingFormal) {
        if (formal.isNamed) {
          (superParametersAsArguments ??= <Object>[]).add(
            new NamedExpression(
              formal.name,
              createVariableGet(formal.variable!, formal.fileOffset),
            )..fileOffset = formal.fileOffset,
          );
        } else {
          (superParametersAsArguments ??= <Object>[]).add(
            createVariableGet(formal.variable!, formal.fileOffset),
          );
        }
      }
    }
    return superParametersAsArguments;
  }

  void finishFunction(
    FormalParameters? formals,
    AsyncMarker asyncModifier,
    Statement? body,
  ) {
    debugEvent("finishFunction");

    // Create variable get expressions for super parameters before finishing
    // the analysis of the assigned variables. Creating the expressions later
    // that point results in a flow analysis error.
    List<Object>? superParametersAsArguments;
    if (formals != null) {
      List<FormalParameterBuilder>? formalParameters = formals.parameters;
      if (formalParameters != null) {
        superParametersAsArguments = createSuperParametersAsArguments(
          formalParameters,
        );
      }
    }
    typeInferrer.assignedVariables.finish();

    FunctionNode function = _context.function;
    _declareFormals();
    if (formals?.parameters != null) {
      for (int i = 0; i < formals!.parameters!.length; i++) {
        FormalParameterBuilder parameter = formals.parameters![i];
        Expression? initializer = parameter.variable!.initializer;
        bool inferInitializer;
        if (parameter.isSuperInitializingFormal) {
          // Super-parameters can inherit the default value from the super
          // constructor so we only handle explicit default values here.
          inferInitializer = parameter.hasImmediatelyDeclaredInitializer;
        } else if (initializer != null) {
          inferInitializer = true;
        } else {
          inferInitializer = parameter.isOptional;
        }
        if (inferInitializer) {
          if (!parameter.initializerWasInferred) {
            // Coverage-ignore(suite): Not run.
            initializer ??= forest.createNullLiteral(
              // TODO(ahe): Should store: originParameter.fileOffset
              // https://github.com/dart-lang/sdk/issues/32289
              noLocation,
            );
            VariableDeclaration originParameter = _context.getFormalParameter(
              i,
            );
            initializer = typeInferrer.inferParameterInitializer(
              this,
              initializer,
              originParameter.type,
              parameter.hasDeclaredInitializer,
            );
            originParameter.initializer = initializer..parent = originParameter;
            if (initializer is InvalidExpression) {
              originParameter.isErroneouslyInitialized = true;
            }
            parameter.initializerWasInferred = true;
          }
          VariableDeclaration? tearOffParameter = _context.getTearOffParameter(
            i,
          );
          if (tearOffParameter != null) {
            Expression tearOffInitializer = _simpleCloner.cloneInContext(
              initializer!,
            );
            tearOffParameter.initializer = tearOffInitializer
              ..parent = tearOffParameter;
            tearOffParameter.isErroneouslyInitialized =
                parameter.variable!.isErroneouslyInitialized;
          }
        }
      }
    }

    if (_context.isConstructor) {
      finishConstructor(
        asyncModifier,
        body,
        superParametersAsArguments: superParametersAsArguments,
      );
    } else if (body != null) {
      _context.setAsyncModifier(asyncModifier);
    }

    InferredFunctionBody? inferredFunctionBody;
    if (body != null) {
      inferredFunctionBody = typeInferrer.inferFunctionBody(
        this,
        _context.memberNameOffset,
        _context.returnTypeContext,
        asyncModifier,
        body,
        null,
      );
      body = inferredFunctionBody.body;
      function.emittedValueType = inferredFunctionBody.emittedValueType;
      assert(
        function.asyncMarker == AsyncMarker.Sync ||
            function.emittedValueType != null,
      );
    }

    if (_context.returnType is! OmittedTypeBuilder) {
      checkAsyncReturnType(
        asyncModifier,
        function.returnType,
        _context.memberNameOffset,
        _context.memberNameLength,
      );
    }

    if (_context.isSetter) {
      if (formals?.parameters == null ||
          formals!.parameters!.length != 1 ||
          formals.parameters!.single.isOptionalPositional) {
        int charOffset =
            formals?.charOffset ??
            // Coverage-ignore(suite): Not run.
            body?.fileOffset ??
            // Coverage-ignore(suite): Not run.
            _context.memberNameOffset;
        if (body == null) {
          body = new EmptyStatement()..fileOffset = charOffset;
        }
        if (_context.formals != null) {
          // Illegal parameters were removed by the function builder.
          // Add them as local variable to put them in scope of the body.
          List<Statement> statements = <Statement>[];
          List<FormalParameterBuilder> formals = _context.formals!;
          for (int i = 0; i < formals.length; i++) {
            FormalParameterBuilder parameter = formals[i];
            VariableDeclaration variable = parameter.variable!;
            // #this should not be redeclared.
            if (i == 0 && identical(variable, thisVariable)) {
              continue;
            }
            statements.add(parameter.variable!);
          }
          statements.add(body);
          body = forest.createBlock(charOffset, noLocation, statements);
        }
        body = forest.createBlock(charOffset, noLocation, <Statement>[
          forest.createExpressionStatement(
            noLocation,
            // This error is added after type inference is done, so we
            // don't need to wrap errors in SyntheticExpressionJudgment.
            buildProblem(
              cfe.codeSetterWithWrongNumberOfFormals,
              charOffset,
              noLength,
            ),
          ),
          body,
        ]);
      }
    }
    // No-such-method forwarders get their bodies injected during outline
    // building, so we should skip them here.
    bool isNoSuchMethodForwarder =
        (function.parent is Procedure &&
        (function.parent as Procedure).isNoSuchMethodForwarder);
    if (body != null) {
      if (_context.isExternalFunction || isNoSuchMethodForwarder) {
        body = new Block(<Statement>[
          new ExpressionStatement(
            buildProblem(
              cfe.codeExternalMethodWithBody,
              body.fileOffset,
              noLength,
            ),
          )..fileOffset = body.fileOffset,
          body,
        ])..fileOffset = body.fileOffset;
      }
      _context.registerFunctionBody(body);
    }

    performBacklogComputations();
  }

  void checkAsyncReturnType(
    AsyncMarker asyncModifier,
    DartType returnType,
    int charOffset,
    int length,
  ) {
    // For async, async*, and sync* functions with declared return types, we
    // need to determine whether those types are valid.
    // We use the same trick in each case below. For example to decide whether
    // Future<T> <: [returnType] for every T, we rely on Future<Bot> and
    // transitivity of the subtyping relation because Future<Bot> <: Future<T>
    // for every T.

    // We use [problem == null] to signal success.
    Message? problem;
    switch (asyncModifier) {
      case AsyncMarker.Async:
        DartType futureBottomType = libraryBuilder.loader.futureOfBottom;
        if (!typeEnvironment.isSubtypeOf(futureBottomType, returnType)) {
          problem = cfe.codeIllegalAsyncReturnType;
        }
        break;

      case AsyncMarker.AsyncStar:
        DartType streamBottomType = libraryBuilder.loader.streamOfBottom;
        if (returnType is VoidType) {
          problem = cfe.codeIllegalAsyncGeneratorVoidReturnType;
        } else if (!typeEnvironment.isSubtypeOf(streamBottomType, returnType)) {
          problem = cfe.codeIllegalAsyncGeneratorReturnType;
        }
        break;

      case AsyncMarker.SyncStar:
        DartType iterableBottomType = libraryBuilder.loader.iterableOfBottom;
        if (returnType is VoidType) {
          problem = cfe.codeIllegalSyncGeneratorVoidReturnType;
        } else if (!typeEnvironment.isSubtypeOf(
          iterableBottomType,
          returnType,
        )) {
          problem = cfe.codeIllegalSyncGeneratorReturnType;
        }
        break;

      case AsyncMarker.Sync:
        break; // skip
    }

    if (problem != null) {
      // TODO(hillerstrom): once types get annotated with location
      // information, we can improve the quality of the error message by
      // using the offset of [returnType] (and the length of its name).
      addProblem(problem, charOffset, length);
    }
  }

  /// Ensure that the containing library of the [member] has been loaded.
  ///
  /// This is for instance important for lazy dill library builders where this
  /// method has to be called to ensure that
  /// a) The library has been fully loaded (and for instance any internal
  ///    transformation needed has been performed); and
  /// b) The library is correctly marked as being used to allow for proper
  ///    'dependency pruning'.
  @override
  void ensureLoaded(Member? member) {
    if (member == null) return;
    Library ensureLibraryLoaded = member.enclosingLibrary;
    LibraryBuilder? builder =
        libraryBuilder.loader.lookupLoadedLibraryBuilder(
          ensureLibraryLoaded.importUri,
        ) ??
        // Coverage-ignore(suite): Not run.
        libraryBuilder.loader.target.dillTarget.loader.lookupLibraryBuilder(
          ensureLibraryLoaded.importUri,
        );
    if (builder is DillLibraryBuilder) {
      builder.ensureLoaded();
    }
  }

  @override
  Expression? checkStaticArguments({
    required Member target,
    required Arguments arguments,
    required int fileOffset,
  }) {
    List<TypeParameter> typeParameters = target.function!.typeParameters;
    if (target is Constructor) {
      assert(!target.enclosingClass.isAbstract);
      typeParameters = target.enclosingClass.typeParameters;
    }
    LocatedMessage? argMessage = checkArgumentsForFunction(
      target.function!,
      arguments,
      fileOffset,
      typeParameters,
    );
    if (argMessage != null) {
      return buildProblemWithContextFromMember(
        name: target.name.text,
        member: target,
        message: argMessage,
      );
    }
    return null;
  }

  void _finishVariableMetadata() {
    List<VariableDeclaration>? variablesWithMetadata =
        this.variablesWithMetadata;
    this.variablesWithMetadata = null;
    List<List<VariableDeclaration>>? multiVariablesWithMetadata =
        this.multiVariablesWithMetadata;
    this.multiVariablesWithMetadata = null;

    if (variablesWithMetadata != null) {
      for (int i = 0; i < variablesWithMetadata.length; i++) {
        inferAnnotations(
          variablesWithMetadata[i],
          variablesWithMetadata[i].annotations,
        );
      }
    }
    if (multiVariablesWithMetadata != null) {
      for (int i = 0; i < multiVariablesWithMetadata.length; i++) {
        List<VariableDeclaration> variables = multiVariablesWithMetadata[i];
        List<Expression> annotations = variables.first.annotations;
        inferAnnotations(variables.first, annotations);
        for (int i = 1; i < variables.length; i++) {
          VariableDeclaration variable = variables[i];
          for (int i = 0; i < annotations.length; i++) {
            variable.addAnnotation(
              _simpleCloner.cloneInContext(annotations[i]),
            );
          }
        }
      }
    }
  }

  List<Expression> finishMetadata(Annotatable? parent) {
    assert(checkState(null, [ValueKinds.AnnotationList]));
    List<Expression> expressions = pop() as List<Expression>;
    inferAnnotations(parent, expressions);

    // The invocation of [resolveRedirectingFactoryTargets] below may change the
    // root nodes of the annotation expressions.  We need to have a parent of
    // the annotation nodes before the resolution is performed, to collect and
    // return them later.  If [parent] is not provided, [temporaryParent] is
    // used.
    ListLiteral? temporaryParent;

    if (parent != null) {
      for (Expression expression in expressions) {
        parent.addAnnotation(expression);
      }
    } else {
      // Coverage-ignore-block(suite): Not run.
      temporaryParent = new ListLiteral(expressions);
    }
    performBacklogComputations();
    // Coverage-ignore(suite): Not run.
    return temporaryParent != null ? temporaryParent.expressions : expressions;
  }

  // Coverage-ignore(suite): Only used in expression compilation.
  Expression parseSingleExpression(
    Parser parser,
    Token token,
    FunctionNode parameters,
    List<VariableDeclarationImpl> extraKnownVariables,
    ExpressionEvaluationHelper expressionEvaluationHelper,
  ) {
    int fileOffset = offsetForToken(token);
    List<NominalParameterBuilder>? typeParameterBuilders;
    for (TypeParameter typeParameter in parameters.typeParameters) {
      typeParameterBuilders ??= <NominalParameterBuilder>[];
      typeParameterBuilders.add(
        new DillNominalParameterBuilder(
          typeParameter,
          loader: libraryBuilder.loader,
        ),
      );
    }
    enterNominalVariablesScope(typeParameterBuilders);

    List<FormalParameterBuilder>? formals =
        parameters.positionalParameters.length == 0
        ? null
        : new List<FormalParameterBuilder>.generate(
            parameters.positionalParameters.length,
            (int i) {
              VariableDeclaration formal = parameters.positionalParameters[i];
              String formalName = formal.name!;
              bool isWildcard =
                  libraryFeatures.wildcardVariables.isEnabled &&
                  formalName == '_';
              if (isWildcard) {
                formalName = createWildcardFormalParameterName(
                  wildcardVariableIndex,
                );
                wildcardVariableIndex++;
              }
              return new FormalParameterBuilder(
                FormalParameterKind.requiredPositional,
                Modifiers.empty,
                const ImplicitTypeBuilder(),
                formalName,
                formal.fileOffset,
                fileUri: uri,
                hasImmediatelyDeclaredInitializer: false,
                isWildcard: isWildcard,
              )..variable = formal;
            },
            growable: false,
          );
    enterLocalScope(
      new FormalParameters(
        formals,
        fileOffset,
        noLength,
        uri,
      ).computeFormalParameterScope(
        _localScope,
        this,
        wildcardVariablesEnabled: libraryFeatures.wildcardVariables.isEnabled,
      ),
    );

    if (extraKnownVariables.isNotEmpty) {
      LocalScope extraKnownVariablesScope = _localScope.createNestedScope(
        debugName: "expression compilation extra known variables scope",
        kind: ScopeKind.ifElement,
      );
      enterLocalScope(extraKnownVariablesScope);
      for (VariableDeclarationImpl extraVariable in extraKnownVariables) {
        declareVariable(extraVariable, _localScope);
        typeInferrer.assignedVariables.declare(extraVariable);
      }
    }

    Token endToken = parser.parseExpression(
      parser.syntheticPreviousToken(token),
    );

    assert(
      checkState(token, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
      ]),
    );
    Expression expression = popForValue();
    Token eof = endToken.next!;

    if (!eof.isEof) {
      expression = wrapInLocatedProblem(
        expression,
        cfe.codeExpectedOneExpression.withLocation(
          uri,
          eof.charOffset,
          eof.length,
        ),
      );
    }

    ReturnStatementImpl fakeReturn = new ReturnStatementImpl(true, expression);
    if (formals != null) {
      for (int i = 0; i < formals.length; i++) {
        VariableDeclaration variable = formals[i].variable!;
        typeInferrer.flowAnalysis.declare(
          variable,
          new SharedTypeView(variable.type),
          initialized: true,
        );
      }
    }
    for (VariableDeclarationImpl extraVariable in extraKnownVariables) {
      typeInferrer.flowAnalysis.declare(
        extraVariable,
        new SharedTypeView(extraVariable.type),
        initialized: true,
      );
    }

    InferredFunctionBody inferredFunctionBody = typeInferrer.inferFunctionBody(
      this,
      fileOffset,
      const DynamicType(),
      AsyncMarker.Sync,
      fakeReturn,
      expressionEvaluationHelper,
    );
    assert(
      fakeReturn == inferredFunctionBody.body,
      "Previously implicit assumption about inferFunctionBody "
      "not returning anything different.",
    );

    performBacklogComputations();

    return fakeReturn.expression!;
  }

  List<Initializer>? parseInitializers(
    Token token, {
    bool doFinishConstructor = true,
  }) {
    Parser parser = new Parser(
      this,
      useImplicitCreationExpression: useImplicitCreationExpressionInCfe,
      allowPatterns: libraryFeatures.patterns.isEnabled,
      enableFeatureEnhancedParts: libraryFeatures.enhancedParts.isEnabled,
    );
    if (!token.isEof) {
      token = parser.parseInitializers(token);
      checkEmpty(token.charOffset);
    } else {
      handleNoInitializers();
    }
    if (doFinishConstructor) {
      List<FormalParameterBuilder>? formals = _context.formals;
      List<Object>? superParametersAsArguments = formals != null
          ? createSuperParametersAsArguments(formals)
          : null;
      _declareFormals();
      finishConstructor(
        AsyncMarker.Sync,
        null,
        superParametersAsArguments: superParametersAsArguments,
      );
    }
    return _initializers;
  }

  Expression parseFieldInitializer(Token token) {
    Parser parser = new Parser(
      this,
      useImplicitCreationExpression: useImplicitCreationExpressionInCfe,
      allowPatterns: libraryFeatures.patterns.isEnabled,
      enableFeatureEnhancedParts: libraryFeatures.enhancedParts.isEnabled,
    );
    Token endToken = parser.parseExpression(
      parser.syntheticPreviousToken(token),
    );
    assert(
      checkState(token, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
      ]),
    );
    Expression expression = popForValue();
    checkEmpty(endToken.charOffset);
    return expression;
  }

  Expression parseAnnotation(Token token) {
    Parser parser = new Parser(
      this,
      useImplicitCreationExpression: useImplicitCreationExpressionInCfe,
      allowPatterns: libraryFeatures.patterns.isEnabled,
      enableFeatureEnhancedParts: libraryFeatures.enhancedParts.isEnabled,
    );
    Token endToken = parser.parseMetadata(parser.syntheticPreviousToken(token));
    assert(checkState(token, [ValueKinds.Expression]));
    Expression annotation = pop() as Expression;
    checkEmpty(endToken.charOffset);
    return annotation;
  }

  ArgumentsImpl parseArguments(Token token) {
    Parser parser = new Parser(
      this,
      useImplicitCreationExpression: useImplicitCreationExpressionInCfe,
      allowPatterns: libraryFeatures.patterns.isEnabled,
      enableFeatureEnhancedParts: libraryFeatures.enhancedParts.isEnabled,
    );
    token = parser.parseArgumentsRest(token);
    ArgumentsImpl arguments = pop() as ArgumentsImpl;
    checkEmpty(token.charOffset);
    return arguments;
  }

  void _declareFormals() {
    if (thisVariable != null && _context.isConstructor) {
      // `thisVariable` usually appears in `_context.formals`, but for a
      // constructor, it doesn't. So declare it separately.
      typeInferrer.flowAnalysis.declare(
        thisVariable!,
        new SharedTypeView(thisVariable!.type),
        initialized: true,
      );
    }
    List<FormalParameterBuilder>? formals = _context.formals;
    if (formals != null) {
      for (int i = 0; i < formals.length; i++) {
        FormalParameterBuilder parameter = formals[i];
        VariableDeclaration variable = parameter.variable!;
        typeInferrer.flowAnalysis.declare(
          variable,
          new SharedTypeView(variable.type),
          initialized: true,
        );
      }
    }
  }

  void finishConstructor(
    AsyncMarker asyncModifier,
    Statement? body, {
    required List<Object /* Expression | NamedExpression */>?
    superParametersAsArguments,
  }) {
    /// Quotes below are from [Dart Programming Language Specification, 4th
    /// Edition](
    /// https://ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf).
    assert(
      () {
        if (superParametersAsArguments == null) {
          return true;
        }
        for (Object superParameterAsArgument in superParametersAsArguments) {
          if (superParameterAsArgument is! Expression &&
              superParameterAsArgument is! NamedExpression) {
            return false;
          }
        }
        return true;
      }(),
      "Expected 'superParametersAsArguments' "
      "to contain nothing but Expressions and NamedExpressions.",
    );
    assert(
      () {
        if (superParametersAsArguments == null) {
          return true;
        }
        int previousOffset = -1;
        for (Object superParameterAsArgument in superParametersAsArguments) {
          int offset;
          if (superParameterAsArgument is Expression) {
            offset = superParameterAsArgument.fileOffset;
          } else if (superParameterAsArgument is NamedExpression) {
            offset = superParameterAsArgument.value.fileOffset;
          } else {
            return false;
          }
          if (previousOffset > offset) {
            return false;
          }
          previousOffset = offset;
        }
        return true;
      }(),
      "Expected 'superParametersAsArguments' "
      "to be sorted by occurrence in file.",
    );

    FunctionNode function = _context.function;

    Set<String>? namedSuperParameterNames;
    List<Expression>? positionalSuperParametersAsArguments;
    List<NamedExpression>? namedSuperParametersAsArguments;
    List<FormalParameterBuilder>? formals = _context.formals;
    if (superParametersAsArguments != null) {
      for (Object superParameterAsArgument in superParametersAsArguments) {
        if (superParameterAsArgument is Expression) {
          (positionalSuperParametersAsArguments ??= <Expression>[]).add(
            superParameterAsArgument,
          );
        } else {
          NamedExpression namedSuperParameterAsArgument =
              superParameterAsArgument as NamedExpression;
          (namedSuperParametersAsArguments ??= <NamedExpression>[]).add(
            namedSuperParameterAsArgument,
          );
          (namedSuperParameterNames ??= <String>{}).add(
            namedSuperParameterAsArgument.name,
          );
        }
      }
    } else if (formals != null) {
      for (FormalParameterBuilder formal in formals) {
        if (formal.isSuperInitializingFormal) {
          // Coverage-ignore-block(suite): Not run.
          if (formal.isNamed) {
            NamedExpression superParameterAsArgument = new NamedExpression(
              formal.name,
              createVariableGet(formal.variable!, formal.fileOffset),
            )..fileOffset = formal.fileOffset;
            (namedSuperParametersAsArguments ??= <NamedExpression>[]).add(
              superParameterAsArgument,
            );
            (namedSuperParameterNames ??= <String>{}).add(formal.name);
            (superParametersAsArguments ??= <Object>[]).add(
              superParameterAsArgument,
            );
          } else {
            Expression superParameterAsArgument = createVariableGet(
              formal.variable!,
              formal.fileOffset,
            );
            (positionalSuperParametersAsArguments ??= <Expression>[]).add(
              superParameterAsArgument,
            );
            (superParametersAsArguments ??= <Object>[]).add(
              superParameterAsArgument,
            );
          }
        }
      }
    }

    List<Initializer>? initializers = _initializers;
    if (initializers != null && initializers.isNotEmpty) {
      if (_context.isMixinClass) {
        // Report an error if a mixin class has a constructor with an
        // initializer.
        buildProblem(
          cfe.codeIllegalMixinDueToConstructors.withArgumentsOld(
            _context.className,
          ),
          _context.memberNameOffset,
          noLength,
        );
      }
      Initializer last = initializers.last;
      if (last is SuperInitializer) {
        if (_context.isEnumClass) {
          initializers[initializers.length - 1] = buildInvalidInitializer(
            buildProblem(
              cfe.codeEnumConstructorSuperInitializer,
              last.fileOffset,
              noLength,
            ),
          )..parent = last.parent;
        } else if (libraryFeatures.superParameters.isEnabled) {
          ArgumentsImpl arguments = last.arguments as ArgumentsImpl;

          if (positionalSuperParametersAsArguments != null) {
            if (arguments.positional.isNotEmpty) {
              addProblem(
                cfe.codePositionalSuperParametersAndArguments,
                arguments.fileOffset,
                noLength,
                context: <LocatedMessage>[
                  cfe.codeSuperInitializerParameter.withLocation(
                    uri,
                    (positionalSuperParametersAsArguments.first as VariableGet)
                        .variable
                        .fileOffset,
                    noLength,
                  ),
                ],
              );
            } else {
              arguments.positional.addAll(positionalSuperParametersAsArguments);
              setParents(positionalSuperParametersAsArguments, arguments);
              arguments.positionalAreSuperParameters = true;
            }
          }
          if (namedSuperParametersAsArguments != null) {
            // TODO(cstefantsova): Report name conflicts.
            arguments.named.addAll(namedSuperParametersAsArguments);
            setParents(namedSuperParametersAsArguments, arguments);
            arguments.namedSuperParameterNames = namedSuperParameterNames;
          }
          if (superParametersAsArguments != null) {
            arguments.argumentsOriginalOrder?.insertAll(
              0,
              superParametersAsArguments,
            );
          }
        }
      } else if (last is RedirectingInitializer) {
        if (_context.isEnumClass && libraryFeatures.enhancedEnums.isEnabled) {
          ArgumentsImpl arguments = last.arguments as ArgumentsImpl;
          List<Expression> enumSyntheticArguments = [
            new VariableGet(function.positionalParameters[0])
              ..parent = last.arguments,
            new VariableGet(function.positionalParameters[1])
              ..parent = last.arguments,
          ];
          arguments.positional.insertAll(0, enumSyntheticArguments);
          arguments.argumentsOriginalOrder?.insertAll(
            0,
            enumSyntheticArguments,
          );
        }
      }

      List<InitializerInferenceResult> inferenceResults =
          new List<InitializerInferenceResult>.generate(
            initializers.length,
            (index) => _context.inferInitializer(
              initializers[index],
              this,
              typeInferrer,
            ),
            growable: false,
          );

      if (!_context.isExternalConstructor) {
        for (int i = 0; i < initializers.length; i++) {
          _context.addInitializer(
            initializers[i],
            this,
            inferenceResult: inferenceResults[i],
          );
        }
      }
    }

    if (asyncModifier != AsyncMarker.Sync) {
      _context.addInitializer(
        buildInvalidInitializer(
          buildProblem(cfe.codeConstructorNotSync, body!.fileOffset, noLength),
        ),
        this,
        inferenceResult: null,
      );
    }
    if (needsImplicitSuperInitializer) {
      /// >If no superinitializer is provided, an implicit superinitializer
      /// >of the form super() is added at the end of k’s initializer list,
      /// >unless the enclosing class is class Object.
      Initializer? initializer;
      ArgumentsImpl arguments;
      List<Expression>? positionalArguments;
      List<NamedExpression>? namedArguments;
      if (libraryFeatures.superParameters.isEnabled) {
        positionalArguments = positionalSuperParametersAsArguments;
        namedArguments = namedSuperParametersAsArguments;
      }
      if (_context.isEnumClass) {
        assert(
          function.positionalParameters.length >= 2 &&
              function.positionalParameters[0].name == "#index" &&
              function.positionalParameters[1].name == "#name",
        );
        (positionalArguments ??= <Expression>[]).insertAll(0, [
          new VariableGet(function.positionalParameters[0]),
          new VariableGet(function.positionalParameters[1]),
        ]);
      }

      int argumentsOffset = -1;
      if (superParametersAsArguments != null) {
        for (Object argument in superParametersAsArguments) {
          assert(argument is Expression || argument is NamedExpression);
          int currentArgumentOffset;
          if (argument is Expression) {
            currentArgumentOffset = argument.fileOffset;
          } else {
            currentArgumentOffset = (argument as NamedExpression).fileOffset;
          }
          argumentsOffset = argumentsOffset <= currentArgumentOffset
              ? argumentsOffset
              : currentArgumentOffset;
        }
      }
      SuperInitializer? explicitSuperInitializer;
      if (_initializers case [..., SuperInitializer superInitializer]
          when argumentsOffset == // Coverage-ignore(suite): Not run.
              -1) {
        // Coverage-ignore-block(suite): Not run.
        argumentsOffset = superInitializer.fileOffset;
        explicitSuperInitializer = superInitializer;
      }
      if (argumentsOffset == -1) {
        argumentsOffset = _context.memberNameOffset;
      }

      if (positionalArguments != null || namedArguments != null) {
        arguments = forest.createArguments(
          argumentsOffset,
          positionalArguments ?? <Expression>[],
          named: namedArguments,
        );
      } else {
        arguments = forest.createArgumentsEmpty(argumentsOffset);
      }

      arguments.positionalAreSuperParameters =
          positionalSuperParametersAsArguments != null;
      arguments.namedSuperParameterNames = namedSuperParameterNames;

      MemberLookupResult? result = lookupSuperConstructor(
        '',
        libraryBuilder.nameOriginBuilder,
      );
      Constructor? superTarget;
      if (result != null) {
        if (result.isInvalidLookup) {
          int length = _context.memberNameLength;
          if (length == 0) {
            length = _context.className.length;
          }
          initializer = buildInvalidInitializer(
            LookupResult.createDuplicateExpression(
              result,
              context: libraryBuilder.loader.target.context,
              name: '',
              fileUri: uri,
              fileOffset: _context.memberNameOffset,
              length: noLength,
            ),
            _context.memberNameOffset,
          );
        } else {
          MemberBuilder? memberBuilder = result.getable;
          Member? member = memberBuilder?.invokeTarget;
          if (member is Constructor) {
            superTarget = member;
          }
        }
      }
      if (initializer == null) {
        if (superTarget == null) {
          String superclass = _context.superClassName;
          int length = _context.memberNameLength;
          if (length == 0) {
            length = _context.className.length;
          }
          initializer = buildInvalidInitializer(
            buildProblem(
              cfe.codeSuperclassHasNoDefaultConstructor.withArgumentsOld(
                superclass,
              ),
              _context.memberNameOffset,
              length,
            ),
            _context.memberNameOffset,
          );
        } else if (checkArgumentsForFunction(
              superTarget.function,
              arguments,
              _context.memberNameOffset,
              const <TypeParameter>[],
            )
            case LocatedMessage argumentIssue) {
          List<int>? positionalSuperParametersIssueOffsets;
          if (positionalSuperParametersAsArguments != null) {
            for (
              int positionalSuperParameterIndex =
                  superTarget.function.positionalParameters.length;
              positionalSuperParameterIndex <
                  positionalSuperParametersAsArguments.length;
              positionalSuperParameterIndex++
            ) {
              (positionalSuperParametersIssueOffsets ??= []).add(
                positionalSuperParametersAsArguments[ // force line break
                    positionalSuperParameterIndex]
                    .fileOffset,
              );
            }
          }

          List<int>? namedSuperParametersIssueOffsets;
          if (namedSuperParametersAsArguments != null) {
            Set<String> superTargetNamedParameterNames = {
              for (VariableDeclaration namedParameter
                  in superTarget.function.namedParameters)
                if (namedParameter // Coverage-ignore(suite): Not run.
                        .name !=
                    null)
                  // Coverage-ignore(suite): Not run.
                  namedParameter.name!,
            };
            for (NamedExpression namedSuperParameter
                in namedSuperParametersAsArguments) {
              if (!superTargetNamedParameterNames.contains(
                namedSuperParameter.name,
              )) {
                (namedSuperParametersIssueOffsets ??= []).add(
                  namedSuperParameter.fileOffset,
                );
              }
            }
          }

          Initializer? errorMessageInitializer;
          if (positionalSuperParametersIssueOffsets != null) {
            for (int issueOffset in positionalSuperParametersIssueOffsets) {
              Expression errorMessageExpression = buildProblem(
                cfe.codeMissingPositionalSuperConstructorParameter,
                issueOffset,
                noLength,
              );
              errorMessageInitializer ??= buildInvalidInitializer(
                errorMessageExpression,
              );
            }
          }
          if (namedSuperParametersIssueOffsets != null) {
            for (int issueOffset in namedSuperParametersIssueOffsets) {
              Expression errorMessageExpression = buildProblem(
                cfe.codeMissingNamedSuperConstructorParameter,
                issueOffset,
                noLength,
              );
              errorMessageInitializer ??= buildInvalidInitializer(
                errorMessageExpression,
              );
            }
          }
          if (explicitSuperInitializer == null) {
            errorMessageInitializer ??= buildInvalidInitializer(
              buildProblem(
                cfe.codeImplicitSuperInitializerMissingArguments
                    .withArgumentsOld(superTarget.enclosingClass.name),
                argumentIssue.charOffset,
                argumentIssue.length,
              ),
            );
          }
          // Coverage-ignore-block(suite): Not run.
          errorMessageInitializer ??= buildInvalidInitializer(
            buildProblem(
              argumentIssue.messageObject,
              argumentIssue.charOffset,
              argumentIssue.length,
            ),
          );
          initializer = errorMessageInitializer;
        } else {
          initializer = buildSuperInitializer(
            true,
            superTarget,
            arguments,
            _context.memberNameOffset,
          );
        }
      }
      if (libraryFeatures.superParameters.isEnabled) {
        InitializerInferenceResult inferenceResult = _context.inferInitializer(
          initializer,
          this,
          typeInferrer,
        );
        _context.addInitializer(
          initializer,
          this,
          inferenceResult: inferenceResult,
        );
      } else {
        _context.addInitializer(initializer, this, inferenceResult: null);
      }
    }
    if (body == null && !_context.isExternalConstructor) {
      /// >If a generative constructor c is not a redirecting constructor
      /// >and no body is provided, then c implicitly has an empty body {}.
      /// We use an empty statement instead.
      _context.registerNoBodyConstructor();
    } else if (body != null && _context.isMixinClass && !_context.isFactory) {
      // Report an error if a mixin class has a non-factory constructor with a
      // body.
      buildProblem(
        cfe.codeIllegalMixinDueToConstructors.withArgumentsOld(
          _context.className,
        ),
        _context.memberNameOffset,
        noLength,
      );
    }
  }

  @override
  void handleExpressionStatement(Token beginToken, Token endToken) {
    assert(
      checkState(endToken, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
      ]),
    );
    debugEvent("ExpressionStatement");
    push(
      forest.createExpressionStatement(
        offsetForToken(endToken),
        popForEffect(),
      ),
    );
  }

  @override
  void endArguments(int count, Token beginToken, Token endToken) {
    debugEvent("Arguments");
    List<Object?>? arguments = count == 0
        ? <Object>[]
        : const FixedNullableList<Object>().pop(stack, count);
    if (arguments == null) {
      push(new ParserRecovery(beginToken.charOffset));
      return;
    }
    List<Object?>? argumentsOriginalOrder;
    if (libraryFeatures.namedArgumentsAnywhere.isEnabled) {
      argumentsOriginalOrder = new List<Object?>.of(arguments);
    }
    int firstNamedArgumentIndex = arguments.length;
    int positionalCount = 0;
    bool hasNamedBeforePositional = false;
    for (int i = 0; i < arguments.length; i++) {
      Object? node = arguments[i];
      if (node is NamedExpression) {
        firstNamedArgumentIndex = i < firstNamedArgumentIndex
            ? i
            : firstNamedArgumentIndex;
      } else {
        positionalCount++;
        Expression argument = toValue(node);
        arguments[i] = argument;
        argumentsOriginalOrder?[i] = argument;
        if (i > firstNamedArgumentIndex) {
          hasNamedBeforePositional = true;
          if (!libraryFeatures.namedArgumentsAnywhere.isEnabled) {
            arguments[i] = new NamedExpression(
              "#$i",
              buildProblem(
                cfe.codeExpectedNamedArgument,
                argument.fileOffset,
                noLength,
              ),
            )..fileOffset = beginToken.charOffset;
          }
        }
      }
    }
    if (!hasNamedBeforePositional) {
      argumentsOriginalOrder = null;
    }
    if (firstNamedArgumentIndex < arguments.length) {
      List<Expression> positional;
      List<NamedExpression> named;
      if (libraryFeatures.namedArgumentsAnywhere.isEnabled) {
        positional = new List<Expression>.filled(
          positionalCount,
          dummyExpression,
          growable: true,
        );
        named = new List<NamedExpression>.filled(
          arguments.length - positionalCount,
          dummyNamedExpression,
          growable: true,
        );
        int positionalIndex = 0;
        int namedIndex = 0;
        for (int i = 0; i < arguments.length; i++) {
          if (arguments[i] is NamedExpression) {
            named[namedIndex++] = arguments[i] as NamedExpression;
          } else {
            positional[positionalIndex++] = arguments[i] as Expression;
          }
        }
        assert(
          positionalIndex == positional.length && namedIndex == named.length,
        );
      } else {
        // arguments have non-null Expression entries after the initial loop.
        positional = new List<Expression>.from(
          arguments.getRange(0, firstNamedArgumentIndex),
        );
        named = new List<NamedExpression>.from(
          arguments.getRange(firstNamedArgumentIndex, arguments.length),
        );
      }

      push(
        forest.createArguments(
          beginToken.offset,
          positional,
          named: named,
          argumentsOriginalOrder: argumentsOriginalOrder,
        ),
      );
    } else {
      // TODO(kmillikin): Find a way to avoid allocating a second list in the
      // case where there were no named arguments, which is a common one.

      // arguments have non-null Expression entries after the initial loop.
      push(
        forest.createArguments(
          beginToken.offset,
          new List<Expression>.from(arguments),
          argumentsOriginalOrder: argumentsOriginalOrder,
        ),
      );
    }
    assert(checkState(beginToken, [ValueKinds.Arguments]));
  }

  @override
  void handleParenthesizedCondition(Token token, Token? case_, Token? when) {
    debugEvent("ParenthesizedCondition");
    if (case_ != null) {
      Expression? guard;
      if (when != null) {
        assert(
          checkState(token, [
            unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
            unionOfKinds([ValueKinds.Expression, ValueKinds.Pattern]),
            unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
          ]),
        );
        guard = popForValue();
      }
      assert(
        checkState(token, [
          unionOfKinds([ValueKinds.Expression, ValueKinds.Pattern]),
          unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
        ]),
      );
      reportIfNotEnabled(
        libraryFeatures.patterns,
        case_.charOffset,
        case_.charCount,
      );
      Pattern pattern = toPattern(pop());
      Expression expression = popForValue();
      push(
        new Condition(
          expression,
          forest.createPatternGuard(expression.fileOffset, pattern, guard),
        ),
      );
    } else {
      assert(
        checkState(token, [
          unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
        ]),
      );
      push(new Condition(popForValue()));
    }
    assert(checkState(token, [ValueKinds.Condition]));
  }

  @override
  void endParenthesizedExpression(Token token) {
    assert(
      checkState(token, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
      ]),
    );
    debugEvent("ParenthesizedExpression");
    Expression value = popForValue();
    if (value is ShadowLargeIntLiteral) {
      // We need to know that the expression was parenthesized because we will
      // treat -n differently from -(n).  If the expression occurs in a double
      // context, -n is a double literal and -(n) is an application of unary- to
      // an integer literal.  And in any other context, '-' is part of the
      // syntax of -n, i.e., -9223372036854775808 is OK and it is the minimum
      // 64-bit integer, and '-' is an application of unary- in -(n), i.e.,
      // -(9223372036854775808) is an error because the literal does not fit in
      // 64-bits.
      push(value..isParenthesized = true);
    } else {
      push(new ParenthesizedExpressionGenerator(this, token.endGroup!, value));
    }
    assert(
      checkState(token, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
      ]),
    );
  }

  @override
  void handleParenthesizedPattern(Token token) {
    debugEvent("ParenthesizedPattern");
    assert(
      checkState(token, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Pattern,
        ]),
      ]),
    );
    // TODO(johnniwinther): Do we need a ParenthesizedPattern ?
    reportIfNotEnabled(
      libraryFeatures.patterns,
      token.charOffset,
      token.charCount,
    );

    Object? value = pop();
    if (value is Pattern) {
      push(value);
    } else {
      push(toValue(value));
    }
  }

  @override
  void handleSend(Token beginToken, Token endToken) {
    assert(
      checkState(beginToken, [
        unionOfKinds([ValueKinds.ArgumentsOrNull, ValueKinds.ParserRecovery]),
        ValueKinds.TypeArgumentsOrNull,
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Identifier,
          ValueKinds.ParserRecovery,
        ]),
      ]),
    );
    debugEvent("Send");
    Object? arguments = pop();
    List<TypeBuilder>? typeArguments = pop() as List<TypeBuilder>?;
    Object receiver = pop()!;
    // Delay adding [typeArguments] to [forest] for type aliases: They
    // must be unaliased to the type arguments of the denoted type.
    bool isInForest =
        arguments is ArgumentsImpl &&
        typeArguments != null &&
        (receiver is! TypeUseGenerator ||
            receiver.declaration is! TypeAliasBuilder);
    if (isInForest) {
      assert(arguments.types.isEmpty);
      arguments.setExplicitTypeArguments(
        buildDartTypeArguments(
          typeArguments,
          TypeUse.invocationTypeArgument,
          allowPotentiallyConstantType: false,
        ),
      );
    } else {
      assert(
        typeArguments == null ||
            (receiver is TypeUseGenerator &&
                receiver.declaration is TypeAliasBuilder),
      );
    }
    if (receiver is ParserRecovery || arguments is ParserRecovery) {
      push(new ParserErrorGenerator(this, beginToken, cfe.codeSyntheticToken));
    } else if (receiver is Identifier) {
      Name name = new Name(receiver.name, libraryBuilder.nameOrigin);
      if (arguments == null) {
        push(new PropertySelector(this, beginToken, name));
      } else {
        push(
          new InvocationSelector(
            this,
            beginToken,
            name,
            typeArguments,
            arguments as ArgumentsImpl,
            isTypeArgumentsInForest: isInForest,
          ),
        );
      }
    } else if (arguments == null) {
      push(receiver);
    } else {
      push(
        finishSend(
          receiver,
          typeArguments,
          arguments as ArgumentsImpl,
          beginToken.charOffset,
          isTypeArgumentsInForest: isInForest,
        ),
      );
    }
    assert(
      checkState(beginToken, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Initializer,
          ValueKinds.Selector,
        ]),
      ]),
    );
  }

  @override
  Expression_Generator_Initializer finishSend(
    Object receiver,
    List<TypeBuilder>? typeArguments,
    ArgumentsImpl arguments,
    int charOffset, {
    bool isTypeArgumentsInForest = false,
  }) {
    if (receiver is Generator) {
      return receiver.doInvocation(
        charOffset,
        typeArguments,
        arguments,
        isTypeArgumentsInForest: isTypeArgumentsInForest,
      );
    } else {
      return forest.createExpressionInvocation(
        charOffset,
        toValue(receiver),
        arguments,
      );
    }
  }

  @override
  void beginCascade(Token token) {
    assert(
      checkState(token, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
      ]),
    );
    debugEvent("beginCascade");
    Expression expression = popForValue();
    if (expression is Cascade) {
      push(expression);
      push(
        _createReadOnlyVariableAccess(
          expression.variable,
          token,
          expression.fileOffset,
          null,
          ReadOnlyAccessKind.LetVariable,
        ),
      );
    } else {
      bool isNullAware = token.isA(TokenType.QUESTION_PERIOD_PERIOD);
      VariableDeclaration variable = createVariableDeclarationForValue(
        expression,
      );
      push(
        new Cascade(variable, isNullAware: isNullAware)
          ..fileOffset = expression.fileOffset,
      );
      push(
        _createReadOnlyVariableAccess(
          variable,
          token,
          expression.fileOffset,
          null,
          ReadOnlyAccessKind.LetVariable,
        ),
      );
    }
    assert(
      checkState(token, [
        ValueKinds.Generator,
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
      ]),
    );
  }

  @override
  void endCascade() {
    assert(
      checkState(null, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
        ValueKinds.Expression,
      ]),
    );
    debugEvent("endCascade");
    Expression expression = popForEffect();
    Cascade cascadeReceiver = pop() as Cascade;
    cascadeReceiver.addCascadeExpression(expression);
    push(cascadeReceiver);
  }

  @override
  void beginCaseExpression(Token caseKeyword) {
    debugEvent("beginCaseExpression");

    // Scope of the preceding case head or a sentinel if it's the first head.
    exitLocalScope(expectedScopeKinds: const [ScopeKind.caseHead]);

    createAndEnterLocalScope(debugName: "case-head", kind: ScopeKind.caseHead);
    super.push(constantContext);
    if (!libraryFeatures.patterns.isEnabled) {
      constantContext = ConstantContext.inferred;
    }
    assert(checkState(caseKeyword, [ValueKinds.ConstantContext]));
  }

  @override
  void endCaseExpression(Token caseKeyword, Token? when, Token colon) {
    debugEvent("endCaseExpression");
    assert(
      checkState(colon, [
        if (when != null)
          unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Pattern,
        ]),
        ValueKinds.ConstantContext,
      ]),
    );

    Expression? guard;
    if (when != null) {
      guard = popForValue();
    }
    Object? value = pop();
    constantContext = pop() as ConstantContext;
    assert(
      _localScopes.previous.kind == ScopeKind.switchBlock,
      "Expected to have scope kind ${ScopeKind.switchBlock}, "
      "but got ${_localScopes.previous.kind}.",
    );
    if (value is Pattern) {
      super.push(
        new ExpressionOrPatternGuardCase.patternGuard(
          caseKeyword.charOffset,
          forest.createPatternGuard(caseKeyword.charOffset, value, guard),
        ),
      );
    } else if (guard != null) {
      super.push(
        new ExpressionOrPatternGuardCase.patternGuard(
          caseKeyword.charOffset,
          forest.createPatternGuard(
            caseKeyword.charOffset,
            toPattern(value),
            guard,
          ),
        ),
      );
    } else {
      Expression expression = toValue(value);
      super.push(
        new ExpressionOrPatternGuardCase.expression(
          caseKeyword.charOffset,
          expression,
        ),
      );
    }
    assert(checkState(colon, [ValueKinds.ExpressionOrPatternGuardCase]));
  }

  @override
  void beginBinaryExpression(Token token) {
    assert(
      checkState(token, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
      ]),
    );
    bool isAnd = token.isA(TokenType.AMPERSAND_AMPERSAND);
    if (isAnd || token.isA(TokenType.BAR_BAR)) {
      Expression lhs = popForValue();
      // This is matched by the call to [endNode] in
      // [doLogicalExpression].
      if (isAnd) {
        typeInferrer.assignedVariables.beginNode();
      }
      push(lhs);
    }
    assert(
      checkState(token, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
      ]),
    );
  }

  @override
  void handleDotAccess(Token token, Token endToken, bool isNullAware) {
    assert(
      checkState(token, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Selector,
        ]),
      ]),
    );
    debugEvent("DotAccess");
    if (isNullAware) {
      doIfNotNull(token);
    } else {
      doDotExpression(token);
    }
    assert(
      checkState(token, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Initializer,
        ]),
      ]),
    );
  }

  @override
  void handleCascadeAccess(Token token, Token endToken, bool isNullAware) {
    assert(
      checkState(token, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Selector,
        ]),
      ]),
    );
    debugEvent("CascadeAccess");
    doCascadeExpression(token);
    assert(
      checkState(token, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Initializer,
        ]),
      ]),
    );
  }

  @override
  void endBinaryExpression(Token token, Token endToken) {
    assert(
      checkState(token, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Selector,
        ]),
      ]),
    );
    debugEvent("BinaryExpression");
    if (token.isA(TokenType.AMPERSAND_AMPERSAND) ||
        token.isA(TokenType.BAR_BAR)) {
      doLogicalExpression(token);
    } else if (token.isA(TokenType.QUESTION_QUESTION)) {
      doIfNull(token);
    } else {
      doBinaryExpression(token);
    }
    assert(
      checkState(token, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Initializer,
        ]),
      ]),
    );
  }

  @override
  void beginPattern(Token token) {
    debugEvent("Pattern");
    if (token.lexeme == "||") {
      createAndEnterLocalScope(
        debugName: "rhs of a binary-or pattern",
        kind: ScopeKind.orPatternRight,
      );
    } else {
      createAndEnterLocalScope(debugName: "pattern", kind: ScopeKind.pattern);
    }
  }

  @override
  void endPattern(Token token) {
    debugEvent("Pattern");
    assert(
      checkState(token, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Pattern,
        ]),
      ]),
    );
    Object pattern = pop()!;
    ScopeKind scopeKind = _localScope.kind;

    exitLocalScope(
      expectedScopeKinds: const [ScopeKind.pattern, ScopeKind.orPatternRight],
    );

    // Bring the variables into the enclosing pattern scope, unless that was
    // the scope of the RHS of a binary-or pattern. In the latter case, the
    // joint variables will be declared in the enclosing scope instead later in
    // the process.
    //
    // Here we only handle the visibility of the pattern declared variables
    // within the pattern itself, so we declare the pattern variables in the
    // enclosing scope only if that enclosing scope is a pattern scope as well,
    // that is, if its kind is [ScopeKind.pattern] or
    // [ScopeKind.orPatternRight].
    bool enclosingScopeIsPatternScope =
        _localScope.kind == ScopeKind.pattern ||
        _localScope.kind == ScopeKind.orPatternRight;
    if (scopeKind != ScopeKind.orPatternRight && enclosingScopeIsPatternScope) {
      if (pattern is Pattern) {
        for (VariableDeclaration variable in pattern.declaredVariables) {
          declareVariable(variable, _localScope);
        }
      }
    }

    push(pattern);
  }

  @override
  void beginBinaryPattern(Token token) {
    debugEvent("BinaryPattern");
    assert(
      checkState(token, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Pattern,
        ]),
      ]),
    );

    // In case of the binary-or pattern, its LHS and RHS should contain
    // declarations of the variables with matching names, and we need to put
    // them into separate scopes to avoid the naming conflict. For that, we're
    // exiting the scope for the LHS, and the scope for the RHS will be created
    // when the RHS will be parsed. Additionally, since it's the first time
    // we're realizing that it's the binary-or pattern, we need to create the
    // enclosing scope for its joint variables as well.
    if (token.lexeme == "||") {
      Object lhsPattern = pop()!;

      // Exit the scope of the LHS.
      exitLocalScope(expectedScopeKinds: const [ScopeKind.pattern]);

      createAndEnterLocalScope(
        debugName: "joint variables of binary-or patterns",
        kind: ScopeKind.pattern,
      );
      push(lhsPattern);
    }
  }

  @override
  void endBinaryPattern(Token token) {
    debugEvent("BinaryPattern");
    assert(
      checkState(token, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Pattern,
        ]),
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Pattern,
        ]),
      ]),
    );
    reportIfNotEnabled(
      libraryFeatures.patterns,
      token.charOffset,
      token.charCount,
    );
    Pattern right = toPattern(pop());
    Pattern left = toPattern(pop());

    String operator = token.lexeme;
    switch (operator) {
      case '&&':
        push(forest.createAndPattern(token.charOffset, left, right));
        break;
      case '||':
        Map<String, VariableDeclaration> leftVariablesByName = {
          for (VariableDeclaration leftVariable in left.declaredVariables)
            leftVariable.name!: leftVariable,
        };
        for (VariableDeclaration rightVariable in right.declaredVariables) {
          if (!leftVariablesByName.containsKey(rightVariable.name)) {
            addProblem(
              cfe.codeMissingVariablePattern.withArgumentsOld(
                rightVariable.name!,
              ),
              left.fileOffset,
              noLength,
            );
          }
        }
        Map<String, VariableDeclaration> rightVariablesByName = {
          for (VariableDeclaration rightVariable in right.declaredVariables)
            rightVariable.name!: rightVariable,
        };
        for (VariableDeclaration leftVariable in left.declaredVariables) {
          if (!rightVariablesByName.containsKey(leftVariable.name)) {
            addProblem(
              cfe.codeMissingVariablePattern.withArgumentsOld(
                leftVariable.name!,
              ),
              right.fileOffset,
              noLength,
            );
          }
        }
        List<VariableDeclaration> jointVariables = [
          for (VariableDeclaration leftVariable in left.declaredVariables)
            forest.createVariableDeclaration(
              leftVariable.fileOffset,
              leftVariable.name!,
            ),
        ];
        for (VariableDeclaration variable in jointVariables) {
          declareVariable(variable, _localScope);
          typeInferrer.assignedVariables.declare(variable);
        }
        push(
          forest.createOrPattern(
            token.charOffset,
            left,
            right,
            orPatternJointVariables: jointVariables,
          ),
        );
        break;
      // Coverage-ignore(suite): Not run.
      default:
        internalProblem(
          cfe.codeInternalProblemUnhandled.withArgumentsOld(
            operator,
            'endBinaryPattern',
          ),
          token.charOffset,
          uri,
        );
    }
  }

  void doBinaryExpression(Token token) {
    assert(
      checkState(token, <ValueKind>[
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
      ]),
    );
    Expression right = popForValue();
    Object? left = pop();
    int fileOffset = offsetForToken(token);
    String operator = token.stringValue!;
    bool isNot = identical("!=", operator);
    if (isNot || identical("==", operator)) {
      if (left is Generator) {
        push(left.buildEqualsOperation(token, right, isNot: isNot));
      } else {
        assert(left is Expression);
        push(
          forest.createEquals(
            fileOffset,
            left as Expression,
            right,
            isNot: isNot,
          ),
        );
      }
    } else {
      Name name = new Name(operator);
      if (!isBinaryOperator(operator) && !isMinusOperator(operator)) {
        if (isUserDefinableOperator(operator)) {
          push(
            buildProblem(
              cfe.codeNotBinaryOperator.withArgumentsOld(token),
              token.charOffset,
              token.length,
            ),
          );
        } else {
          push(
            buildProblem(
              cfe.codeInvalidOperator.withArgumentsOld(token),
              token.charOffset,
              token.length,
            ),
          );
        }
      } else if (left is Generator) {
        push(left.buildBinaryOperation(token, name, right));
      } else {
        assert(left is Expression);
        push(forest.createBinary(fileOffset, left as Expression, name, right));
      }
    }
    assert(checkState(token, <ValueKind>[ValueKinds.Expression]));
  }

  /// Handle `a && b` and `a || b`.
  void doLogicalExpression(Token token) {
    assert(
      checkState(token, <ValueKind>[
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
      ]),
    );
    Expression argument = popForValue();
    Expression receiver = pop() as Expression;
    Expression logicalExpression = forest.createLogicalExpression(
      offsetForToken(token),
      receiver,
      token.stringValue!,
      argument,
    );
    push(logicalExpression);
    if (token.isA(TokenType.AMPERSAND_AMPERSAND)) {
      // This is matched by the call to [beginNode] in
      // [beginBinaryExpression].
      typeInferrer.assignedVariables.endNode(logicalExpression);
    }
    assert(checkState(token, <ValueKind>[ValueKinds.Expression]));
  }

  /// Handle `a ?? b`.
  void doIfNull(Token token) {
    assert(
      checkState(token, <ValueKind>[
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
      ]),
    );
    Expression b = popForValue();
    Expression a = popForValue();
    push(new IfNullExpression(a, b)..fileOffset = offsetForToken(token));
    assert(checkState(token, <ValueKind>[ValueKinds.Expression]));
  }

  /// Handle `a?.b(...)`.
  void doIfNotNull(Token token) {
    assert(
      checkState(token, <ValueKind>[
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Selector,
        ]),
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Initializer,
        ]),
      ]),
    );
    Object? send = pop();
    if (send is Selector) {
      push(send.withReceiver(pop(), token.charOffset, isNullAware: true));
    } else {
      pop();
      token = token.next!;
      push(
        buildProblem(
          cfe.codeExpectedIdentifier.withArgumentsOld(token),
          offsetForToken(token),
          lengthForToken(token),
        ),
      );
    }
    assert(
      checkState(token, <ValueKind>[
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Initializer,
        ]),
      ]),
    );
  }

  void doDotExpression(Token token) {
    assert(
      checkState(token, <ValueKind>[
        /* after . */ unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Selector,
        ]),
        /* before . */ unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Initializer,
        ]),
      ]),
    );
    Object? send = pop();
    if (send is Selector) {
      Object? receiver = pop();
      push(send.withReceiver(receiver, token.charOffset));
    } else if (send is IncompleteErrorGenerator) {
      // Pop the "receiver" and push the error.
      pop();
      push(send);
    } else {
      // Pop the "receiver" and push the error.
      pop();
      token = token.next!;
      push(
        buildProblem(
          cfe.codeExpectedIdentifier.withArgumentsOld(token),
          offsetForToken(token),
          lengthForToken(token),
        ),
      );
    }
    assert(
      checkState(token, <ValueKind>[
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Initializer,
        ]),
      ]),
    );
  }

  void doCascadeExpression(Token token) {
    assert(
      checkState(token, <ValueKind>[
        /* after .. */ unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Selector,
        ]),
        /* before .. */ unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Initializer,
        ]),
      ]),
    );
    Object? send = pop();
    if (send is Selector) {
      Object? receiver = popForValue();
      push(send.withReceiver(receiver, token.charOffset));
    }
    // Coverage-ignore(suite): Not run.
    else if (send is IncompleteErrorGenerator) {
      // Pop the "receiver" and push the error.
      pop();
      push(send);
    } else {
      // Pop the "receiver" and push the error.
      pop();
      token = token.next!;
      push(
        buildProblem(
          cfe.codeExpectedIdentifier.withArgumentsOld(token),
          offsetForToken(token),
          lengthForToken(token),
        ),
      );
    }
    assert(
      checkState(token, <ValueKind>[
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Initializer,
        ]),
      ]),
    );
  }

  @override
  Expression buildUnresolvedError(
    String name,
    int charOffset, {
    bool isSuper = false,
    required UnresolvedKind kind,
    int? length,
    bool errorHasBeenReported = false,
  }) {
    // TODO(johnniwinther): Use [arguments] and [rhs] to create an unresolved
    // access expression to include in the invalid expression.
    if (length == null) {
      length = name.length;
      int periodIndex = name.lastIndexOf(".");
      if (periodIndex != -1) {
        length -= periodIndex + 1;
      }
    }
    Name kernelName = new Name(name, libraryBuilder.nameOrigin);
    LocatedMessage? message;
    switch (kind) {
      case UnresolvedKind.Unknown:
        assert(!isSuper);
        message = cfe.codeNameNotFound
            .withArgumentsOld(name)
            .withLocation(uri, charOffset, length);
        break;
      case UnresolvedKind.Member:
        message = warnUnresolvedMember(
          kernelName,
          charOffset,
          isSuper: isSuper,
          reportWarning: false,
        ).withLocation(uri, charOffset, length);
        break;
      case UnresolvedKind.Getter:
        message = warnUnresolvedGet(
          kernelName,
          charOffset,
          isSuper: isSuper,
          reportWarning: false,
        ).withLocation(uri, charOffset, length);
        break;
      case UnresolvedKind.Setter:
        message = warnUnresolvedSet(
          kernelName,
          charOffset,
          isSuper: isSuper,
          reportWarning: false,
        ).withLocation(uri, charOffset, length);
        break;
      case UnresolvedKind.Method:
        message = warnUnresolvedMethod(
          kernelName,
          charOffset,
          isSuper: isSuper,
          reportWarning: false,
        ).withLocation(uri, charOffset, length);
        break;
      case UnresolvedKind.Constructor:
        message = warnUnresolvedConstructor(
          kernelName,
          isSuper: isSuper,
        ).withLocation(uri, charOffset, length);
        break;
    }
    return buildProblem(
      message.messageObject,
      message.charOffset,
      message.length,
      errorHasBeenReported: errorHasBeenReported,
    );
  }

  @override
  Expression buildProblemWithContextFromMember({
    required String name,
    required Member member,
    required LocatedMessage message,
  }) {
    List<LocatedMessage>? context;
    Location? location = member.location;
    if (location != null) {
      Uri uri = location.file;
      int offset = member.fileOffset;
      Message contextMessage;
      int length = noLength;
      if (member is Constructor && member.isSynthetic) {
        offset = member.enclosingClass.fileOffset;
        contextMessage = cfe.codeCandidateFoundIsDefaultConstructor
            .withArgumentsOld(member.enclosingClass.name);
      } else {
        if (member is Constructor) {
          if (member.name.text == '') {
            length = member.enclosingClass.name.length;
          } else {
            // Assume no spaces around the dot. Not perfect, but probably the
            // best we can do with the information available.
            length = member.enclosingClass.name.length + 1 + name.length;
          }
        } else {
          length = name.length;
        }
        contextMessage = cfe.codeCandidateFound;
      }
      context = [contextMessage.withLocation(uri, offset, length)];
    }
    return buildProblem(
      message.messageObject,
      message.charOffset,
      message.length,
      context: context,
    );
  }

  @override
  Expression buildProblemFromLocatedMessage(LocatedMessage message) {
    return buildProblem(
      message.messageObject,
      message.charOffset,
      message.length,
    );
  }

  Message warnUnresolvedMember(
    Name name,
    int charOffset, {
    bool isSuper = false,
    bool reportWarning = true,
    List<LocatedMessage>? context,
  }) {
    Message message = isSuper
        ?
          // Coverage-ignore(suite): Not run.
          cfe.codeSuperclassHasNoMember.withArgumentsOld(name.text)
        : cfe.codeMemberNotFound.withArgumentsOld(name.text);
    if (reportWarning) {
      // Coverage-ignore-block(suite): Not run.
      addProblemErrorIfConst(
        message,
        charOffset,
        name.text.length,
        context: context,
      );
    }
    return message;
  }

  Message warnUnresolvedGet(
    Name name,
    int charOffset, {
    bool isSuper = false,
    bool reportWarning = true,
    List<LocatedMessage>? context,
  }) {
    Message message = isSuper
        ? cfe.codeSuperclassHasNoGetter.withArgumentsOld(name.text)
        : cfe.codeGetterNotFound.withArgumentsOld(name.text);
    if (reportWarning) {
      // Coverage-ignore-block(suite): Not run.
      addProblemErrorIfConst(
        message,
        charOffset,
        name.text.length,
        context: context,
      );
    }
    return message;
  }

  Message warnUnresolvedSet(
    Name name,
    int charOffset, {
    bool isSuper = false,
    bool reportWarning = true,
    List<LocatedMessage>? context,
  }) {
    Message message = isSuper
        ? cfe.codeSuperclassHasNoSetter.withArgumentsOld(name.text)
        : cfe.codeSetterNotFound.withArgumentsOld(name.text);
    if (reportWarning) {
      // Coverage-ignore-block(suite): Not run.
      addProblemErrorIfConst(
        message,
        charOffset,
        name.text.length,
        context: context,
      );
    }
    return message;
  }

  Message warnUnresolvedMethod(
    Name name,
    int charOffset, {
    bool isSuper = false,
    bool reportWarning = true,
    List<LocatedMessage>? context,
  }) {
    String plainName = name.text;

    int dotIndex = plainName.lastIndexOf(".");
    if (dotIndex != -1) {
      plainName = plainName.substring(dotIndex + 1);
    }
    // TODO(ahe): This is rather brittle. We would probably be better off with
    // more precise location information in this case.
    int length = plainName.length;
    if (plainName.startsWith("[")) {
      length = 1;
    }
    Message message = isSuper
        ? cfe.codeSuperclassHasNoMethod.withArgumentsOld(name.text)
        : cfe.codeMethodNotFound.withArgumentsOld(name.text);
    if (reportWarning) {
      // Coverage-ignore-block(suite): Not run.
      addProblemErrorIfConst(message, charOffset, length, context: context);
    }
    return message;
  }

  Message warnUnresolvedConstructor(Name name, {bool isSuper = false}) {
    Message message = isSuper
        ?
          // Coverage-ignore(suite): Not run.
          cfe.codeSuperclassHasNoConstructor.withArgumentsOld(name.text)
        : cfe.codeConstructorNotFound.withArgumentsOld(name.text);
    return message;
  }

  @override
  Member? lookupSuperMember(Name name, {bool isSetter = false}) {
    return _context.lookupSuperMember(hierarchy, name, isSetter: isSetter);
  }

  @override
  MemberLookupResult? lookupSuperConstructor(
    String name,
    LibraryBuilder accessingLibrary,
  ) {
    return _context.lookupSuperConstructor(name, accessingLibrary);
  }

  @override
  void handleIdentifier(Token token, IdentifierContext context) {
    debugEvent("handleIdentifier");
    if (context.isScopeReference) {
      assert(
        !inInitializerLeftHandSide ||
            _localScopes.current == enclosingScope ||
            _localScopes.previous == enclosingScope,
      );
      // This deals with this kind of initializer: `C(a) : a = a;`
      LocalScope scope = inInitializerLeftHandSide
          ? enclosingScope
          : this._localScope;
      push(scopeLookup(scope, token));
    } else {
      if (!context.inDeclaration &&
          constantContext != ConstantContext.none &&
          !context.allowedInConstantExpression) {
        // Coverage-ignore-block(suite): Not run.
        addProblem(
          cfe.codeNotAConstantExpression,
          token.charOffset,
          token.length,
        );
      }
      if (token.isSynthetic) {
        push(new ParserRecovery(offsetForToken(token)));
      } else {
        push(new SimpleIdentifier(token));
      }
    }
    assert(
      checkState(token, [
        unionOfKinds([
          ValueKinds.Identifier,
          ValueKinds.Generator,
          ValueKinds.ParserRecovery,
        ]),
      ]),
    );
  }

  @override
  void registerVariableRead(VariableDeclaration variable) {
    if (!(variable as VariableDeclarationImpl).isLocalFunction &&
        !variable.isWildcard) {
      typeInferrer.assignedVariables.read(variable);
    }
  }

  /// Helper method to create a [VariableGet] of the [variable] using
  /// [charOffset] as the file offset.
  @override
  VariableGet createVariableGet(VariableDeclaration variable, int charOffset) {
    registerVariableRead(variable);
    return new VariableGet(variable)..fileOffset = charOffset;
  }

  /// Helper method to create a [ReadOnlyAccessGenerator] on the [variable]
  /// using [token] and [charOffset] for offset information and [name]
  /// for `ExpressionGenerator._plainNameForRead`.
  ReadOnlyAccessGenerator _createReadOnlyVariableAccess(
    VariableDeclaration variable,
    Token token,
    int charOffset,
    String? name,
    ReadOnlyAccessKind kind,
  ) {
    return new ReadOnlyAccessGenerator(
      this,
      token,
      createVariableGet(variable, charOffset),
      name ?? '',
      kind,
    );
  }

  @override
  bool isDeclaredInEnclosingCase(VariableDeclaration variable) {
    return declaredInCurrentGuard?.contains(variable) ?? false;
  }

  bool isGuardScope(LocalScope scope) =>
      scope.kind == ScopeKind.caseHead || scope.kind == ScopeKind.ifCaseHead;

  /// Look up the name from [nameToken] in [scope] using [nameToken] as location
  /// information.
  Generator scopeLookup(LocalScope scope, Token nameToken) {
    String name = nameToken.lexeme;
    int nameOffset = nameToken.charOffset;
    LookupResult? lookupResult = scope.lookup(name, fileOffset: nameOffset);
    return processLookupResult(
      lookupResult: lookupResult,
      name: name,
      nameToken: nameToken,
      nameOffset: nameOffset,
      scopeKind: scope.kind,
    );
  }

  @override
  Generator processLookupResult({
    required LookupResult? lookupResult,
    required String name,
    required Token nameToken,
    required int nameOffset,
    required ScopeKind scopeKind,
    PrefixBuilder? prefix,
    Token? prefixToken,
  }) {
    if (nameToken.isSynthetic) {
      return new ParserErrorGenerator(this, nameToken, cfe.codeSyntheticToken);
    }
    if (lookupResult != null && lookupResult.isInvalidLookup) {
      return new DuplicateDeclarationGenerator(
        this,
        nameToken,
        lookupResult,
        new Name(name, libraryBuilder.nameOrigin),
        name.length,
      );
    }

    bool isQualified = prefixToken != null;
    bool mustBeConst =
        constantContext != ConstantContext.none && !inInitializerLeftHandSide;
    bool hasThisAccess;
    if (inInitializerLeftHandSide) {
      // The left hand side of an initializer, like 'x' in:
      //
      //    class C {
      //      C() : x = 0;
      //    }
      //
      // must always refer to field in the encoding class. By assuming we
      // have `this` access, the error reported in when creating the
      // initializer will mention this.
      // TODO(johnniwinther): Could we just report that error here instead?
      hasThisAccess = true;
    } else {
      // TODO(johnniwinther): This should exclude identifies occurring in
      //  metadata.
      hasThisAccess = isDeclarationInstanceContext && !inFormals;
      if (hasThisAccess) {
        if (isQualified) {
          hasThisAccess = false;
        } else if (inFieldInitializer) {
          if (!inLateFieldInitializer ||
              _context.isExtensionDeclaration ||
              _context.isExtensionTypeDeclaration) {
            hasThisAccess = false;
          }
        }
      }
    }

    if (lookupResult == null) {
      Name memberName = new Name(name, libraryBuilder.nameOrigin);
      if (hasThisAccess) {
        if (mustBeConst) {
          return new IncompleteErrorGenerator(
            this,
            nameToken,
            cfe.codeNotAConstantExpression,
          );
        }
        // This is an implicit access on 'this'.
        return new ThisPropertyAccessGenerator(
          this,
          nameToken,
          memberName,
          thisVariable: thisVariable,
        );
      } else {
        // [name] is unresolved.
        return new UnresolvedNameGenerator(
          this,
          nameToken,
          memberName,
          unresolvedReadKind: UnresolvedKind.Unknown,
        );
      }
    }
    Builder? getable = lookupResult.getable;
    Builder? setable = lookupResult.setable;
    if (getable != null) {
      if (getable is InvalidBuilder) {
        // TODO(johnniwinther): Create an `InvalidGenerator` instead.
        return new TypeUseGenerator(
          this,
          nameToken,
          getable,
          prefixToken != null
              ? new QualifiedTypeName(
                  prefixToken.lexeme,
                  prefixToken.charOffset,
                  name,
                  nameOffset,
                )
              : new IdentifierTypeName(name, nameOffset),
        );
      } else if (getable is VariableBuilder) {
        if (mustBeConst &&
            !getable.isConst &&
            !(_context.isConstructor && inFieldInitializer) &&
            !libraryFeatures.constFunctions.isEnabled) {
          return new IncompleteErrorGenerator(
            this,
            nameToken,
            cfe.codeNotAConstantExpression,
          );
        }
        VariableDeclaration variable = getable.variable!;
        // TODO(johnniwinther): The handling of for-in variables should be
        //  done through the builder.
        if (scopeKind == ScopeKind.forStatement &&
            variable.isAssignable &&
            variable.isLate &&
            variable.isFinal) {
          return new ForInLateFinalVariableUseGenerator(
            this,
            nameToken,
            variable,
          );
        } else if (!getable.isAssignable ||
            (variable.isFinal && scopeKind == ScopeKind.forStatement)) {
          return _createReadOnlyVariableAccess(
            variable,
            nameToken,
            nameOffset,
            name,
            variable.isConst
                ? ReadOnlyAccessKind.ConstVariable
                : ReadOnlyAccessKind.FinalVariable,
          );
        } else {
          return new VariableUseGenerator(this, nameToken, variable);
        }
      } else if (getable.isDeclarationInstanceMember) {
        if (!inInitializerLeftHandSide && inFieldInitializer) {
          // We cannot access a class instance member in an initializer of a
          // field.
          //
          // For instance
          //
          //     class M {
          //       int foo = bar; // Implicit this access on `bar`.
          //       int bar;
          //       int baz = 4;
          //       M() : bar = baz; // Implicit this access on `baz`.
          //     }
          //
          // We can if it's late, but not if we're in an extension (type), even
          // if it's late.
          if (!inLateFieldInitializer ||
              _context.isExtensionDeclaration ||
              _context.isExtensionTypeDeclaration) {
            return new IncompleteErrorGenerator(
              this,
              nameToken,
              cfe.codeThisAccessInFieldInitializer.withArgumentsOld(name),
            );
          }
        }

        if (mustBeConst && !libraryFeatures.constFunctions.isEnabled) {
          return new IncompleteErrorGenerator(
            this,
            nameToken,
            cfe.codeNotAConstantExpression,
          );
        }

        Name memberName = new Name(name, libraryBuilder.nameOrigin);
        if (hasThisAccess) {
          // This is an implicit access on 'this'.
          if (getable.isExtensionInstanceMember && thisVariable != null) {
            ExtensionBuilder extensionBuilder =
                getable.parent as ExtensionBuilder;
            if (getable is PropertyBuilder && getable.hasConcreteField) {
              getable = null;
            }
            if (setable != null &&
                ((setable is PropertyBuilder && setable.hasConcreteField) ||
                    setable.isStatic)) {
              setable = null;
            }
            if (getable == null && setable == null) {
              return new UnresolvedNameGenerator(
                this,
                nameToken,
                memberName,
                unresolvedReadKind: UnresolvedKind.Unknown,
              );
            }
            return new ExtensionInstanceAccessGenerator.fromBuilder(
              this,
              nameToken,
              extensionBuilder.extension,
              memberName,
              thisVariable!,
              thisTypeParameters,
              getable as MemberBuilder?,
              setable as MemberBuilder?,
            );
          }
          return new ThisPropertyAccessGenerator(
            this,
            nameToken,
            memberName,
            thisVariable: thisVariable,
          );
        } else {
          // [name] is an instance member but this is not an instance context.
          return new UnresolvedNameGenerator(
            this,
            nameToken,
            memberName,
            unresolvedReadKind: UnresolvedKind.Unknown,
          );
        }
      } else if (getable is TypeDeclarationBuilder) {
        return new TypeUseGenerator(
          this,
          nameToken,
          getable,
          prefixToken != null
              ? new QualifiedTypeName(
                  prefixToken.lexeme,
                  prefixToken.charOffset,
                  name,
                  nameOffset,
                )
              : new IdentifierTypeName(name, nameOffset),
        );
      } else if (getable is MemberBuilder) {
        assert(
          getable.isStatic || getable.isTopLevel,
          "Unexpected getable: $getable",
        );
        assert(
          setable == null ||
              setable.isStatic ||
              // Coverage-ignore(suite): Not run.
              setable.isTopLevel,
          "Unexpected setable: $setable",
        );

        if (mustBeConst &&
            !(getable is PropertyBuilder && getable.hasConstField) &&
            !(getable is MethodBuilder && getable.isRegularMethod) &&
            !libraryFeatures.constFunctions.isEnabled) {
          return new IncompleteErrorGenerator(
            this,
            nameToken,
            cfe.codeNotAConstantExpression,
          );
        }
        return new StaticAccessGenerator.fromBuilder(
          this,
          new Name(name, libraryBuilder.nameOrigin),
          nameToken,
          getable,
          setable as MemberBuilder?,
        );
      } else if (getable is PrefixBuilder) {
        // Wildcard import prefixes are non-binding and cannot be used.
        if (libraryFeatures.wildcardVariables.isEnabled && getable.isWildcard) {
          // TODO(kallentu): Provide a helpful error related to wildcard
          //  prefixes.
          return new UnresolvedNameGenerator(
            this,
            nameToken,
            new Name(getable.name, libraryBuilder.nameOrigin),
            unresolvedReadKind: UnresolvedKind.Unknown,
          );
        }
        return new PrefixUseGenerator(this, nameToken, getable);
      } else if (getable is LoadLibraryBuilder) {
        return new LoadLibraryGenerator(this, nameToken, getable);
      }
    } else {
      if (setable is InvalidBuilder) {
        // Coverage-ignore-block(suite): Not run.
        return new TypeUseGenerator(
          this,
          nameToken,
          setable,
          prefixToken != null
              ? new QualifiedTypeName(
                  prefixToken.lexeme,
                  prefixToken.charOffset,
                  name,
                  nameOffset,
                )
              : new IdentifierTypeName(name, nameOffset),
        );
      } else if (setable!.isDeclarationInstanceMember) {
        Name memberName = new Name(name, libraryBuilder.nameOrigin);
        if (hasThisAccess) {
          if (setable.isExtensionInstanceMember && thisVariable != null) {
            ExtensionBuilder extensionBuilder =
                setable.parent as ExtensionBuilder;
            if (setable is PropertyBuilder && setable.hasConcreteField) {
              setable = null;
            }
            if (setable == null) {
              // Coverage-ignore-block(suite): Not run.
              return new UnresolvedNameGenerator(
                this,
                nameToken,
                memberName,
                unresolvedReadKind: UnresolvedKind.Unknown,
              );
            }
            return new ExtensionInstanceAccessGenerator.fromBuilder(
              this,
              nameToken,
              extensionBuilder.extension,
              memberName,
              thisVariable!,
              thisTypeParameters,
              getable as MemberBuilder?,
              setable as MemberBuilder?,
            );
          }
          // This is an implicit access on 'this'.
          return new ThisPropertyAccessGenerator(
            this,
            nameToken,
            memberName,
            thisVariable: thisVariable,
          );
        } else {
          // [name] is an instance member but this is not an instance context.
          return new UnresolvedNameGenerator(
            this,
            nameToken,
            memberName,
            unresolvedReadKind: UnresolvedKind.Unknown,
          );
        }
      } else if (setable is MemberBuilder) {
        assert(
          setable.isStatic ||
              // Coverage-ignore(suite): Not run.
              setable.isTopLevel,
          "Unexpected setable: $setable",
        );
        return new StaticAccessGenerator.fromBuilder(
          this,
          new Name(name, libraryBuilder.nameOrigin),
          nameToken,
          null,
          setable,
        );
      }
    }

    // Coverage-ignore(suite): Not run.
    return new UnresolvedNameGenerator(
      this,
      nameToken,
      new Name(name, libraryBuilder.nameOrigin),
      unresolvedReadKind: UnresolvedKind.Unknown,
    );
  }

  @override
  void handleQualified(Token period) {
    // handleQualified is called after two handleIdentifier calls.
    // This happens via one of these:
    // * ComplexTypeInfo.parseType (with context prefixedTypeReference)
    // * parseLibraryName (with context libraryName)
    // * parsePartOf (with context partName)
    // * parseMetadata (with context metadataReference)
    // * parseMethod (with context methodDeclaration)
    // * parseFactoryMethod (with context methodDeclaration)
    // * parseConstructorReference (with context constructorReference)
    // Of these ComplexTypeInfo.parseType, parseMetadata, parseFactoryMethod and
    // parseConstructorReference has a context where isScopeReference is true,
    // meaning handleIdentifier pushes a scopeLookup which returns either a
    // Generator or a Builder. In the below we thus assume those are the two
    // prefixes we'll have.
    debugEvent("handleQualified");
    assert(
      checkState(period, [
        /* suffix */ ValueKinds.IdentifierOrParserRecovery,
        /* prefix */ unionOfKinds([ValueKinds.Generator]),
      ]),
    );

    Object? node = pop();
    Object? qualifier = pop();
    if (node is ParserRecovery) {
      push(node);
    } else {
      SimpleIdentifier identifier = node as SimpleIdentifier;
      if (qualifier is Generator) {
        push(identifier.withGeneratorQualifier(qualifier));
      }
      // Coverage-ignore(suite): Not run.
      else if (qualifier is Builder) {
        push(identifier.withBuilderQualifier(qualifier));
      } else {
        unhandled(
          "qualifier is ${qualifier.runtimeType}",
          "handleQualified",
          period.charOffset,
          uri,
        );
      }
    }
  }

  @override
  void beginLiteralString(Token token) {
    debugEvent("beginLiteralString");
    push(token);
  }

  @override
  void handleStringPart(Token token) {
    debugEvent("handleStringPart");
    push(token);
  }

  @override
  void endLiteralString(int interpolationCount, Token endToken) {
    debugEvent("endLiteralString");
    if (interpolationCount == 0) {
      Token token = pop() as Token;
      String value = unescapeString(token.lexeme, token, this);
      push(forest.createStringLiteral(offsetForToken(token), value));
    } else {
      int count = 1 + interpolationCount * 2;
      List<Object>? parts = const FixedNullableList<Object>().popNonNullable(
        stack,
        count,
        /* dummyValue = */ 0,
      );
      if (parts == null) {
        // Coverage-ignore-block(suite): Not run.
        push(new ParserRecovery(endToken.charOffset));
        return;
      }
      Token first = parts.first as Token;
      Token last = parts.last as Token;
      Quote quote = analyzeQuote(first.lexeme);
      List<Expression> expressions = <Expression>[];
      // Contains more than just \' or \".
      if (first.lexeme.length > 1) {
        String value = unescapeFirstStringPart(
          first.lexeme,
          quote,
          first,
          this,
        );
        if (value.isNotEmpty) {
          expressions.add(
            forest.createStringLiteral(offsetForToken(first), value),
          );
        }
      }
      for (int i = 1; i < parts.length - 1; i++) {
        Object part = parts[i];
        if (part is Token) {
          if (part.lexeme.length != 0) {
            String value = unescape(part.lexeme, quote, part, this);
            expressions.add(
              forest.createStringLiteral(offsetForToken(part), value),
            );
          }
        } else {
          expressions.add(toValue(part));
        }
      }
      // Contains more than just \' or \".
      if (last.lexeme.length > 1) {
        String value = unescapeLastStringPart(
          last.lexeme,
          quote,
          last,
          last.isSynthetic,
          this,
        );
        if (value.isNotEmpty) {
          expressions.add(
            forest.createStringLiteral(offsetForToken(last), value),
          );
        }
      }
      push(
        forest.createStringConcatenation(offsetForToken(endToken), expressions),
      );
    }
  }

  @override
  void handleNativeClause(Token nativeToken, bool hasName) {
    debugEvent("NativeClause");
    if (hasName) {
      pop() as StringLiteral;
    }
  }

  @override
  // Coverage-ignore(suite): Not run.
  void handleScript(Token token) {
    debugEvent("Script");
  }

  @override
  void handleAdjacentStringLiterals(Token startToken, int literalCount) {
    debugEvent("AdjacentStringLiterals");
    List<Expression> parts = popListForValue(literalCount);
    List<Expression>? expressions;
    // Flatten string juxtapositions of string interpolation.
    for (int i = 0; i < parts.length; i++) {
      Expression part = parts[i];
      if (part is StringConcatenation) {
        if (expressions == null) {
          expressions = parts.sublist(0, i);
        }
        for (Expression expression in part.expressions) {
          expressions.add(expression);
        }
      } else {
        if (expressions != null) {
          expressions.add(part);
        }
      }
    }
    push(
      forest.createStringConcatenation(
        offsetForToken(startToken),
        expressions ?? parts,
      ),
    );
  }

  @override
  void handleLiteralInt(Token token) {
    debugEvent("LiteralInt");
    int? value = intFromToken(token, hasSeparators: false);
    // Postpone parsing of literals resulting in a negative value
    // (hex literals >= 2^63). These are only allowed when not negated.
    if (value == null || value < 0) {
      push(
        forest.createIntLiteralLarge(
          offsetForToken(token),
          token.lexeme,
          token.lexeme,
        ),
      );
    } else {
      push(forest.createIntLiteral(offsetForToken(token), value, token.lexeme));
    }
  }

  @override
  void handleLiteralIntWithSeparators(Token token) {
    debugEvent("LiteralIntWithSeparators");

    if (!libraryFeatures.digitSeparators.isEnabled) {
      addProblem(
        codeExperimentNotEnabledOffByDefault.withArgumentsOld(
          ExperimentalFlag.digitSeparators.name,
        ),
        token.offset,
        token.length,
      );
    }

    String source = stripSeparators(token.lexeme);
    int? value = int.tryParse(source);
    // Postpone parsing of literals resulting in a negative value
    // (hex literals >= 2^63). These are only allowed when not negated.
    if (value == null || value < 0) {
      push(
        forest.createIntLiteralLarge(
          offsetForToken(token),
          source,
          token.lexeme,
        ),
      );
    } else {
      push(forest.createIntLiteral(offsetForToken(token), value, token.lexeme));
    }
  }

  @override
  void handleEmptyFunctionBody(Token semicolon) {
    debugEvent("ExpressionFunctionBody");
    endBlockFunctionBody(0, null, semicolon);
  }

  @override
  void handleExpressionFunctionBody(Token arrowToken, Token? endToken) {
    debugEvent("ExpressionFunctionBody");
    endReturnStatement(true, arrowToken.next!, endToken);
  }

  @override
  void endReturnStatement(
    bool hasExpression,
    Token beginToken,
    Token? endToken,
  ) {
    debugEvent("ReturnStatement");
    Expression? expression = hasExpression ? popForValue() : null;
    if (expression != null && inConstructor) {
      push(
        buildProblemStatement(
          cfe.codeConstructorWithReturnType,
          beginToken.charOffset,
        ),
      );
    } else {
      push(
        forest.createReturnStatement(
          offsetForToken(beginToken),
          expression,
          isArrow: !identical(beginToken.lexeme, "return"),
        ),
      );
    }
  }

  @override
  void beginPatternGuard(Token when) {
    debugEvent("PatternGuard");
    assert(
      checkState(when, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Pattern]),
      ]),
    );

    Pattern pattern = toPattern(peek());
    createAndEnterLocalScope(
      debugName: "if-case-head",
      kind: ScopeKind.ifCaseHead,
    );
    for (VariableDeclaration variable in pattern.declaredVariables) {
      declareVariable(variable, _localScope);
    }
  }

  @override
  void endPatternGuard(Token token) {
    debugEvent("PatternGuard");
  }

  @override
  void beginThenStatement(Token token) {
    debugEvent("beginThenStatement");
    assert(checkState(token, [ValueKinds.Condition]));
    // This is matched by the call to [deferNode] in
    // [endThenStatement].
    typeInferrer.assignedVariables.beginNode();
    Condition condition = pop() as Condition;
    PatternGuard? patternGuard = condition.patternGuard;
    if (patternGuard != null && patternGuard.guard != null) {
      LocalScope thenScope = _localScope.createNestedScope(
        debugName: "then body",
        kind: ScopeKind.statementLocalScope,
      );
      exitLocalScope(expectedScopeKinds: const [ScopeKind.ifCaseHead]);
      push(condition);
      enterLocalScope(thenScope);
    } else {
      push(condition);
      // There is no guard, so the scope for "then" isn't entered yet. We need
      // to enter the scope and declare all of the pattern variables.
      if (patternGuard != null) {
        createAndEnterLocalScope(
          debugName: "if-case-head",
          kind: ScopeKind.ifCaseHead,
        );
        for (VariableDeclaration variable
            in patternGuard.pattern.declaredVariables) {
          declareVariable(variable, _localScope);
        }
        LocalScope thenScope = _localScope.createNestedScope(
          debugName: "then body",
          kind: ScopeKind.statementLocalScope,
        );
        exitLocalScope();
        enterLocalScope(thenScope);
      } else {
        createAndEnterLocalScope(
          debugName: "then body",
          kind: ScopeKind.statementLocalScope,
        );
      }
    }
  }

  @override
  void endThenStatement(Token beginToken, Token endToken) {
    debugEvent("endThenStatement");
    Object? body = pop();
    exitLocalScope();
    push(body);
    // This is matched by the call to [beginNode] in
    // [beginThenStatement] and by the call to [storeInfo] in
    // [endIfStatement].
    push(typeInferrer.assignedVariables.deferNode());
  }

  @override
  void endIfStatement(Token ifToken, Token? elseToken, Token endToken) {
    assert(
      checkState(ifToken, [
        /* else = */ if (elseToken != null)
          unionOfKinds([ValueKinds.Statement, ValueKinds.ParserRecovery]),
        ValueKinds.AssignedVariablesNodeInfo,
        /* then = */ unionOfKinds([
          ValueKinds.Statement,
          ValueKinds.ParserRecovery,
        ]),
        /* condition = */ ValueKinds.Condition,
      ]),
    );
    Statement? elsePart = popStatementIfNotNull(elseToken);
    AssignedVariablesNodeInfo assignedVariablesInfo =
        pop() as AssignedVariablesNodeInfo;
    Statement thenPart = popStatement(ifToken);
    Condition condition = pop() as Condition;
    PatternGuard? patternGuard = condition.patternGuard;
    Expression expression = condition.expression;
    Statement node;
    if (patternGuard != null) {
      node = forest.createIfCaseStatement(
        ifToken.charOffset,
        expression,
        patternGuard,
        thenPart,
        elsePart,
      );
    } else {
      node = forest.createIfStatement(
        offsetForToken(ifToken),
        expression,
        thenPart,
        elsePart,
      );
    }
    // This is matched by the call to [deferNode] in
    // [endThenStatement].
    typeInferrer.assignedVariables.storeInfo(node, assignedVariablesInfo);
    push(node);
  }

  @override
  void beginVariableInitializer(Token token) {
    if (currentLocalVariableModifiers.isLate) {
      // This is matched by the call to [endNode] in [endVariableInitializer].
      typeInferrer.assignedVariables.beginNode();
    }
  }

  @override
  void endVariableInitializer(Token assignmentOperator) {
    debugEvent("VariableInitializer");
    assert(assignmentOperator.stringValue == "=");
    AssignedVariablesNodeInfo? assignedVariablesInfo;
    bool isLate = currentLocalVariableModifiers.isLate;
    Expression initializer = popForValue();
    if (isLate) {
      assignedVariablesInfo = typeInferrer.assignedVariables.deferNode(
        isClosureOrLateVariableInitializer: true,
      );
    }
    pushNewLocalVariable(initializer, equalsToken: assignmentOperator);
    if (isLate) {
      VariableDeclaration node = peek() as VariableDeclaration;
      // This is matched by the call to [beginNode] in
      // [beginVariableInitializer].
      typeInferrer.assignedVariables.storeInfo(node, assignedVariablesInfo!);
    }
  }

  @override
  void handleNoVariableInitializer(Token token) {
    debugEvent("NoVariableInitializer");
    bool isConst = currentLocalVariableModifiers.isConst;
    Expression? initializer;
    if (!token.next!.isA(Keyword.IN)) {
      // A for-in loop-variable can't have an initializer. So let's remain
      // silent if the next token is `in`. Since a for-in loop can only have
      // one variable it must be followed by `in`.
      if (!token.isSynthetic) {
        // If [token] is synthetic it is created from error recovery.
        if (isConst) {
          initializer = buildProblem(
            cfe.codeConstFieldWithoutInitializer.withArgumentsOld(token.lexeme),
            token.charOffset,
            token.length,
          );
        }
      }
    }
    pushNewLocalVariable(initializer);
  }

  void pushNewLocalVariable(Expression? initializer, {Token? equalsToken}) {
    Object? node = pop();
    if (node is ParserRecovery) {
      push(node);
      return;
    }
    Identifier identifier = node as Identifier;
    assert(currentLocalVariableModifiers != noCurrentLocalVariableModifiers);
    bool isConst = currentLocalVariableModifiers.isConst;
    bool isFinal = currentLocalVariableModifiers.isFinal;
    bool isLate = currentLocalVariableModifiers.isLate;
    bool isRequired = currentLocalVariableModifiers.isRequired;
    assert(isConst == (constantContext == ConstantContext.inferred));
    String name = identifier.name;
    bool isWildcard =
        libraryFeatures.wildcardVariables.isEnabled && name == '_';
    if (isWildcard) {
      name = createWildcardVariableName(wildcardVariableIndex);
      wildcardVariableIndex++;
    }
    VariableDeclaration variable =
        new VariableDeclarationImpl(
            name,
            forSyntheticToken: identifier.token.isSynthetic,
            initializer: initializer,
            type: currentLocalVariableType,
            isFinal: isFinal,
            isConst: isConst,
            isLate: isLate,
            isRequired: isRequired,
            hasDeclaredInitializer: initializer != null,
            isStaticLate: isFinal && initializer == null,
            isWildcard: isWildcard,
          )
          ..fileOffset = identifier.nameOffset
          ..fileEqualsOffset = offsetForToken(equalsToken);
    typeInferrer.assignedVariables.declare(variable);
    push(variable);
  }

  @override
  void beginFieldInitializer(Token token) {
    inFieldInitializer = true;
    constantContext = _context.constantContext;
    inLateFieldInitializer = _context.isLateField;
    if (_context.isAbstractField) {
      addProblem(cfe.codeAbstractFieldInitializer, token.charOffset, noLength);
    } else if (_context.isExternalField) {
      addProblem(cfe.codeExternalFieldInitializer, token.charOffset, noLength);
    }
  }

  @override
  void endFieldInitializer(Token assignmentOperator, Token endToken) {
    debugEvent("FieldInitializer");
    inFieldInitializer = false;
    inLateFieldInitializer = false;
    assert(assignmentOperator.stringValue == "=");
    push(popForValue());
    constantContext = ConstantContext.none;
  }

  @override
  void handleNoFieldInitializer(Token token) {
    debugEvent("NoFieldInitializer");
    constantContext = _context.constantContext;
    if (constantContext == ConstantContext.inferred) {
      // Creating a null value to prevent the Dart VM from crashing.
      push(forest.createNullLiteral(offsetForToken(token)));
    } else {
      push(NullValues.FieldInitializer);
    }
    constantContext = ConstantContext.none;
  }

  @override
  void endInitializedIdentifier(Token nameToken) {
    // TODO(ahe): Use [InitializedIdentifier] here?
    debugEvent("InitializedIdentifier");
    Object? node = pop();
    if (node is ParserRecovery) {
      push(node);
      return;
    }
    VariableDeclaration variable = node as VariableDeclaration;
    variable.fileOffset = nameToken.charOffset;
    push(variable);

    // Avoid adding the local identifier to scope if it's a wildcard.
    // TODO(kallentu): Emit better error on lookup, rather than not adding it to
    // the scope.
    if (!(libraryFeatures.wildcardVariables.isEnabled && variable.isWildcard)) {
      declareVariable(variable, _localScope);
    }
  }

  @override
  void beginVariablesDeclaration(
    Token token,
    Token? lateToken,
    Token? varFinalOrConst,
  ) {
    debugEvent("beginVariablesDeclaration");
    TypeBuilder? unresolvedType = pop(NullValues.TypeBuilder) as TypeBuilder?;
    DartType? type = unresolvedType != null
        ? buildDartType(
            unresolvedType,
            TypeUse.variableType,
            allowPotentiallyConstantType: false,
          )
        : null;
    Modifiers modifiers = Modifiers.from(
      lateToken: lateToken,
      varFinalOrConst: varFinalOrConst,
    );
    _enterLocalState(inLateLocalInitializer: lateToken != null);
    super.push(currentLocalVariableModifiers);
    super.push(currentLocalVariableType ?? NullValues.Type);
    currentLocalVariableType = type;
    currentLocalVariableModifiers = modifiers;
    super.push(constantContext);
    constantContext = modifiers.isConst
        ? ConstantContext.inferred
        : ConstantContext.none;
  }

  @override
  void endVariablesDeclaration(int count, Token? endToken) {
    debugEvent("VariablesDeclaration");
    if (count == 1) {
      Object? node = pop();
      constantContext = pop() as ConstantContext;
      currentLocalVariableType = pop(NullValues.Type) as DartType?;
      currentLocalVariableModifiers = pop() as Modifiers;
      List<Expression>? annotations = pop() as List<Expression>?;
      if (node is ParserRecovery) {
        push(node);
        return;
      }
      VariableDeclaration variable = node as VariableDeclaration;
      if (annotations != null) {
        for (int i = 0; i < annotations.length; i++) {
          variable.addAnnotation(annotations[i]);
        }
        (variablesWithMetadata ??= <VariableDeclaration>[]).add(variable);
      }
      push(variable);
    } else {
      List<VariableDeclaration>? variables =
          const FixedNullableList<VariableDeclaration>().popNonNullable(
            stack,
            count,
            dummyVariableDeclaration,
          );
      constantContext = pop() as ConstantContext;
      currentLocalVariableType = pop(NullValues.Type) as DartType?;
      currentLocalVariableModifiers = pop() as Modifiers;
      List<Expression>? annotations = pop() as List<Expression>?;
      if (variables == null) {
        push(new ParserRecovery(offsetForToken(endToken)));
        return;
      }
      if (annotations != null) {
        VariableDeclaration first = variables.first;
        for (int i = 0; i < annotations.length; i++) {
          first.addAnnotation(annotations[i]);
        }
        (multiVariablesWithMetadata ??= <List<VariableDeclaration>>[]).add(
          variables,
        );
      }
      push(forest.variablesDeclaration(variables, uri));
    }
    _exitLocalState();
  }

  /// Stack containing assigned variables info for try statements.
  ///
  /// These are created in [beginTryStatement] and ended in either [beginBlock]
  /// when a finally block starts or in [endTryStatement] when the try statement
  /// ends. Since these need to be associated with the try statement created in
  /// in [endTryStatement] we store them the stack until the try statement is
  /// created.
  Link<AssignedVariablesNodeInfo> tryStatementInfoStack =
      const Link<AssignedVariablesNodeInfo>();

  @override
  void beginBlock(Token token, BlockKind blockKind) {
    if (blockKind == BlockKind.tryStatement) {
      // This is matched by the call to [endNode] in [endBlock].
      typeInferrer.assignedVariables.beginNode();
    } else if (blockKind == BlockKind.finallyClause) {
      // This is matched by the call to [beginNode] in [beginTryStatement].
      tryStatementInfoStack = tryStatementInfoStack.prepend(
        typeInferrer.assignedVariables.deferNode(),
      );
    }
    debugEvent("beginBlock");
    createAndEnterLocalScope(
      debugName: "block",
      kind: ScopeKind.statementLocalScope,
    );
  }

  @override
  void endBlock(
    int count,
    Token openBrace,
    Token closeBrace,
    BlockKind blockKind,
  ) {
    debugEvent("Block");
    Statement block = popBlock(count, openBrace, closeBrace);
    exitLocalScope();
    push(block);
    if (blockKind == BlockKind.tryStatement) {
      // This is matched by the call to [beginNode] in [beginBlock].
      typeInferrer.assignedVariables.endNode(block);
    }
  }

  @override
  // Coverage-ignore(suite): Not run.
  void handleInvalidTopLevelBlock(Token token) {
    // TODO(danrubel): Consider improved recovery by adding this block
    // as part of a synthetic top level function.
    pop(); // block
  }

  @override
  void handleAssignmentExpression(Token token, Token endToken) {
    assert(
      checkState(token, [
        unionOfKinds(<ValueKind>[ValueKinds.Expression, ValueKinds.Generator]),
        unionOfKinds(<ValueKind>[ValueKinds.Expression, ValueKinds.Generator]),
      ]),
    );
    debugEvent("AssignmentExpression");
    Expression value = popForValue();
    Object? generator = pop();
    if (generator is! Generator) {
      push(
        buildProblem(
          cfe.codeNotAnLvalue,
          offsetForToken(token),
          lengthForToken(token),
          errorHasBeenReported: generator is InvalidExpression,
        ),
      );
    } else {
      push(
        new DelayedAssignment(
          this,
          token,
          generator,
          value,
          token.stringValue!,
        ),
      );
    }
  }

  void enterLoop(int charOffset) {
    enterBreakTarget(charOffset);
    enterContinueTarget(charOffset);
  }

  void exitLoopOrSwitch(Statement statement) {
    if (problemInLoopOrSwitch != null) {
      push(problemInLoopOrSwitch);
      problemInLoopOrSwitch = null;
    } else {
      push(statement);
    }
  }

  List<VariableDeclaration>? _buildForLoopVariableDeclarations(
    variableOrExpression,
  ) {
    // TODO(ahe): This can be simplified now that we have the events
    // `handleForInitializer...` events.
    if (variableOrExpression is Generator) {
      variableOrExpression = variableOrExpression.buildForEffect();
    }
    if (variableOrExpression is VariableDeclaration) {
      // Late for loop variables are not supported. An error has already been
      // reported by the parser.
      variableOrExpression.isLate = false;
      return <VariableDeclaration>[variableOrExpression];
    } else if (variableOrExpression is Expression) {
      VariableDeclaration variable = new VariableDeclarationImpl.forEffect(
        variableOrExpression,
      );
      return <VariableDeclaration>[variable];
    } else if (variableOrExpression is ExpressionStatement) {
      // Coverage-ignore-block(suite): Not run.
      VariableDeclaration variable = new VariableDeclarationImpl.forEffect(
        variableOrExpression.expression,
      );
      return <VariableDeclaration>[variable];
    } else if (forest.isVariablesDeclaration(variableOrExpression)) {
      return forest.variablesDeclarationExtractDeclarations(
        variableOrExpression,
      );
    } else if (variableOrExpression is List<Object>) {
      // Coverage-ignore-block(suite): Not run.
      List<VariableDeclaration> variables = <VariableDeclaration>[];
      for (Object v in variableOrExpression) {
        variables.addAll(_buildForLoopVariableDeclarations(v)!);
      }
      return variables;
    } else if (variableOrExpression is PatternVariableDeclaration) {
      // Coverage-ignore-block(suite): Not run.
      return <VariableDeclaration>[];
    } else if (variableOrExpression is ParserRecovery) {
      return <VariableDeclaration>[];
    } else if (variableOrExpression == null) {
      return <VariableDeclaration>[];
    }
    return null;
  }

  @override
  void handleForInitializerEmptyStatement(Token token) {
    debugEvent("ForInitializerEmptyStatement");
    push(NullValues.Expression);
    // This is matched by the call to [deferNode] in [endForStatement] or
    // [endForControlFlow].
    typeInferrer.assignedVariables.beginNode();
  }

  @override
  void handleForInitializerExpressionStatement(Token token, bool forIn) {
    debugEvent("ForInitializerExpressionStatement");
    if (!forIn) {
      // This is matched by the call to [deferNode] in [endForStatement] or
      // [endForControlFlow].
      typeInferrer.assignedVariables.beginNode();
    }
  }

  @override
  void handleForInitializerLocalVariableDeclaration(Token token, bool forIn) {
    debugEvent("ForInitializerLocalVariableDeclaration");
    if (forIn) {
      // If the declaration is of the form `for (final x in ...)`, then we may
      // have erroneously set the `isStaticLate` flag, so un-set it.
      Object? declaration = peek();
      if (declaration is VariableDeclarationImpl) {
        declaration.isStaticLate = false;
      }
    } else {
      // This is matched by the call to [deferNode] in [endForStatement] or
      // [endForControlFlow].
      typeInferrer.assignedVariables.beginNode();
    }
  }

  @override
  void handleForInitializerPatternVariableAssignment(
    Token keyword,
    Token equals,
  ) {
    debugEvent("handleForInitializerPatternVariableAssignment");
    assert(
      checkState(keyword, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Pattern,
        ]),
      ]),
    );

    Object expression = pop() as Object;
    Object pattern = pop() as Object;

    if (pattern is Pattern) {
      pop(); // Metadata.
      for (VariableDeclaration variable in pattern.declaredVariables) {
        declareVariable(variable, _localScope);
      }
      LocalScope forScope = _localScope.createNestedScope(
        debugName: "pattern-for internal variables",
        kind: ScopeKind.forStatement,
      );
      exitLocalScope();
      enterLocalScope(forScope);

      bool isFinal = keyword.lexeme == "final";

      // We use intermediate variables to transfer values between the pattern
      // variables and the replacement internal variables. It allows to avoid
      // using the variables with the same name within the same block.
      List<VariableDeclaration> intermediateVariables = [];
      List<VariableDeclaration> internalVariables = [];
      for (VariableDeclaration variable in pattern.declaredVariables) {
        variable.isFinal |= isFinal;

        VariableDeclaration intermediateVariable = forest
            .createVariableDeclarationForValue(
              forest.createVariableGet(variable.fileOffset, variable),
            );
        intermediateVariables.add(intermediateVariable);

        VariableDeclaration internalVariable = forest.createVariableDeclaration(
          variable.fileOffset,
          variable.name!,
          initializer: forest.createVariableGet(
            variable.fileOffset,
            intermediateVariable,
          ),
          isFinal: isFinal,
        );
        internalVariables.add(internalVariable);

        declareVariable(internalVariable, _localScope);
        typeInferrer.assignedVariables.declare(internalVariable);
      }
      push(intermediateVariables);
      push(internalVariables);
      push(
        forest.createPatternVariableDeclaration(
          offsetForToken(keyword),
          pattern,
          toValue(expression),
          isFinal: isFinal,
        ),
      );
    }

    // This is matched by the call to [deferNode] in [endForStatement].
    typeInferrer.assignedVariables.beginNode();
  }

  @override
  void handleForLoopParts(
    Token forKeyword,
    Token leftParen,
    Token leftSeparator,
    Token rightSeparator,
    int updateExpressionCount,
  ) {
    push(forKeyword);
    // TODO(jensj): Seems like leftParen and leftSeparator are just popped and
    // thrown away. If that's the case there's no reason to push them.
    push(leftParen);
    push(leftSeparator);
    push(updateExpressionCount);
  }

  @override
  void endForControlFlow(Token token) {
    assert(
      checkState(token, <ValueKind>[
        /* entry = */ unionOfKinds(<ValueKind>[
          ValueKinds.Generator,
          ValueKinds.ExpressionOrNull,
          ValueKinds.Statement,
          ValueKinds.ParserRecovery,
          ValueKinds.MapLiteralEntry,
        ]),
        /* update expression count = */ ValueKinds.Integer,
        /* left separator = */ ValueKinds.Token,
        /* left parenthesis = */ ValueKinds.Token,
        /* for keyword = */ ValueKinds.Token,
      ]),
    );
    debugEvent("ForControlFlow");
    Object? entry = pop();
    int updateExpressionCount = pop() as int;
    pop(); // left separator
    pop(); // left parenthesis
    Token forToken = pop() as Token;

    assert(
      checkState(token, <ValueKind>[
        /* updates = */ ...repeatedKind(
          unionOfKinds(<ValueKind>[
            ValueKinds.Expression,
            ValueKinds.Generator,
          ]),
          updateExpressionCount,
        ),
        /* condition = */ ValueKinds.Statement,
      ]),
    );
    List<Expression> updates = popListForEffect(updateExpressionCount);
    Statement conditionStatement = popStatement(forToken); // condition

    if (constantContext != ConstantContext.none) {
      pop(); // Pop variable or expression.
      exitLocalScope();
      typeInferrer.assignedVariables.discardNode();

      push(
        buildProblem(
          cfe.codeCantUseControlFlowOrSpreadAsConstant.withArgumentsOld(
            forToken,
          ),
          forToken.charOffset,
          forToken.charCount,
        ),
      );
      return;
    }

    // This is matched by the call to [beginNode] in
    // [handleForInitializerEmptyStatement],
    // [handleForInitializerPatternVariableAssignment],
    // [handleForInitializerExpressionStatement], and
    // [handleForInitializerLocalVariableDeclaration].
    AssignedVariablesNodeInfo assignedVariablesNodeInfo = typeInferrer
        .assignedVariables
        .popNode();

    Object? variableOrExpression = pop();
    List<VariableDeclaration>? variables;
    List<VariableDeclaration>? intermediateVariables;
    if (variableOrExpression is PatternVariableDeclaration) {
      variables = pop() as List<VariableDeclaration>; // Internal variables.
      intermediateVariables = pop() as List<VariableDeclaration>;
    } else {
      variables = _buildForLoopVariableDeclarations(variableOrExpression)!;
    }
    exitLocalScope();

    typeInferrer.assignedVariables.pushNode(assignedVariablesNodeInfo);
    Expression? condition;
    if (conditionStatement is ExpressionStatement) {
      condition = conditionStatement.expression;
    } else {
      assert(conditionStatement is EmptyStatement);
    }
    if (entry is MapLiteralEntry) {
      TreeNode result;
      if (variableOrExpression is PatternVariableDeclaration) {
        result = forest.createPatternForMapEntry(
          offsetForToken(forToken),
          patternVariableDeclaration: variableOrExpression,
          intermediateVariables: intermediateVariables!,
          variables: variables,
          condition: condition,
          updates: updates,
          body: entry,
        );
      } else {
        result = forest.createForMapEntry(
          offsetForToken(forToken),
          variables,
          condition,
          updates,
          entry,
        );
      }
      typeInferrer.assignedVariables.endNode(result);
      push(result);
    } else {
      TreeNode result;
      if (variableOrExpression is PatternVariableDeclaration) {
        result = forest.createPatternForElement(
          offsetForToken(forToken),
          patternVariableDeclaration: variableOrExpression,
          intermediateVariables: intermediateVariables!,
          variables: variables,
          condition: condition,
          updates: updates,
          body: toValue(entry),
        );
      } else {
        result = forest.createForElement(
          offsetForToken(forToken),
          variables,
          condition,
          updates,
          toValue(entry),
        );
      }
      typeInferrer.assignedVariables.endNode(result);
      push(result);
    }
  }

  @override
  void endForStatement(Token endToken) {
    assert(
      checkState(endToken, <ValueKind>[
        /* body */ unionOfKinds([
          ValueKinds.Statement,
          ValueKinds.ParserRecovery,
        ]),
        /* expression count */ ValueKinds.Integer,
        /* left separator */ ValueKinds.Token,
        /* left parenthesis */ ValueKinds.Token,
        /* for keyword */ ValueKinds.Token,
      ]),
    );
    debugEvent("ForStatement");
    Statement body = popStatement(endToken);

    int updateExpressionCount = pop() as int;
    pop(); // Left separator.
    pop(); // Left parenthesis.
    Token forKeyword = pop() as Token;

    assert(
      checkState(endToken, <ValueKind>[
        /* expressions */ ...repeatedKind(
          unionOfKinds(<ValueKind>[
            ValueKinds.Expression,
            ValueKinds.Generator,
          ]),
          updateExpressionCount,
        ),
        /* condition */ ValueKinds.Statement,
        /* variable or expression */ unionOfKinds(<ValueKind>[
          ValueKinds.Generator,
          ValueKinds.ExpressionOrNull,
          ValueKinds.Statement,
          ValueKinds.ObjectList,
          ValueKinds.ParserRecovery,
        ]),
      ]),
    );

    List<Expression> updates = popListForEffect(updateExpressionCount);
    Statement conditionStatement = popStatement(forKeyword);
    // This is matched by the call to [beginNode] in
    // [handleForInitializerEmptyStatement],
    // [handleForInitializerPatternVariableAssignment],
    // [handleForInitializerExpressionStatement], and
    // [handleForInitializerLocalVariableDeclaration].
    AssignedVariablesNodeInfo assignedVariablesNodeInfo = typeInferrer
        .assignedVariables
        .deferNode();

    Object? variableOrExpression = pop();
    List<VariableDeclaration>? variables;
    List<VariableDeclaration>? intermediateVariables;
    if (variableOrExpression is PatternVariableDeclaration) {
      variables = pop() as List<VariableDeclaration>;
      intermediateVariables = pop() as List<VariableDeclaration>;
    } else {
      variables = _buildForLoopVariableDeclarations(variableOrExpression);
    }
    exitLocalScope();
    JumpTarget continueTarget = exitContinueTarget() as JumpTarget;
    JumpTarget breakTarget = exitBreakTarget() as JumpTarget;
    List<BreakStatementImpl>? continueStatements;
    if (continueTarget.hasUsers) {
      LabeledStatement labeledStatement = forest.createLabeledStatement(body);
      continueStatements = continueTarget.resolveContinues(
        forest,
        labeledStatement,
      );
      body = labeledStatement;
    }
    Expression? condition;
    if (conditionStatement is ExpressionStatement) {
      condition = conditionStatement.expression;
    } else {
      assert(conditionStatement is EmptyStatement);
    }
    Statement forStatement = forest.createForStatement(
      offsetForToken(forKeyword),
      variables,
      condition,
      updates,
      body,
    );
    typeInferrer.assignedVariables.storeInfo(
      forStatement,
      assignedVariablesNodeInfo,
    );
    if (continueStatements != null) {
      for (BreakStatementImpl continueStatement in continueStatements) {
        continueStatement.targetStatement = forStatement;
      }
    }
    Statement result = forStatement;
    if (breakTarget.hasUsers) {
      LabeledStatement labeledStatement = forest.createLabeledStatement(result);
      breakTarget.resolveBreaks(forest, labeledStatement, forStatement);
      result = labeledStatement;
    }
    if (variableOrExpression is PatternVariableDeclaration) {
      result = forest.createBlock(
        result.fileOffset,
        result.fileOffset,
        <Statement>[variableOrExpression, ...intermediateVariables!, result],
      );
    }
    if (variableOrExpression is ParserRecovery) {
      problemInLoopOrSwitch ??= buildProblemStatement(
        cfe.codeSyntheticToken,
        variableOrExpression.charOffset,
        errorHasBeenReported: true,
      );
    }
    exitLoopOrSwitch(result);
  }

  @override
  void endAwaitExpression(Token keyword, Token endToken) {
    debugEvent("AwaitExpression");
    int fileOffset = offsetForToken(keyword);
    Expression value = popForValue();
    if (inLateLocalInitializer) {
      push(
        buildProblem(
          cfe.codeAwaitInLateLocalInitializer,
          fileOffset,
          keyword.charCount,
        ),
      );
    } else {
      push(forest.createAwaitExpression(fileOffset, value));
    }
  }

  @override
  void endInvalidAwaitExpression(
    Token keyword,
    Token endToken,
    cfe.MessageCode errorCode,
  ) {
    debugEvent("AwaitExpression");
    popForValue();
    push(buildProblem(errorCode, keyword.offset, keyword.length));
  }

  @override
  void endInvalidYieldStatement(
    Token keyword,
    Token? starToken,
    Token endToken,
    cfe.MessageCode errorCode,
  ) {
    debugEvent("YieldStatement");
    popForValue();
    push(buildProblemStatement(errorCode, keyword.offset));
  }

  @override
  void handleAsyncModifier(Token? asyncToken, Token? starToken) {
    debugEvent("AsyncModifier");
    push(asyncMarkerFromTokens(asyncToken, starToken));
  }

  @override
  void handleLiteralList(
    int count,
    Token leftBracket,
    Token? constKeyword,
    Token rightBracket,
  ) {
    debugEvent("LiteralList");
    assert(
      checkState(leftBracket, [
        ...repeatedKind(
          unionOfKinds([ValueKinds.Generator, ValueKinds.Expression]),
          count,
        ),
        ValueKinds.TypeArgumentsOrNull,
      ]),
    );

    if (constantContext == ConstantContext.required && constKeyword == null) {
      addProblem(
        cfe.codeMissingExplicitConst,
        offsetForToken(leftBracket),
        noLength,
      );
    }

    List<Expression> expressions = popListForValue(count);

    List<TypeBuilder>? typeArguments = pop() as List<TypeBuilder>?;

    DartType typeArgument;
    if (typeArguments != null) {
      if (typeArguments.length > 1) {
        addProblem(
          cfe.codeListLiteralTooManyTypeArguments,
          offsetForToken(leftBracket),
          lengthOfSpan(leftBracket, leftBracket.endGroup),
        );
        typeArgument = const InvalidType();
      } else {
        typeArgument = buildDartType(
          typeArguments.single,
          TypeUse.literalTypeArgument,
          allowPotentiallyConstantType: false,
        );
        typeArgument = instantiateToBounds(typeArgument, coreTypes.objectClass);
      }
    } else {
      typeArgument = implicitTypeArgument;
    }

    ListLiteral node = forest.createListLiteral(
      // TODO(johnniwinther): The file offset computed below will not be
      // correct if there are type arguments but no `const` keyword.
      offsetForToken(constKeyword ?? leftBracket),
      typeArgument,
      expressions,
      isConst:
          constKeyword != null || constantContext == ConstantContext.inferred,
    );
    push(node);
  }

  @override
  void handleListPattern(int count, Token leftBracket, Token rightBracket) {
    debugEvent("ListPattern");
    assert(
      checkState(leftBracket, [
        ...repeatedKind(
          unionOfKinds([
            ValueKinds.Generator,
            ValueKinds.Expression,
            ValueKinds.Pattern,
          ]),
          count,
        ),
        ValueKinds.TypeArgumentsOrNull,
      ]),
    );

    reportIfNotEnabled(
      libraryFeatures.patterns,
      leftBracket.charOffset,
      leftBracket.charCount,
    );

    List<Pattern> patterns = new List<Pattern>.filled(
      count,
      dummyPattern,
      growable: true,
    );
    for (int i = count - 1; i >= 0; i--) {
      patterns[i] = toPattern(pop());
    }
    List<TypeBuilder>? typeArguments = pop() as List<TypeBuilder>?;
    DartType? typeArgument;
    if (typeArguments != null) {
      if (typeArguments.length > 1) {
        addProblem(
          cfe.codeListPatternTooManyTypeArguments,
          offsetForToken(leftBracket),
          lengthOfSpan(leftBracket, leftBracket.endGroup),
        );
        typeArgument = const InvalidType();
      } else {
        typeArgument = buildDartType(
          typeArguments.single,
          TypeUse.literalTypeArgument,
          allowPotentiallyConstantType: false,
        );
        typeArgument = instantiateToBounds(typeArgument, coreTypes.objectClass);
      }
    }

    push(
      forest.createListPattern(leftBracket.charOffset, typeArgument, patterns),
    );
  }

  @override
  void endRecordLiteral(Token token, int count, Token? constKeyword) {
    debugEvent("RecordLiteral");
    assert(
      checkState(
        token,
        repeatedKind(
          unionOfKinds([
            ValueKinds.Generator,
            ValueKinds.Expression,
            ValueKinds.NamedExpression,
            ValueKinds.ParserRecovery,
          ]),
          count,
        ),
      ),
    );

    reportIfNotEnabled(
      libraryFeatures.records,
      token.charOffset,
      token.charCount,
    );

    // Pop all elements. This will put them in evaluation order.
    List<Object?>? elements = const FixedNullableList<Object>().pop(
      stack,
      count,
    );

    List<Object> originalElementOrder = [];
    List<Expression> positional = [];
    List<NamedExpression> named = [];
    Map<String, NamedExpression>? namedElements;
    const List<String> forbiddenObjectMemberNames = [
      "noSuchMethod",
      "toString",
      "hashCode",
      "runtimeType",
    ];
    if (elements != null) {
      for (Object? element in elements) {
        if (element is NamedExpression) {
          if (forbiddenObjectMemberNames.contains(element.name)) {
            libraryBuilder.addProblem(
              cfe.codeObjectMemberNameUsedForRecordField,
              element.fileOffset,
              element.name.length,
              uri,
            );
          }
          if (element.name.startsWith("_")) {
            libraryBuilder.addProblem(
              cfe.codeRecordFieldsCantBePrivate,
              element.fileOffset,
              element.name.length,
              uri,
            );
          }
          namedElements ??= {};
          NamedExpression? existingExpression = namedElements[element.name];
          if (existingExpression != null) {
            existingExpression.value = buildProblem(
              codeDuplicatedRecordLiteralFieldName.withArgumentsOld(
                element.name,
              ),
              element.fileOffset,
              element.name.length,
              context: [
                codeDuplicatedRecordLiteralFieldNameContext
                    .withArgumentsOld(element.name)
                    .withLocation(
                      uri,
                      existingExpression.fileOffset,
                      element.name.length,
                    ),
              ],
            )..parent = existingExpression;
          } else {
            originalElementOrder.add(element);
            namedElements[element.name] = element;
            named.add(element);
          }
        } else {
          Expression expression = toValue(element);
          positional.add(expression);
          originalElementOrder.add(expression);
        }
      }
      if (namedElements != null) {
        for (NamedExpression element in namedElements.values) {
          if (tryParseRecordPositionalGetterName(
                element.name,
                positional.length,
              ) !=
              null) {
            libraryBuilder.addProblem(
              codeNamedFieldClashesWithPositionalFieldInRecord,
              element.fileOffset,
              element.name.length,
              uri,
            );
          }
        }
      }
    }

    push(
      new InternalRecordLiteral(
        positional,
        named,
        namedElements,
        originalElementOrder,
        isConst:
            constKeyword != null || constantContext == ConstantContext.inferred,
        offset: token.offset,
      ),
    );
  }

  @override
  void handleRecordPattern(Token token, int count) {
    debugEvent("RecordPattern");
    assert(
      checkState(
        token,
        repeatedKind(
          unionOfKinds([
            ValueKinds.Generator,
            ValueKinds.Expression,
            ValueKinds.NamedExpression,
            ValueKinds.Pattern,
          ]),
          count,
        ),
      ),
    );

    reportIfNotEnabled(
      libraryFeatures.patterns,
      token.charOffset,
      token.charCount,
    );

    List<Pattern> patterns = new List<Pattern>.filled(count, dummyPattern);
    for (int i = count - 1; i >= 0; i--) {
      patterns[i] = toPattern(pop());
    }
    push(forest.createRecordPattern(token.charOffset, patterns));
  }

  void buildLiteralSet(
    List<TypeBuilder>? typeArguments,
    Token? constKeyword,
    Token leftBrace,
    List<dynamic>? setOrMapEntries,
  ) {
    DartType typeArgument;
    if (typeArguments != null) {
      typeArgument = buildDartType(
        typeArguments.single,
        TypeUse.literalTypeArgument,
        allowPotentiallyConstantType: false,
      );
      typeArgument = instantiateToBounds(typeArgument, coreTypes.objectClass);
    } else {
      typeArgument = implicitTypeArgument;
    }

    List<Expression> expressions = <Expression>[];
    if (setOrMapEntries != null) {
      for (dynamic entry in setOrMapEntries) {
        if (entry is MapLiteralEntry) {
          // TODO(danrubel): report the error on the colon
          addProblem(
            cfe.codeExpectedButGot.withArgumentsOld(','),
            entry.fileOffset,
            1,
          );
        } else {
          // TODO(danrubel): Revise once control flow and spread
          //  collection entries are supported.
          expressions.add(entry as Expression);
        }
      }
    }

    SetLiteral node = forest.createSetLiteral(
      // TODO(johnniwinther): The file offset computed below will not be
      // correct if there are type arguments but no `const` keyword.
      offsetForToken(constKeyword ?? leftBrace),
      typeArgument,
      expressions,
      isConst:
          constKeyword != null || constantContext == ConstantContext.inferred,
    );
    push(node);
  }

  @override
  void handleLiteralSetOrMap(
    int count,
    Token leftBrace,
    Token? constKeyword,
    Token rightBrace,
    // TODO(danrubel): hasSetEntry parameter exists for replicating existing
    // behavior and will be removed once unified collection has been enabled
    bool hasSetEntry,
  ) {
    debugEvent("LiteralSetOrMap");
    assert(
      checkState(leftBrace, [
        ...repeatedKind(
          unionOfKinds([
            ValueKinds.Expression,
            ValueKinds.Generator,
            ValueKinds.MapLiteralEntry,
          ]),
          count,
        ),
        ValueKinds.TypeArgumentsOrNull,
      ]),
    );

    if (constantContext == ConstantContext.required && constKeyword == null) {
      addProblem(
        cfe.codeMissingExplicitConst,
        offsetForToken(leftBrace),
        noLength,
      );
    }

    List<dynamic> setOrMapEntries = new List<dynamic>.filled(
      count,
      null,
      growable: true,
    );
    for (int i = count - 1; i >= 0; i--) {
      Object? elem = pop();
      if (elem is MapLiteralEntry) {
        setOrMapEntries[i] = elem;
      } else {
        setOrMapEntries[i] = toValue(elem);
      }
    }
    List<TypeBuilder>? typeArguments = pop() as List<TypeBuilder>?;

    // Replicate existing behavior that has been removed from the parser.
    // This will be removed once unified collections is implemented.

    // Determine if this is a set or map based on type args and content
    // TODO(danrubel): Since type resolution is needed to disambiguate
    // set or map in some situations, consider always deferring determination
    // until the type resolution phase.
    final int? typeArgCount = typeArguments?.length;
    bool? isSet = typeArgCount == 1
        ? true
        : typeArgCount != null
        ? false
        : null;

    for (int i = 0; i < setOrMapEntries.length; ++i) {
      if (setOrMapEntries[i] is! MapLiteralEntry &&
          !isConvertibleToMapEntry(setOrMapEntries[i])) {
        hasSetEntry = true;
      }
    }

    // TODO(danrubel): If the type arguments are not known (null) then
    // defer set/map determination until after type resolution as per the
    // unified collection spec: https://github.com/dart-lang/language/pull/200
    // rather than trying to guess as done below.
    isSet ??= hasSetEntry;

    if (isSet) {
      buildLiteralSet(typeArguments, constKeyword, leftBrace, setOrMapEntries);
    } else {
      List<MapLiteralEntry> mapEntries = new List<MapLiteralEntry>.filled(
        setOrMapEntries.length,
        dummyMapLiteralEntry,
      );
      for (int i = 0; i < setOrMapEntries.length; ++i) {
        if (setOrMapEntries[i] is MapLiteralEntry) {
          mapEntries[i] = setOrMapEntries[i];
        } else {
          mapEntries[i] = convertToMapEntry(
            setOrMapEntries[i],
            this,
            typeInferrer.assignedVariables.reassignInfo,
          );
        }
      }
      buildLiteralMap(typeArguments, constKeyword, leftBrace, mapEntries);
    }
  }

  @override
  void handleMapPatternEntry(Token colon, Token endToken) {
    debugEvent('MapPatternEntry');
    assert(
      checkState(colon, [
        /* value */ unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Pattern,
        ]),
        /* key */ unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
      ]),
    );
    Pattern value = toPattern(pop());
    Expression key = toValue(pop());
    push(forest.createMapPatternEntry(colon.charOffset, key, value));
  }

  @override
  void handleMapPattern(int count, Token leftBrace, Token rightBrace) {
    debugEvent('MapPattern');
    assert(
      checkState(leftBrace, [
        ...repeatedKind(
          unionOfKinds([ValueKinds.MapPatternEntry, ValueKinds.Pattern]),
          count,
        ),
        ValueKinds.TypeArgumentsOrNull,
      ]),
    );

    reportIfNotEnabled(
      libraryFeatures.patterns,
      leftBrace.charOffset,
      leftBrace.charCount,
    );
    List<MapPatternEntry> entries = <MapPatternEntry>[];
    for (int i = 0; i < count; i++) {
      Object? entry = pop();
      if (entry is MapPatternEntry) {
        entries.add(entry);
      } else {
        entry as RestPattern;
        entries.add(forest.createMapPatternRestEntry(entry.fileOffset));
      }
    }

    for (int i = 0, j = entries.length - 1; i < j; i++, j--) {
      MapPatternEntry entry = entries[i];
      entries[i] = entries[j];
      entries[j] = entry;
    }

    List<TypeBuilder>? typeArguments = pop() as List<TypeBuilder>?;
    DartType? keyType;
    DartType? valueType;
    if (typeArguments != null) {
      if (typeArguments.length != 2) {
        keyType = const InvalidType();
        valueType = const InvalidType();
        addProblem(
          cfe.codeMapPatternTypeArgumentMismatch,
          leftBrace.charOffset,
          noLength,
        );
      } else {
        keyType = buildDartType(
          typeArguments[0],
          TypeUse.literalTypeArgument,
          allowPotentiallyConstantType: false,
        );
        valueType = buildDartType(
          typeArguments[1],
          TypeUse.literalTypeArgument,
          allowPotentiallyConstantType: false,
        );
        keyType = instantiateToBounds(keyType, coreTypes.objectClass);
        valueType = instantiateToBounds(valueType, coreTypes.objectClass);
      }
    }

    push(
      forest.createMapPattern(
        leftBrace.charOffset,
        keyType,
        valueType,
        entries,
      ),
    );
  }

  @override
  void handleLiteralBool(Token token) {
    debugEvent("LiteralBool");
    bool value = boolFromToken(token);
    push(forest.createBoolLiteral(offsetForToken(token), value));
  }

  @override
  void handleLiteralDouble(Token token) {
    debugEvent("LiteralDouble");
    push(
      forest.createDoubleLiteral(
        offsetForToken(token),
        doubleFromToken(token, hasSeparators: false),
      ),
    );
  }

  @override
  void handleLiteralDoubleWithSeparators(Token token) {
    debugEvent("LiteralDoubleWithSeparators");

    if (!libraryFeatures.digitSeparators.isEnabled) {
      addProblem(
        codeExperimentNotEnabledOffByDefault.withArgumentsOld(
          ExperimentalFlag.digitSeparators.name,
        ),
        token.offset,
        token.length,
      );
    }

    double value = doubleFromToken(token, hasSeparators: true);
    push(forest.createDoubleLiteral(offsetForToken(token), value));
  }

  @override
  void handleLiteralNull(Token token) {
    debugEvent("LiteralNull");
    push(forest.createNullLiteral(offsetForToken(token)));
  }

  void buildLiteralMap(
    List<TypeBuilder>? typeArguments,
    Token? constKeyword,
    Token leftBrace,
    List<MapLiteralEntry> entries,
  ) {
    DartType keyType;
    DartType valueType;
    if (typeArguments != null) {
      if (typeArguments.length != 2) {
        keyType = const InvalidType();
        valueType = const InvalidType();
      } else {
        keyType = buildDartType(
          typeArguments[0],
          TypeUse.literalTypeArgument,
          allowPotentiallyConstantType: false,
        );
        valueType = buildDartType(
          typeArguments[1],
          TypeUse.literalTypeArgument,
          allowPotentiallyConstantType: false,
        );
        keyType = instantiateToBounds(keyType, coreTypes.objectClass);
        valueType = instantiateToBounds(valueType, coreTypes.objectClass);
      }
    } else {
      keyType = implicitTypeArgument;
      valueType = implicitTypeArgument;
    }

    MapLiteral node = forest.createMapLiteral(
      // TODO(johnniwinther): The file offset computed below will not be
      // correct if there are type arguments but no `const` keyword.
      offsetForToken(constKeyword ?? leftBrace),
      keyType,
      valueType,
      entries,
      isConst:
          constKeyword != null || constantContext == ConstantContext.inferred,
    );
    push(node);
  }

  @override
  void handleLiteralMapEntry(
    Token colon,
    Token endToken, {
    Token? nullAwareKeyToken,
    Token? nullAwareValueToken,
  }) {
    debugEvent("LiteralMapEntry");
    Expression value = popForValue();
    Expression key = popForValue();
    if (nullAwareKeyToken == null && nullAwareValueToken == null) {
      push(forest.createMapEntry(offsetForToken(colon), key, value));
    } else {
      if (!libraryFeatures.nullAwareElements.isEnabled) {
        // Coverage-ignore-block(suite): Not run.
        addProblem(
          codeExperimentNotEnabledOffByDefault.withArgumentsOld(
            ExperimentalFlag.nullAwareElements.name,
          ),
          (nullAwareKeyToken ?? nullAwareValueToken!).offset,
          noLength,
        );
      }
      push(
        forest.createNullAwareMapEntry(
          offsetForToken(colon),
          isKeyNullAware: nullAwareKeyToken != null,
          key: key,
          isValueNullAware: nullAwareValueToken != null,
          value: value,
        ),
      );
    }
  }

  String symbolPartToString(name) {
    if (name is Identifier) {
      return name.name;
    } else if (name is Operator) {
      return name.name;
    } else {
      return unhandled("${name.runtimeType}", "symbolPartToString", -1, uri);
    }
  }

  @override
  void endLiteralSymbol(Token hashToken, int identifierCount) {
    debugEvent("LiteralSymbol");
    if (identifierCount == 1) {
      Object? part = pop();
      if (part is ParserRecovery) {
        push(new ParserErrorGenerator(this, hashToken, cfe.codeSyntheticToken));
      } else {
        push(
          forest.createSymbolLiteral(
            offsetForToken(hashToken),
            symbolPartToString(part),
          ),
        );
      }
    } else {
      List<Identifier>? parts = const FixedNullableList<Identifier>()
          .popNonNullable(stack, identifierCount, dummyIdentifier);
      if (parts == null) {
        // Coverage-ignore-block(suite): Not run.
        push(new ParserErrorGenerator(this, hashToken, cfe.codeSyntheticToken));
        return;
      }
      String value = symbolPartToString(parts.first);
      for (int i = 1; i < parts.length; i++) {
        value += ".${symbolPartToString(parts[i])}";
      }
      push(forest.createSymbolLiteral(offsetForToken(hashToken), value));
    }
  }

  @override
  void handleNonNullAssertExpression(Token bang) {
    assert(
      checkState(bang, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Initializer,
        ]),
      ]),
    );
    Expression operand = popForValue();
    push(forest.createNullCheck(offsetForToken(bang), operand));
  }

  @override
  void handleType(Token beginToken, Token? questionMark) {
    // TODO(ahe): The scope is wrong for return types of generic functions.
    debugEvent("Type");
    assert(
      checkState(beginToken, [
        ValueKinds.TypeArgumentsOrNull,
        unionOfKinds([ValueKinds.QualifiedName, ValueKinds.Generator]),
      ]),
    );

    bool isMarkedAsNullable = questionMark != null;
    List<TypeBuilder>? arguments = pop() as List<TypeBuilder>?;
    Object? name = pop();

    // Coverage-ignore(suite): Not run.
    void errorCase(String name, Token suffix) {
      String displayName = debugName(name, suffix.lexeme);
      int offset = offsetForToken(beginToken);
      Message message = cfe.codeNotAType.withArgumentsOld(displayName);
      libraryBuilder.addProblem(
        message,
        offset,
        lengthOfSpan(beginToken, suffix),
        uri,
      );
      push(
        new NamedTypeBuilderImpl.forInvalidType(
          name,
          isMarkedAsNullable
              ? const NullabilityBuilder.nullable()
              : const NullabilityBuilder.omitted(),
          message.withLocation(uri, offset, lengthOfSpan(beginToken, suffix)),
        ),
      );
    }

    if (name is QualifiedName) {
      QualifiedName qualified = name;
      switch (qualified) {
        case QualifiedNameGenerator():
          Generator prefix = qualified.qualifier;
          Token suffix = qualified.suffix;
          if (prefix is ParserErrorGenerator) {
            // An error have already been issued.
            push(
              prefix.buildTypeWithResolvedArgumentsDoNotAddProblem(
                isMarkedAsNullable
                    ? const NullabilityBuilder.nullable()
                    : const NullabilityBuilder.omitted(),
              ),
            );
            return;
          } else {
            name = prefix.qualifiedLookup(suffix);
          }
        // Coverage-ignore(suite): Not run.
        case QualifiedNameBuilder():
          errorCase(qualified.qualifier.fullNameForErrors, qualified.suffix);
          return;
        // Coverage-ignore(suite): Not run.
        case QualifiedNameIdentifier():
          unhandled(
            "qualified is ${qualified.runtimeType}",
            "handleType",
            qualified.charOffset,
            uri,
          );
      }
    }
    TypeBuilder result;
    if (name is Generator) {
      bool allowPotentiallyConstantType;
      if (libraryFeatures.constructorTearoffs.isEnabled) {
        allowPotentiallyConstantType = true;
      } else {
        allowPotentiallyConstantType = inIsOrAsOperatorType;
      }
      result = name.buildTypeWithResolvedArguments(
        isMarkedAsNullable
            ? const NullabilityBuilder.nullable()
            : const NullabilityBuilder.omitted(),
        arguments,
        allowPotentiallyConstantType: allowPotentiallyConstantType,
        performTypeCanonicalization: constantContext != ConstantContext.none,
      );
    } else {
      unhandled(
        "${name.runtimeType}",
        "handleType",
        beginToken.charOffset,
        uri,
      );
    }
    push(result);
  }

  @override
  void beginFunctionType(Token beginToken) {
    debugEvent("beginFunctionType");
    _structuralParameterDepthLevel++;
  }

  void enterNominalVariablesScope(
    List<NominalParameterBuilder>? nominalVariableBuilders,
  ) {
    debugEvent("enterNominalVariableScope");
    Map<String, TypeParameterBuilder> typeParameters = {};
    if (nominalVariableBuilders != null) {
      for (NominalParameterBuilder builder in nominalVariableBuilders) {
        if (builder.isWildcard) continue;
        String name = builder.name;
        TypeParameterBuilder? existing = typeParameters[name];
        if (existing == null) {
          typeParameters[name] = builder;
        } else {
          // Coverage-ignore-block(suite): Not run.
          reportDuplicatedDeclaration(existing, name, builder.fileOffset);
        }
      }
    }
    enterLocalScope(
      new LocalTypeParameterScope(
        local: typeParameters,
        parent: _localScope,
        debugName: "local function type parameter scope",
        kind: ScopeKind.typeParameters,
      ),
    );
  }

  void enterStructuralVariablesScope(
    List<StructuralParameterBuilder>? structuralVariableBuilders,
  ) {
    debugEvent("enterStructuralVariableScope");
    Map<String, TypeParameterBuilder> typeParameters = {};
    if (structuralVariableBuilders != null) {
      for (StructuralParameterBuilder builder in structuralVariableBuilders) {
        if (builder.isWildcard) continue;
        String name = builder.name;
        TypeParameterBuilder? existing = typeParameters[name];
        if (existing == null) {
          typeParameters[name] = builder;
        } else {
          // Coverage-ignore-block(suite): Not run.
          reportDuplicatedDeclaration(existing, name, builder.fileOffset);
        }
      }
    }
    enterLocalScope(
      new LocalTypeParameterScope(
        local: typeParameters,
        parent: _localScope,
        debugName: "function-type scope",
        kind: ScopeKind.typeParameters,
      ),
    );
  }

  @override
  void endRecordType(
    Token leftBracket,
    Token? questionMark,
    int count,
    bool hasNamedFields,
  ) {
    debugEvent("RecordType");
    assert(
      checkState(leftBracket, [
        if (hasNamedFields) ValueKinds.RecordTypeFieldBuilderListOrNull,
        ...repeatedKind(
          ValueKinds.RecordTypeFieldBuilder,
          hasNamedFields ? count - 1 : count,
        ),
      ]),
    );

    if (!libraryFeatures.records.isEnabled) {
      addProblem(
        codeExperimentNotEnabledOffByDefault.withArgumentsOld(
          ExperimentalFlag.records.name,
        ),
        leftBracket.offset,
        noLength,
      );
    }

    List<RecordTypeFieldBuilder>? namedFields;
    if (hasNamedFields) {
      namedFields =
          pop(NullValues.RecordTypeFieldList) as List<RecordTypeFieldBuilder>?;
    }
    List<RecordTypeFieldBuilder>? positionalFields =
        const FixedNullableList<RecordTypeFieldBuilder>().popNonNullable(
          stack,
          hasNamedFields ? count - 1 : count,
          dummyRecordTypeFieldBuilder,
        );

    push(
      new RecordTypeBuilderImpl(
        positionalFields,
        namedFields,
        questionMark != null
            ? const NullabilityBuilder.nullable()
            : const NullabilityBuilder.omitted(),
        uri,
        leftBracket.charOffset,
      ),
    );
  }

  @override
  void endRecordTypeEntry() {
    debugEvent("RecordTypeEntry");
    assert(
      checkState(null, [
        unionOfKinds([ValueKinds.IdentifierOrNull, ValueKinds.ParserRecovery]),
        unionOfKinds([ValueKinds.TypeBuilder, ValueKinds.ParserRecovery]),
        ValueKinds.AnnotationListOrNull,
      ]),
    );

    Object? name = pop();
    Object? type = pop();
    // TODO(johnniwinther): How should we handle annotations?
    pop(NullValues.Metadata); // Annotations.

    String? fieldName = name is Identifier ? name.name : null;
    push(
      new RecordTypeFieldBuilder(
        [],
        type is ParserRecovery
            ?
              // Coverage-ignore(suite): Not run.
              new InvalidTypeBuilderImpl(uri, type.charOffset)
            : type as TypeBuilder,
        fieldName,
        name is Identifier ? name.nameOffset : TreeNode.noOffset,
        isWildcard:
            libraryFeatures.wildcardVariables.isEnabled && fieldName == '_',
      ),
    );
  }

  @override
  void endRecordTypeNamedFields(int count, Token leftBracket) {
    debugEvent("RecordTypeNamedFields");
    assert(
      checkState(leftBracket, [
        ...repeatedKind(ValueKinds.RecordTypeFieldBuilder, count),
      ]),
    );
    List<RecordTypeFieldBuilder>? fields =
        const FixedNullableList<RecordTypeFieldBuilder>().popNonNullable(
          stack,
          count,
          dummyRecordTypeFieldBuilder,
        );
    push(fields ?? NullValues.RecordTypeFieldList);
  }

  @override
  void endFunctionType(Token functionToken, Token? questionMark) {
    debugEvent("FunctionType");
    _structuralParameterDepthLevel--;
    FunctionTypeParameters parameters = pop() as FunctionTypeParameters;
    TypeBuilder? returnType = pop() as TypeBuilder?;
    List<StructuralParameterBuilder>? typeParameters =
        pop() as List<StructuralParameterBuilder>?;
    TypeBuilder type = parameters.toFunctionType(
      returnType ?? const ImplicitTypeBuilder(),
      questionMark != null
          ? const NullabilityBuilder.nullable()
          : const NullabilityBuilder.omitted(),
      structuralVariableBuilders: typeParameters,
      hasFunctionFormalParameterSyntax: false,
    );
    exitLocalScope();
    push(type);
  }

  @override
  void handleVoidKeyword(Token token) {
    debugEvent("VoidKeyword");
    int offset = offsetForToken(token);
    push(new VoidTypeBuilder(uri, offset));
  }

  @override
  // Coverage-ignore(suite): Not run.
  void handleVoidKeywordWithTypeArguments(Token token) {
    assert(
      checkState(token, <ValueKind>[
        /* arguments */ ValueKinds.TypeArgumentsOrNull,
      ]),
    );

    debugEvent("handleVoidKeywordWithTypeArguments");
    pop(); // arguments.
    handleVoidKeyword(token);
  }

  @override
  void beginAsOperatorType(Token operator) {
    _isOrAsOperatorTypeState = _isOrAsOperatorTypeState.prepend(true);
  }

  @override
  void endAsOperatorType(Token operator) {
    _isOrAsOperatorTypeState = _isOrAsOperatorTypeState.tail!;
  }

  @override
  void handleAsOperator(Token operator) {
    debugEvent("AsOperator");
    assert(
      checkState(operator, [
        ValueKinds.TypeBuilder,
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
      ]),
    );
    DartType type = buildDartType(
      pop() as TypeBuilder,
      TypeUse.asType,
      allowPotentiallyConstantType: true,
    );
    Expression expression = popForValue();
    Expression asExpression = forest.createAsExpression(
      offsetForToken(operator),
      expression,
      type,
    );
    push(asExpression);
  }

  @override
  void handleCastPattern(Token operator) {
    debugEvent('CastPattern');
    assert(
      checkState(operator, [
        ValueKinds.TypeBuilder,
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Pattern,
        ]),
      ]),
    );
    reportIfNotEnabled(
      libraryFeatures.patterns,
      operator.charOffset,
      operator.charCount,
    );
    DartType type = buildDartType(
      pop() as TypeBuilder,
      TypeUse.asType,
      allowPotentiallyConstantType: true,
    );
    Pattern operand = toPattern(pop());
    push(forest.createCastPattern(operator.charOffset, operand, type));
  }

  @override
  void beginIsOperatorType(Token operator) {
    _isOrAsOperatorTypeState = _isOrAsOperatorTypeState.prepend(true);
  }

  @override
  void endIsOperatorType(Token operator) {
    _isOrAsOperatorTypeState = _isOrAsOperatorTypeState.tail!;
  }

  @override
  void handleIsOperator(Token isOperator, Token? not) {
    debugEvent("IsOperator");
    DartType type = buildDartType(
      pop() as TypeBuilder,
      TypeUse.isType,
      allowPotentiallyConstantType: true,
    );
    Expression operand = popForValue();
    Expression isExpression = forest.createIsExpression(
      offsetForToken(isOperator),
      operand,
      type,
      notFileOffset: not != null ? offsetForToken(not) : null,
    );
    push(isExpression);
  }

  @override
  void beginConditionalExpression(Token question) {
    Expression condition = popForValue();
    // This is matched by the call to [deferNode] in
    // [handleConditionalExpressionColon].
    typeInferrer.assignedVariables.beginNode();
    push(condition);
    super.beginConditionalExpression(question);
  }

  @override
  void handleConditionalExpressionColon() {
    Expression then = popForValue();
    // This is matched by the call to [beginNode] in
    // [beginConditionalExpression] and by the call to [storeInfo] in
    // [endConditionalExpression].
    push(typeInferrer.assignedVariables.deferNode());
    push(then);
    super.handleConditionalExpressionColon();
  }

  @override
  void endConditionalExpression(Token question, Token colon, Token endToken) {
    debugEvent("ConditionalExpression");
    Expression elseExpression = popForValue();
    Expression thenExpression = pop() as Expression;
    AssignedVariablesNodeInfo assignedVariablesInfo =
        pop() as AssignedVariablesNodeInfo;
    Expression condition = pop() as Expression;
    Expression node = forest.createConditionalExpression(
      offsetForToken(question),
      condition,
      thenExpression,
      elseExpression,
    );
    push(node);
    // This is matched by the call to [deferNode] in
    // [handleConditionalExpressionColon].
    typeInferrer.assignedVariables.storeInfo(node, assignedVariablesInfo);
  }

  @override
  void handleThrowExpression(Token throwToken, Token endToken) {
    debugEvent("ThrowExpression");
    Expression expression = popForValue();
    if (constantContext != ConstantContext.none) {
      push(
        buildProblem(
          cfe.codeNotConstantExpression.withArgumentsOld('Throw'),
          throwToken.offset,
          throwToken.length,
        ),
      );
    } else {
      push(forest.createThrow(offsetForToken(throwToken), expression));
    }
  }

  @override
  void beginFormalParameter(
    Token token,
    MemberKind kind,
    Token? requiredToken,
    Token? covariantToken,
    Token? varFinalOrConst,
  ) {
    _insideOfFormalParameterType = true;
    push(
      Modifiers.from(
        requiredToken: requiredToken,
        covariantToken: covariantToken,
        varFinalOrConst: varFinalOrConst,
      ),
    );
    push(varFinalOrConst ?? NullValues.Token);
  }

  @override
  void endFormalParameter(
    Token? thisKeyword,
    Token? superKeyword,
    Token? periodAfterThisOrSuper,
    Token nameToken,
    Token? initializerStart,
    Token? initializerEnd,
    FormalParameterKind kind,
    MemberKind memberKind,
  ) {
    debugEvent("FormalParameter");

    _insideOfFormalParameterType = false;

    if (thisKeyword != null) {
      if (!inConstructor) {
        handleRecoverableError(
          cfe.codeFieldInitializerOutsideConstructor,
          thisKeyword,
          thisKeyword,
        );
        thisKeyword = null;
      }
    }
    if (superKeyword != null) {
      if (!inConstructor) {
        handleRecoverableError(
          cfe.codeSuperParameterInitializerOutsideConstructor,
          superKeyword,
          superKeyword,
        );
        superKeyword = null;
      }
    }
    Object? nameNode = pop();
    TypeBuilder? type = pop() as TypeBuilder?;
    Token? varOrFinalOrConst = pop(NullValues.Token) as Token?;
    if (superKeyword != null &&
        varOrFinalOrConst != null &&
        varOrFinalOrConst.isA(Keyword.VAR)) {
      handleRecoverableError(
        cfe.codeExtraneousModifier.withArgumentsOld(varOrFinalOrConst),
        varOrFinalOrConst,
        varOrFinalOrConst,
      );
    }
    Modifiers modifiers = pop() as Modifiers;
    if (inCatchClause) {
      modifiers |= Modifiers.Final;
    }
    List<Expression>? annotations = pop() as List<Expression>?;
    if (nameNode is ParserRecovery) {
      push(nameNode);
      return;
    }
    Identifier? name = nameNode as Identifier?;
    FormalParameterBuilder? parameter;
    if (!inCatchClause &&
        functionNestingLevel == 0 &&
        memberKind != MemberKind.GeneralizedFunctionType) {
      parameter = _context.getFormalParameterByName(name!);

      if (parameter == null) {
        // This happens when the list of formals (originally) contains a
        // ParserRecovery - then the popped list becomes null.
        push(new ParserRecovery(nameToken.charOffset));
        return;
      }
    } else {
      String parameterName = name?.name ?? '';
      bool isWildcard =
          libraryFeatures.wildcardVariables.isEnabled && parameterName == '_';
      if (isWildcard) {
        parameterName = createWildcardFormalParameterName(
          wildcardVariableIndex,
        );
        wildcardVariableIndex++;
      }
      if (memberKind.isFunctionType) {
        push(
          new FunctionTypeParameterBuilder(
            kind,
            type ?? const ImplicitTypeBuilder(),
            parameterName,
          ),
        );
        return;
      }
      parameter = new FormalParameterBuilder(
        kind,
        modifiers,
        type ?? const ImplicitTypeBuilder(),
        parameterName,
        offsetForToken(nameToken),
        fileUri: uri,
        hasImmediatelyDeclaredInitializer: initializerStart != null,
        isWildcard: isWildcard,
      );
    }
    VariableDeclaration variable = parameter.build(libraryBuilder);
    Expression? initializer = name?.initializer;
    if (initializer != null) {
      if (_context.isRedirectingFactory) {
        addProblem(
          cfe.codeDefaultValueInRedirectingFactoryConstructor.withArgumentsOld(
            _context.redirectingFactoryTargetName,
          ),
          initializer.fileOffset,
          noLength,
        );
        variable.isErroneouslyInitialized = true;
      } else {
        if (!parameter.initializerWasInferred) {
          variable.initializer = initializer..parent = variable;
        }
      }
    } else if (kind.isOptional) {
      variable.initializer ??= forest.createNullLiteral(noLocation)
        ..parent = variable;
    }
    if (annotations != null) {
      if (functionNestingLevel == 0) {
        inferAnnotations(variable, annotations);
      }
      variable.clearAnnotations();
      for (Expression annotation in annotations) {
        variable.addAnnotation(annotation);
      }
    }
    push(parameter);
    // We pass `ignoreDuplicates: true` because the variable might have been
    // previously passed to `declare` in the `BodyBuilder` constructor.
    typeInferrer.assignedVariables.declare(variable, ignoreDuplicates: true);
  }

  @override
  void endOptionalFormalParameters(
    int count,
    Token beginToken,
    Token endToken,
    MemberKind kind,
  ) {
    debugEvent("OptionalFormalParameters");
    // When recovering from an empty list of optional arguments, count may be
    // 0. It might be simpler if the parser didn't call this method in that
    // case, however, then [beginOptionalFormalParameters] wouldn't always be
    // matched by this method.
    if (kind.isFunctionType) {
      List<FunctionTypeParameterBuilder>? parameters =
          const FixedNullableList<FunctionTypeParameterBuilder>()
              .popNonNullable(stack, count, dummyFunctionTypeParameterBuilder);
      if (parameters == null) {
        push(new ParserRecovery(offsetForToken(beginToken)));
      } else {
        push(parameters);
      }
    } else {
      List<FormalParameterBuilder>? parameters =
          const FixedNullableList<FormalParameterBuilder>().popNonNullable(
            stack,
            count,
            dummyFormalParameterBuilder,
          );
      if (parameters == null) {
        push(new ParserRecovery(offsetForToken(beginToken)));
      } else {
        push(parameters);
      }
    }
  }

  @override
  void beginFunctionTypedFormalParameter(Token token) {
    debugEvent("beginFunctionTypedFormalParameter");
    _insideOfFormalParameterType = false;
    functionNestingLevel++;
  }

  @override
  void endFunctionTypedFormalParameter(Token nameToken, Token? question) {
    debugEvent("FunctionTypedFormalParameter");
    if (inCatchClause || functionNestingLevel != 0) {
      exitLocalScope();
    }
    FunctionTypeParameters parameters = pop() as FunctionTypeParameters;
    TypeBuilder? returnType = pop() as TypeBuilder?;
    List<StructuralParameterBuilder>? typeParameters =
        pop() as List<StructuralParameterBuilder>?;
    TypeBuilder type = parameters.toFunctionType(
      returnType ?? const ImplicitTypeBuilder(),
      question != null
          ? const NullabilityBuilder.nullable()
          : const NullabilityBuilder.omitted(),
      structuralVariableBuilders: typeParameters,
      hasFunctionFormalParameterSyntax: true,
    );
    push(type);
    functionNestingLevel--;
  }

  @override
  void beginFormalParameterDefaultValueExpression() {
    super.push(constantContext);
    _insideOfFormalParameterType = false;
    constantContext = ConstantContext.required;
  }

  @override
  void endFormalParameterDefaultValueExpression() {
    debugEvent("FormalParameterDefaultValueExpression");
    Object? defaultValueExpression = pop();
    constantContext = pop() as ConstantContext;
    push(defaultValueExpression);
  }

  @override
  void handleValuedFormalParameter(
    Token equals,
    Token token,
    FormalParameterKind kind,
  ) {
    debugEvent("ValuedFormalParameter");
    Expression initializer = popForValue();
    Object? name = pop();
    if (name is ParserRecovery) {
      push(name);
    } else {
      push(new InitializedIdentifier(name as Identifier, initializer));
    }
    if ((kind == FormalParameterKind.optionalNamed ||
            kind == FormalParameterKind.requiredNamed) &&
        equals.lexeme == ':' &&
        libraryBuilder.languageVersion.major >= 3) {
      addProblem(
        cfe.codeObsoleteColonForDefaultValue,
        equals.charOffset,
        equals.charCount,
      );
    }
  }

  @override
  void handleFormalParameterWithoutValue(Token token) {
    debugEvent("FormalParameterWithoutValue");
  }

  @override
  void beginFormalParameters(Token token, MemberKind kind) {
    super.push(constantContext);
    super.push(inFormals);
    constantContext = ConstantContext.none;
    inFormals = true;
  }

  @override
  void endFormalParameters(
    int count,
    Token beginToken,
    Token endToken,
    MemberKind kind,
  ) {
    debugEvent("FormalParameters");
    if (kind.isFunctionType) {
      assert(
        checkState(beginToken, [
          if (count > 0 && peek() is List<FunctionTypeParameterBuilder>) ...[
            ValueKinds.FunctionTypeParameterBuilderList,
            ...repeatedKind(
              unionOfKinds([
                ValueKinds.FunctionTypeParameterBuilder,
                ValueKinds.ParserRecovery,
              ]),
              count - 1,
            ),
          ] else
            ...repeatedKind(
              unionOfKinds([
                ValueKinds.FunctionTypeParameterBuilder,
                ValueKinds.ParserRecovery,
              ]),
              count,
            ),
          /* inFormals */ ValueKinds.Bool,
          /* constantContext */ ValueKinds.ConstantContext,
        ]),
      );
      List<FunctionTypeParameterBuilder>? optionals;
      int optionalsCount = 0;
      if (count > 0 && peek() is List<FunctionTypeParameterBuilder>) {
        optionals = pop() as List<FunctionTypeParameterBuilder>;
        count--;
        optionalsCount = optionals.length;
      }
      List<FunctionTypeParameterBuilder>? parameters =
          const FixedNullableList<FunctionTypeParameterBuilder>()
              .popPaddedNonNullable(
                stack,
                count,
                optionalsCount,
                dummyFunctionTypeParameterBuilder,
              );
      if (optionals != null && parameters != null) {
        parameters.setRange(count, count + optionalsCount, optionals);
      }
      assert(parameters?.isNotEmpty ?? true);
      FunctionTypeParameters formals = new FunctionTypeParameters(
        parameters,
        offsetForToken(beginToken),
        lengthOfSpan(beginToken, endToken),
        uri,
      );
      inFormals = pop() as bool;
      constantContext = pop() as ConstantContext;
      push(formals);
    } else {
      assert(
        checkState(beginToken, [
          if (count > 0 && peek() is List<FormalParameterBuilder>) ...[
            ValueKinds.FormalList,
            ...repeatedKind(
              unionOfKinds([
                ValueKinds.FormalParameterBuilder,
                ValueKinds.ParserRecovery,
              ]),
              count - 1,
            ),
          ] else
            ...repeatedKind(
              unionOfKinds([
                ValueKinds.FormalParameterBuilder,
                ValueKinds.ParserRecovery,
              ]),
              count,
            ),
          /* inFormals */ ValueKinds.Bool,
          /* constantContext */ ValueKinds.ConstantContext,
        ]),
      );
      List<FormalParameterBuilder>? optionals;
      int optionalsCount = 0;
      if (count > 0 && peek() is List<FormalParameterBuilder>) {
        optionals = pop() as List<FormalParameterBuilder>;
        count--;
        optionalsCount = optionals.length;
      }
      List<FormalParameterBuilder>? parameters =
          const FixedNullableList<FormalParameterBuilder>()
              .popPaddedNonNullable(
                stack,
                count,
                optionalsCount,
                dummyFormalParameterBuilder,
              );
      if (optionals != null && parameters != null) {
        parameters.setRange(count, count + optionalsCount, optionals);
      }
      assert(parameters?.isNotEmpty ?? true);
      FormalParameters formals = new FormalParameters(
        parameters,
        offsetForToken(beginToken),
        lengthOfSpan(beginToken, endToken),
        uri,
      );
      inFormals = pop() as bool;
      constantContext = pop() as ConstantContext;
      push(formals);
      if ((inCatchClause || functionNestingLevel != 0) &&
          kind != MemberKind.GeneralizedFunctionType) {
        enterLocalScope(
          formals.computeFormalParameterScope(
            _localScope,
            this,
            wildcardVariablesEnabled:
                libraryFeatures.wildcardVariables.isEnabled,
          ),
        );
      }
    }
  }

  @override
  void beginCatchClause(Token token) {
    debugEvent("beginCatchClause");
    inCatchClause = true;
  }

  @override
  void endCatchClause(Token token) {
    debugEvent("CatchClause");
    inCatchClause = false;
    push(inCatchBlock);
    inCatchBlock = true;
  }

  @override
  void handleCatchBlock(Token? onKeyword, Token? catchKeyword, Token? comma) {
    debugEvent("CatchBlock");
    Statement body = pop() as Statement;
    inCatchBlock = pop() as bool;
    if (catchKeyword != null) {
      exitLocalScope();
    }
    FormalParameters? catchParameters =
        popIfNotNull(catchKeyword) as FormalParameters?;
    TypeBuilder? unresolvedExceptionType =
        popIfNotNull(onKeyword) as TypeBuilder?;
    DartType exceptionType;
    if (unresolvedExceptionType != null) {
      exceptionType = buildDartType(
        unresolvedExceptionType,
        TypeUse.catchType,
        allowPotentiallyConstantType: false,
      );
    } else {
      exceptionType = coreTypes.objectNonNullableRawType;
    }
    FormalParameterBuilder? exception;
    FormalParameterBuilder? stackTrace;
    List<Statement>? compileTimeErrors;
    if (catchParameters?.parameters != null) {
      int parameterCount = catchParameters!.parameters!.length;
      if (parameterCount > 0) {
        exception = catchParameters.parameters![0];
        exception.build(libraryBuilder).type = exceptionType;
        if (parameterCount > 1) {
          stackTrace = catchParameters.parameters![1];
          stackTrace.build(libraryBuilder).type = coreTypes.stackTraceRawType(
            Nullability.nonNullable,
          );
        }
      }
      if (parameterCount > 2) {
        // If parameterCount is 0, the parser reported an error already.
        if (parameterCount != 0) {
          for (int i = 2; i < parameterCount; i++) {
            FormalParameterBuilder parameter = catchParameters.parameters![i];
            compileTimeErrors ??= <Statement>[];
            compileTimeErrors.add(
              buildProblemStatement(
                cfe.codeCatchSyntaxExtraParameters,
                parameter.fileOffset,
                length: parameter.name.length,
              ),
            );
          }
        }
      }
    }
    push(
      forest.createCatch(
        offsetForToken(onKeyword ?? catchKeyword),
        exceptionType,
        exception?.variable,
        stackTrace?.variable,
        coreTypes.stackTraceRawType(Nullability.nonNullable),
        body,
      ),
    );
    if (compileTimeErrors == null) {
      push(NullValues.Block);
    } else {
      push(forest.createBlock(noLocation, noLocation, compileTimeErrors));
    }
  }

  @override
  void beginTryStatement(Token token) {
    // This is matched by the call to [endNode] in [endTryStatement].
    typeInferrer.assignedVariables.beginNode();
  }

  @override
  void endTryStatement(
    int catchCount,
    Token tryKeyword,
    Token? finallyKeyword,
    Token endToken,
  ) {
    Statement? finallyBlock;
    if (finallyKeyword != null) {
      finallyBlock = pop() as Statement;
    } else {
      // This is matched by the call to [beginNode] in [beginTryStatement].
      tryStatementInfoStack = tryStatementInfoStack.prepend(
        typeInferrer.assignedVariables.deferNode(),
      );
    }
    List<Catch>? catchBlocks;
    List<Statement>? compileTimeErrors;
    if (catchCount != 0) {
      List<Object?> catchBlocksAndErrors = const FixedNullableList<Object?>()
          .pop(stack, catchCount * 2)!;
      catchBlocks = new List<Catch>.filled(
        catchCount,
        dummyCatch,
        growable: true,
      );
      for (int i = 0; i < catchCount; i++) {
        catchBlocks[i] = catchBlocksAndErrors[i * 2] as Catch;
        Statement? error = catchBlocksAndErrors[i * 2 + 1] as Statement?;
        if (error != null) {
          compileTimeErrors ??= <Statement>[];
          compileTimeErrors.add(error);
        }
      }
    }
    Statement tryBlock = popStatement(tryKeyword);
    int fileOffset = offsetForToken(tryKeyword);
    Statement result = forest.createTryStatement(
      fileOffset,
      tryBlock,
      catchBlocks,
      finallyBlock,
    );
    typeInferrer.assignedVariables.storeInfo(
      result,
      tryStatementInfoStack.head,
    );
    tryStatementInfoStack = tryStatementInfoStack.tail!;

    if (compileTimeErrors != null) {
      compileTimeErrors.add(result);
      push(forest.createBlock(noLocation, noLocation, compileTimeErrors));
    } else {
      push(result);
    }
  }

  @override
  void handleIndexedExpression(
    Token? question,
    Token openSquareBracket,
    Token closeSquareBracket,
  ) {
    assert(
      checkState(openSquareBracket, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Initializer,
        ]),
      ]),
    );
    debugEvent("IndexedExpression");
    Expression index = popForValue();
    Object? receiver = pop();
    bool isNullAware = question != null;
    if (receiver is Generator) {
      push(
        receiver.buildIndexedAccess(
          index,
          openSquareBracket,
          isNullAware: isNullAware,
        ),
      );
    } else if (receiver is Expression) {
      push(
        IndexedAccessGenerator.make(
          this,
          openSquareBracket,
          receiver,
          index,
          isNullAware: isNullAware,
        ),
      );
    } else {
      assert(receiver is Initializer);
      push(
        IndexedAccessGenerator.make(
          this,
          openSquareBracket,
          toValue(receiver),
          index,
          isNullAware: isNullAware,
        ),
      );
    }
  }

  @override
  void handleUnaryPrefixExpression(Token token) {
    assert(
      checkState(token, <ValueKind>[
        unionOfKinds(<ValueKind>[ValueKinds.Expression, ValueKinds.Generator]),
      ]),
    );
    debugEvent("UnaryPrefixExpression");
    Object? receiver = pop();
    if (token.isA(TokenType.BANG)) {
      push(forest.createNot(offsetForToken(token), toValue(receiver)));
    } else {
      String operator = token.stringValue!;
      if (token.isA(TokenType.MINUS)) {
        operator = "unary-";
      }
      int fileOffset = offsetForToken(token);
      Name name = new Name(operator);
      if (receiver is Generator) {
        push(receiver.buildUnaryOperation(token, name));
      } else if (receiver is Expression) {
        push(forest.createUnary(fileOffset, name, receiver));
      } else {
        // Coverage-ignore-block(suite): Not run.
        Expression value = toValue(receiver);
        push(forest.createUnary(fileOffset, name, value));
      }
    }
  }

  Name incrementOperator(Token token) {
    if (token.isA(TokenType.PLUS_PLUS)) return plusName;
    if (token.isA(TokenType.MINUS_MINUS)) return minusName;
    return unhandled(token.lexeme, "incrementOperator", token.charOffset, uri);
  }

  @override
  void handleUnaryPrefixAssignmentExpression(Token token) {
    debugEvent("UnaryPrefixAssignmentExpression");
    Object? generator = pop();
    if (generator is Generator) {
      push(
        generator.buildPrefixIncrement(
          incrementOperator(token),
          operatorOffset: token.charOffset,
        ),
      );
    } else {
      Expression value = toValue(generator);
      push(
        wrapInProblem(value, cfe.codeNotAnLvalue, value.fileOffset, noLength),
      );
    }
  }

  @override
  void handleUnaryPostfixAssignmentExpression(Token token) {
    debugEvent("UnaryPostfixAssignmentExpression");
    Object? generator = pop();
    if (generator is Generator) {
      push(
        new DelayedPostfixIncrement(
          this,
          token,
          generator,
          incrementOperator(token),
        ),
      );
    } else {
      Expression value = toValue(generator);
      push(
        wrapInProblem(value, cfe.codeNotAnLvalue, value.fileOffset, noLength),
      );
    }
  }

  @override
  void endConstructorReference(
    Token start,
    Token? periodBeforeName,
    Token endToken,
    ConstructorReferenceContext constructorReferenceContext,
  ) {
    debugEvent("ConstructorReference");
    pushQualifiedReference(
      start,
      periodBeforeName,
      constructorReferenceContext,
    );
  }

  /// A qualified reference is something that matches one of:
  ///
  ///     identifier
  ///     identifier typeArguments? '.' identifier
  ///     identifier '.' identifier typeArguments? '.' identifier
  ///
  /// That is, one to three identifiers separated by periods and optionally one
  /// list of type arguments.
  ///
  /// A qualified reference can be used to represent both a reference to
  /// compile-time constant variable (metadata) or a constructor reference
  /// (used by metadata, new/const expression, and redirecting factories).
  ///
  /// Note that the parser will report errors if metadata includes type
  /// arguments, but will other preserve them for error recovery.
  ///
  /// A constructor reference can contain up to three identifiers:
  ///
  ///     a) type typeArguments?
  ///     b) type typeArguments? '.' name
  ///     c) prefix '.' type typeArguments?
  ///     d) prefix '.' type typeArguments? '.' name
  ///
  /// This isn't a legal constructor reference:
  ///
  ///     type '.' name typeArguments?
  ///
  /// But the parser can't tell this from type c) above.
  ///
  /// This method pops 2 (or 3 if `periodBeforeName != null`) values from the
  /// stack and pushes 3 values: a generator (the type in a constructor
  /// reference, or an expression in metadata), a list of type arguments, and a
  /// name.
  void pushQualifiedReference(
    Token start,
    Token? periodBeforeName,
    ConstructorReferenceContext constructorReferenceContext,
  ) {
    assert(
      checkState(start, [
        /*suffix*/ if (periodBeforeName != null)
          unionOfKinds([ValueKinds.Identifier, ValueKinds.ParserRecovery]),
        /*type arguments*/ ValueKinds.TypeArgumentsOrNull,
        /*type*/ unionOfKinds([
          ValueKinds.Generator,
          ValueKinds.QualifiedName,
          ValueKinds.ParserRecovery,
        ]),
      ]),
    );
    Object? suffixObject = popIfNotNull(periodBeforeName);
    Identifier? suffix;
    if (suffixObject is Identifier) {
      suffix = suffixObject;
    } else {
      assert(
        suffixObject == null ||
            // Coverage-ignore(suite): Not run.
            suffixObject is ParserRecovery,
        "Unexpected qualified name suffix $suffixObject "
        "(${suffixObject.runtimeType})",
      );
      // There was a `.` without a suffix.
    }

    Identifier? identifier;
    List<TypeBuilder>? typeArguments = pop() as List<TypeBuilder>?;
    Object? type = pop();
    if (type is QualifiedName) {
      identifier = type;
      QualifiedName qualified = type;
      switch (qualified) {
        case QualifiedNameGenerator():
          Generator qualifier = qualified.qualifier;
          if (qualifier is TypeUseGenerator && suffix == null) {
            type = qualifier;
            if (typeArguments != null) {
              // TODO(ahe): Point to the type arguments instead.
              addProblem(
                cfe.codeConstructorWithTypeArguments,
                identifier.nameOffset,
                identifier.name.length,
              );
            }
          } else {
            if (constructorReferenceContext !=
                ConstructorReferenceContext.Implicit) {
              type = qualifier.qualifiedLookup(qualified.token);
            } else {
              type = qualifier.buildSelectorAccess(
                new PropertySelector(
                  this,
                  qualified.token,
                  new Name(qualified.name, libraryBuilder.nameOrigin),
                ),
                qualified.token.charOffset,
                false,
              );
            }
            identifier = null;
          }
        // Coverage-ignore(suite): Not run.
        case QualifiedNameBuilder():
        case QualifiedNameIdentifier():
          unhandled(
            "${qualified.runtimeType}",
            "pushQualifiedReference",
            start.charOffset,
            uri,
          );
      }
    }
    String name;
    if (identifier != null && suffix != null) {
      // Coverage-ignore-block(suite): Not run.
      name = "${identifier.name}.${suffix.name}";
    } else if (identifier != null) {
      name = identifier.name;
    } else if (suffix != null) {
      name = suffix.name;
    } else {
      name = "";
    }

    // TODO(johnniwinther): Provide sufficient offsets for pointing correctly
    //  to prefix, class name and suffix.
    push(type);
    push(typeArguments ?? NullValues.TypeArguments);
    push(name);
    push(suffix ?? identifier ?? NullValues.Identifier);

    assert(
      checkState(start, [
        /*constructor name identifier*/ ValueKinds.IdentifierOrNull,
        /*constructor name*/ ValueKinds.Name,
        /*type arguments*/ ValueKinds.TypeArgumentsOrNull,
        /*class*/ unionOfKinds([
          ValueKinds.Generator,
          ValueKinds.ParserRecovery,
          ValueKinds.Expression,
        ]),
      ]),
    );
  }

  Expression buildConstructorInvocation(
    Member target,
    ArgumentsImpl arguments, {
    Constness constness = Constness.implicit,
    TypeAliasBuilder? typeAliasBuilder,
    int fileOffset = -1,
    int charLength = noLength,
  }) {
    Expression? result = checkStaticArguments(
      target: target,
      arguments: arguments,
      fileOffset: fileOffset,
    );
    if (result != null) {
      return result;
    }

    bool isConst =
        constness == Constness.explicitConst ||
        constantContext != ConstantContext.none;
    if (target is Constructor) {
      if (constantContext == ConstantContext.required &&
          constness == Constness.implicit) {
        addProblem(cfe.codeMissingExplicitConst, fileOffset, charLength);
      }
      if (isConst && !target.isConst) {
        return buildProblem(
          cfe.codeNonConstConstructor,
          fileOffset,
          charLength,
        );
      }
      Expression node;
      if (typeAliasBuilder == null) {
        node = new ConstructorInvocation(target, arguments, isConst: isConst)
          ..fileOffset = fileOffset;
        libraryBuilder.checkBoundsInConstructorInvocation(
          constructor: target,
          typeArguments: arguments.types,
          typeEnvironment: typeEnvironment,
          fileUri: uri,
          fileOffset: fileOffset,
        );
      } else {
        node = new TypeAliasedConstructorInvocation(
          typeAliasBuilder,
          target,
          arguments,
          isConst: isConst,
        )..fileOffset = fileOffset;
        // No type arguments were passed, so we need not check bounds.
        assert(arguments.types.isEmpty);
      }
      return node;
    } else {
      Procedure procedure = target as Procedure;
      if (constantContext == ConstantContext.required &&
          // Coverage-ignore(suite): Not run.
          constness == Constness.implicit) {
        // Coverage-ignore-block(suite): Not run.
        addProblem(cfe.codeMissingExplicitConst, fileOffset, charLength);
      }
      if (isConst && !procedure.isConst) {
        if (procedure.isExtensionTypeMember) {
          // Both generative constructors and factory constructors from
          // extension type declarations are encoded as procedures so we use
          // the message for non-const constructors here.
          return buildProblem(
            cfe.codeNonConstConstructor,
            fileOffset,
            charLength,
          );
        } else {
          return buildProblem(cfe.codeNonConstFactory, fileOffset, charLength);
        }
      }
      Expression node;
      if (typeAliasBuilder == null) {
        FactoryConstructorInvocation factoryConstructorInvocation =
            new FactoryConstructorInvocation(
              target,
              arguments,
              isConst: isConst,
            )..fileOffset = fileOffset;
        libraryBuilder.checkBoundsInFactoryInvocation(
          factory: target,
          typeArguments: arguments.types,
          typeEnvironment: typeEnvironment,
          fileUri: uri,
          fileOffset: fileOffset,
          inferred: !arguments.hasExplicitTypeArguments,
        );
        node = factoryConstructorInvocation;
      } else {
        TypeAliasedFactoryInvocation typeAliasedFactoryInvocation =
            new TypeAliasedFactoryInvocation(
              typeAliasBuilder,
              target,
              arguments,
              isConst: isConst,
            )..fileOffset = fileOffset;
        // No type arguments were passed, so we need not check bounds.
        assert(arguments.types.isEmpty);
        node = typeAliasedFactoryInvocation;
      }
      return node;
    }
  }

  @override
  Expression buildStaticInvocation({
    required Procedure target,
    required Arguments arguments,
    required int fileOffset,
  }) {
    Expression? result = checkStaticArguments(
      target: target,
      arguments: arguments,
      fileOffset: fileOffset,
    );
    if (result != null) {
      return result;
    }

    return new StaticInvocation(target, arguments, isConst: false)
      ..fileOffset = fileOffset;
  }

  @override
  LocatedMessage? checkArgumentsForFunction(
    FunctionNode function,
    Arguments arguments,
    int offset,
    List<TypeParameter> typeParameters, {
    Extension? extension,
  }) {
    int typeParameterCount = typeParameters.length;
    int requiredParameterCount = function.requiredParameterCount;
    int positionalParameterCount = function.positionalParameters.length;
    int positionalArgumentsCount = arguments.positional.length;
    if (extension != null) {
      // Extension member invocations have additional synthetic parameter for
      // `this`.
      --requiredParameterCount;
      --positionalParameterCount;
      typeParameterCount -= extension.typeParameters.length;
    }
    if (positionalArgumentsCount < requiredParameterCount) {
      return cfe.codeTooFewArguments
          .withArgumentsOld(requiredParameterCount, positionalArgumentsCount)
          .withLocation(uri, arguments.fileOffset, noLength);
    }
    if (positionalArgumentsCount > positionalParameterCount) {
      return cfe.codeTooManyArguments
          .withArgumentsOld(positionalParameterCount, positionalArgumentsCount)
          .withLocation(uri, arguments.fileOffset, noLength);
    }
    List<NamedExpression> named = arguments.named;
    if (named.isNotEmpty) {
      Set<String?> parameterNames = new Set.of(
        function.namedParameters.map((a) => a.name),
      );
      for (int i = 0; i < named.length; i++) {
        NamedExpression argument = named[i];
        if (!parameterNames.contains(argument.name)) {
          return cfe.codeNoSuchNamedParameter
              .withArgumentsOld(argument.name)
              .withLocation(uri, argument.fileOffset, argument.name.length);
        }
      }
    }
    if (function.namedParameters.isNotEmpty) {
      Set<String> argumentNames = new Set.of(named.map((a) => a.name));
      for (int i = 0; i < function.namedParameters.length; i++) {
        VariableDeclaration parameter = function.namedParameters[i];
        if (parameter.isRequired && !argumentNames.contains(parameter.name)) {
          return cfe.codeValueForRequiredParameterNotProvidedError
              .withArgumentsOld(parameter.name!)
              .withLocation(uri, arguments.fileOffset, cfe.noLength);
        }
      }
    }

    List<DartType> types = arguments.types;
    if (typeParameterCount != types.length) {
      if (types.length == 0) {
        // Expected `typeParameters.length` type arguments, but none given, so
        // we use type inference.
      } else {
        // A wrong (non-zero) amount of type arguments given. That's an error.
        // TODO(jensj): Position should be on type arguments instead.
        return cfe.codeTypeArgumentMismatch
            .withArgumentsOld(typeParameterCount)
            .withLocation(uri, offset, noLength);
      }
    }

    return null;
  }

  @override
  LocatedMessage? checkArgumentsForType(
    FunctionType function,
    Arguments arguments,
    int offset,
  ) {
    int requiredPositionalParameterCountToReport =
        function.requiredParameterCount;
    int positionalParameterCountToReport = function.positionalParameters.length;
    int positionalArgumentCountToReport = arguments.positional.length;
    if (arguments.positional.length < function.requiredParameterCount) {
      return cfe.codeTooFewArguments
          .withArgumentsOld(
            requiredPositionalParameterCountToReport,
            positionalArgumentCountToReport,
          )
          .withLocation(uri, arguments.fileOffset, noLength);
    }
    if (arguments.positional.length > function.positionalParameters.length) {
      return cfe.codeTooManyArguments
          .withArgumentsOld(
            positionalParameterCountToReport,
            positionalArgumentCountToReport,
          )
          .withLocation(uri, arguments.fileOffset, noLength);
    }
    List<NamedExpression> named = arguments.named;
    if (named.isNotEmpty) {
      Set<String> names = new Set.of(
        function.namedParameters.map((a) => a.name),
      );
      for (int i = 0; i < named.length; i++) {
        NamedExpression argument = named[i];
        if (!names.contains(argument.name)) {
          return cfe.codeNoSuchNamedParameter
              .withArgumentsOld(argument.name)
              .withLocation(uri, argument.fileOffset, argument.name.length);
        }
      }
    }
    if (function.namedParameters.isNotEmpty) {
      Set<String> argumentNames = new Set.of(named.map((a) => a.name));
      for (int i = 0; i < function.namedParameters.length; i++) {
        NamedType parameter = function.namedParameters[i];
        if (parameter.isRequired && !argumentNames.contains(parameter.name)) {
          return cfe.codeValueForRequiredParameterNotProvidedError
              .withArgumentsOld(parameter.name)
              .withLocation(uri, arguments.fileOffset, cfe.noLength);
        }
      }
    }
    List<Object> types = arguments.types;
    List<StructuralParameter> typeParameters = function.typeParameters;
    if (typeParameters.length != types.length && types.length != 0) {
      // A wrong (non-zero) amount of type arguments given. That's an error.
      // TODO(jensj): Position should be on type arguments instead.
      return cfe.codeTypeArgumentMismatch
          .withArgumentsOld(typeParameters.length)
          .withLocation(uri, offset, noLength);
    }

    return null;
  }

  @override
  void beginNewExpression(Token token) {
    debugEvent("beginNewExpression");
    super.push(constantContext);
    if (constantContext != ConstantContext.none) {
      addProblem(
        cfe.codeNotConstantExpression.withArgumentsOld('New expression'),
        token.charOffset,
        token.length,
      );
    }
    constantContext = ConstantContext.none;
  }

  @override
  void beginConstExpression(Token token) {
    debugEvent("beginConstExpression");
    super.push(constantContext);
    constantContext = ConstantContext.inferred;
  }

  @override
  void beginConstLiteral(Token token) {
    debugEvent("beginConstLiteral");
    super.push(constantContext);
    constantContext = ConstantContext.inferred;
  }

  @override
  void beginImplicitCreationExpression(Token token) {
    debugEvent("beginImplicitCreationExpression");
    super.push(constantContext);
  }

  @override
  void endConstLiteral(Token endToken) {
    debugEvent("endConstLiteral");
    Object? literal = pop();
    constantContext = pop() as ConstantContext;
    push(literal);
  }

  @override
  void endNewExpression(Token token) {
    debugEvent("NewExpression");
    _buildConstructorReferenceInvocation(
      token.next!,
      token.offset,
      Constness.explicitNew,
      inMetadata: false,
      inImplicitCreationContext: false,
    );
  }

  void _buildConstructorReferenceInvocation(
    Token nameToken,
    int offset,
    Constness constness, {
    required bool inMetadata,
    required bool inImplicitCreationContext,
  }) {
    assert(
      checkState(nameToken, [
        /*arguments*/ unionOfKinds([
          ValueKinds.Arguments,
          ValueKinds.ParserRecovery,
        ]),
        /*constructor name identifier*/ ValueKinds.IdentifierOrNull,
        /*constructor name*/ ValueKinds.Name,
        /*type arguments*/ ValueKinds.TypeArgumentsOrNull,
        /*class*/ unionOfKinds([
          ValueKinds.Generator,
          ValueKinds.ParserRecovery,
          ValueKinds.Expression,
        ]),
        /*previous constant context*/ ValueKinds.ConstantContext,
      ]),
    );
    Object? arguments = pop();
    Identifier? nameLastIdentifier = pop(NullValues.Identifier) as Identifier?;
    Token nameLastToken = nameLastIdentifier?.token ?? nameToken;
    String name = pop() as String;
    List<TypeBuilder>? typeArguments = pop() as List<TypeBuilder>?;
    if (inMetadata && typeArguments != null) {
      if (!libraryFeatures.genericMetadata.isEnabled) {
        handleRecoverableError(
          cfe.codeMetadataTypeArguments,
          nameLastToken.next!,
          nameLastToken.next!,
        );
      }
    }

    Object? type = pop();

    ConstantContext savedConstantContext = pop() as ConstantContext;

    if (arguments is! ArgumentsImpl) {
      push(new ParserErrorGenerator(this, nameToken, cfe.codeSyntheticToken));
      arguments = forest.createArguments(offset, []);
    } else if (type is Generator) {
      push(
        type.invokeConstructor(
          typeArguments,
          name,
          arguments,
          nameToken,
          nameLastToken,
          constness,
          inImplicitCreationContext: inImplicitCreationContext,
        ),
      );
    } else if (type is ParserRecovery) {
      push(new ParserErrorGenerator(this, nameToken, cfe.codeSyntheticToken));
    } else if (type is InvalidExpression) {
      // Coverage-ignore-block(suite): Not run.
      push(type);
    } else if (type is Expression) {
      push(
        createInstantiationAndInvocation(
          () => type,
          typeArguments,
          name,
          name,
          arguments,
          instantiationOffset: offset,
          invocationOffset: nameLastToken.charOffset,
          inImplicitCreationContext: inImplicitCreationContext,
        ),
      );
    } else {
      // Coverage-ignore-block(suite): Not run.
      String? typeName;
      push(
        buildUnresolvedError(
          debugName(typeName!, name),
          nameLastToken.charOffset,
          kind: UnresolvedKind.Constructor,
        ),
      );
    }
    constantContext = savedConstantContext;
    assert(
      checkState(nameToken, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
      ]),
    );
  }

  @override
  Expression createInstantiationAndInvocation(
    Expression Function() receiverFunction,
    List<TypeBuilder>? typeArguments,
    String className,
    String constructorName,
    ArgumentsImpl arguments, {
    required int instantiationOffset,
    required int invocationOffset,
    required bool inImplicitCreationContext,
  }) {
    if (libraryFeatures.constructorTearoffs.isEnabled &&
        inImplicitCreationContext) {
      Expression receiver = receiverFunction();
      if (typeArguments != null) {
        if (receiver is StaticTearOff &&
                (receiver.target.isFactory ||
                    isTearOffLowering(receiver.target)) ||
            receiver is ConstructorTearOff ||
            receiver is RedirectingFactoryTearOff) {
          return buildProblem(
            cfe.codeConstructorTearOffWithTypeArguments,
            instantiationOffset,
            noLength,
          );
        }
        receiver = forest.createInstantiation(
          instantiationOffset,
          receiver,
          buildDartTypeArguments(
            typeArguments,
            TypeUse.tearOffTypeArgument,
            allowPotentiallyConstantType: true,
          ),
        );
      }
      return forest.createMethodInvocation(
        invocationOffset,
        receiver,
        new Name(constructorName, libraryBuilder.nameOrigin),
        arguments,
        isNullAware: false,
      );
    } else {
      if (typeArguments != null) {
        assert(arguments.types.isEmpty);
        arguments.setExplicitTypeArguments(
          buildDartTypeArguments(
            typeArguments,
            TypeUse.constructorTypeArgument,
            allowPotentiallyConstantType: false,
          ),
        );
      }
      return buildUnresolvedError(
        constructorNameForDiagnostics(constructorName, className: className),
        invocationOffset,
        kind: UnresolvedKind.Constructor,
      );
    }
  }

  @override
  void endImplicitCreationExpression(Token token, Token openAngleBracket) {
    debugEvent("ImplicitCreationExpression");
    _buildConstructorReferenceInvocation(
      token,
      openAngleBracket.offset,
      Constness.implicit,
      inMetadata: false,
      inImplicitCreationContext: true,
    );
  }

  @override
  Expression resolveAndBuildConstructorInvocation(
    TypeDeclarationBuilder? typeDeclarationBuilder,
    Token nameToken,
    Token nameLastToken,
    ArgumentsImpl arguments,
    String name,
    List<TypeBuilder>? typeArguments,
    int charOffset,
    Constness constness, {
    bool isTypeArgumentsInForest = false,
    TypeDeclarationBuilder? typeAliasBuilder,
    required UnresolvedKind unresolvedKind,
  }) {
    if (name.isNotEmpty && arguments.types.isNotEmpty) {
      // TODO(ahe): Point to the type arguments instead.
      addProblem(
        cfe.codeConstructorWithTypeArguments,
        nameToken.charOffset,
        nameToken.length,
      );
    }

    String? errorName;
    LocatedMessage? message;

    if (typeDeclarationBuilder is TypeAliasBuilder) {
      errorName = debugName(typeDeclarationBuilder.name, name);
      TypeAliasBuilder aliasBuilder = typeDeclarationBuilder;
      int numberOfTypeParameters = aliasBuilder.typeParametersCount;
      int numberOfTypeArguments = typeArguments?.length ?? 0;
      if (typeArguments != null &&
          numberOfTypeParameters != numberOfTypeArguments) {
        // TODO(eernst): Use position of type arguments, not nameToken.
        return evaluateArgumentsBefore(
          arguments,
          buildProblem(
            cfe.codeTypeArgumentMismatch.withArgumentsOld(
              numberOfTypeParameters,
            ),
            charOffset,
            noLength,
          ),
        );
      }
      typeDeclarationBuilder = aliasBuilder.unaliasDeclaration(
        null,
        isUsedAsClass: true,
        usedAsClassCharOffset: nameToken.charOffset,
        usedAsClassFileUri: uri,
      );
      List<TypeBuilder> typeArgumentBuilders = [];
      if (typeArguments != null) {
        for (TypeBuilder typeBuilder in typeArguments) {
          typeArgumentBuilders.add(typeBuilder);
        }
      } else {
        if (aliasBuilder.typeParametersCount > 0) {
          // Raw generic type alias used for instance creation, needs inference.
          switch (typeDeclarationBuilder) {
            case ClassBuilder():
              MemberLookupResult? result = typeDeclarationBuilder
                  .findConstructorOrFactory(name, libraryBuilder);
              Member? target;
              if (result == null) {
                // Not found. Reported below.
                target = null;
              } else if (result.isInvalidLookup) {
                message = LookupResult.createDuplicateMessage(
                  result,
                  enclosingDeclaration: typeDeclarationBuilder,
                  name: name,
                  fileUri: uri,
                  fileOffset: charOffset,
                  length: noLength,
                );
                target = null;
              } else {
                MemberBuilder? constructorBuilder = result.getable!;
                if (constructorBuilder is ConstructorBuilder) {
                  if (typeDeclarationBuilder.isAbstract) {
                    return evaluateArgumentsBefore(
                      arguments,
                      buildAbstractClassInstantiationError(
                        cfe.codeAbstractClassInstantiation.withArgumentsOld(
                          typeDeclarationBuilder.name,
                        ),
                        typeDeclarationBuilder.name,
                        nameToken.charOffset,
                      ),
                    );
                  }
                  target = constructorBuilder.invokeTarget;
                } else {
                  target = constructorBuilder.invokeTarget;
                }
              }
              if (target is Constructor ||
                  (target is Procedure &&
                      target.kind == ProcedureKind.Factory)) {
                return buildConstructorInvocation(
                  target!,
                  arguments,
                  constness: constness,
                  typeAliasBuilder: aliasBuilder,
                  fileOffset: nameToken.charOffset,
                  charLength: nameToken.length,
                );
              } else {
                if (message != null) {
                  return buildProblemFromLocatedMessage(message);
                } else {
                  return buildUnresolvedError(
                    errorName,
                    nameLastToken.charOffset,
                    kind: UnresolvedKind.Constructor,
                  );
                }
              }
            case ExtensionTypeDeclarationBuilder():
              // TODO(johnniwinther): Add shared interface between
              //  [ClassBuilder] and [ExtensionTypeDeclarationBuilder].
              MemberLookupResult? result = typeDeclarationBuilder
                  .findConstructorOrFactory(name, libraryBuilder);
              MemberBuilder? constructorBuilder = result?.getable;
              if (result != null && result.isInvalidLookup) {
                // Coverage-ignore-block(suite): Not run.
                message = LookupResult.createDuplicateMessage(
                  result,
                  enclosingDeclaration: typeDeclarationBuilder,
                  name: name,
                  fileUri: uri,
                  fileOffset: charOffset,
                  length: noLength,
                );
              } else if (constructorBuilder == null) {
                // Not found. Reported below.
              } else if (constructorBuilder is ConstructorBuilder ||
                  // Coverage-ignore(suite): Not run.
                  constructorBuilder is FactoryBuilder) {
                Member target = constructorBuilder.invokeTarget!;
                return buildConstructorInvocation(
                  target,
                  arguments,
                  constness: constness,
                  typeAliasBuilder: aliasBuilder,
                  fileOffset: nameToken.charOffset,
                  charLength: nameToken.length,
                );
              }
              if (message != null) {
                // Coverage-ignore-block(suite): Not run.
                return buildProblemFromLocatedMessage(message);
              } else {
                return buildUnresolvedError(
                  errorName,
                  nameLastToken.charOffset,
                  kind: UnresolvedKind.Constructor,
                );
              }
            case InvalidBuilder():
              // Coverage-ignore(suite): Not run.
              LocatedMessage message = typeDeclarationBuilder.message;
              // Coverage-ignore(suite): Not run.
              return evaluateArgumentsBefore(
                arguments,
                buildProblem(
                  message.messageObject,
                  nameToken.charOffset,
                  nameToken.lexeme.length,
                ),
              );
            case TypeAliasBuilder():
            // Coverage-ignore(suite): Not run.
            case NominalParameterBuilder():
            // Coverage-ignore(suite): Not run.
            case StructuralParameterBuilder():
            // Coverage-ignore(suite): Not run.
            case ExtensionBuilder():
            // Coverage-ignore(suite): Not run.
            case BuiltinTypeDeclarationBuilder():
            case null:
              return buildUnresolvedError(
                errorName,
                nameLastToken.charOffset,
                kind: UnresolvedKind.Constructor,
              );
          }
        } else {
          // Empty `typeArguments` and `aliasBuilder``is non-generic, but it
          // may still unalias to a class type with some type arguments.
          switch (typeDeclarationBuilder) {
            case ClassBuilder():
            case ExtensionTypeDeclarationBuilder():
              List<TypeBuilder>? unaliasedTypeArgumentBuilders = aliasBuilder
                  .unaliasTypeArguments(const []);
              if (unaliasedTypeArgumentBuilders == null) {
                // Coverage-ignore-block(suite): Not run.
                // TODO(eernst): This is a wrong number of type arguments,
                // occurring indirectly (in an alias of an alias, etc.).
                return evaluateArgumentsBefore(
                  arguments,
                  buildProblem(
                    cfe.codeTypeArgumentMismatch.withArgumentsOld(
                      numberOfTypeParameters,
                    ),
                    nameToken.charOffset,
                    nameToken.length,
                    errorHasBeenReported: true,
                  ),
                );
              }
              List<DartType> dartTypeArguments = [];
              for (TypeBuilder typeBuilder in unaliasedTypeArgumentBuilders) {
                dartTypeArguments.add(
                  typeBuilder.build(
                    libraryBuilder,
                    TypeUse.constructorTypeArgument,
                  ),
                );
              }
              assert(arguments.types.isEmpty);
              arguments.setExplicitTypeArguments(dartTypeArguments);
            case TypeAliasBuilder():
            // Coverage-ignore(suite): Not run.
            case NominalParameterBuilder():
            // Coverage-ignore(suite): Not run.
            case StructuralParameterBuilder():
            // Coverage-ignore(suite): Not run.
            case ExtensionBuilder():
            // Coverage-ignore(suite): Not run.
            case InvalidBuilder():
            // Coverage-ignore(suite): Not run.
            case BuiltinTypeDeclarationBuilder():
            case null:
          }
        }
      }

      List<DartType> typeArgumentsToCheck = const <DartType>[];
      if (typeArgumentBuilders.isNotEmpty) {
        typeArgumentsToCheck = new List.filled(
          typeArgumentBuilders.length,
          const DynamicType(),
          growable: false,
        );
        for (int i = 0; i < typeArgumentsToCheck.length; ++i) {
          typeArgumentsToCheck[i] = typeArgumentBuilders[i].build(
            libraryBuilder,
            TypeUse.constructorTypeArgument,
          );
        }
      }
      DartType typeToCheck = new TypedefType(
        aliasBuilder.typedef,
        Nullability.nonNullable,
        typeArgumentsToCheck,
      );
      libraryBuilder.checkBoundsInType(
        typeToCheck,
        typeEnvironment,
        uri,
        charOffset,
        allowSuperBounded: false,
      );

      switch (typeDeclarationBuilder) {
        case ClassBuilder():
        case ExtensionTypeDeclarationBuilder():
          if (typeArguments != null) {
            int numberOfTypeParameters =
                aliasBuilder.typeParameters?.length ?? 0;
            if (numberOfTypeParameters != typeArgumentBuilders.length) {
              // Coverage-ignore-block(suite): Not run.
              // TODO(eernst): Use position of type arguments, not nameToken.
              return evaluateArgumentsBefore(
                arguments,
                buildProblem(
                  cfe.codeTypeArgumentMismatch.withArgumentsOld(
                    numberOfTypeParameters,
                  ),
                  nameToken.charOffset,
                  nameToken.length,
                ),
              );
            }
            List<TypeBuilder>? unaliasedTypeArgumentBuilders = aliasBuilder
                .unaliasTypeArguments(typeArgumentBuilders);
            if (unaliasedTypeArgumentBuilders == null) {
              // Coverage-ignore-block(suite): Not run.
              // TODO(eernst): This is a wrong number of type arguments,
              // occurring indirectly (in an alias of an alias, etc.).
              return evaluateArgumentsBefore(
                arguments,
                buildProblem(
                  cfe.codeTypeArgumentMismatch.withArgumentsOld(
                    numberOfTypeParameters,
                  ),
                  nameToken.charOffset,
                  nameToken.length,
                  errorHasBeenReported: true,
                ),
              );
            }
            List<DartType> dartTypeArguments = [];
            for (TypeBuilder typeBuilder in unaliasedTypeArgumentBuilders) {
              dartTypeArguments.add(
                typeBuilder.build(
                  libraryBuilder,
                  TypeUse.constructorTypeArgument,
                ),
              );
            }
            assert(arguments.types.isEmpty);
            arguments.setExplicitTypeArguments(dartTypeArguments);
          } else {
            LibraryBuilder libraryBuilder;
            List<NominalParameterBuilder>? typeParameters;
            // TODO(johnniwinther): Add a shared interface for [ClassBuilder]
            // and [ExtensionTypeDeclarationBuilder].
            if (typeDeclarationBuilder is ClassBuilder) {
              libraryBuilder = typeDeclarationBuilder.libraryBuilder;
              typeParameters = typeDeclarationBuilder.typeParameters;
            } else {
              typeDeclarationBuilder as ExtensionTypeDeclarationBuilder;
              libraryBuilder = typeDeclarationBuilder.libraryBuilder;
              typeParameters = typeDeclarationBuilder.typeParameters;
            }
            if (typeParameters == null || typeParameters.isEmpty) {
              assert(arguments.types.isEmpty);
              arguments.setExplicitTypeArguments([]);
            } else {
              if (arguments.types.isEmpty) {
                // No type arguments provided to unaliased class, use defaults.
                List<DartType> result = new List<DartType>.generate(
                  typeParameters.length,
                  (int i) => typeParameters![i].defaultType!.build(
                    libraryBuilder,
                    TypeUse.constructorTypeArgument,
                  ),
                  growable: true,
                );
                arguments.setExplicitTypeArguments(result);
              }
            }
          }
        case TypeAliasBuilder():
        case NominalParameterBuilder():
        case StructuralParameterBuilder():
        case ExtensionBuilder():
        case InvalidBuilder():
        // Coverage-ignore(suite): Not run.
        case BuiltinTypeDeclarationBuilder():
        case null:
      }
    } else {
      if (typeArguments != null && !isTypeArgumentsInForest) {
        assert(arguments.types.isEmpty);
        arguments.setExplicitTypeArguments(
          buildDartTypeArguments(
            typeArguments,
            TypeUse.constructorTypeArgument,
            allowPotentiallyConstantType: false,
          ),
        );
      }
    }
    switch (typeDeclarationBuilder) {
      case ClassBuilder():
        MemberLookupResult? result = typeDeclarationBuilder
            .findConstructorOrFactory(name, libraryBuilder);
        MemberBuilder? constructorBuilder = result?.getable;
        Member? target;
        if (result != null && result.isInvalidLookup) {
          message = LookupResult.createDuplicateMessage(
            result,
            enclosingDeclaration: typeDeclarationBuilder,
            name: name,
            fileUri: uri,
            fileOffset: charOffset,
            length: noLength,
          );
        } else if (constructorBuilder == null) {
          // Not found. Reported below.
        } else if (constructorBuilder is ConstructorBuilder) {
          if (typeDeclarationBuilder.isAbstract) {
            return evaluateArgumentsBefore(
              arguments,
              buildAbstractClassInstantiationError(
                cfe.codeAbstractClassInstantiation.withArgumentsOld(
                  typeDeclarationBuilder.name,
                ),
                typeDeclarationBuilder.name,
                nameToken.charOffset,
              ),
            );
          }
          target = constructorBuilder.invokeTarget;
        } else {
          target = constructorBuilder.invokeTarget;
        }
        if (typeDeclarationBuilder.isEnum &&
            !(libraryFeatures.enhancedEnums.isEnabled &&
                target is Procedure &&
                target.kind == ProcedureKind.Factory)) {
          return buildProblem(
            cfe.codeEnumInstantiation,
            nameToken.charOffset,
            nameToken.length,
          );
        }
        if (target is Constructor ||
            (target is Procedure && target.kind == ProcedureKind.Factory)) {
          Expression invocation;

          invocation = buildConstructorInvocation(
            target!,
            arguments,
            constness: constness,
            fileOffset: nameToken.charOffset,
            charLength: nameToken.length,
            typeAliasBuilder: typeAliasBuilder as TypeAliasBuilder?,
          );
          return invocation;
        } else {
          errorName ??= debugName(typeDeclarationBuilder.name, name);
        }
      case ExtensionTypeDeclarationBuilder():
        MemberLookupResult? result = typeDeclarationBuilder
            .findConstructorOrFactory(name, libraryBuilder);
        MemberBuilder? constructorBuilder = result?.getable;
        Member? target;
        if (result != null && result.isInvalidLookup) {
          // Coverage-ignore-block(suite): Not run.
          message = LookupResult.createDuplicateMessage(
            result,
            enclosingDeclaration: typeDeclarationBuilder,
            name: name,
            fileUri: uri,
            fileOffset: charOffset,
            length: noLength,
          );
        } else if (constructorBuilder == null) {
          // Not found. Reported below.
        } else {
          target = constructorBuilder.invokeTarget;
        }
        if (target != null) {
          return buildConstructorInvocation(
            target,
            arguments,
            constness: constness,
            fileOffset: nameToken.charOffset,
            charLength: nameToken.length,
            typeAliasBuilder: typeAliasBuilder as TypeAliasBuilder?,
          );
        } else {
          errorName ??= debugName(typeDeclarationBuilder.name, name);
        }
      case InvalidBuilder():
        LocatedMessage message = typeDeclarationBuilder.message;
        return evaluateArgumentsBefore(
          arguments,
          buildProblem(
            message.messageObject,
            nameToken.charOffset,
            nameToken.lexeme.length,
          ),
        );
      case TypeAliasBuilder():
      case NominalParameterBuilder():
      case StructuralParameterBuilder():
      case ExtensionBuilder():
      case BuiltinTypeDeclarationBuilder():
      case null:
        errorName ??= debugName(
          typeDeclarationBuilder!.fullNameForErrors,
          name,
        );
    }
    if (message != null) {
      return buildProblemFromLocatedMessage(message);
    } else {
      return buildUnresolvedError(
        errorName,
        nameLastToken.charOffset,
        kind: unresolvedKind,
      );
    }
  }

  @override
  void endConstExpression(Token token) {
    debugEvent("endConstExpression");
    _buildConstructorReferenceInvocation(
      token.next!,
      token.offset,
      Constness.explicitConst,
      inMetadata: false,
      inImplicitCreationContext: false,
    );
  }

  @override
  // Coverage-ignore(suite): Not run.
  void handleConstFactory(Token constKeyword) {
    debugEvent("ConstFactory");
    if (!libraryFeatures.constFunctions.isEnabled) {
      handleRecoverableError(cfe.codeConstFactory, constKeyword, constKeyword);
    }
  }

  @override
  void beginIfControlFlow(Token ifToken) {
    // TODO(danrubel): consider removing this when control flow support is added
    // if the ifToken is not needed for error reporting
    push(ifToken);
  }

  @override
  void handleThenControlFlow(Token token) {
    assert(checkState(token, [ValueKinds.Condition]));
    // This is matched by the call to [deferNode] in
    // [handleElseControlFlow] and by the call to [endNode] in
    // [endIfControlFlow].
    typeInferrer.assignedVariables.beginNode();

    Condition condition = pop() as Condition;
    PatternGuard? patternGuard = condition.patternGuard;
    if (patternGuard != null) {
      if (patternGuard.guard != null) {
        LocalScope thenScope = _localScope.createNestedScope(
          debugName: "then-control-flow",
          kind: ScopeKind.ifElement,
        );
        exitLocalScope(expectedScopeKinds: const [ScopeKind.ifCaseHead]);
        enterLocalScope(thenScope);
      } else {
        createAndEnterLocalScope(
          debugName: "if-case-head",
          kind: ScopeKind.ifCaseHead,
        );
        for (VariableDeclaration variable
            in patternGuard.pattern.declaredVariables) {
          declareVariable(variable, _localScope);
        }
        LocalScope thenScope = _localScope.createNestedScope(
          debugName: "then-control-flow",
          kind: ScopeKind.ifElement,
        );
        exitLocalScope(expectedScopeKinds: const [ScopeKind.ifCaseHead]);
        enterLocalScope(thenScope);
      }
    } else {
      createAndEnterLocalScope(
        debugName: "then-control-flow",
        kind: ScopeKind.ifElement,
      );
    }
    push(condition);

    super.handleThenControlFlow(token);
  }

  @override
  void handleElseControlFlow(Token elseToken) {
    assert(
      checkState(elseToken, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.MapLiteralEntry,
        ]),
        ValueKinds.Condition,
      ]),
    );
    // Resolve the top of the stack so that if it's a delayed assignment it
    // happens before we go into the else block.
    Object then = pop() as Object;
    if (then is! MapLiteralEntry) then = toValue(then);

    Object condition = pop() as Condition;
    exitLocalScope(expectedScopeKinds: const [ScopeKind.ifElement]);
    push(condition);

    // This is matched by the call to [beginNode] in
    // [handleThenControlFlow] and by the call to [storeInfo] in
    // [endIfElseControlFlow].
    push(typeInferrer.assignedVariables.deferNode());
    push(then);
  }

  @override
  void endIfControlFlow(Token token) {
    debugEvent("endIfControlFlow");
    assert(
      checkState(token, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.MapLiteralEntry,
        ]),
        ValueKinds.Condition,
        ValueKinds.Token,
      ]),
    );

    Object? entry = pop();
    Condition condition = pop() as Condition;
    exitLocalScope(expectedScopeKinds: const [ScopeKind.ifElement]);
    Token ifToken = pop() as Token;

    PatternGuard? patternGuard = condition.patternGuard;
    TreeNode node;
    if (entry is MapLiteralEntry) {
      if (patternGuard == null) {
        node = forest.createIfMapEntry(
          offsetForToken(ifToken),
          condition.expression,
          entry,
        );
      } else {
        node = forest.createIfCaseMapEntry(
          offsetForToken(ifToken),
          prelude: [],
          expression: condition.expression,
          patternGuard: patternGuard,
          then: entry,
        );
      }
    } else {
      if (patternGuard == null) {
        node = forest.createIfElement(
          offsetForToken(ifToken),
          condition.expression,
          toValue(entry),
        );
      } else {
        node = forest.createIfCaseElement(
          offsetForToken(ifToken),
          prelude: [],
          expression: condition.expression,
          patternGuard: patternGuard,
          then: toValue(entry),
        );
      }
    }
    push(node);
    // This is matched by the call to [beginNode] in
    // [handleThenControlFlow].
    typeInferrer.assignedVariables.endNode(node);
  }

  @override
  void endIfElseControlFlow(Token token) {
    debugEvent("endIfElseControlFlow");
    assert(
      checkState(token, [
        /* else element */ unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.MapLiteralEntry,
        ]),
        /* then element */ unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.MapLiteralEntry,
        ]),
        ValueKinds.AssignedVariablesNodeInfo,
        ValueKinds.Condition,
        ValueKinds.Token,
      ]),
    );

    Object? elseEntry = pop(); // else entry
    Object? thenEntry = pop(); // then entry
    AssignedVariablesNodeInfo assignedVariablesInfo =
        pop() as AssignedVariablesNodeInfo;
    Condition condition = pop() as Condition; // parenthesized expression
    Token ifToken = pop() as Token;

    PatternGuard? patternGuard = condition.patternGuard;
    TreeNode node;
    if (thenEntry is MapLiteralEntry) {
      if (elseEntry is MapLiteralEntry) {
        if (patternGuard == null) {
          node = forest.createIfMapEntry(
            offsetForToken(ifToken),
            condition.expression,
            thenEntry,
            elseEntry,
          );
        } else {
          node = forest.createIfCaseMapEntry(
            offsetForToken(ifToken),
            prelude: [],
            expression: condition.expression,
            patternGuard: patternGuard,
            then: thenEntry,
            otherwise: elseEntry,
          );
        }
      } else if (elseEntry is ControlFlowElement) {
        MapLiteralEntry? elseMapEntry = elseEntry.toMapLiteralEntry(
          typeInferrer.assignedVariables.reassignInfo,
        );
        if (elseMapEntry != null) {
          if (patternGuard == null) {
            node = forest.createIfMapEntry(
              offsetForToken(ifToken),
              condition.expression,
              thenEntry,
              elseMapEntry,
            );
          } else {
            node = forest.createIfCaseMapEntry(
              offsetForToken(ifToken),
              prelude: [],
              expression: condition.expression,
              patternGuard: patternGuard,
              then: thenEntry,
              otherwise: elseMapEntry,
            );
          }
        } else {
          int offset = elseEntry.fileOffset;
          node = new MapLiteralEntry(
            buildProblem(
              cfe.codeCantDisambiguateAmbiguousInformation,
              offset,
              1,
            ),
            new NullLiteral(),
          )..fileOffset = offsetForToken(ifToken);
        }
      } else {
        int offset = elseEntry is Expression
            ? elseEntry.fileOffset
            :
              // Coverage-ignore(suite): Not run.
              offsetForToken(ifToken);
        node = new MapLiteralEntry(
          buildProblem(
            cfe.codeExpectedAfterButGot.withArgumentsOld(':'),
            offset,
            1,
          ),
          new NullLiteral(),
        )..fileOffset = offsetForToken(ifToken);
      }
    } else if (elseEntry is MapLiteralEntry) {
      if (thenEntry is ControlFlowElement) {
        MapLiteralEntry? thenMapEntry = thenEntry.toMapLiteralEntry(
          typeInferrer.assignedVariables.reassignInfo,
        );
        if (thenMapEntry != null) {
          if (patternGuard == null) {
            node = forest.createIfMapEntry(
              offsetForToken(ifToken),
              condition.expression,
              thenMapEntry,
              elseEntry,
            );
          } else {
            // Coverage-ignore-block(suite): Not run.
            node = forest.createIfCaseMapEntry(
              offsetForToken(ifToken),
              prelude: [],
              expression: condition.expression,
              patternGuard: patternGuard,
              then: thenMapEntry,
              otherwise: elseEntry,
            );
          }
        } else {
          int offset = thenEntry.fileOffset;
          node = new MapLiteralEntry(
            buildProblem(
              cfe.codeCantDisambiguateAmbiguousInformation,
              offset,
              1,
            ),
            new NullLiteral(),
          )..fileOffset = offsetForToken(ifToken);
        }
      } else {
        int offset = thenEntry is Expression
            ? thenEntry.fileOffset
            :
              // Coverage-ignore(suite): Not run.
              offsetForToken(ifToken);
        node = new MapLiteralEntry(
          buildProblem(
            cfe.codeExpectedAfterButGot.withArgumentsOld(':'),
            offset,
            1,
          ),
          new NullLiteral(),
        )..fileOffset = offsetForToken(ifToken);
      }
    } else {
      if (condition.patternGuard == null) {
        node = forest.createIfElement(
          offsetForToken(ifToken),
          condition.expression,
          toValue(thenEntry),
          toValue(elseEntry),
        );
      } else {
        node = forest.createIfCaseElement(
          offsetForToken(ifToken),
          prelude: [],
          expression: condition.expression,
          patternGuard: condition.patternGuard!,
          then: toValue(thenEntry),
          otherwise: toValue(elseEntry),
        );
      }
    }
    push(node);
    // This is matched by the call to [deferNode] in
    // [handleElseControlFlow].
    typeInferrer.assignedVariables.storeInfo(node, assignedVariablesInfo);
  }

  @override
  void handleNullAwareElement(Token nullAwareElement) {
    debugEvent("NullAwareElement");
    if (!libraryFeatures.nullAwareElements.isEnabled) {
      addProblem(
        codeExperimentNotEnabledOffByDefault.withArgumentsOld(
          ExperimentalFlag.nullAwareElements.name,
        ),
        nullAwareElement.offset,
        noLength,
      );
    }
    Expression expression = popForValue(); // Expression.
    push(
      forest.createNullAwareElement(
        offsetForToken(nullAwareElement),
        expression,
      ),
    );
  }

  @override
  void handleSpreadExpression(Token spreadToken) {
    debugEvent("SpreadExpression");
    Object? expression = pop();
    push(
      forest.createSpreadElement(
        offsetForToken(spreadToken),
        toValue(expression),
        isNullAware: spreadToken.lexeme == '...?',
      ),
    );
  }

  @override
  void endTypeArguments(int count, Token beginToken, Token endToken) {
    debugEvent("TypeArguments");
    push(
      const FixedNullableList<TypeBuilder>().popNonNullable(
            stack,
            count,
            dummyTypeBuilder,
          ) ??
          NullValues.TypeArguments,
    );
  }

  @override
  void handleInvalidTypeArguments(Token token) {
    debugEvent("InvalidTypeArguments");
    pop(NullValues.TypeArguments);
  }

  @override
  void handleThisExpression(Token token, IdentifierContext context) {
    debugEvent("ThisExpression");
    if (context.isScopeReference && isDeclarationInstanceContext) {
      if (thisVariable != null && !inConstructorInitializer) {
        if (constantContext != ConstantContext.none) {
          push(
            new IncompleteErrorGenerator(this, token, cfe.codeThisAsIdentifier),
          );
        } else {
          push(
            _createReadOnlyVariableAccess(
              thisVariable!,
              token,
              offsetForToken(token),
              'this',
              ReadOnlyAccessKind.ExtensionThis,
            ),
          );
        }
      } else if ((!inConstructorInitializer || !inInitializerLeftHandSide) &&
          (_context.isExtensionDeclaration ||
              _context.isExtensionTypeDeclaration)) {
        // In an extension (type) where we don't (here) have a "this" variable.
        push(
          new IncompleteErrorGenerator(this, token, cfe.codeThisAsIdentifier),
        );
      } else {
        push(
          new ThisAccessGenerator(
            this,
            token,
            inInitializerLeftHandSide,
            inFieldInitializer,
            inLateFieldInitializer,
          ),
        );
      }
    } else {
      push(new IncompleteErrorGenerator(this, token, cfe.codeThisAsIdentifier));
    }
  }

  @override
  void handleSuperExpression(Token token, IdentifierContext context) {
    debugEvent("SuperExpression");
    if (context.isScopeReference &&
        isDeclarationInstanceContext &&
        thisVariable == null) {
      _context.registerSuperCall();
      push(
        new ThisAccessGenerator(
          this,
          token,
          inInitializerLeftHandSide,
          inFieldInitializer,
          inLateFieldInitializer,
          isSuper: true,
        ),
      );
    } else {
      push(
        new IncompleteErrorGenerator(this, token, cfe.codeSuperAsIdentifier),
      );
    }
  }

  @override
  // Coverage-ignore(suite): Not run.
  void handleAugmentSuperExpression(
    Token augmentToken,
    Token superToken,
    IdentifierContext context,
  ) {
    debugEvent("AugmentSuperExpression");
    AugmentSuperTarget? augmentSuperTarget = _context.augmentSuperTarget;
    if (augmentSuperTarget != null) {
      push(
        new AugmentSuperAccessGenerator(this, augmentToken, augmentSuperTarget),
      );
      return;
    }
    push(
      new IncompleteErrorGenerator(
        this,
        augmentToken,
        cfe.codeInvalidAugmentSuper,
      ),
    );
  }

  @override
  void handleNamedArgument(Token colon) {
    debugEvent("NamedArgument");
    assert(
      checkState(colon, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
        unionOfKinds([ValueKinds.Identifier, ValueKinds.ParserRecovery]),
      ]),
    );
    Expression value = popForValue();
    Object? identifier = pop();
    if (identifier is Identifier) {
      push(
        new NamedExpression(identifier.name, value)
          ..fileOffset = identifier.nameOffset,
      );
    } else {
      assert(
        identifier is ParserRecovery,
        "Unexpected argument name: "
        "${identifier} (${identifier.runtimeType})",
      );
      push(identifier);
    }
  }

  @override
  // TODO: Handle directly.
  void handleNamedRecordField(Token colon) => handleNamedArgument(colon);

  @override
  void endFunctionName(
    Token beginToken,
    Token token,
    bool isFunctionExpression,
  ) {
    debugEvent("FunctionName");
    Identifier name = pop() as Identifier;
    Token nameToken = name.token;
    String identifierName = name.name;
    bool isWildcard =
        libraryFeatures.wildcardVariables.isEnabled && identifierName == '_';
    if (isWildcard) {
      identifierName = createWildcardVariableName(wildcardVariableIndex);
      wildcardVariableIndex++;
    }
    VariableDeclaration variable = new VariableDeclarationImpl(
      identifierName,
      forSyntheticToken: nameToken.isSynthetic,
      isFinal: true,
      isLocalFunction: true,
      isWildcard: isWildcard,
    )..fileOffset = name.nameOffset;
    push(
      new FunctionDeclarationImpl(
        variable,
        // The real function node is created later.
        dummyFunctionNode,
      )..fileOffset = beginToken.charOffset,
    );
    if (!(libraryFeatures.wildcardVariables.isEnabled && variable.isWildcard)) {
      // The local scope stack contains a type parameter scope for the local
      // function on top of the scope for the block in which the local function
      // declaration occurs. So for a local function declaration, we add the
      // declaration to the previous scope, i.e. the block scope.
      //
      // For a named function expression, a nested scope is created to hold the
      // name, so that it doesn't pollute the block scope (the named function
      // expression is erroneous and should introduce the name in the scope) and
      // we therefore use the current scope in this case.
      LocalScope scope = isFunctionExpression
          ? _localScope
          : _localScopes.previous;
      declareVariable(variable, scope);
    }
  }

  void enterFunction() {
    _enterLocalState();
    debugEvent("enterFunction");
    functionNestingLevel++;
    _switchScopes.push(null);
    push(inCatchBlock);
    inCatchBlock = false;
    // This is matched by the call to [endNode] in [pushNamedFunction] or
    // [endFunctionExpression].
    typeInferrer.assignedVariables.beginNode();
    assert(checkState(null, [/* inCatchBlock */ ValueKinds.Bool]));
  }

  void exitFunction() {
    assert(
      checkState(null, [
        /* inCatchBlock */ ValueKinds.Bool,
        /* nominal parameters */ ValueKinds.NominalVariableListOrNull,
      ]),
    );
    debugEvent("exitFunction");
    functionNestingLevel--;
    inCatchBlock = pop() as bool;
    _switchScopes.pop();
    List<NominalParameterBuilder>? typeParameters =
        pop() as List<NominalParameterBuilder>?;
    exitLocalScope();
    push(typeParameters ?? NullValues.NominalParameters);
    _exitLocalState();
    assert(checkState(null, [ValueKinds.NominalVariableListOrNull]));
  }

  @override
  void beginLocalFunctionDeclaration(Token token) {
    debugEvent("beginLocalFunctionDeclaration");
    enterFunction();
  }

  @override
  void beginNamedFunctionExpression(Token token) {
    debugEvent("beginNamedFunctionExpression");
    List<NominalParameterBuilder>? typeParameters =
        pop() as List<NominalParameterBuilder>?;
    // Create an additional scope in which the named function expression is
    // declared.
    createAndEnterLocalScope(
      debugName: "named function",
      kind: ScopeKind.namedFunctionExpression,
    );
    push(typeParameters ?? NullValues.NominalParameters);
    enterFunction();
  }

  @override
  void beginFunctionExpression(Token token) {
    debugEvent("beginFunctionExpression");
    enterFunction();
  }

  void pushNamedFunction(Token token, bool isFunctionExpression) {
    Statement body = popStatement(token);
    AsyncMarker asyncModifier = pop() as AsyncMarker;
    exitLocalScope();
    FormalParameters formals = pop() as FormalParameters;
    Object? declaration = pop();
    TypeBuilder? returnType = pop() as TypeBuilder?;
    bool hasImplicitReturnType = returnType == null;
    exitFunction();
    List<NominalParameterBuilder>? typeParameters =
        pop() as List<NominalParameterBuilder>?;
    List<Expression>? annotations;
    if (!isFunctionExpression) {
      annotations = pop() as List<Expression>?; // Metadata.
    }
    FunctionNode function = formals.buildFunctionNode(
      libraryBuilder,
      returnType,
      typeParameters,
      asyncModifier,
      body,
      token.charOffset,
    );

    if (declaration is FunctionDeclaration) {
      VariableDeclaration variable = declaration.variable;
      if (annotations != null) {
        for (Expression annotation in annotations) {
          variable.addAnnotation(annotation);
        }
      }
      FunctionDeclarationImpl.setHasImplicitReturnType(
        declaration as FunctionDeclarationImpl,
        hasImplicitReturnType,
      );
      if (!hasImplicitReturnType) {
        checkAsyncReturnType(
          asyncModifier,
          function.returnType,
          variable.fileOffset,
          variable.name!.length,
        );
      }

      variable.type = function.computeFunctionType(Nullability.nonNullable);

      declaration.function = function;
      function.parent = declaration;
      Statement statement;
      if (variable.initializer != null) {
        // This must have been a compile-time error.
        assert(isErroneousNode(variable.initializer!));

        statement = forest
            .createBlock(declaration.fileOffset, noLocation, <Statement>[
              forest.createExpressionStatement(
                offsetForToken(token),
                variable.initializer!,
              ),
              declaration,
            ]);
        variable.initializer = null;
      } else {
        statement = declaration;
      }
      // This is matched by the call to [beginNode] in [enterFunction].
      typeInferrer.assignedVariables.endNode(
        declaration,
        isClosureOrLateVariableInitializer: true,
      );
      if (isFunctionExpression) {
        // This is an error case. An expression is expected but we got a
        // function declaration instead. We wrap it in a [BlockExpression].
        exitLocalScope();
        push(
          new BlockExpression(
            forest.createBlock(declaration.fileOffset, noLocation, [statement]),
            buildProblem(
              cfe.codeNamedFunctionExpression,
              declaration.fileOffset,
              noLength,
              // Error has already been reported by the parser.
              errorHasBeenReported: true,
            ),
          )..fileOffset = declaration.fileOffset,
        );
      } else {
        push(statement);
      }
    } else {
      unhandled(
        "${declaration.runtimeType}",
        "pushNamedFunction",
        token.charOffset,
        uri,
      );
    }
  }

  @override
  void endNamedFunctionExpression(Token endToken) {
    debugEvent("NamedFunctionExpression");
    pushNamedFunction(endToken, true);
  }

  @override
  void endLocalFunctionDeclaration(Token token) {
    debugEvent("LocalFunctionDeclaration");
    pushNamedFunction(token, false);
  }

  @override
  void endFunctionExpression(Token beginToken, Token endToken) {
    debugEvent("FunctionExpression");
    assert(
      checkState(beginToken, [
        /* body */ ValueKinds.StatementOrNull,
        /* async marker */ ValueKinds.AsyncMarker,
        /* formal parameters */ ValueKinds.FormalParameters,
        /* inCatchBlock */ ValueKinds.Bool,
        /* nominal parameters */ ValueKinds.NominalVariableListOrNull,
      ]),
    );
    Statement body =
        popNullableStatement() ??
        // In erroneous cases, there might not be function body. In such cases
        // we use an empty statement instead.
        // TODO(jensj): Is this the offset we want?
        forest.createEmptyStatement(endToken.next!.charOffset);
    AsyncMarker asyncModifier = pop() as AsyncMarker;
    exitLocalScope();
    FormalParameters formals = pop() as FormalParameters;
    exitFunction();
    List<NominalParameterBuilder>? typeParameters =
        pop() as List<NominalParameterBuilder>?;
    FunctionNode function = formals.buildFunctionNode(
      libraryBuilder,
      null,
      typeParameters,
      asyncModifier,
      body,
      // TODO(jensj): Is this the offset we want?
      endToken.next!.charOffset,
    )..fileOffset = beginToken.charOffset;

    Expression result;
    if (constantContext != ConstantContext.none) {
      result = buildProblem(
        cfe.codeNotAConstantExpression,
        formals.charOffset,
        formals.length,
      );
    } else {
      result = new FunctionExpression(function)
        ..fileOffset = offsetForToken(beginToken);
    }
    push(result);
    // This is matched by the call to [beginNode] in [enterFunction].
    typeInferrer.assignedVariables.endNode(
      result,
      isClosureOrLateVariableInitializer: true,
    );
    assert(
      checkState(beginToken, [
        /* function expression or problem */ ValueKinds.Expression,
      ]),
    );
  }

  @override
  void beginDoWhileStatement(Token token) {
    debugEvent("beginDoWhileStatement");
    // This is matched by the [endNode] call in [endDoWhileStatement].
    typeInferrer.assignedVariables.beginNode();
    enterLoop(token.charOffset);
  }

  @override
  void endDoWhileStatement(
    Token doKeyword,
    Token whileKeyword,
    Token endToken,
  ) {
    debugEvent("DoWhileStatement");
    assert(
      checkState(doKeyword, [
        /* condition = */ ValueKinds.Condition,
        /* body = */ ValueKinds.Statement,
        /* continue target = */ ValueKinds.ContinueTarget,
        /* break target = */ ValueKinds.BreakTarget,
      ]),
    );
    Condition condition = pop() as Condition;
    assert(
      condition.patternGuard == null,
      "Unexpected pattern in do statement: ${condition.patternGuard}.",
    );
    Expression expression = condition.expression;
    Statement body = popStatement(doKeyword);
    JumpTarget continueTarget = exitContinueTarget()!;
    JumpTarget breakTarget = exitBreakTarget()!;
    List<BreakStatementImpl>? continueStatements;
    if (continueTarget.hasUsers) {
      LabeledStatement labeledStatement = forest.createLabeledStatement(body);
      continueStatements = continueTarget.resolveContinues(
        forest,
        labeledStatement,
      );
      body = labeledStatement;
    }
    Statement doStatement = forest.createDoStatement(
      offsetForToken(doKeyword),
      body,
      expression,
    );
    // This is matched by the [beginNode] call in [beginDoWhileStatement].
    typeInferrer.assignedVariables.endNode(doStatement);
    if (continueStatements != null) {
      for (BreakStatementImpl continueStatement in continueStatements) {
        continueStatement.targetStatement = doStatement;
      }
    }
    Statement result = doStatement;
    if (breakTarget.hasUsers) {
      LabeledStatement labeledStatement = forest.createLabeledStatement(result);
      breakTarget.resolveBreaks(forest, labeledStatement, doStatement);
      result = labeledStatement;
    }
    exitLoopOrSwitch(result);
  }

  @override
  void beginForInExpression(Token token) {
    if (_localScopes.hasPrevious) {
      enterLocalScope(_localScopes.previous);
    } else {
      // Coverage-ignore-block(suite): Not run.
      createAndEnterLocalScope(
        debugName: 'forIn',
        kind: ScopeKind.statementLocalScope,
      );
    }
  }

  @override
  void endForInExpression(Token token) {
    debugEvent("ForInExpression");
    Expression expression = popForValue();
    exitLocalScope();
    push(expression);
  }

  @override
  void handleForInLoopParts(
    Token? awaitToken,
    Token forToken,
    Token leftParenthesis,
    Token? patternKeyword,
    Token inKeyword,
  ) {
    debugEvent("ForInLoopParts");
    assert(
      checkState(forToken, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Pattern,
          ValueKinds.Statement, // Variable for non-pattern for-in loop.
          ValueKinds.ParserRecovery,
        ]),
      ]),
    );
    Object expression = pop() as Object;
    Object pattern = pop() as Object;

    if (pattern is Pattern) {
      pop(); // Metadata.
      bool isFinal = patternKeyword?.lexeme == 'final';
      for (VariableDeclaration variable in pattern.declaredVariables) {
        variable.isFinal |= isFinal;
        declareVariable(variable, _localScope);
      }
    }

    push(pattern);
    push(expression);
    push(awaitToken ?? NullValues.AwaitToken);
    push(forToken);
    push(inKeyword);
    // This is matched by the call to [deferNode] in [endForIn] or
    // [endForInControlFlow].
    typeInferrer.assignedVariables.beginNode();
  }

  @override
  void endForInControlFlow(Token token) {
    debugEvent("ForInControlFlow");
    Object? entry = pop();
    Token inToken = pop() as Token;
    Token forToken = pop() as Token;
    Token? awaitToken = pop(NullValues.AwaitToken) as Token?;

    if (constantContext != ConstantContext.none) {
      popForValue(); // Pop iterable
      pop(); // Pop lvalue
      exitLocalScope();
      typeInferrer.assignedVariables.discardNode();

      push(
        buildProblem(
          cfe.codeCantUseControlFlowOrSpreadAsConstant.withArgumentsOld(
            forToken,
          ),
          forToken.charOffset,
          forToken.charCount,
        ),
      );
      return;
    }

    // This is matched by the call to [beginNode] in [handleForInLoopParts].
    AssignedVariablesNodeInfo assignedVariablesNodeInfo = typeInferrer
        .assignedVariables
        .popNode();

    Expression iterable = popForValue();
    Object? lvalue = pop(); // lvalue
    exitLocalScope();

    ForInElements elements = _computeForInElements(
      forToken,
      inToken,
      lvalue,
      null,
    );
    typeInferrer.assignedVariables.pushNode(assignedVariablesNodeInfo);
    VariableDeclaration variable = elements.variable;
    Expression? problem = elements.expressionProblem;
    if (entry is MapLiteralEntry) {
      ForInMapEntry result = forest.createForInMapEntry(
        offsetForToken(forToken),
        variable,
        iterable,
        elements.syntheticAssignment,
        elements.expressionEffects,
        entry,
        problem,
        isAsync: awaitToken != null,
      );
      typeInferrer.assignedVariables.endNode(result);
      push(result);
    } else {
      ForInElement result = forest.createForInElement(
        offsetForToken(forToken),
        variable,
        iterable,
        elements.syntheticAssignment,
        elements.expressionEffects,
        toValue(entry),
        problem,
        isAsync: awaitToken != null,
      );
      typeInferrer.assignedVariables.endNode(result);
      push(result);
    }
  }

  ForInElements _computeForInElements(
    Token forToken,
    Token inToken,
    Object? lvalue,
    Statement? body,
  ) {
    ForInElements elements = new ForInElements();
    if (lvalue is VariableDeclaration) {
      // Late for-in variables are not supported. An error has already been
      // reported by the parser.
      lvalue.isLate = false;
      elements.explicitVariableDeclaration = lvalue;
      if (lvalue.isConst) {
        elements.expressionProblem = buildProblem(
          cfe.codeForInLoopWithConstVariable,
          lvalue.fileOffset,
          lvalue.name!.length,
        );
        // As a recovery step, remove the const flag, to not confuse the
        // constant evaluator further in the pipeline.
        lvalue.isConst = false;
      }
    } else {
      VariableDeclaration variable = elements.syntheticVariableDeclaration =
          forest.createVariableDeclaration(
            offsetForToken(forToken),
            null,
            isFinal: true,
            isSynthesized: true,
          );
      if (lvalue is Generator) {
        /// We are in this case, where `lvalue` isn't a [VariableDeclaration]:
        ///
        ///     for (lvalue in expression) body
        ///
        /// This is normalized to:
        ///
        ///     for (final #t in expression) {
        ///       lvalue = #t;
        ///       body;
        ///     }
        elements.syntheticAssignment = lvalue.buildAssignment(
          new VariableGet(variable)..fileOffset = inToken.offset,
          voidContext: true,
        );
      } else if (lvalue is Pattern) {
        /// We are in the case where `lvalue` is a pattern:
        ///
        ///     for (pattern in expression) body
        ///
        /// This is normalized to:
        ///
        ///     for (final #t in expression) {
        ///       pattern = #t;
        ///       body;
        ///     }
        elements.syntheticAssignment = null;
        elements.expressionEffects = forest.createPatternVariableDeclaration(
          inToken.offset,
          lvalue,
          new VariableGet(variable),
          isFinal: false,
        );
      } else if (lvalue is InvalidExpression) {
        // Coverage-ignore-block(suite): Not run.
        elements.expressionProblem = lvalue;
      } else if (lvalue is ParserRecovery) {
        elements.expressionProblem = buildProblem(
          cfe.codeSyntheticToken,
          lvalue.charOffset,
          noLength,
        );
      } else {
        Message message = forest.isVariablesDeclaration(lvalue)
            ? cfe.codeForInLoopExactlyOneVariable
            : cfe.codeForInLoopNotAssignable;
        Token token = forToken.next!.next!;
        elements.expressionProblem = buildProblem(
          message,
          offsetForToken(token),
          lengthForToken(token),
        );
        Statement effects;
        if (forest.isVariablesDeclaration(lvalue)) {
          effects = forest.createBlock(
            noLocation,
            noLocation,
            // New list because the declarations are not a growable list.
            new List<Statement>.of(
              forest.variablesDeclarationExtractDeclarations(lvalue),
            ),
          );
        } else {
          effects = forest.createExpressionStatement(
            noLocation,
            lvalue as Expression,
          );
        }
        elements.expressionEffects = combineStatements(
          forest.createExpressionStatement(
            noLocation,
            buildProblem(message, offsetForToken(token), lengthForToken(token)),
          ),
          effects,
        );
      }
    }
    return elements;
  }

  @override
  void endForIn(Token endToken) {
    debugEvent("ForIn");
    assert(
      checkState(endToken, [
        /* body= */ unionOfKinds([
          ValueKinds.Statement,
          ValueKinds.ParserRecovery,
        ]),
        /* inKeyword = */ ValueKinds.Token,
        /* forToken = */ ValueKinds.Token,
        /* awaitToken = */ ValueKinds.AwaitTokenOrNull,
        /* expression = */ unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
        ]),
        /* lvalue = */ unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Pattern,
          ValueKinds.Statement,
          ValueKinds.ParserRecovery,
        ]),
      ]),
    );
    Statement body = popStatement(endToken);

    Token inKeyword = pop() as Token;
    Token forToken = pop() as Token;
    Token? awaitToken = pop(NullValues.AwaitToken) as Token?;

    // This is matched by the call to [beginNode] in [handleForInLoopParts].
    AssignedVariablesNodeInfo assignedVariablesNodeInfo = typeInferrer
        .assignedVariables
        .deferNode();

    Expression expression = popForValue();
    Object? lvalue = pop();
    exitLocalScope();
    JumpTarget continueTarget = exitContinueTarget()!;
    JumpTarget breakTarget = exitBreakTarget()!;
    List<BreakStatementImpl>? continueStatements;
    if (continueTarget.hasUsers) {
      LabeledStatement labeledStatement = forest.createLabeledStatement(body);
      continueStatements = continueTarget.resolveContinues(
        forest,
        labeledStatement,
      );
      body = labeledStatement;
    }
    ForInElements elements = _computeForInElements(
      forToken,
      inKeyword,
      lvalue,
      body,
    );
    VariableDeclaration variable = elements.variable;
    Expression? problem = elements.expressionProblem;
    Statement forInStatement;
    if (elements.explicitVariableDeclaration != null) {
      forInStatement =
          new ForInStatement(
              variable,
              expression,
              body,
              isAsync: awaitToken != null,
            )
            ..fileOffset = awaitToken?.charOffset ?? forToken.charOffset
            ..bodyOffset = body.fileOffset; // TODO(ahe): Isn't this redundant?
    } else {
      forInStatement =
          new ForInStatementWithSynthesizedVariable(
              variable,
              expression,
              elements.syntheticAssignment,
              elements.expressionEffects,
              body,
              isAsync: awaitToken != null,
              hasProblem: problem != null,
            )
            ..fileOffset = awaitToken?.charOffset ?? forToken.charOffset
            ..bodyOffset = body.fileOffset; // TODO(ahe): Isn't this redundant?
    }
    typeInferrer.assignedVariables.storeInfo(
      forInStatement,
      assignedVariablesNodeInfo,
    );
    if (continueStatements != null) {
      for (BreakStatementImpl continueStatement in continueStatements) {
        continueStatement.targetStatement = forInStatement;
      }
    }
    Statement result = forInStatement;
    if (breakTarget.hasUsers) {
      LabeledStatement labeledStatement = forest.createLabeledStatement(result);
      breakTarget.resolveBreaks(forest, labeledStatement, forInStatement);
      result = labeledStatement;
    }
    if (problem != null) {
      result = combineStatements(
        forest.createExpressionStatement(noLocation, problem),
        result,
      );
    }
    exitLoopOrSwitch(result);
  }

  @override
  void handleLabel(Token token) {
    debugEvent("Label");
    Identifier identifier = pop() as Identifier;
    push(new Label(identifier.name, identifier.nameOffset));
  }

  @override
  void beginLabeledStatement(Token token, int labelCount) {
    debugEvent("beginLabeledStatement");
    List<Label>? labels = const FixedNullableList<Label>().popNonNullable(
      stack,
      labelCount,
      dummyLabel,
    );
    _labelScopes.push(new LabelScopeImpl(_labelScope));
    LabelTarget target = new LabelTarget(
      functionNestingLevel,
      uri,
      token.charOffset,
    );
    if (labels != null) {
      for (Label label in labels) {
        _labelScope.declareLabel(label.name, target);
      }
    }
    push(target);
  }

  @override
  void endLabeledStatement(int labelCount) {
    debugEvent("LabeledStatement");
    Statement statement = popStatementNoWrap();
    LabelTarget target = pop() as LabelTarget;
    _labelScopes.pop();
    // TODO(johnniwinther): Split the handling of breaks and continue.
    if (target.breakTarget.hasUsers || target.continueTarget.hasUsers) {
      if (forest.isVariablesDeclaration(statement)) {
        internalProblem(
          cfe.codeInternalProblemLabelUsageInVariablesDeclaration,
          statement.fileOffset,
          uri,
        );
      }
      if (statement is! LabeledStatement) {
        statement = forest.createLabeledStatement(statement);
      }
      target.breakTarget.resolveBreaks(forest, statement, statement);
      List<BreakStatementImpl>? continueStatements = target.continueTarget
          .resolveContinues(forest, statement);
      if (continueStatements != null) {
        for (BreakStatementImpl continueStatement in continueStatements) {
          continueStatement.targetStatement = statement;
          Statement labelStatementBody = statement.body;
          if (labelStatementBody is LoopStatement) {
            Statement loopBody = labelStatementBody.body;
            if (loopBody is LabeledStatement) {
              continueStatement.target = loopBody;
            } else {
              labelStatementBody.body = continueStatement.target =
                  forest.createLabeledStatement(labelStatementBody.body)
                    ..parent = labelStatementBody;
            }
          } else {
            push(
              buildProblemStatement(
                cfe.codeContinueLabelInvalid,
                continueStatement.fileOffset,
                length: 8,
              ),
            );
            return;
          }
        }
      }
    }
    push(statement);
  }

  @override
  void endRethrowStatement(Token rethrowToken, Token endToken) {
    debugEvent("RethrowStatement");
    if (inCatchBlock) {
      push(
        forest.createRethrowStatement(
          offsetForToken(rethrowToken),
          offsetForToken(endToken),
        ),
      );
    } else {
      push(
        new ExpressionStatement(
          buildProblem(
            cfe.codeRethrowNotCatch,
            offsetForToken(rethrowToken),
            lengthForToken(rethrowToken),
          ),
        )..fileOffset = offsetForToken(rethrowToken),
      );
    }
  }

  @override
  void handleFinallyBlock(Token finallyKeyword) {
    debugEvent("FinallyBlock");
    // Do nothing, handled by [endTryStatement].
  }

  @override
  void beginWhileStatement(Token token) {
    debugEvent("beginWhileStatement");
    // This is matched by the [endNode] call in [endWhileStatement].
    typeInferrer.assignedVariables.beginNode();
    enterLoop(token.charOffset);
  }

  @override
  void endWhileStatement(Token whileKeyword, Token endToken) {
    debugEvent("WhileStatement");
    assert(
      checkState(whileKeyword, [
        /* body = */ unionOfKinds([
          ValueKinds.Statement,
          ValueKinds.ParserRecovery,
        ]),
        /* condition = */ ValueKinds.Condition,
        /* continue target = */ ValueKinds.ContinueTarget,
        /* break target = */ ValueKinds.BreakTarget,
      ]),
    );
    Statement body = popStatement(whileKeyword);
    Condition condition = pop() as Condition;
    assert(
      condition.patternGuard == null,
      "Unexpected pattern in while statement: ${condition.patternGuard}.",
    );
    Expression expression = condition.expression;
    JumpTarget continueTarget = exitContinueTarget()!;
    JumpTarget breakTarget = exitBreakTarget()!;
    List<BreakStatementImpl>? continueStatements;
    if (continueTarget.hasUsers) {
      LabeledStatement labeledStatement = forest.createLabeledStatement(body);
      continueStatements = continueTarget.resolveContinues(
        forest,
        labeledStatement,
      );
      body = labeledStatement;
    }
    Statement whileStatement = forest.createWhileStatement(
      offsetForToken(whileKeyword),
      expression,
      body,
    );
    if (continueStatements != null) {
      for (BreakStatementImpl continueStatement in continueStatements) {
        continueStatement.targetStatement = whileStatement;
      }
    }
    Statement result = whileStatement;
    if (breakTarget.hasUsers) {
      LabeledStatement labeledStatement = forest.createLabeledStatement(result);
      breakTarget.resolveBreaks(forest, labeledStatement, whileStatement);
      result = labeledStatement;
    }
    exitLoopOrSwitch(result);
    // This is matched by the [beginNode] call in [beginWhileStatement].
    typeInferrer.assignedVariables.endNode(whileStatement);
  }

  @override
  void handleEmptyStatement(Token token) {
    debugEvent("EmptyStatement");
    push(forest.createEmptyStatement(offsetForToken(token)));
  }

  @override
  void beginAssert(Token assertKeyword, Assert kind) {
    debugEvent("beginAssert");
    // If in an assert initializer, make sure [inInitializer] is false so we
    // use the formal parameter scope. If this is any other kind of assert,
    // inInitializer should be false anyway.
    inInitializerLeftHandSide = false;
  }

  @override
  void endAssert(
    Token assertKeyword,
    Assert kind,
    Token leftParenthesis,
    Token? commaToken,
    Token endToken,
  ) {
    debugEvent("Assert");
    Expression? message = popForValueIfNotNull(commaToken);
    Expression condition = popForValue();
    int fileOffset = offsetForToken(assertKeyword);

    /// Return a representation of an assert that appears as a statement.
    AssertStatement createAssertStatement() {
      // Compute start and end offsets for the condition expression.
      // This code is a temporary workaround because expressions don't carry
      // their start and end offsets currently.
      //
      // The token that follows leftParenthesis is considered to be the
      // first token of the condition.
      // TODO(ahe): this really should be condition.fileOffset.
      int startOffset = leftParenthesis.next!.offset;
      int endOffset;

      // Search forward from leftParenthesis to find the last token of
      // the condition - which is a token immediately followed by a commaToken,
      // right parenthesis or a trailing comma.
      Token? conditionBoundary = commaToken ?? leftParenthesis.endGroup;
      Token conditionLastToken = leftParenthesis;
      while (!conditionLastToken.isEof) {
        Token nextToken = conditionLastToken.next!;
        if (nextToken == conditionBoundary) {
          break;
        } else if (nextToken.isA(TokenType.COMMA) &&
            nextToken.next == conditionBoundary) {
          // The next token is trailing comma, which means current token is
          // the last token of the condition.
          break;
        }
        conditionLastToken = nextToken;
      }
      if (conditionLastToken.isEof) {
        // Coverage-ignore-block(suite): Not run.
        endOffset = startOffset = -1;
      } else {
        endOffset = conditionLastToken.offset + conditionLastToken.length;
      }

      return forest.createAssertStatement(
        fileOffset,
        condition,
        message,
        startOffset,
        endOffset,
      );
    }

    switch (kind) {
      case Assert.Statement:
        push(createAssertStatement());
        break;

      case Assert.Expression:
        // The parser has already reported an error indicating that assert
        // cannot be used in an expression.
        push(
          buildProblem(
            cfe.codeAssertAsExpression,
            fileOffset,
            assertKeyword.length,
          ),
        );
        break;

      case Assert.Initializer:
        push(
          forest.createAssertInitializer(fileOffset, createAssertStatement()),
        );
        break;
    }
  }

  @override
  void endYieldStatement(Token yieldToken, Token? starToken, Token endToken) {
    debugEvent("YieldStatement");
    push(
      forest.createYieldStatement(
        offsetForToken(yieldToken),
        popForValue(),
        isYieldStar: starToken != null,
      ),
    );
  }

  @override
  void beginSwitchBlock(Token token) {
    debugEvent("beginSwitchBlock");
    // This is matched by the [endNode] call in [endSwitchStatement].
    typeInferrer.assignedVariables.beginNode();
    createAndEnterLocalScope(
      debugName: "switch block",
      kind: ScopeKind.switchBlock,
    );
    enterSwitchScope();
    enterBreakTarget(token.charOffset);
    createAndEnterLocalScope(
      debugName: "case-head",
      kind: ScopeKind.caseHead,
    ); // Sentinel scope.
  }

  @override
  void beginSwitchCase(int labelCount, int expressionCount, Token beginToken) {
    debugEvent("beginSwitchCase");
    int count = labelCount + expressionCount;
    assert(
      checkState(
        beginToken,
        repeatedKind(
          unionOfKinds([
            ValueKinds.Label,
            ValueKinds.ExpressionOrPatternGuardCase,
          ]),
          count,
        ),
      ),
    );

    List<Label>? labels = labelCount == 0
        ? null
        : new List<Label>.filled(labelCount, dummyLabel);
    int labelIndex = labelCount - 1;
    bool containsPatterns = false;
    List<ExpressionOrPatternGuardCase> expressionOrPatterns =
        new List<ExpressionOrPatternGuardCase>.filled(
          expressionCount,
          dummyExpressionOrPatternGuardCase,
          growable: true,
        );
    int expressionOrPatternIndex = expressionCount - 1;

    for (int i = 0; i < count; i++) {
      Object? value = pop();
      if (value is Label) {
        labels![labelIndex--] = value;
      } else {
        expressionOrPatterns[expressionOrPatternIndex--] =
            value as ExpressionOrPatternGuardCase;
        if (value.patternGuard != null) {
          containsPatterns = true;
        }
      }
    }

    LocalScope switchCaseScope;
    if (expressionCount == 1) {
      // The single-head case. The scope of the head should be remembered
      // and reused later; it already contains the declared pattern
      // variables.
      switchCaseScope = _localScope;
      exitLocalScope(expectedScopeKinds: const [ScopeKind.caseHead]);
    } else {
      // The multi-head or "default" case. The scope of the last head should
      // be exited, and the new scope for the joint variables should be
      // created.
      exitLocalScope(expectedScopeKinds: const [ScopeKind.caseHead]);
      switchCaseScope = _localScope.createNestedScope(
        debugName: "joint-variables",
        kind: ScopeKind.jointVariables,
      );
    }

    assert(_labelScope == _switchScope);

    if (labels != null) {
      for (Label label in labels) {
        String labelName = label.name;
        if (_labelScope.hasLocalLabel(labelName)) {
          // TODO(ahe): Should validate this is a goto target.
          if (!_labelScope.claimLabel(labelName)) {
            addProblem(
              cfe.codeDuplicateLabelInSwitchStatement.withArgumentsOld(
                labelName,
              ),
              label.charOffset,
              labelName.length,
            );
          }
        } else {
          _labelScope.declareLabel(
            labelName,
            createGotoTarget(beginToken.charOffset),
          );
        }
      }
    }
    push(expressionOrPatterns);
    push(containsPatterns);
    push(labels ?? NullValues.Labels);

    List<VariableDeclaration>? jointPatternVariables;
    List<VariableDeclaration>? jointPatternVariablesWithMismatchingFinality;
    List<VariableDeclaration>? jointPatternVariablesNotInAll;
    enterLocalScope(switchCaseScope);
    if (expressionCount > 1) {
      for (int i = 0; i < expressionOrPatterns.length; i++) {
        ExpressionOrPatternGuardCase expressionOrPattern =
            expressionOrPatterns[i];
        PatternGuard? patternGuard = expressionOrPattern.patternGuard;
        if (patternGuard != null) {
          if (jointPatternVariables == null) {
            jointPatternVariables = [
              for (VariableDeclaration variable
                  in patternGuard.pattern.declaredVariables)
                forest.createVariableDeclaration(
                  variable.fileOffset,
                  variable.name!,
                )..isFinal = variable.isFinal,
            ];
            if (i != 0) {
              // The previous heads were non-pattern ones, so no variables can
              // be joined.
              (jointPatternVariablesNotInAll ??= []).addAll(
                jointPatternVariables,
              );
            }
          } else {
            Map<String, VariableDeclaration> patternVariablesByName = {
              for (VariableDeclaration variable
                  in patternGuard.pattern.declaredVariables)
                variable.name!: variable,
            };
            for (VariableDeclaration jointVariable in jointPatternVariables) {
              String jointVariableName = jointVariable.name!;
              VariableDeclaration? patternVariable = patternVariablesByName
                  .remove(jointVariableName);
              if (patternVariable != null) {
                if (patternVariable.isFinal != jointVariable.isFinal) {
                  (jointPatternVariablesWithMismatchingFinality ??= []).add(
                    jointVariable,
                  );
                }
              } else {
                (jointPatternVariablesNotInAll ??= []).add(jointVariable);
              }
            }
            if (patternVariablesByName.isNotEmpty) {
              for (VariableDeclaration variable
                  in patternVariablesByName.values) {
                VariableDeclaration jointVariable =
                    forest.createVariableDeclaration(
                      variable.fileOffset,
                      variable.name!,
                    )..isFinal = variable.isFinal;
                (jointPatternVariablesNotInAll ??= []).add(jointVariable);
                jointPatternVariables.add(jointVariable);
              }
            }
          }
        } else {
          // It's a non-pattern head, so no variables can be joined.
          if (jointPatternVariables != null) {
            (jointPatternVariablesNotInAll ??= []).addAll(
              jointPatternVariables,
            );
          }
        }
      }
      if (jointPatternVariables != null) {
        if (jointPatternVariables.isEmpty) {
          jointPatternVariables = null;
        } else {
          for (VariableDeclaration jointVariable in jointPatternVariables) {
            assert(_localScope.kind == ScopeKind.jointVariables);
            declareVariable(jointVariable, _localScope);
            typeInferrer.assignedVariables.declare(jointVariable);
          }
        }
      }
      switchCaseScope = _localScope.createNestedScope(
        debugName: "switch case",
        kind: ScopeKind.switchCase,
      );
      exitLocalScope(expectedScopeKinds: const [ScopeKind.jointVariables]);
      enterLocalScope(switchCaseScope);
    } else if (expressionCount == 1) {
      switchCaseScope = _localScope.createNestedScope(
        debugName: "switch case",
        kind: ScopeKind.switchCase,
      );
      exitLocalScope(expectedScopeKinds: const [ScopeKind.caseHead]);
      enterLocalScope(switchCaseScope);
    }
    push(jointPatternVariablesNotInAll ?? NullValues.VariableDeclarationList);
    push(
      jointPatternVariablesWithMismatchingFinality ??
          NullValues.VariableDeclarationList,
    );
    push(jointPatternVariables ?? NullValues.VariableDeclarationList);

    createAndEnterLocalScope(
      debugName: "switch-case-body",
      kind: ScopeKind.switchCaseBody,
    );

    assert(
      checkState(beginToken, [
        ValueKinds.VariableDeclarationListOrNull,
        ValueKinds.VariableDeclarationListOrNull,
        ValueKinds.VariableDeclarationListOrNull,
        ValueKinds.LabelListOrNull,
        ValueKinds.Bool,
        ValueKinds.ExpressionOrPatternGuardCaseList,
      ]),
    );
  }

  @override
  void beginSwitchCaseWhenClause(Token when) {
    debugEvent("SwitchCaseWhenClause");
    assert(
      checkState(when, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Pattern,
        ]),
        ValueKinds.ConstantContext,
      ]),
    );

    // Here we declare the pattern variables in the scope of the case head. It
    // makes the variables visible in the 'when' clause of the head.
    Object? pattern = peek();
    if (pattern is Pattern) {
      for (VariableDeclaration variable in pattern.declaredVariables) {
        declareVariable(variable, _localScope);
      }
    }
    push(constantContext);
    constantContext = ConstantContext.none;
  }

  @override
  void endSwitchCaseWhenClause(Token token) {
    debugEvent("SwitchCaseWhenClause");
    assert(
      checkState(token, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
        ValueKinds.ConstantContext,
      ]),
    );
    Object? guard = pop();
    constantContext = pop() as ConstantContext;
    push(guard);
  }

  @override
  void handleSwitchCaseNoWhenClause(Token token) {
    debugEvent("SwitchCaseWhenClause");
    assert(
      checkState(token, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Pattern,
        ]),
      ]),
    );

    // Here we declare the pattern variables. It makes the variables visible
    // body of the case.
    Object? pattern = peek();
    if (pattern is Pattern) {
      for (VariableDeclaration variable in pattern.declaredVariables) {
        declareVariable(variable, _localScope);
      }
    }
  }

  @override
  void endSwitchCase(
    int labelCount,
    int expressionCount,
    Token? defaultKeyword,
    Token? colonAfterDefault,
    int statementCount,
    Token beginToken,
    Token endToken,
  ) {
    debugEvent("SwitchCase");
    assert(
      checkState(beginToken, [
        ...repeatedKind(ValueKinds.Statement, statementCount),
        ValueKinds.VariableDeclarationListOrNull,
        ValueKinds.VariableDeclarationListOrNull,
        ValueKinds.VariableDeclarationListOrNull,
        ValueKinds.LabelListOrNull,
        ValueKinds.Bool,
        ValueKinds.ExpressionOrPatternGuardCaseList,
      ]),
    );

    // We always create a block here so that we later know that there's always
    // one synthetic block when we finish compiling the switch statement and
    // check this switch case to see if it falls through to the next case.
    Statement block = popBlock(statementCount, beginToken, null);
    exitLocalScope(expectedScopeKinds: const [ScopeKind.switchCaseBody]);
    List<VariableDeclaration>? jointPatternVariables =
        pop() as List<VariableDeclaration>?;
    List<VariableDeclaration>? jointPatternVariablesWithMismatchingFinality =
        pop() as List<VariableDeclaration>?;
    List<VariableDeclaration>? jointPatternVariablesNotInAll =
        pop() as List<VariableDeclaration>?;

    // The current scope should be the scope of the body of the switch case
    // because we want to lookup the first use of the pattern variables
    // specifically in the body of the case, as opposed to, for example, the
    // guard in one of the heads of the case.
    assert(
      _localScope.kind == ScopeKind.switchCase ||
          _localScope.kind == ScopeKind.jointVariables,
      "Expected the current scope to be of kind '${ScopeKind.switchCase}' "
      "or '${ScopeKind.jointVariables}', but got '${_localScope.kind}.",
    );
    Map<String, List<int>>? usedNamesOffsets = _localScope.usedNames;

    bool hasDefaultOrLabels = defaultKeyword != null || labelCount > 0;

    List<VariableDeclaration>? usedJointPatternVariables;
    List<int>? jointVariableFirstUseOffsets;
    if (jointPatternVariables != null) {
      usedJointPatternVariables = [];
      Map<VariableDeclaration, int> firstUseOffsets = {};
      for (VariableDeclaration variable in jointPatternVariables) {
        if (usedNamesOffsets?[variable.name!] case [int offset, ...]) {
          usedJointPatternVariables.add(variable);
          firstUseOffsets[variable] = offset;
        }
      }
      if (jointPatternVariablesWithMismatchingFinality != null ||
          jointPatternVariablesNotInAll != null ||
          hasDefaultOrLabels) {
        for (VariableDeclaration jointVariable in usedJointPatternVariables) {
          if (jointPatternVariablesWithMismatchingFinality?.contains(
                jointVariable,
              ) ??
              false) {
            String jointVariableName = jointVariable.name!;
            addProblem(
              cfe.codeJointPatternVariablesMismatch.withArgumentsOld(
                jointVariableName,
              ),
              firstUseOffsets[jointVariable]!,
              jointVariableName.length,
            );
          }
          if (jointPatternVariablesNotInAll?.contains(jointVariable) ?? false) {
            String jointVariableName = jointVariable.name!;
            addProblem(
              cfe.codeJointPatternVariableNotInAll.withArgumentsOld(
                jointVariableName,
              ),
              firstUseOffsets[jointVariable]!,
              jointVariableName.length,
            );
          }
          if (hasDefaultOrLabels) {
            String jointVariableName = jointVariable.name!;
            addProblem(
              cfe.codeJointPatternVariableWithLabelDefault.withArgumentsOld(
                jointVariableName,
              ),
              firstUseOffsets[jointVariable]!,
              jointVariableName.length,
            );
          }
        }
      }
      jointVariableFirstUseOffsets = [
        for (VariableDeclaration variable in usedJointPatternVariables)
          firstUseOffsets[variable]!,
      ];
    }

    exitLocalScope(
      expectedScopeKinds: const [
        ScopeKind.switchCase,
        ScopeKind.caseHead,
        ScopeKind.jointVariables,
      ],
    );

    List<Label>? labels = pop() as List<Label>?;
    assert(labels == null || labels.isNotEmpty);
    bool containsPatterns = pop() as bool;
    List<ExpressionOrPatternGuardCase> expressionsOrPatternGuards =
        pop() as List<ExpressionOrPatternGuardCase>;

    if (expressionCount == 1 &&
        containsPatterns &&
        hasDefaultOrLabels &&
        usedNamesOffsets != null) {
      PatternGuard? patternGuard =
          expressionsOrPatternGuards.first.patternGuard;
      if (patternGuard != null) {
        for (VariableDeclaration variable
            in patternGuard.pattern.declaredVariables) {
          String variableName = variable.name!;
          if (usedNamesOffsets[variableName] case [int offset, ...]) {
            addProblem(
              cfe.codeJointPatternVariableWithLabelDefault.withArgumentsOld(
                variableName,
              ),
              offset,
              variableName.length,
            );
          }
        }
      }
    }
    if (containsPatterns || libraryFeatures.patterns.isEnabled) {
      // If patterns are enabled, we always use the pattern switch encoding.
      // Otherwise, we use pattern switch encoding to handle the erroneous case
      // of an unsupported use of patterns.
      List<int> caseOffsets = [];
      List<PatternGuard> patternGuards = <PatternGuard>[];
      for (ExpressionOrPatternGuardCase expressionOrPatternGuard
          in expressionsOrPatternGuards) {
        caseOffsets.add(expressionOrPatternGuard.caseOffset);
        if (expressionOrPatternGuard.patternGuard != null) {
          patternGuards.add(expressionOrPatternGuard.patternGuard!);
        } else {
          patternGuards.add(
            forest.createPatternGuard(
              expressionOrPatternGuard.caseOffset,
              toPattern(expressionOrPatternGuard.expression!),
            ),
          );
        }
      }
      push(
        forest.createPatternSwitchCase(
          beginToken.charOffset,
          caseOffsets,
          patternGuards,
          block,
          isDefault: defaultKeyword != null,
          hasLabel: labels != null,
          jointVariables: usedJointPatternVariables ?? [],
          jointVariableFirstUseOffsets: jointVariableFirstUseOffsets,
        ),
      );
    } else {
      List<Expression> expressions = <Expression>[];
      List<int> caseOffsets = [];
      List<int> expressionOffsets = <int>[];
      for (ExpressionOrPatternGuardCase expressionOrPatternGuard
          in expressionsOrPatternGuards) {
        Expression expression = expressionOrPatternGuard.expression!;
        expressions.add(expression);
        caseOffsets.add(expressionOrPatternGuard.caseOffset);
        expressionOffsets.add(expression.fileOffset);
      }
      push(
        new SwitchCaseImpl(
          caseOffsets,
          expressions,
          expressionOffsets,
          block,
          isDefault: defaultKeyword != null,
          hasLabel: labels != null,
        )..fileOffset = beginToken.charOffset,
      );
    }
    push(labels ?? NullValues.Labels);
    createAndEnterLocalScope(
      debugName: "case-head",
      kind: ScopeKind.caseHead,
    ); // Sentinel scope.
    assert(
      checkState(beginToken, [
        ValueKinds.LabelListOrNull,
        ValueKinds.SwitchCase,
      ]),
    );
  }

  @override
  void endSwitchStatement(Token switchKeyword, Token endToken) {
    debugEvent("SwitchStatement");
    assert(
      checkState(switchKeyword, [
        /* labelUsers = */ ValueKinds.StatementListOrNullList,
        /* cases = */ ValueKinds.SwitchCaseList,
        /* containsPatterns */ ValueKinds.Bool,
        /* break target = */ ValueKinds.BreakTarget,
        /* expression = */ ValueKinds.Condition,
      ]),
    );
    List<List<Statement>?> labelUsers = pop() as List<List<Statement>?>;
    List<SwitchCase> cases = pop() as List<SwitchCase>;
    bool containsPatterns = pop() as bool;
    JumpTarget target = exitBreakTarget()!;
    exitSwitchScope();
    exitLocalScope();
    Condition condition = pop() as Condition;
    assert(
      condition.patternGuard == null,
      "Unexpected pattern in switch statement: ${condition.patternGuard}.",
    );
    Expression expression = condition.expression;
    Statement switchStatement;
    if (containsPatterns || libraryFeatures.patterns.isEnabled) {
      // If patterns are enabled, we always use the pattern switch encoding.
      // Otherwise, we use pattern switch encoding to handle the erroneous case
      // of an unsupported use of patterns.
      List<PatternSwitchCase> patternSwitchCases =
          new List<PatternSwitchCase>.generate(cases.length, (int index) {
            SwitchCase switchCase = cases[index];
            PatternSwitchCase patternSwitchCase;
            if (switchCase is PatternSwitchCase) {
              patternSwitchCase = switchCase;
            } else {
              // Coverage-ignore-block(suite): Not run.
              List<PatternGuard> patterns = new List<PatternGuard>.generate(
                switchCase.expressions.length,
                (int index) {
                  return forest.createPatternGuard(
                    switchCase.expressions[index].fileOffset,
                    forest.createConstantPattern(switchCase.expressions[index]),
                  );
                },
              );
              patternSwitchCase = forest.createPatternSwitchCase(
                switchCase.fileOffset,
                (switchCase as SwitchCaseImpl).caseOffsets,
                patterns,
                switchCase.body,
                isDefault: switchCase.isDefault,
                hasLabel: switchCase.hasLabel,
                jointVariables: [],
                jointVariableFirstUseOffsets: null,
              );
            }
            List<Statement>? users = labelUsers[index];
            if (users != null) {
              patternSwitchCase.labelUsers.addAll(users);
            }
            return patternSwitchCase;
          });
      switchStatement = forest.createPatternSwitchStatement(
        switchKeyword.charOffset,
        expression,
        patternSwitchCases,
      );
    } else {
      switchStatement = new SwitchStatement(expression, cases)
        ..fileOffset = switchKeyword.charOffset;
    }
    Statement result = switchStatement;
    // We create a labeled statement enclosing the switch statement if it has
    // explicit break statements targeting it, or if the patterns feature is
    // enabled, in which case synthetic break statements might be inserted.
    // TODO(johnniwinther): Remove [LabeledStatement]s in inference visitor
    // when they have no target.
    if (target.hasUsers || libraryFeatures.patterns.isEnabled) {
      LabeledStatement labeledStatement = forest.createLabeledStatement(result);
      target.resolveBreaks(forest, labeledStatement, switchStatement);
      result = labeledStatement;
    }
    exitLoopOrSwitch(result);
    // This is matched by the [beginNode] call in [beginSwitchBlock].
    typeInferrer.assignedVariables.endNode(switchStatement);
  }

  @override
  void handleSwitchExpressionCasePattern(Token token) {
    debugEvent("SwitchExpressionCasePattern");
    assert(
      checkState(token, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Pattern,
        ]),
      ]),
    );
    Object? pattern = pop();
    createAndEnterLocalScope(
      debugName: "switch-expression-case",
      kind: ScopeKind.caseHead,
    );
    if (pattern is Pattern) {
      for (VariableDeclaration variable in pattern.declaredVariables) {
        declareVariable(variable, _localScope);
      }
    }
    push(pattern);
  }

  @override
  void endSwitchExpressionCase(
    Token beginToken,
    Token? when,
    Token arrow,
    Token endToken,
  ) {
    debugEvent("endSwitchExpressionCase");
    assert(
      checkState(arrow, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
        if (when != null)
          unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Pattern,
        ]),
      ]),
    );

    Expression expression = popForValue();
    Expression? guard;
    if (when != null) {
      guard = popForValue();
    }
    Object? value = pop();
    exitLocalScope();
    PatternGuard patternGuard = forest.createPatternGuard(
      arrow.charOffset,
      toPattern(value),
      guard,
    );
    push(
      forest.createSwitchExpressionCase(
        arrow.charOffset,
        patternGuard,
        expression,
      ),
    );
    assert(checkState(arrow, [ValueKinds.SwitchExpressionCase]));
  }

  @override
  void endSwitchExpressionBlock(
    int caseCount,
    Token beginToken,
    Token endToken,
  ) {
    debugEvent("endSwitchExpressionBlock");
    assert(
      checkState(
        beginToken,
        repeatedKind(ValueKinds.SwitchExpressionCase, caseCount),
      ),
    );
    List<SwitchExpressionCase> cases = new List<SwitchExpressionCase>.filled(
      caseCount,
      dummySwitchExpressionCase,
    );
    for (int i = caseCount - 1; i >= 0; i--) {
      cases[i] = pop() as SwitchExpressionCase;
    }
    push(cases);
  }

  @override
  void endSwitchExpression(Token switchKeyword, Token endToken) {
    debugEvent("endSwitchExpression");
    assert(
      checkState(switchKeyword, [
        ValueKinds.SwitchExpressionCaseList,
        ValueKinds.Condition,
      ]),
    );

    List<SwitchExpressionCase> cases = pop() as List<SwitchExpressionCase>;
    Condition condition = pop() as Condition;
    assert(
      condition.patternGuard == null,
      "Unexpected pattern in switch expression: ${condition.patternGuard}.",
    );
    Expression expression = condition.expression;
    push(
      forest.createSwitchExpression(
        switchKeyword.charOffset,
        expression,
        cases,
      ),
    );
  }

  @override
  void endSwitchBlock(int caseCount, Token beginToken, Token endToken) {
    debugEvent("SwitchBlock");
    assert(
      checkState(
        beginToken,
        repeatedKinds([
          ValueKinds.LabelListOrNull,
          ValueKinds.SwitchCase,
        ], caseCount),
      ),
    );

    exitLocalScope(
      expectedScopeKinds: const [ScopeKind.caseHead],
    ); // Exit the sentinel scope.

    bool containsPatterns = false;
    List<SwitchCase> cases = new List<SwitchCase>.filled(
      caseCount,
      dummySwitchCase,
      growable: true,
    );
    List<List<Statement>?> caseLabelUsers = new List<List<Statement>?>.filled(
      caseCount,
      null,
      growable: true,
    );
    for (int i = caseCount - 1; i >= 0; i--) {
      List<Label>? labels = pop() as List<Label>?;
      SwitchCase current = cases[i] = pop() as SwitchCase;
      if (labels != null) {
        for (Label label in labels) {
          JumpTarget? target = _switchScope!.lookupLabel(label.name);
          if (target != null) {
            (caseLabelUsers[i] ??= <Statement>[]).addAll(target.users);
            target.resolveGotos(forest, current);
          }
        }
      }
      if (current is PatternSwitchCase) {
        containsPatterns = true;
      }
    }
    for (int i = 0; i < caseCount - 1; i++) {
      SwitchCase current = cases[i];
      Block block = current.body as Block;
      // [block] is a synthetic block that is added to handle variable
      // declarations in the switch case.
      TreeNode? lastNode = block.statements.isEmpty
          ? null
          : block.statements.last;
      if (lastNode is Block) {
        // This is a non-synthetic block.
        Block block = lastNode;
        lastNode = block.statements.isEmpty ? null : block.statements.last;
      }
      if (lastNode is ExpressionStatement) {
        ExpressionStatement statement = lastNode;
        lastNode = statement.expression;
      }
    }

    push(containsPatterns);
    push(cases);
    push(caseLabelUsers);
    assert(
      checkState(beginToken, [
        ValueKinds.StatementListOrNullList,
        ValueKinds.SwitchCaseList,
        ValueKinds.Bool,
      ]),
    );
  }

  @override
  void handleBreakStatement(
    bool hasTarget,
    Token breakKeyword,
    Token endToken,
  ) {
    debugEvent("BreakStatement");
    JumpTarget? target = breakTarget;
    Identifier? identifier;
    String? name;
    if (hasTarget) {
      identifier = pop() as Identifier;
      name = identifier.name;
      target = _labelScope.lookupLabel(name);
    }
    if (target == null && name == null) {
      push(
        problemInLoopOrSwitch = buildProblemStatement(
          cfe.codeBreakOutsideOfLoop,
          breakKeyword.charOffset,
        ),
      );
    } else if (target == null || !target.isBreakTarget) {
      Token labelToken = breakKeyword.next!;
      push(
        problemInLoopOrSwitch = buildProblemStatement(
          cfe.codeInvalidBreakTarget.withArgumentsOld(name!),
          labelToken.charOffset,
          length: labelToken.length,
        ),
      );
    } else if (target.functionNestingLevel != functionNestingLevel) {
      push(buildProblemTargetOutsideLocalFunction(name, breakKeyword));
    } else {
      Statement statement = forest.createBreakStatement(
        offsetForToken(breakKeyword),
        identifier,
      );
      target.addBreak(statement);
      push(statement);
    }
  }

  Statement buildProblemTargetOutsideLocalFunction(
    String? name,
    Token keyword,
  ) {
    Statement problem;
    bool isBreak = keyword.isA(Keyword.BREAK);
    if (name != null) {
      Template<Message Function(String), Function> template = isBreak
          ? cfe.codeBreakTargetOutsideFunction
          : cfe.codeContinueTargetOutsideFunction;
      problem = buildProblemStatement(
        template.withArgumentsOld(name),
        offsetForToken(keyword),
        length: lengthOfSpan(keyword, keyword.next),
      );
    } else {
      Message message = isBreak
          ? cfe.codeAnonymousBreakTargetOutsideFunction
          : cfe.codeAnonymousContinueTargetOutsideFunction;
      problem = buildProblemStatement(
        message,
        offsetForToken(keyword),
        length: lengthForToken(keyword),
      );
    }
    problemInLoopOrSwitch ??= problem;
    return problem;
  }

  @override
  void handleContinueStatement(
    bool hasTarget,
    Token continueKeyword,
    Token endToken,
  ) {
    debugEvent("ContinueStatement");
    JumpTarget? target = continueTarget;
    Identifier? identifier;
    String? name;
    if (hasTarget) {
      identifier = pop() as Identifier;
      name = identifier.name;
      target = _labelScope.lookupLabel(identifier.name);
      if (target == null) {
        if (_switchScope == null) {
          push(
            buildProblemStatement(
              cfe.codeLabelNotFound.withArgumentsOld(name),
              continueKeyword.next!.charOffset,
            ),
          );
          return;
        }
        _switchScope!.forwardDeclareLabel(
          identifier.name,
          target = createGotoTarget(identifier.nameOffset),
        );
      }
      if (target.isGotoTarget &&
          target.functionNestingLevel == functionNestingLevel) {
        ContinueSwitchStatement statement = new ContinueSwitchStatement(
          dummySwitchCase,
        )..fileOffset = continueKeyword.charOffset;
        target.addGoto(statement);
        push(statement);
        return;
      }
    }
    if (target == null) {
      push(
        problemInLoopOrSwitch = buildProblemStatement(
          cfe.codeContinueWithoutLabelInCase,
          continueKeyword.charOffset,
          length: continueKeyword.length,
        ),
      );
    } else if (!target.isContinueTarget) {
      Token labelToken = continueKeyword.next!;
      push(
        problemInLoopOrSwitch = buildProblemStatement(
          cfe.codeInvalidContinueTarget.withArgumentsOld(name!),
          labelToken.charOffset,
          length: labelToken.length,
        ),
      );
    } else if (target.functionNestingLevel != functionNestingLevel) {
      push(buildProblemTargetOutsideLocalFunction(name, continueKeyword));
    } else {
      Statement statement = forest.createContinueStatement(
        offsetForToken(continueKeyword),
        identifier,
      );
      target.addContinue(statement);
      push(statement);
    }
  }

  @override
  void beginTypeVariable(Token token) {
    debugEvent("beginTypeVariable");
    assert(
      checkState(token, [
        unionOfKinds([ValueKinds.Identifier, ValueKinds.ParserRecovery]),
        ValueKinds.AnnotationListOrNull,
      ]),
    );
    Object? name = pop();
    List<Expression>? annotations = pop() as List<Expression>?;
    String? typeParameterName;
    int typeParameterNameOffset;
    if (name is Identifier) {
      typeParameterName = name.name;
      typeParameterNameOffset = name.nameOffset;
    } else if (name is ParserRecovery) {
      typeParameterName = inFunctionType
          ? StructuralParameterBuilder.noNameSentinel
          : NominalParameterBuilder.noNameSentinel;
      typeParameterNameOffset = name.charOffset;
    } else {
      unhandled(
        "${name.runtimeType}",
        "beginTypeVariable.name",
        token.charOffset,
        uri,
      );
    }
    bool isWildcard =
        libraryFeatures.wildcardVariables.isEnabled && typeParameterName == '_';
    if (isWildcard) {
      typeParameterName = createWildcardTypeParameterName(
        wildcardVariableIndex,
      );
      wildcardVariableIndex++;
    }
    TypeParameterBuilder variable = inFunctionType
        ? new SourceStructuralParameterBuilder(
            new RegularStructuralParameterDeclaration(
              metadata: null,
              name: typeParameterName,
              fileOffset: typeParameterNameOffset,
              fileUri: uri,
              isWildcard: isWildcard,
            ),
          )
        : new SourceNominalParameterBuilder(
            new DirectNominalParameterDeclaration(
              name: typeParameterName,
              kind: TypeParameterKind.function,
              isWildcard: isWildcard,
              fileOffset: typeParameterNameOffset,
              fileUri: uri,
            ),
          );
    if (annotations != null) {
      switch (variable) {
        case StructuralParameterBuilder():
          if (!libraryFeatures.genericMetadata.isEnabled) {
            addProblem(
              cfe.codeAnnotationOnFunctionTypeTypeParameter,
              variable.fileOffset,
              variable.name.length,
            );
          }
          break;
        case NominalParameterBuilder():
          inferAnnotations(variable.parameter, annotations);
          for (Expression annotation in annotations) {
            variable.parameter.addAnnotation(annotation);
          }
          break;
      }
    }
    push(variable);
  }

  @override
  void handleTypeVariablesDefined(Token token, int count) {
    debugEvent("handleTypeVariablesDefined");
    assert(count > 0);
    if (inFunctionType) {
      List<StructuralParameterBuilder>? structuralVariableBuilders =
          const FixedNullableList<StructuralParameterBuilder>().popNonNullable(
            stack,
            count,
            dummyStructuralVariableBuilder,
          );
      enterStructuralVariablesScope(structuralVariableBuilders);
      push(structuralVariableBuilders);
    } else {
      List<NominalParameterBuilder>? nominalVariableBuilders =
          const FixedNullableList<NominalParameterBuilder>().popNonNullable(
            stack,
            count,
            dummyNominalVariableBuilder,
          );
      enterNominalVariablesScope(nominalVariableBuilders);
      push(nominalVariableBuilders);
    }
  }

  @override
  void endTypeVariable(
    Token token,
    int index,
    Token? extendsOrSuper,
    Token? variance,
  ) {
    debugEvent("TypeVariable");
    TypeBuilder? bound = pop() as TypeBuilder?;
    // Peek to leave type parameters on top of stack.
    List<TypeParameterBuilder> typeParameters =
        peek() as List<TypeParameterBuilder>;

    TypeParameterBuilder typeParameter = typeParameters[index];
    typeParameter.bound = bound;
    if (variance != null) {
      // Coverage-ignore-block(suite): Not run.
      if (!libraryFeatures.variance.isEnabled) {
        reportVarianceModifierNotEnabled(variance);
      }
      typeParameter.variance = new Variance.fromKeywordString(variance.lexeme);
    }
  }

  @override
  void endTypeVariables(Token beginToken, Token endToken) {
    debugEvent("TypeVariables");
    // Peek to leave type parameters on top of stack.
    List<TypeParameterBuilder> typeParameters =
        peek() as List<TypeParameterBuilder>;
    checkTypeParameterDependencies(libraryBuilder, typeParameters);

    TypeParameterFactory typeParameterFactory = new TypeParameterFactory();
    List<TypeBuilder> calculatedBounds = calculateBounds(
      typeParameters,
      libraryBuilder.loader.target.dynamicType,
      libraryBuilder.loader.target.nullType,
      typeParameterFactory: typeParameterFactory,
    );
    for (int i = 0; i < typeParameters.length; ++i) {
      typeParameters[i].defaultType = calculatedBounds[i];
      typeParameters[i].finish(
        libraryBuilder,
        libraryBuilder.loader.target.objectClassBuilder,
        libraryBuilder.loader.target.dynamicType,
      );
    }
    for (TypeParameterBuilder builder
        in typeParameterFactory.collectTypeParameters()) {
      // Coverage-ignore-block(suite): Not run.
      builder.finish(
        libraryBuilder,
        libraryBuilder.loader.target.objectClassBuilder,
        libraryBuilder.loader.target.dynamicType,
      );
    }
  }

  @override
  void handleNoTypeVariables(Token token) {
    debugEvent("NoTypeVariables");
    if (inFunctionType) {
      enterStructuralVariablesScope(null);
      push(NullValues.StructuralParameters);
    } else {
      enterNominalVariablesScope(null);
      push(NullValues.NominalParameters);
    }
  }

  @override
  void handleInvalidStatement(Token token, Message message) {
    Statement statement = pop() as Statement;
    push(
      new ExpressionStatement(
        buildProblem(message, statement.fileOffset, noLength),
      ),
    );
  }

  @override
  InvalidExpression buildProblem(
    Message message,
    int charOffset,
    int length, {
    List<LocatedMessage>? context,
    bool errorHasBeenReported = false,
    Expression? expression,
  }) {
    if (!errorHasBeenReported) {
      addProblem(
        message,
        charOffset,
        length,
        wasHandled: true,
        context: context,
      );
    }
    String text = libraryBuilder.loader.target.context
        .format(
          message.withLocation(uri, charOffset, length),
          CfeSeverity.error,
        )
        .plain;
    return new InvalidExpression(text, expression)..fileOffset = charOffset;
  }

  @override
  Expression wrapInProblem(
    Expression expression,
    Message message,
    int fileOffset,
    int length, {
    List<LocatedMessage>? context,
    bool? errorHasBeenReported,
    bool includeExpression = true,
  }) {
    CfeSeverity severity = message.code.severity;
    if (severity == CfeSeverity.error) {
      return wrapInLocatedProblem(
        expression,
        message.withLocation(uri, fileOffset, length),
        context: context,
        errorHasBeenReported:
            errorHasBeenReported ?? expression is InvalidExpression,
        includeExpression: includeExpression,
      );
    } else {
      // Coverage-ignore-block(suite): Not run.
      if (expression is! InvalidExpression) {
        addProblem(message, fileOffset, length, context: context);
      }
      return expression;
    }
  }

  @override
  Expression wrapInLocatedProblem(
    Expression expression,
    LocatedMessage message, {
    List<LocatedMessage>? context,
    bool errorHasBeenReported = false,
    bool includeExpression = true,
  }) {
    // TODO(askesc): Produce explicit error expression wrapping the original.
    // See [issue 29717](https://github.com/dart-lang/sdk/issues/29717)
    int offset = expression.fileOffset;
    if (offset == -1) {
      offset = message.charOffset;
    }
    return buildProblem(
      message.messageObject,
      message.charOffset,
      message.length,
      context: context,
      expression: includeExpression ? expression : null,
      errorHasBeenReported: errorHasBeenReported,
    );
  }

  Expression buildAbstractClassInstantiationError(
    Message message,
    String className, [
    int charOffset = -1,
  ]) {
    addProblemErrorIfConst(message, charOffset, className.length);
    return new InvalidExpression(message.problemMessage);
  }

  Statement buildProblemStatement(
    Message message,
    int charOffset, {
    List<LocatedMessage>? context,
    int? length,
    bool errorHasBeenReported = false,
  }) {
    length ??= noLength;
    return new ExpressionStatement(
      buildProblem(
        message,
        charOffset,
        length,
        context: context,
        errorHasBeenReported: errorHasBeenReported,
      ),
    );
  }

  Statement wrapInProblemStatement(Statement statement, Message message) {
    // TODO(askesc): Produce explicit error statement wrapping the original.
    // See [issue 29717](https://github.com/dart-lang/sdk/issues/29717)
    return buildProblemStatement(message, statement.fileOffset);
  }

  @override
  Initializer buildInvalidInitializer(
    Expression expression, [
    int charOffset = -1,
  ]) {
    needsImplicitSuperInitializer = false;
    return new ShadowInvalidInitializer(
      new VariableDeclaration.forValue(expression),
    )..fileOffset = charOffset;
  }

  Initializer buildDuplicatedInitializer(
    SourcePropertyBuilder fieldBuilder,
    Expression value,
    String name,
    int offset,
    int previousInitializerOffset,
  ) {
    return fieldBuilder.buildErroneousInitializer(
      buildProblem(
        cfe.codeConstructorInitializeSameInstanceVariableSeveralTimes
            .withArgumentsOld(name),
        offset,
        noLength,
      ),
      value,
      fileOffset: offset,
    );
  }

  /// Parameter [formalType] should only be passed in the special case of
  /// building a field initializer as a desugaring of an initializing formal
  /// parameter.  The spec says the following:
  ///
  /// "If an explicit type is attached to the initializing formal, that is its
  /// static type.  Otherwise, the type of an initializing formal named _id_ is
  /// _Tid_, where _Tid_ is the type of the instance variable named _id_ in the
  /// immediately enclosing class.  It is a static warning if the static type of
  /// _id_ is not a subtype of _Tid_."
  @override
  List<Initializer> buildFieldInitializer(
    String name,
    int fieldNameOffset,
    int assignmentOffset,
    Expression expression, {
    FormalParameterBuilder? formal,
  }) {
    if (isWildcardLoweredFormalParameter(name)) {
      name = '_';
    }
    LookupResult? result = _context.lookupLocalMember(name);
    NamedBuilder? builder = result?.getable;
    if (result != null && result is DuplicateMemberLookupResult) {
      // Duplicated name, already reported.
      MemberBuilder firstBuilder = result.declarations.first;
      if (firstBuilder is SourcePropertyBuilder && firstBuilder.hasField) {
        // Assume the first field has been initialized.
        _context.registerInitializedField(firstBuilder);
      }
      return <Initializer>[
        buildInvalidInitializer(
          LookupResult.createDuplicateExpression(
            result,
            context: libraryBuilder.loader.target.context,
            name: name,
            fileUri: uri,
            fileOffset: fieldNameOffset,
            length: name.length,
          ),
          fieldNameOffset,
        ),
      ];
    } else if (builder is SourcePropertyBuilder &&
        builder.hasField &&
        builder.isDeclarationInstanceMember) {
      if (builder.isExtensionTypeDeclaredInstanceField) {
        // Operating on an invalid field. Don't report anything though
        // as we've already reported that the field isn't valid.
        return <Initializer>[
          buildInvalidInitializer(new InvalidExpression(null), fieldNameOffset),
        ];
      }

      initializedFields ??= <String, int>{};
      if (initializedFields!.containsKey(name)) {
        return <Initializer>[
          buildDuplicatedInitializer(
            builder,
            expression,
            name,
            assignmentOffset,
            initializedFields![name]!,
          ),
        ];
      }
      initializedFields![name] = assignmentOffset;
      if (builder.hasAbstractField) {
        return <Initializer>[
          buildInvalidInitializer(
            buildProblem(
              cfe.codeAbstractFieldConstructorInitializer,
              fieldNameOffset,
              name.length,
            ),
            fieldNameOffset,
          ),
        ];
      } else if (builder.hasExternalField) {
        return <Initializer>[
          buildInvalidInitializer(
            buildProblem(
              cfe.codeExternalFieldConstructorInitializer,
              fieldNameOffset,
              name.length,
            ),
            fieldNameOffset,
          ),
        ];
      } else if (builder.isFinal && builder.hasInitializer) {
        addProblem(
          cfe.codeFieldAlreadyInitializedAtDeclaration.withArgumentsOld(name),
          assignmentOffset,
          noLength,
          context: [
            cfe.codeFieldAlreadyInitializedAtDeclarationCause
                .withArgumentsOld(name)
                .withLocation(uri, builder.fileOffset, name.length),
          ],
        );
        MemberBuilder constructor = libraryBuilder.loader
            .getDuplicatedFieldInitializerError();
        Expression invocation = buildConstructorInvocation(
          constructor.invokeTarget!,
          forest.createArguments(assignmentOffset, <Expression>[
            forest.createStringLiteral(assignmentOffset, name),
          ]),
          constness: Constness.explicitNew,
          fileOffset: assignmentOffset,
        );
        return <Initializer>[
          builder.buildErroneousInitializer(
            forest.createThrow(assignmentOffset, invocation),
            expression,
            fileOffset: assignmentOffset,
          ),
        ];
      } else {
        if (formal != null && formal.type is! OmittedTypeBuilder) {
          DartType formalType = formal.variable!.type;
          DartType fieldType = _context.substituteFieldType(builder.fieldType);
          if (!typeEnvironment.isSubtypeOf(formalType, fieldType)) {
            libraryBuilder.addProblem(
              cfe.codeInitializingFormalTypeMismatch.withArgumentsOld(
                name,
                formalType,
                builder.fieldType,
              ),
              assignmentOffset,
              noLength,
              uri,
              context: [
                cfe.codeInitializingFormalTypeMismatchField.withLocation(
                  builder.fileUri,
                  builder.fileOffset,
                  noLength,
                ),
              ],
            );
          }
        }
        _context.registerInitializedField(builder);
        return builder.buildInitializer(
          assignmentOffset,
          expression,
          isSynthetic: formal != null,
        );
      }
    } else {
      return <Initializer>[
        buildInvalidInitializer(
          buildProblem(
            cfe.codeInitializerForStaticField.withArgumentsOld(name),
            fieldNameOffset,
            name.length,
          ),
          fieldNameOffset,
        ),
      ];
    }
  }

  @override
  Initializer buildSuperInitializer(
    bool isSynthetic,
    Constructor constructor,
    Arguments arguments, [
    int charOffset = -1,
  ]) {
    if (_context.isConstConstructor && !constructor.isConst) {
      addProblem(
        cfe.codeConstConstructorWithNonConstSuper,
        charOffset,
        constructor.name.text.length,
      );
    }
    needsImplicitSuperInitializer = false;
    return new SuperInitializer(constructor, arguments)
      ..fileOffset = charOffset
      ..isSynthetic = isSynthetic;
  }

  @override
  Initializer buildRedirectingInitializer(
    Name name,
    ArgumentsImpl arguments, {
    required int fileOffset,
  }) {
    Builder? constructorBuilder = _context.lookupConstructor(name);
    if (constructorBuilder == null) {
      int length = name.text.length;
      if (length == 0) {
        // The constructor is unnamed so the offset points to 'this'.
        length = "this".length;
      }
      String fullName = constructorNameForDiagnostics(name.text);
      LocatedMessage message = cfe.codeConstructorNotFound
          .withArgumentsOld(fullName)
          .withLocation(uri, fileOffset, length);
      return buildInvalidInitializer(
        buildProblemFromLocatedMessage(message),
        fileOffset,
      );
    } else {
      if (_context.isConstructorCyclic(name.text)) {
        int length = name.text.length;
        if (length == 0) length = "this".length;
        addProblem(cfe.codeConstructorCyclic, fileOffset, length);
        // TODO(askesc): Produce invalid initializer.
      }
      if (_context.formals != null) {
        for (FormalParameterBuilder formal in _context.formals!) {
          if (formal.isSuperInitializingFormal) {
            addProblem(
              cfe.codeUnexpectedSuperParametersInGenerativeConstructors,
              formal.fileOffset,
              noLength,
            );
            if (constructorBuilder is SourceConstructorBuilder) {
              constructorBuilder.markAsErroneous();
            }
          }
        }
      }
      needsImplicitSuperInitializer = false;
      return _context.buildRedirectingInitializer(
        constructorBuilder,
        arguments,
        fileOffset: fileOffset,
      );
    }
  }

  @override
  void handleOperator(Token token) {
    debugEvent("Operator");
    push(new Operator(token, token.charOffset));
  }

  @override
  void handleSymbolVoid(Token token) {
    debugEvent("SymbolVoid");
    push(new SimpleIdentifier(token));
  }

  @override
  void handleInvalidFunctionBody(Token token) {
    if (_context.isNativeMethod) {
      // Coverage-ignore-block(suite): Not run.
      push(NullValues.FunctionBody);
    } else {
      push(
        forest.createBlock(offsetForToken(token), noLocation, <Statement>[
          buildProblemStatement(
            cfe.codeExpectedFunctionBody.withArgumentsOld(token),
            token.charOffset,
            length: token.length,
          ),
        ]),
      );
    }
  }

  @override
  void handleTypeArgumentApplication(Token openAngleBracket) {
    assert(
      checkState(openAngleBracket, [
        ValueKinds.TypeArguments,
        unionOfKinds([ValueKinds.Generator, ValueKinds.Expression]),
      ]),
    );
    List<TypeBuilder>? typeArguments =
        pop() as List<TypeBuilder>?; // typeArguments
    if (libraryFeatures.constructorTearoffs.isEnabled) {
      Object? operand = pop();
      if (operand is DotShorthandPropertyGet && typeArguments != null) {
        operand.hasTypeParameters = true;
      }
      if (operand is Generator) {
        push(
          operand.applyTypeArguments(
            openAngleBracket.charOffset,
            typeArguments,
          ),
        );
      } else if (operand is StaticTearOff &&
              (operand.target.isFactory || isTearOffLowering(operand.target)) ||
          operand is ConstructorTearOff ||
          operand is RedirectingFactoryTearOff) {
        push(
          buildProblem(
            cfe.codeConstructorTearOffWithTypeArguments,
            openAngleBracket.charOffset,
            noLength,
          ),
        );
      } else {
        push(
          new Instantiation(
            toValue(operand),
            buildDartTypeArguments(
              typeArguments,
              TypeUse.tearOffTypeArgument,
              allowPotentiallyConstantType: true,
            ),
          )..fileOffset = openAngleBracket.charOffset,
        );
      }
    } else {
      libraryBuilder.reportFeatureNotEnabled(
        libraryFeatures.constructorTearoffs,
        uri,
        openAngleBracket.charOffset,
        noLength,
      );
    }
  }

  @override
  TypeBuilder validateTypeParameterUse(
    TypeBuilder typeBuilder, {
    required bool allowPotentiallyConstantType,
  }) {
    _validateTypeParameterUseInternal(
      typeBuilder,
      allowPotentiallyConstantType: allowPotentiallyConstantType,
    );
    return typeBuilder;
  }

  void _validateTypeParameterUseInternal(
    TypeBuilder? builder, {
    required bool allowPotentiallyConstantType,
  }) {
    switch (builder) {
      case NamedTypeBuilder(
        :TypeDeclarationBuilder? declaration,
        typeArguments: List<TypeBuilder>? arguments,
      ):
        if (declaration!.isTypeParameter &&
            builder.declaration is NominalParameterBuilder) {
          NominalParameterBuilder typeParameterBuilder =
              declaration as NominalParameterBuilder;
          TypeParameter typeParameter = typeParameterBuilder.parameter;
          GenericDeclaration? typeParameterDeclaration =
              typeParameter.declaration;
          if (typeParameterDeclaration is Class ||
              typeParameterDeclaration is Extension ||
              typeParameterDeclaration is ExtensionTypeDeclaration) {
            if (constantContext != ConstantContext.none &&
                (!inConstructorInitializer || !allowPotentiallyConstantType)) {
              LocatedMessage message = cfe.codeTypeVariableInConstantContext
                  .withLocation(
                    builder.fileUri!,
                    builder.charOffset!,
                    typeParameter.name!.length,
                  );
              builder.bind(
                libraryBuilder,
                new InvalidBuilder(typeParameter.name!, message),
              );
              addProblem(
                message.messageObject,
                message.charOffset,
                message.length,
              );
            }
          }
        }
        if (arguments != null) {
          for (TypeBuilder typeBuilder in arguments) {
            _validateTypeParameterUseInternal(
              typeBuilder,
              allowPotentiallyConstantType: allowPotentiallyConstantType,
            );
          }
        }
      case FunctionTypeBuilder(
        typeParameters: List<StructuralParameterBuilder>? typeParameters,
        :List<ParameterBuilder>? formals,
        :TypeBuilder returnType,
      ):
        if (typeParameters != null) {
          for (StructuralParameterBuilder typeParameter in typeParameters) {
            _validateTypeParameterUseInternal(
              typeParameter.bound,
              allowPotentiallyConstantType: allowPotentiallyConstantType,
            );
            _validateTypeParameterUseInternal(
              typeParameter.defaultType,
              allowPotentiallyConstantType: allowPotentiallyConstantType,
            );
          }
        }
        _validateTypeParameterUseInternal(
          returnType,
          allowPotentiallyConstantType: allowPotentiallyConstantType,
        );
        if (formals != null) {
          for (ParameterBuilder formalParameterBuilder in formals) {
            _validateTypeParameterUseInternal(
              formalParameterBuilder.type,
              allowPotentiallyConstantType: allowPotentiallyConstantType,
            );
          }
        }
      case RecordTypeBuilder(
        :List<RecordTypeFieldBuilder>? positionalFields,
        :List<RecordTypeFieldBuilder>? namedFields,
      ):
        if (positionalFields != null) {
          for (RecordTypeFieldBuilder field in positionalFields) {
            _validateTypeParameterUseInternal(
              field.type,
              allowPotentiallyConstantType: allowPotentiallyConstantType,
            );
          }
        }
        if (namedFields != null) {
          for (RecordTypeFieldBuilder field in namedFields) {
            _validateTypeParameterUseInternal(
              field.type,
              allowPotentiallyConstantType: allowPotentiallyConstantType,
            );
          }
        }
      case OmittedTypeBuilder():
      case FixedTypeBuilder():
      case InvalidTypeBuilder():
      case null:
    }
  }

  @override
  Expression evaluateArgumentsBefore(
    ArgumentsImpl? arguments,
    Expression expression,
  ) {
    if (arguments == null) return expression;
    List<Expression> expressions = new List<Expression>.of(
      arguments.positional,
    );
    for (NamedExpression named in arguments.named) {
      // Coverage-ignore-block(suite): Not run.
      expressions.add(named.value);
    }
    for (Expression argument in expressions.reversed) {
      expression = new Let(
        new VariableDeclaration.forValue(
          argument,
          isFinal: true,
          type: coreTypes.objectRawType(Nullability.nullable),
        ),
        expression,
      );
    }
    return expression;
  }

  @override
  bool isIdentical(Member? member) => member == coreTypes.identicalProcedure;

  @override
  Expression buildMethodInvocation(
    Expression receiver,
    Name name,
    ArgumentsImpl arguments,
    int offset, {
    bool isConstantExpression = false,
    bool isNullAware = false,
  }) {
    if (constantContext != ConstantContext.none &&
        !isConstantExpression &&
        !libraryFeatures.constFunctions.isEnabled) {
      return buildProblem(
        cfe.codeNotConstantExpression.withArgumentsOld('Method invocation'),
        offset,
        name.text.length,
      );
    }
    return forest.createMethodInvocation(
      offset,
      receiver,
      name,
      arguments,
      isNullAware: isNullAware,
    );
  }

  @override
  Expression buildSuperInvocation(
    Name name,
    ArgumentsImpl arguments,
    int offset, {
    bool isConstantExpression = false,
    bool isNullAware = false,
    bool isImplicitCall = false,
  }) {
    if (constantContext != ConstantContext.none &&
        !isConstantExpression &&
        !libraryFeatures.constFunctions.isEnabled) {
      return buildProblem(
        cfe.codeNotConstantExpression.withArgumentsOld('Method invocation'),
        offset,
        name.text.length,
      );
    }
    Member? target = lookupSuperMember(name);

    if (target == null) {
      return buildUnresolvedError(
        name.text,
        offset,
        isSuper: true,
        kind: UnresolvedKind.Method,
      );
    } else if (target is Procedure && !target.isAccessor) {
      return new SuperMethodInvocation(name, arguments, target)
        ..fileOffset = offset;
    }
    if (isImplicitCall) {
      return buildProblem(
        cfe.codeImplicitSuperCallOfNonMethod,
        offset,
        noLength,
      );
    } else {
      Expression receiver = new SuperPropertyGet(name, target)
        ..fileOffset = offset;
      return forest.createExpressionInvocation(
        arguments.fileOffset,
        receiver,
        arguments,
      );
    }
  }

  @override
  void addProblem(
    Message message,
    int charOffset,
    int length, {
    bool wasHandled = false,
    List<LocatedMessage>? context,
    CfeSeverity? severity,
  }) {
    libraryBuilder.addProblem(
      message,
      charOffset,
      length,
      uri,
      wasHandled: wasHandled,
      context: context,
      severity: severity,
    );
  }

  @override
  void addProblemErrorIfConst(
    Message message,
    int charOffset,
    int length, {
    bool wasHandled = false,
    List<LocatedMessage>? context,
  }) {
    // TODO(askesc): Instead of deciding on the severity, this method should
    // take two messages: one to use when a constant expression is
    // required and one to use otherwise.
    CfeSeverity severity = message.code.severity;
    if (constantContext != ConstantContext.none) {
      severity = CfeSeverity.error;
    }
    addProblem(
      message,
      charOffset,
      length,
      wasHandled: wasHandled,
      context: context,
      severity: severity,
    );
  }

  @override
  Expression buildProblemErrorIfConst(
    Message message,
    int charOffset,
    int length, {
    bool wasHandled = false,
    List<LocatedMessage>? context,
  }) {
    addProblemErrorIfConst(
      message,
      charOffset,
      length,
      wasHandled: wasHandled,
      context: context,
    );
    String text = libraryBuilder.loader.target.context
        .format(
          message.withLocation(uri, charOffset, length),
          CfeSeverity.error,
        )
        .plain;
    InvalidExpression expression = new InvalidExpression(text)
      ..fileOffset = charOffset;
    return expression;
  }

  @override
  void reportDuplicatedDeclaration(
    Builder existing,
    String name,
    int charOffset,
  ) {
    List<LocatedMessage>? context = existing.isSynthetic
        ? null
        : <LocatedMessage>[
            cfe.codeDuplicatedDeclarationCause
                .withArgumentsOld(name)
                .withLocation(
                  existing.fileUri!,
                  existing.fileOffset,
                  name.length,
                ),
          ];
    addProblem(
      cfe.codeDuplicatedDeclaration.withArgumentsOld(name),
      charOffset,
      name.length,
      context: context,
    );
  }

  @override
  void debugEvent(String name) {
    // printEvent('BodyBuilder: $name');
  }

  @override
  Expression wrapInDeferredCheck(
    Expression expression,
    PrefixBuilder prefix,
    int charOffset,
  ) {
    VariableDeclaration check = new VariableDeclaration.forValue(
      forest.checkLibraryIsLoaded(charOffset, prefix.dependency!),
    );
    return new DeferredCheck(check, expression)..fileOffset = charOffset;
  }

  bool isErroneousNode(TreeNode node) {
    return libraryBuilder.loader.handledErrors.isNotEmpty &&
        forest.isErroneousNode(node);
  }

  @override
  DartType buildDartType(
    TypeBuilder typeBuilder,
    TypeUse typeUse, {
    required bool allowPotentiallyConstantType,
  }) {
    return validateTypeParameterUse(
      typeBuilder,
      allowPotentiallyConstantType: allowPotentiallyConstantType,
    ).build(libraryBuilder, typeUse);
  }

  @override
  List<DartType> buildDartTypeArguments(
    List<TypeBuilder>? unresolvedTypes,
    TypeUse typeUse, {
    required bool allowPotentiallyConstantType,
  }) {
    if (unresolvedTypes == null) {
      // Coverage-ignore-block(suite): Not run.
      return <DartType>[];
    }
    return new List<DartType>.generate(
      unresolvedTypes.length,
      (int i) => buildDartType(
        unresolvedTypes[i],
        typeUse,
        allowPotentiallyConstantType: allowPotentiallyConstantType,
      ),
      growable: true,
    );
  }

  @override
  String constructorNameForDiagnostics(String name, {String? className}) {
    className ??= _context.className;
    return name.isEmpty ? className : "$className.$name";
  }

  @override
  String superConstructorNameForDiagnostics(String name) {
    String className = _context.superClassName;
    return name.isEmpty ? className : "$className.$name";
  }

  @override
  void handleNewAsIdentifier(Token token) {
    reportIfNotEnabled(
      libraryFeatures.constructorTearoffs,
      token.charOffset,
      token.length,
    );
  }

  @override
  void beginConstantPattern(Token? constKeyword) {
    debugEvent("ConstantPattern");
    push(constantContext);
    constantContext = ConstantContext.inferred;
  }

  @override
  void endConstantPattern(Token? constKeyword) {
    debugEvent("ConstantPattern");
    assert(
      checkState(constKeyword, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
        ValueKinds.ConstantContext,
      ]),
    );
    Expression expression = toValue(pop());
    constantContext = pop() as ConstantContext;
    push(expression);
  }

  @override
  void handleObjectPatternFields(int count, Token beginToken, Token endToken) {
    debugEvent("ObjectPattern");
    assert(
      checkState(
        beginToken,
        repeatedKind(
          unionOfKinds([
            ValueKinds.Expression,
            ValueKinds.Generator,
            ValueKinds.Pattern,
          ]),
          count,
        ),
      ),
    );
    reportIfNotEnabled(
      libraryFeatures.patterns,
      beginToken.charOffset,
      beginToken.charCount,
    );
    List<NamedPattern>? fields;
    for (int i = 0; i < count; i++) {
      Object? field = pop();
      if (field is NamedPattern) {
        (fields ??= <NamedPattern>[]).add(field);
      } else {
        Pattern pattern = toPattern(field);
        if (pattern is! InvalidPattern) {
          addProblem(
            cfe.codeUnnamedObjectPatternField,
            pattern.fileOffset,
            noLength,
          );
        }
      }
    }
    if (fields != null) {
      for (int i = 0, j = fields.length - 1; i < j; i++, j--) {
        NamedPattern field = fields[i];
        fields[i] = fields[j];
        fields[j] = field;
      }
    }
    push(fields ?? NullValues.PatternList);
  }

  @override
  void handleObjectPattern(
    Token firstIdentifier,
    Token? dot,
    Token? secondIdentifier,
  ) {
    debugEvent("ObjectPattern");
    assert(
      checkState(firstIdentifier, [
        ValueKinds.PatternListOrNull,
        ValueKinds.TypeArgumentsOrNull,
      ]),
    );

    reportIfNotEnabled(
      libraryFeatures.patterns,
      firstIdentifier.charOffset,
      firstIdentifier.charCount,
    );

    List<NamedPattern>? fields = pop() as List<NamedPattern>?;
    List<TypeBuilder>? typeArguments = pop() as List<TypeBuilder>?;

    handleIdentifier(firstIdentifier, IdentifierContext.prefixedTypeReference);
    if (secondIdentifier != null) {
      handleIdentifier(
        secondIdentifier,
        IdentifierContext.typeReferenceContinuation,
      );
      handleQualified(dot!);
    }
    push(typeArguments ?? NullValues.TypeArguments);
    handleType(firstIdentifier, null);
    TypeBuilder typeBuilder = pop() as TypeBuilder;
    TypeDeclarationBuilder? typeDeclaration = typeBuilder.declaration;
    DartType type = buildDartType(
      typeBuilder,
      TypeUse.objectPatternType,
      allowPotentiallyConstantType: true,
    );
    push(
      new ObjectPatternInternal(
        type,
        fields ?? <NamedPattern>[],
        typeDeclaration is TypeAliasBuilder ? typeDeclaration.typedef : null,
        hasExplicitTypeArguments: typeArguments != null,
      )..fileOffset = firstIdentifier.charOffset,
    );
  }

  @override
  void handleRestPattern(Token dots, {required bool hasSubPattern}) {
    debugEvent("RestPattern");
    assert(
      checkState(dots, [
        if (hasSubPattern)
          unionOfKinds([
            ValueKinds.Expression,
            ValueKinds.Generator,
            ValueKinds.Pattern,
          ]),
      ]),
    );

    Pattern? subPattern;
    if (hasSubPattern) {
      subPattern = toPattern(pop());
    }
    push(forest.createRestPattern(dots.charOffset, subPattern));
  }

  @override
  void handleRelationalPattern(Token token) {
    debugEvent("RelationalPattern");
    assert(
      checkState(token, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Pattern,
        ]),
      ]),
    );
    reportIfNotEnabled(
      libraryFeatures.patterns,
      token.charOffset,
      token.charCount,
    );
    Expression operand = toValue(pop());
    RelationalPatternKind kind;
    String operator = token.lexeme;
    switch (operator) {
      case '==':
        kind = RelationalPatternKind.equals;
        break;
      case '!=':
        kind = RelationalPatternKind.notEquals;
        break;
      case '<':
        kind = RelationalPatternKind.lessThan;
        break;
      case '<=':
        kind = RelationalPatternKind.lessThanEqual;
        break;
      case '>':
        kind = RelationalPatternKind.greaterThan;
        break;
      case '>=':
        kind = RelationalPatternKind.greaterThanEqual;
        break;
      // Coverage-ignore(suite): Not run.
      default:
        internalProblem(
          cfe.codeInternalProblemUnhandled.withArgumentsOld(
            operator,
            'handleRelationalPattern',
          ),
          token.charOffset,
          uri,
        );
    }
    push(forest.createRelationalPattern(token.charOffset, kind, operand));
  }

  @override
  void handleNullAssertPattern(Token bang) {
    debugEvent("NullAssertPattern");
    assert(
      checkState(bang, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Pattern,
        ]),
      ]),
    );
    reportIfNotEnabled(
      libraryFeatures.patterns,
      bang.charOffset,
      bang.charCount,
    );
    Pattern operand = toPattern(pop());
    push(forest.createNullAssertPattern(bang.charOffset, operand));
  }

  @override
  void handleNullCheckPattern(Token question) {
    debugEvent('NullCheckPattern');
    assert(
      checkState(question, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Pattern,
        ]),
      ]),
    );
    reportIfNotEnabled(
      libraryFeatures.patterns,
      question.charOffset,
      question.charCount,
    );
    Pattern operand = toPattern(pop());
    push(forest.createNullCheckPattern(question.charOffset, operand));
  }

  @override
  void handleAssignedVariablePattern(Token variable) {
    debugEvent('AssignedVariablePattern');

    reportIfNotEnabled(
      libraryFeatures.patterns,
      variable.charOffset,
      variable.charCount,
    );
    assert(variable.lexeme != '_');
    Pattern pattern;
    Expression variableUse = scopeLookup(
      _localScope,
      variable,
    ).buildSimpleRead();
    if (variableUse is VariableGet) {
      VariableDeclaration variableDeclaration = variableUse.variable;
      pattern = forest.createAssignedVariablePattern(
        variable.charOffset,
        variableDeclaration,
      );
      registerVariableAssignment(variableDeclaration);
    } else {
      addProblem(
        cfe.codePatternAssignmentNotLocalVariable,
        variable.charOffset,
        variable.charCount,
      );
      // Recover by using [WildcardPattern] instead.
      pattern = forest.createWildcardPattern(variable.charOffset, null);
    }
    push(pattern);
  }

  @override
  void handleDeclaredVariablePattern(
    Token? keyword,
    Token variable, {
    required bool inAssignmentPattern,
  }) {
    debugEvent('DeclaredVariablePattern');
    assert(checkState(keyword ?? variable, [ValueKinds.TypeBuilderOrNull]));

    reportIfNotEnabled(
      libraryFeatures.patterns,
      variable.charOffset,
      variable.charCount,
    );
    assert(variable.lexeme != '_');
    TypeBuilder? type = pop(NullValues.TypeBuilder) as TypeBuilder?;
    DartType? patternType = type?.build(libraryBuilder, TypeUse.variableType);
    Pattern pattern;
    if (inAssignmentPattern) {
      // Error has already been reported.
      pattern = forest.createInvalidPattern(
        new InvalidExpression('declared variable pattern in assignment'),
        declaredVariables: const [],
      );
    } else {
      VariableDeclaration declaredVariable = forest.createVariableDeclaration(
        variable.charOffset,
        variable.lexeme,
        type: patternType,
        isFinal: Modifiers.from(varFinalOrConst: keyword).isFinal,
      );
      pattern = forest.createVariablePattern(
        variable.charOffset,
        patternType,
        declaredVariable,
      );
      declareVariable(declaredVariable, _localScope);
      typeInferrer.assignedVariables.declare(declaredVariable);
    }
    push(pattern);
  }

  @override
  void handleWildcardPattern(Token? keyword, Token wildcard) {
    debugEvent('WildcardPattern');
    assert(checkState(keyword ?? wildcard, [ValueKinds.TypeBuilderOrNull]));

    reportIfNotEnabled(
      libraryFeatures.patterns,
      wildcard.charOffset,
      wildcard.charCount,
    );
    TypeBuilder? type = pop(NullValues.TypeBuilder) as TypeBuilder?;
    DartType? patternType = type?.build(libraryBuilder, TypeUse.variableType);
    // Note: if `default` appears in a switch expression, parser error recovery
    // treats it as a wildcard pattern.
    assert(wildcard.lexeme == '_' || wildcard.lexeme == 'default');

    push(forest.createWildcardPattern(wildcard.charOffset, patternType));
  }

  @override
  void handlePatternField(Token? colon) {
    debugEvent("PatternField");
    assert(
      checkState(colon, [
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Pattern,
        ]),
        if (colon != null)
          unionOfKinds([
            ValueKinds.IdentifierOrNull,
            ValueKinds.ParserRecovery,
          ]),
      ]),
    );

    Object? value = pop();
    Pattern pattern = toPattern(value);
    if (colon != null) {
      Object? identifier = pop();
      if (identifier is ParserRecovery) {
        push(new ParserErrorGenerator(this, colon, cfe.codeSyntheticToken));
      } else {
        String? name;
        if (identifier is Identifier) {
          name = identifier.name;
        } else {
          name = pattern.variableName;
        }
        if (name == null) {
          push(
            forest.createInvalidPattern(
              buildProblem(
                cfe.codeUnspecifiedGetterNameInObjectPattern,
                colon.charOffset,
                noLength,
              ),
              declaredVariables: const [],
            ),
          );
        } else {
          push(forest.createNamedPattern(colon.charOffset, name, pattern));
        }
      }
    } else {
      push(pattern);
    }
  }

  @override
  void handlePatternVariableDeclarationStatement(
    Token keyword,
    Token equals,
    Token semicolon,
  ) {
    debugEvent('PatternVariableDeclarationStatement');
    assert(
      checkState(keyword, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
        unionOfKinds([
          ValueKinds.Expression,
          ValueKinds.Generator,
          ValueKinds.Pattern,
        ]),
        ValueKinds.AnnotationListOrNull,
      ]),
    );
    Expression initializer = popForValue();
    Pattern pattern = toPattern(pop());
    bool isFinal = keyword.lexeme == 'final';
    for (VariableDeclaration variable in pattern.declaredVariables) {
      variable.isFinal = isFinal;
      variable.hasDeclaredInitializer = true;
      declareVariable(variable, _localScope);
    }
    // TODO(johnniwinther,cstefantsova): Handle metadata.
    pop(NullValues.Metadata) as List<Expression>?;
    push(
      forest.createPatternVariableDeclaration(
        keyword.charOffset,
        pattern,
        initializer,
        isFinal: isFinal,
      ),
    );
  }

  @override
  void handlePatternAssignment(Token equals) {
    debugEvent("PatternAssignment");
    assert(
      checkState(equals, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
        unionOfKinds([
          ValueKinds.Pattern,
          ValueKinds.Expression,
          ValueKinds.Generator,
        ]),
      ]),
    );
    Expression expression = popForValue();
    Pattern pattern = toPattern(pop());
    push(
      forest.createPatternAssignment(equals.charOffset, pattern, expression),
    );
  }

  @override
  void handleDotShorthandContext(Token token) {
    debugEvent("DotShorthandContext");
    if (!libraryFeatures.dotShorthands.isEnabled) {
      addProblem(
        codeExperimentNotEnabledOffByDefault.withArgumentsOld(
          ExperimentalFlag.dotShorthands.name,
        ),
        token.offset,
        token.length,
      );
    }

    assert(
      checkState(token, [
        unionOfKinds([ValueKinds.Expression, ValueKinds.Generator]),
      ]),
    );
    Expression value = popForValue();
    push(forest.createDotShorthandContext(token.charOffset, value));
  }

  @override
  void handleDotShorthandHead(Token token) {
    debugEvent("DotShorthandHead");
    if (!libraryFeatures.dotShorthands.isEnabled) {
      addProblem(
        codeExperimentNotEnabledOffByDefault.withArgumentsOld(
          ExperimentalFlag.dotShorthands.name,
        ),
        token.offset,
        token.length,
      );
    }

    assert(
      checkState(token, [
        unionOfKinds([ValueKinds.Selector, ValueKinds.ParserRecovery]),
      ]),
    );
    Object? node = pop();
    if (node is InvocationSelector) {
      // e.g. `.parse(2)`
      push(
        forest.createDotShorthandInvocation(
          offsetForToken(token),
          node.name,
          node.arguments,
          nameOffset: offsetForToken(token.next),
          isConst: constantContext == ConstantContext.inferred,
        ),
      );
    } else if (node is PropertySelector) {
      // e.g. `.zero`
      push(
        forest.createDotShorthandPropertyGet(
          offsetForToken(token),
          node.name,
          nameOffset: offsetForToken(token.next),
        ),
      );
    } else if (node is ParserRecovery) {
      // Recovery for cases like `var x = .;` where we're missing an identifier.
      token = token.next!;
      push(
        buildProblem(
          cfe.codeExpectedIdentifier.withArgumentsOld(token),
          offsetForToken(token),
          lengthForToken(token),
        ),
      );
    }
  }

  @override
  void beginConstDotShorthand(Token token) {
    debugEvent("beginConstDotShorthand");
    super.push(constantContext);
    constantContext = ConstantContext.inferred;
  }

  @override
  void endConstDotShorthand(Token token) {
    debugEvent("endConstDotShorthand");
    Object? dotShorthand = pop();
    constantContext = pop() as ConstantContext;
    push(dotShorthand);
  }
}
