// 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.

library fasta.body_builder;

import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';

import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;

import 'package:_fe_analyzer_shared/src/parser/parser.dart'
    show
        Assert,
        BlockKind,
        FormalParameterKind,
        IdentifierContext,
        MemberKind,
        Parser,
        lengthForToken,
        lengthOfSpan,
        optional;

import 'package:_fe_analyzer_shared/src/parser/quote.dart'
    show
        Quote,
        analyzeQuote,
        unescape,
        unescapeFirstStringPart,
        unescapeLastStringPart,
        unescapeString;

import 'package:_fe_analyzer_shared/src/parser/value_kind.dart';

import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' show Token;
import 'package:_fe_analyzer_shared/src/scanner/token_impl.dart'
    show isBinaryOperator, isMinusOperator, isUserDefinableOperator;

import 'package:_fe_analyzer_shared/src/util/link.dart';

import 'package:kernel/ast.dart';
import 'package:kernel/type_environment.dart';

import '../builder/builder.dart';
import '../builder/class_builder.dart';
import '../builder/constructor_builder.dart';
import '../builder/declaration_builder.dart';
import '../builder/enum_builder.dart';
import '../builder/extension_builder.dart';
import '../builder/factory_builder.dart';
import '../builder/field_builder.dart';
import '../builder/fixed_type_builder.dart';
import '../builder/formal_parameter_builder.dart';
import '../builder/function_builder.dart';
import '../builder/function_type_builder.dart';
import '../builder/invalid_type_declaration_builder.dart';
import '../builder/library_builder.dart';
import '../builder/member_builder.dart';
import '../builder/modifier_builder.dart';
import '../builder/named_type_builder.dart';
import '../builder/nullability_builder.dart';
import '../builder/prefix_builder.dart';
import '../builder/procedure_builder.dart';
import '../builder/type_alias_builder.dart';
import '../builder/type_builder.dart';
import '../builder/type_declaration_builder.dart';
import '../builder/type_variable_builder.dart';
import '../builder/unresolved_type.dart';
import '../builder/variable_builder.dart';
import '../builder/void_type_declaration_builder.dart';

import '../constant_context.dart' show ConstantContext;

import '../dill/dill_library_builder.dart' show DillLibraryBuilder;

import '../fasta_codes.dart' as fasta;

import '../fasta_codes.dart'
    show
        LocatedMessage,
        Message,
        Template,
        noLength,
        templateExperimentNotEnabled;

import '../identifiers.dart'
    show Identifier, InitializedIdentifier, QualifiedName, flattenName;

import '../kernel/utils.dart';

import '../messages.dart' as messages show getLocationFromUri;

import '../modifier.dart'
    show Modifier, constMask, covariantMask, finalMask, lateMask, requiredMask;

import '../names.dart' show emptyName, minusName, plusName;

import '../problems.dart'
    show internalProblem, unexpected, unhandled, unsupported;

import '../scope.dart';

import '../source/scope_listener.dart'
    show
        FixedNullableList,
        GrowableList,
        JumpTargetKind,
        NullValue,
        ParserRecovery,
        ScopeListener;

import '../source/source_library_builder.dart' show SourceLibraryBuilder;

import '../source/stack_listener_impl.dart' show offsetForToken;

import '../source/value_kinds.dart';

import '../type_inference/type_inferrer.dart'
    show TypeInferrer, InferredFunctionBody;

import '../type_inference/type_schema.dart' show UnknownType;

import '../util/helpers.dart' show DelayedActionPerformer;

import 'collections.dart';

import 'constness.dart' show Constness;

import 'expression_generator.dart';

import 'expression_generator_helper.dart' show ExpressionGeneratorHelper;

import 'forest.dart' show Forest;

import 'implicit_type_argument.dart' show ImplicitTypeArgument;

import 'redirecting_factory_body.dart'
    show
        RedirectingFactoryBody,
        RedirectionTarget,
        getRedirectingFactoryBody,
        getRedirectionTarget,
        isRedirectingFactory;

import 'type_algorithms.dart' show calculateBounds;

import 'kernel_api.dart';

import 'kernel_ast_api.dart';

import 'internal_ast.dart';

import 'kernel_builder.dart';

// TODO(ahe): Remove this and ensure all nodes have a location.
const int noLocation = TreeNode.noOffset;

// TODO(danrubel): Remove this once control flow and spread collection support
// has been enabled by default.
const Object invalidCollectionElement = const Object();

class BodyBuilder extends ScopeListener<JumpTarget>
    implements ExpressionGeneratorHelper, EnsureLoaded, DelayedActionPerformer {
  final Forest forest;

  // TODO(ahe): Rename [library] to 'part'.
  @override
  final SourceLibraryBuilder libraryBuilder;

  final ModifierBuilder member;

  /// The class, mixin or extension declaration in which [member] is declared,
  /// if any.
  final DeclarationBuilder? declarationBuilder;

  /// The class or mixin declaration in which [member] is declared, if any.
  final ClassBuilder? classBuilder;

  final ClassHierarchy hierarchy;

  @override
  final CoreTypes coreTypes;

  final bool isDeclarationInstanceMember;

  final Scope enclosingScope;

  final bool enableNative;

  final bool stringExpectedAfterNative;

  /// Whether to ignore an unresolved reference to `main` within the body of
  /// `_getMainClosure` when compiling the current library.
  ///
  /// This as a temporary workaround. The standalone VM and flutter have
  /// special logic to resolve `main` in `_getMainClosure`, this flag is used to
  /// ignore that reference to `main`, but only on libraries where we expect to
  /// see it (today that is dart:_builtin and dart:ui).
  ///
  // TODO(ahe,sigmund): remove when the VM gets rid of the special rule, see
  // https://github.com/dart-lang/sdk/issues/28989.
  final bool ignoreMainInGetMainClosure;

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

  final TypeInferrer typeInferrer;

  /// 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;

  Scope? 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 inInitializer = 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;

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

  @override
  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;

  // Set when a spread element is encountered in a collection so the collection
  // needs to be desugared after type inference.
  bool transformCollections = false;

  // Set by type inference when a set literal is encountered that needs to be
  // transformed because the backend target does not support set literals.
  bool transformSetLiterals = false;

  Statement? problemInLoopOrSwitch;

  Scope? switchScope;

  CloneVisitorNotMembers? cloner;

  ConstantContext constantContext = ConstantContext.none;

  UnresolvedType? currentLocalVariableType;

  // Using non-null value to initialize this field based on performance advice
  // from VM engineers. TODO(ahe): Does this still apply?
  int currentLocalVariableModifiers = -1;

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

  /// List of built redirecting factory invocations.  The targets of the
  /// invocations are to be resolved in a separate step.
  final List<StaticInvocation> redirectingFactoryInvocations =
      <StaticInvocation>[];

  /// List of redirecting factory invocations delayed for resolution.
  ///
  /// A resolution of a redirecting factory invocation can be delayed because
  /// the inference in the declaration of the redirecting factory isn't done
  /// yet.
  final List<StaticInvocation> delayedRedirectingFactoryInvocations =
      <StaticInvocation>[];

  /// List of built type aliased generative constructor invocations that
  /// require unaliasing.
  final List<TypeAliasedConstructorInvocationJudgment>
      typeAliasedConstructorInvocations = [];

  /// List of built type aliased factory constructor invocations that require
  /// unaliasing.
  final List<TypeAliasedFactoryInvocationJudgment>
      typeAliasedFactoryInvocations = [];

  /// 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,
  /// [extensionThis] holds the synthetically add parameter holding the value
  /// for `this`.
  final VariableDeclaration? extensionThis;

  final List<TypeParameter>? extensionTypeParameters;

  BodyBuilder(
      {required this.libraryBuilder,
      required this.member,
      required this.enclosingScope,
      this.formalParameterScope,
      required this.hierarchy,
      required this.coreTypes,
      this.declarationBuilder,
      required this.isDeclarationInstanceMember,
      this.extensionThis,
      this.extensionTypeParameters,
      required this.uri,
      required this.typeInferrer})
      : forest = const Forest(),
        classBuilder =
            declarationBuilder is ClassBuilder ? declarationBuilder : null,
        enableNative = libraryBuilder.loader.target.backendTarget
            .enableNative(libraryBuilder.importUri),
        stringExpectedAfterNative = libraryBuilder
            .loader.target.backendTarget.nativeExtensionExpectsString,
        ignoreMainInGetMainClosure =
            libraryBuilder.importUri.scheme == 'dart' &&
                (libraryBuilder.importUri.path == "_builtin" ||
                    libraryBuilder.importUri.path == "ui"),
        needsImplicitSuperInitializer = declarationBuilder is ClassBuilder &&
            coreTypes.objectClass != declarationBuilder.cls,
        super(enclosingScope) {
    formalParameterScope?.forEach((String name, Builder builder) {
      if (builder is VariableBuilder) {
        typeInferrer.assignedVariables.declare(builder.variable!);
      }
    });
  }

  BodyBuilder.withParents(FieldBuilder field, SourceLibraryBuilder part,
      DeclarationBuilder? declarationBuilder, TypeInferrer typeInferrer)
      : this(
            libraryBuilder: part,
            member: field,
            enclosingScope: declarationBuilder?.scope ?? field.library.scope,
            formalParameterScope: null,
            hierarchy: part.loader.hierarchy,
            coreTypes: part.loader.coreTypes,
            declarationBuilder: declarationBuilder,
            isDeclarationInstanceMember: field.isDeclarationInstanceMember,
            extensionThis: null,
            uri: field.fileUri!,
            typeInferrer: typeInferrer);

  BodyBuilder.forField(FieldBuilder field, TypeInferrer typeInferrer)
      : this.withParents(
            field,
            field.parent is DeclarationBuilder
                ? field.parent!.parent as SourceLibraryBuilder
                : field.parent as SourceLibraryBuilder,
            field.parent is DeclarationBuilder
                ? field.parent as DeclarationBuilder
                : null,
            typeInferrer);

  BodyBuilder.forOutlineExpression(
      SourceLibraryBuilder library,
      DeclarationBuilder? declarationBuilder,
      ModifierBuilder member,
      Scope scope,
      Uri fileUri)
      : this(
            libraryBuilder: library,
            member: member,
            enclosingScope: scope,
            formalParameterScope: null,
            hierarchy: library.loader.hierarchy,
            coreTypes: library.loader.coreTypes,
            declarationBuilder: declarationBuilder,
            isDeclarationInstanceMember: member.isDeclarationInstanceMember,
            extensionThis: null,
            uri: fileUri,
            typeInferrer: library.loader.typeInferenceEngine
                .createLocalTypeInferrer(
                    fileUri, declarationBuilder?.thisType, library, null));

  bool get inConstructor {
    return functionNestingLevel == 0 && member is ConstructorBuilder;
  }

  bool get isDeclarationInstanceContext {
    return isDeclarationInstanceMember || member is ConstructorBuilder;
  }

  TypeEnvironment get typeEnvironment => typeInferrer.typeSchemaEnvironment;

  DartType get implicitTypeArgument => const ImplicitTypeArgument();

  @override
  bool get enableExtensionTypesInLibrary {
    return libraryBuilder.enableExtensionTypesInLibrary;
  }

  @override
  bool get enableConstFunctionsInLibrary {
    return libraryBuilder.enableConstFunctionsInLibrary;
  }

  @override
  bool get enableConstructorTearOffsInLibrary {
    return libraryBuilder.enableConstructorTearOffsInLibrary;
  }

  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);
    }
    inInitializer = 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(
          fasta.messageSuperAsExpression, node.fileOffset, noLength);
    } else if (node is ProblemBuilder) {
      return buildProblem(node.message, node.charOffset, noLength);
    } else {
      return unhandled("${node.runtimeType}", "toValue", -1, uri);
    }
  }

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

  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(Object? value) {
    return value == null ? null : popStatement();
  }

  Statement popStatement() => forest.wrapVariables(pop() as Statement);

  void enterSwitchScope() {
    push(switchScope ?? NullValue.SwitchScope);
    switchScope = scope;
  }

  void exitSwitchScope() {
    Scope? outerSwitchScope = pop() as Scope?;
    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,
                    fasta.templateLabelNotFound.withArguments(name)));
          }
        } else {
          outerSwitchScope.forwardDeclareLabel(name, declaration);
        }
      });
    }
    switchScope = outerSwitchScope;
  }

  void wrapVariableInitializerInError(
      VariableDeclaration variable,
      Template<Message Function(String name)> template,
      List<LocatedMessage> context) {
    String name = variable.name!;
    int offset = variable.fileOffset;
    Message message = template.withArguments(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, Scope scope) {
    String name = variable.name!;
    Builder? existing = scope.lookupLocalMember(name, setter: false);
    if (existing != null) {
      // This reports an error for duplicated declarations in the same scope:
      // `{ var x; var x; }`
      wrapVariableInitializerInError(
          variable, fasta.templateDuplicatedDeclaration, <LocatedMessage>[
        fasta.templateDuplicatedDeclarationCause
            .withArguments(name)
            .withLocation(uri, existing.charOffset, name.length)
      ]);
      return;
    }
    LocatedMessage? context = scope.declare(
        variable.name!, new VariableBuilderImpl(variable, member, uri), uri);
    if (context != null) {
      // 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`.
      wrapVariableInitializerInError(
          variable,
          fasta.templateDuplicatedNamePreviouslyUsed,
          <LocatedMessage>[context]);
    }
  }

  @override
  JumpTarget createJumpTarget(JumpTargetKind kind, int charOffset) {
    return new JumpTarget(
        kind, functionNestingLevel, member as MemberBuilder, charOffset);
  }

  void inferAnnotations(TreeNode? parent, List<Expression>? annotations) {
    if (annotations != null) {
      typeInferrer.inferMetadata(this, parent, annotations);
      libraryBuilder.loader.transformListPostInference(annotations,
          transformSetLiterals, transformCollections, libraryBuilder.library);
    }
  }

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

  @override
  void endMetadata(Token beginToken, Token? periodBeforeName, Token endToken) {
    debugEvent("Metadata");
    Arguments? arguments = pop() as Arguments?;
    pushQualifiedReference(beginToken.next!, periodBeforeName);
    if (arguments != null) {
      push(arguments);
      _buildConstructorReferenceInvocation(
          beginToken.next!, beginToken.offset, Constness.explicitConst,
          inMetadata: true);
      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) {
        Identifier identifier = expression;
        expression = new UnresolvedNameGenerator(this, identifier.token,
            new Name(identifier.name, libraryBuilder.nameOrigin));
      }
      if (name?.isNotEmpty ?? false) {
        Token period = periodBeforeName ?? beginToken.next!.next!;
        Generator generator = expression as Generator;
        expression = generator.buildPropertyAccess(
            new IncompletePropertyAccessGenerator(
                this, period.next!, new Name(name!, libraryBuilder.nameOrigin)),
            period.next!.offset,
            false);
      }

      ConstantContext savedConstantContext = pop() as ConstantContext;
      if (expression is! StaticAccessGenerator &&
          expression is! VariableUseGenerator &&
          // TODO(johnniwinther): Stop using the type of the generator here.
          // Ask a property instead.
          (expression is! ReadOnlyAccessGenerator ||
              expression is TypeUseGenerator ||
              expression is ParenthesizedExpressionGenerator)) {
        Expression value = toValue(expression);
        push(wrapInProblem(value, fasta.messageExpressionNotMetadata,
            value.fileOffset, noLength));
      } else {
        push(toValue(expression));
      }
      constantContext = savedConstantContext;
    }
  }

  @override
  void endMetadataStar(int count) {
    debugEvent("MetadataStar");
    if (count == 0) {
      push(NullValue.Metadata);
    } else {
      push(const GrowableList<Expression>()
              .popNonNullable(stack, count, dummyExpression) ??
          NullValue.Metadata /* Ignore parser recovery */);
    }
  }

  @override
  void endTopLevelFields(
      Token? externalToken,
      Token? staticToken,
      Token? covariantToken,
      Token? lateToken,
      Token? varFinalOrConst,
      int count,
      Token beginToken,
      Token endToken) {
    debugEvent("TopLevelFields");
    if (!libraryBuilder.isNonNullableByDefault) {
      reportNonNullableModifierError(lateToken);
      if (externalToken != null) {
        handleRecoverableError(
            fasta.messageExternalField, externalToken, externalToken);
      }
    }
    push(count);
  }

  @override
  void endClassFields(
      Token? abstractToken,
      Token? externalToken,
      Token? staticToken,
      Token? covariantToken,
      Token? lateToken,
      Token? varFinalOrConst,
      int count,
      Token beginToken,
      Token endToken) {
    debugEvent("Fields");
    if (!libraryBuilder.isNonNullableByDefault) {
      reportNonNullableModifierError(lateToken);
      if (abstractToken != null) {
        handleRecoverableError(
            fasta.messageAbstractClassMember, abstractToken, abstractToken);
      }
      if (externalToken != null) {
        handleRecoverableError(
            fasta.messageExternalField, externalToken, externalToken);
      }
    }
    push(count);
  }

  @override
  void finishFields() {
    debugEvent("finishFields");
    int count = pop() as int;
    List<FieldBuilder> fields = <FieldBuilder>[];
    for (int i = 0; i < count; i++) {
      Expression? initializer = pop() as Expression?;
      Identifier identifier = pop() as Identifier;
      String name = identifier.name;
      Builder declaration;
      if (declarationBuilder != null) {
        declaration =
            declarationBuilder!.lookupLocalMember(name, required: true)!;
      } else {
        declaration = libraryBuilder.lookupLocalMember(name, required: true)!;
      }
      FieldBuilder fieldBuilder;
      if (declaration.isField && declaration.next == null) {
        fieldBuilder = declaration as FieldBuilder;
      } else {
        continue;
      }
      fields.add(fieldBuilder);
      if (initializer != null) {
        if (fieldBuilder.isDuplicate) {
          // Duplicate definition. The field might not be the correct one,
          // so we skip inference of the initializer.
          // Error reporting and recovery is handled elsewhere.
        } else if (fieldBuilder.hasBodyBeenBuilt) {
          // The initializer was already compiled (e.g., if it appear in the
          // outline, like constant field initializers) so we do not need to
          // perform type inference or transformations.
        } else {
          initializer = typeInferrer.inferFieldInitializer(
              this, fieldBuilder.builtType, initializer);

          if (transformCollections || transformSetLiterals) {
            // Wrap the initializer in a temporary parent expression; the
            // transformations need a parent relation.
            Not wrapper = new Not(initializer);
            libraryBuilder.loader.transformPostInference(
                wrapper,
                transformSetLiterals,
                transformCollections,
                libraryBuilder.library);
            initializer = wrapper.operand;
          }
          fieldBuilder.buildBody(coreTypes, initializer);
        }
      } else if (!fieldBuilder.hasBodyBeenBuilt) {
        fieldBuilder.buildBody(coreTypes, null);
      }
    }
    {
      // 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`.
      UnresolvedType? type = pop() as UnresolvedType?;
      if (type != null) {
        buildDartType(type);
      }
    }
    pop(); // Annotations.

    resolveRedirectingFactoryTargets();
    finishVariableMetadata();
  }

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

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

  void prepareInitializers() {
    FunctionBuilder member = this.member as FunctionBuilder;
    scope = member.computeFormalParameterInitializerScope(scope);
    if (member is ConstructorBuilder) {
      member.prepareInitializers();
      if (member.formals != null) {
        for (FormalParameterBuilder formal in member.formals!) {
          if (formal.isInitializingFormal) {
            List<Initializer> initializers;
            if (member.isExternal) {
              initializers = <Initializer>[
                buildInvalidInitializer(
                    buildProblem(
                        fasta.messageExternalConstructorWithFieldInitializers,
                        formal.charOffset,
                        formal.name.length),
                    formal.charOffset)
              ];
            } else {
              initializers = buildFieldInitializer(
                  formal.name,
                  formal.charOffset,
                  formal.charOffset,
                  new VariableGet(formal.variable!),
                  formal: formal);
            }
            for (Initializer initializer in initializers) {
              member.addInitializer(initializer, this);
            }
          }
        }
      }
    }
  }

  @override
  void handleNoInitializers() {
    debugEvent("NoInitializers");
    if (functionNestingLevel == 0) {
      prepareInitializers();
      scope = formalParameterScope ?? new Scope.immutable();
    }
  }

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

  @override
  void endInitializers(int count, Token beginToken, Token endToken) {
    debugEvent("Initializers");
    if (functionNestingLevel == 0) {
      scope = formalParameterScope ?? new Scope.immutable();
    }
  }

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

  @override
  void endInitializer(Token token) {
    debugEvent("endInitializer");
    inFieldInitializer = false;
    assert(!inInitializer);
    Object? node = pop();
    List<Initializer> initializers;

    final ModifierBuilder member = this.member;
    if (!(member is ConstructorBuilder && !member.isExternal)) {
      // 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) {
      initializers = <Initializer>[
        buildSuperInitializer(
            false, node.target, node.arguments, token.charOffset)
      ];
    } else {
      Expression value = toValue(node);
      if (!forest.isThrow(node)) {
        value = wrapInProblem(value, fasta.messageExpectedAnInitializer,
            value.fileOffset, noLength);
      }
      initializers = <Initializer>[
        // TODO(johnniwinther): This should probably be [value] instead of
        //  [node].
        buildInvalidInitializer(node as Expression, token.charOffset)
      ];
    }
    _initializers ??= <Initializer>[];
    _initializers!.addAll(initializers);
  }

  DartType _computeReturnTypeContext(MemberBuilder member) {
    if (member is ProcedureBuilder) {
      return member.function.returnType;
    } else if (member is SourceFactoryBuilder) {
      return member.function.returnType;
    } else {
      assert(member is ConstructorBuilder);
      return const DynamicType();
    }
  }

  @override
  void finishFunction(
      FormalParameters? formals, AsyncMarker asyncModifier, Statement? body) {
    debugEvent("finishFunction");
    typeInferrer.assignedVariables.finish();

    final FunctionBuilder builder = member as FunctionBuilder;
    if (extensionThis != null) {
      typeInferrer.flowAnalysis.declare(extensionThis!, true);
    }
    if (formals?.parameters != null) {
      for (int i = 0; i < formals!.parameters!.length; i++) {
        FormalParameterBuilder parameter = formals.parameters![i];
        typeInferrer.flowAnalysis.declare(parameter.variable!, true);
      }
      for (int i = 0; i < formals.parameters!.length; i++) {
        FormalParameterBuilder parameter = formals.parameters![i];
        Expression? initializer = parameter.variable!.initializer;
        if (parameter.isOptional || initializer != null) {
          if (!parameter.initializerWasInferred) {
            parameter.initializerWasInferred = true;
            if (parameter.isOptional) {
              initializer ??= forest.createNullLiteral(
                  // TODO(ahe): Should store: originParameter.fileOffset
                  // https://github.com/dart-lang/sdk/issues/32289
                  noLocation);
            }
            VariableDeclaration originParameter = builder.getFormalParameter(i);
            initializer = typeInferrer.inferParameterInitializer(
                this,
                initializer!,
                originParameter.type,
                parameter.hasDeclaredInitializer);
            originParameter.initializer = initializer..parent = originParameter;
            libraryBuilder.loader.transformPostInference(
                originParameter,
                transformSetLiterals,
                transformCollections,
                libraryBuilder.library);
          }

          VariableDeclaration? tearOffParameter =
              builder.getTearOffParameter(i);
          if (tearOffParameter != null) {
            cloner ??= new CloneVisitorNotMembers();
            Expression tearOffInitializer = cloner!.clone(initializer!);
            tearOffParameter.initializer = tearOffInitializer
              ..parent = tearOffParameter;
            libraryBuilder.loader.transformPostInference(
                tearOffParameter,
                transformSetLiterals,
                transformCollections,
                libraryBuilder.library);
          }
        }
      }
    }
    if (builder is ConstructorBuilder) {
      finishConstructor(builder, asyncModifier, body);
    } else if (builder is ProcedureBuilder) {
      builder.asyncModifier = asyncModifier;
    } else if (builder is SourceFactoryBuilder) {
      builder.asyncModifier = asyncModifier;
    } else {
      unhandled("${builder.runtimeType}", "finishFunction", builder.charOffset,
          builder.fileUri);
    }

    InferredFunctionBody? inferredFunctionBody;
    if (body != null) {
      inferredFunctionBody = typeInferrer.inferFunctionBody(
          this,
          builder.charOffset,
          _computeReturnTypeContext(builder),
          asyncModifier,
          body);
      body = inferredFunctionBody.body;
      builder.function.futureValueType = inferredFunctionBody.futureValueType;
      libraryBuilder.loader.transformPostInference(body, transformSetLiterals,
          transformCollections, libraryBuilder.library);
    }

    if (builder.returnType != null) {
      checkAsyncReturnType(asyncModifier, builder.function.returnType,
          builder.charOffset, builder.name.length);
    }

    if (builder.kind == ProcedureKind.Setter) {
      if (formals?.parameters == null ||
          formals!.parameters!.length != 1 ||
          formals.parameters!.single.isOptional) {
        int charOffset = formals?.charOffset ??
            body?.fileOffset ??
            builder.member.fileOffset;
        if (body == null) {
          body = new EmptyStatement()..fileOffset = charOffset;
        }
        if (builder.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>[];
          for (FormalParameterBuilder parameter in builder.formals!) {
            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(fasta.messageSetterWithWrongNumberOfFormals,
                  charOffset, noLength)),
          body,
        ]);
      }
    }
    // No-such-method forwarders get their bodies injected during outline
    // building, so we should skip them here.
    bool isNoSuchMethodForwarder = (builder.function.parent is Procedure &&
        (builder.function.parent as Procedure).isNoSuchMethodForwarder);
    if (body != null) {
      if (!builder.isExternal && !isNoSuchMethodForwarder) {
        builder.body = body;
      } else {
        builder.body = new Block(<Statement>[
          new ExpressionStatement(buildProblem(
              fasta.messageExternalMethodWithBody, body.fileOffset, noLength))
            ..fileOffset = body.fileOffset,
          body,
        ])
          ..fileOffset = body.fileOffset;
      }
    }

    resolveRedirectingFactoryTargets();
    finishVariableMetadata();
    libraryBuilder.checkUncheckedTypedefTypes(typeEnvironment);
  }

  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, SubtypeCheckMode.withNullabilities)) {
          problem = fasta.messageIllegalAsyncReturnType;
        }
        break;

      case AsyncMarker.AsyncStar:
        DartType streamBottomType = libraryBuilder.loader.streamOfBottom;
        if (returnType is VoidType) {
          problem = fasta.messageIllegalAsyncGeneratorVoidReturnType;
        } else if (!typeEnvironment.isSubtypeOf(
            streamBottomType, returnType, SubtypeCheckMode.withNullabilities)) {
          problem = fasta.messageIllegalAsyncGeneratorReturnType;
        }
        break;

      case AsyncMarker.SyncStar:
        DartType iterableBottomType = libraryBuilder.loader.iterableOfBottom;
        if (returnType is VoidType) {
          problem = fasta.messageIllegalSyncGeneratorVoidReturnType;
        } else if (!typeEnvironment.isSubtypeOf(iterableBottomType, returnType,
            SubtypeCheckMode.withNullabilities)) {
          problem = fasta.messageIllegalSyncGeneratorReturnType;
        }
        break;

      case AsyncMarker.Sync:
        break; // skip
      case AsyncMarker.SyncYielding:
        unexpected("async, async*, sync, or sync*", "$asyncModifier",
            member.charOffset, uri);
    }

    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'.
  void ensureLoaded(Member? member) {
    if (member == null) return;
    Library ensureLibraryLoaded = member.enclosingLibrary;
    LibraryBuilder? builder =
        libraryBuilder.loader.builders[ensureLibraryLoaded.importUri] ??
            libraryBuilder.loader.target.dillTarget.loader
                .builders[ensureLibraryLoaded.importUri];
    if (builder is DillLibraryBuilder) {
      builder.ensureLoaded();
    }
  }

  /// Check if the containing library of the [member] has been loaded.
  ///
  /// This is designed for use with asserts.
  /// See [ensureLoaded] for a description of what 'loaded' means and the ideas
  /// behind that.
  bool isLoaded(Member? member) {
    if (member == null) return true;
    Library ensureLibraryLoaded = member.enclosingLibrary;
    LibraryBuilder? builder =
        libraryBuilder.loader.builders[ensureLibraryLoaded.importUri] ??
            libraryBuilder.loader.target.dillTarget.loader
                .builders[ensureLibraryLoaded.importUri];
    if (builder is DillLibraryBuilder) {
      return builder.isBuiltAndMarked;
    }
    return true;
  }

  // TODO(eernst): Rename this method now that it handles more tasks.
  void resolveRedirectingFactoryTargets() {
    _unaliasTypeAliasedConstructorInvocations();
    _unaliasTypeAliasedFactoryInvocations();
    _resolveRedirectingFactoryTargets(
        redirectingFactoryInvocations, delayedRedirectingFactoryInvocations);
  }

  /// Return an [Expression] resolving the argument invocation.
  ///
  /// The arguments specify the [StaticInvocation] whose `.target` is
  /// [target], `.arguments` is [arguments], `.fileOffset` is [fileOffset],
  /// and `.isConst` is [isConst].
  /// Returns null if the invocation can't be resolved.
  Expression? _resolveRedirectingFactoryTarget(
      Procedure target, Arguments arguments, int fileOffset, bool isConst) {
    Procedure initialTarget = target;
    Expression replacementNode;

    RedirectionTarget? redirectionTarget =
        getRedirectionTarget(initialTarget, this);
    Member? resolvedTarget = redirectionTarget?.target;
    if (redirectionTarget != null &&
        redirectionTarget.typeArguments.any((type) => type is UnknownType)) {
      return null;
    }

    if (resolvedTarget == null) {
      String name = constructorNameForDiagnostics(initialTarget.name.text,
          className: initialTarget.enclosingClass!.name);
      // TODO(dmitryas): Report this error earlier.
      replacementNode = buildProblem(
          fasta.templateCyclicRedirectingFactoryConstructors
              .withArguments(name),
          initialTarget.fileOffset,
          name.length);
    } else if (resolvedTarget is Constructor &&
        resolvedTarget.enclosingClass.isAbstract) {
      replacementNode = evaluateArgumentsBefore(
          forest.createArguments(noLocation, arguments.positional,
              types: arguments.types, named: arguments.named),
          buildAbstractClassInstantiationError(
              fasta.templateAbstractRedirectedClassInstantiation
                  .withArguments(resolvedTarget.enclosingClass.name),
              resolvedTarget.enclosingClass.name,
              initialTarget.fileOffset));
    } else {
      RedirectingFactoryBody? redirectingFactoryBody =
          getRedirectingFactoryBody(resolvedTarget);
      if (redirectingFactoryBody != null) {
        // If the redirection target is itself a redirecting factory, it means
        // that it is unresolved.
        assert(redirectingFactoryBody.isUnresolved);
        String errorName = redirectingFactoryBody.unresolvedName!;
        replacementNode = buildProblem(
            fasta.templateMethodNotFound.withArguments(errorName),
            fileOffset,
            noLength,
            suppressMessage: true);
      } else {
        Substitution substitution = Substitution.fromPairs(
            initialTarget.function.typeParameters, arguments.types);
        for (int i = 0; i < redirectionTarget!.typeArguments.length; i++) {
          DartType typeArgument =
              substitution.substituteType(redirectionTarget.typeArguments[i]);
          if (i < arguments.types.length) {
            arguments.types[i] = typeArgument;
          } else {
            arguments.types.add(typeArgument);
          }
        }
        arguments.types.length = redirectionTarget.typeArguments.length;

        replacementNode = buildStaticInvocation(
            resolvedTarget,
            forest.createArguments(noLocation, arguments.positional,
                types: arguments.types,
                named: arguments.named,
                hasExplicitTypeArguments: hasExplicitTypeArguments(arguments)),
            constness:
                isConst ? Constness.explicitConst : Constness.explicitNew,
            charOffset: fileOffset);
      }
    }
    return replacementNode;
  }

  void _resolveRedirectingFactoryTargets(
      List<StaticInvocation> redirectingFactoryInvocations,
      List<StaticInvocation>? delayedRedirectingFactoryInvocations) {
    for (StaticInvocation invocation in redirectingFactoryInvocations) {
      // If the invocation was invalid, it or its parent has already been
      // desugared into an exception throwing expression.  There is nothing to
      // resolve anymore.  Note that in the case where the invocation's parent
      // was invalid, type inference won't reach the invocation node and won't
      // set its inferredType field.  If type inference is disabled, reach to
      // the outermost parent to check if the node is a dead code.
      if (invocation.parent == null) continue;
      // ignore: unnecessary_null_comparison
      if (typeInferrer != null) {
        if (invocation is FactoryConstructorInvocationJudgment &&
            !invocation.hasBeenInferred) {
          continue;
        }
      } else {
        TreeNode? parent = invocation.parent;
        while (parent is! Component && parent != null) {
          parent = parent.parent;
        }
        if (parent == null) continue;
      }
      Expression? replacement = _resolveRedirectingFactoryTarget(
          invocation.target,
          invocation.arguments,
          invocation.fileOffset,
          invocation.isConst);
      if (replacement == null) {
        delayedRedirectingFactoryInvocations?.add(invocation);
      } else {
        invocation.replaceWith(replacement);
      }
    }
    redirectingFactoryInvocations.clear();
  }

  void _unaliasTypeAliasedConstructorInvocations() {
    for (TypeAliasedConstructorInvocationJudgment invocation
        in typeAliasedConstructorInvocations) {
      bool inferred = !hasExplicitTypeArguments(invocation.arguments);
      DartType aliasedType = new TypedefType(
          invocation.typeAliasBuilder.typedef,
          Nullability.nonNullable,
          invocation.arguments.types);
      libraryBuilder.checkBoundsInType(
          aliasedType, typeEnvironment, uri, invocation.fileOffset,
          allowSuperBounded: false, inferred: inferred);
      DartType unaliasedType = aliasedType.unalias;
      List<DartType>? invocationTypeArguments = null;
      if (unaliasedType is InterfaceType) {
        invocationTypeArguments = unaliasedType.typeArguments;
      }
      Arguments invocationArguments = forest.createArguments(
          noLocation, invocation.arguments.positional,
          types: invocationTypeArguments, named: invocation.arguments.named);
      invocation.replaceWith(new ConstructorInvocation(
          invocation.target, invocationArguments,
          isConst: invocation.isConst));
    }
    typeAliasedConstructorInvocations.clear();
  }

  void _unaliasTypeAliasedFactoryInvocations() {
    for (TypeAliasedFactoryInvocationJudgment invocation
        in typeAliasedFactoryInvocations) {
      bool inferred = !hasExplicitTypeArguments(invocation.arguments);
      DartType aliasedType = new TypedefType(
          invocation.typeAliasBuilder.typedef,
          Nullability.nonNullable,
          invocation.arguments.types);
      libraryBuilder.checkBoundsInType(
          aliasedType, typeEnvironment, uri, invocation.fileOffset,
          allowSuperBounded: false, inferred: inferred);
      DartType unaliasedType = aliasedType.unalias;
      List<DartType>? invocationTypeArguments = null;
      if (unaliasedType is InterfaceType) {
        invocationTypeArguments = unaliasedType.typeArguments;
      }
      Arguments invocationArguments = forest.createArguments(
          noLocation, invocation.arguments.positional,
          types: invocationTypeArguments,
          named: invocation.arguments.named,
          hasExplicitTypeArguments:
              hasExplicitTypeArguments(invocation.arguments));
      invocation.replaceWith(_resolveRedirectingFactoryTarget(invocation.target,
          invocationArguments, invocation.fileOffset, invocation.isConst)!);
    }
    typeAliasedFactoryInvocations.clear();
  }

  /// Perform actions that were delayed
  ///
  /// An action can be delayed, for instance, because it depends on some
  /// calculations in another library.  For example, a resolution of a
  /// redirecting factory invocation depends on the type inference in the
  /// redirecting factory.
  void performDelayedActions() {
    if (delayedRedirectingFactoryInvocations.isNotEmpty) {
      _resolveRedirectingFactoryTargets(
          delayedRedirectingFactoryInvocations, null);
      if (delayedRedirectingFactoryInvocations.isNotEmpty) {
        for (StaticInvocation invocation
            in delayedRedirectingFactoryInvocations) {
          internalProblem(
              fasta.templateInternalProblemUnhandled.withArguments(
                  invocation.target.name.text, 'performDelayedActions'),
              invocation.fileOffset,
              uri);
        }
      }
    }
  }

  bool get hasDelayedActions {
    return delayedRedirectingFactoryInvocations.isNotEmpty;
  }

  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++) {
          cloner ??= new CloneVisitorNotMembers();
          VariableDeclaration variable = variables[i];
          for (int i = 0; i < annotations.length; i++) {
            variable.addAnnotation(cloner!.clone(annotations[i]));
          }
        }
      }
    }
  }

  @override
  List<Expression> finishMetadata(Annotatable? parent) {
    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 {
      temporaryParent = new ListLiteral(expressions);
    }
    resolveRedirectingFactoryTargets();
    finishVariableMetadata();
    return temporaryParent != null ? temporaryParent.expressions : expressions;
  }

  @override
  Expression parseSingleExpression(
      Parser parser, Token token, FunctionNode parameters) {
    assert(redirectingFactoryInvocations.isEmpty);
    int fileOffset = offsetForToken(token);
    List<TypeVariableBuilder>? typeParameterBuilders;
    for (TypeParameter typeParameter in parameters.typeParameters) {
      typeParameterBuilders ??= <TypeVariableBuilder>[];
      typeParameterBuilders.add(
          new TypeVariableBuilder.fromKernel(typeParameter, libraryBuilder));
    }
    enterFunctionTypeScope(typeParameterBuilders);

    List<FormalParameterBuilder>? formals =
        parameters.positionalParameters.length == 0
            ? null
            : new List<FormalParameterBuilder>.generate(
                parameters.positionalParameters.length, (int i) {
                VariableDeclaration formal = parameters.positionalParameters[i];
                return new FormalParameterBuilder(null, 0, null, formal.name!,
                    libraryBuilder, formal.fileOffset,
                    fileUri: uri)
                  ..variable = formal;
              }, growable: false);
    enterLocalScope(
        'formalParameters',
        new FormalParameters(formals, fileOffset, noLength, uri)
            .computeFormalParameterScope(scope, member, this));

    token = parser.parseExpression(parser.syntheticPreviousToken(token));

    Expression expression = popForValue();
    Token eof = token.next!;

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

    ReturnStatementImpl fakeReturn = new ReturnStatementImpl(true, expression);
    if (formals != null) {
      for (int i = 0; i < formals.length; i++) {
        typeInferrer.flowAnalysis.declare(formals[i].variable!, true);
      }
    }
    InferredFunctionBody inferredFunctionBody = typeInferrer.inferFunctionBody(
        this, fileOffset, const DynamicType(), AsyncMarker.Sync, fakeReturn);
    assert(
        fakeReturn == inferredFunctionBody.body,
        "Previously implicit assumption about inferFunctionBody "
        "not returning anything different.");

    resolveRedirectingFactoryTargets();
    libraryBuilder.loader.transformPostInference(fakeReturn,
        transformSetLiterals, transformCollections, libraryBuilder.library);

    return fakeReturn.expression!;
  }

  void parseInitializers(Token token) {
    Parser parser = new Parser(this);
    if (!token.isEof) {
      token = parser.parseInitializers(token);
      checkEmpty(token.charOffset);
    } else {
      handleNoInitializers();
    }
    // We are passing [AsyncMarker.Sync] because the error will be reported
    // already.
    finishConstructor(member as ConstructorBuilder, AsyncMarker.Sync, null);
  }

  Expression parseFieldInitializer(Token token) {
    Parser parser = new Parser(this);
    token = parser.parseExpression(parser.syntheticPreviousToken(token));
    Expression expression = popForValue();
    checkEmpty(token.charOffset);
    return expression;
  }

  Expression parseAnnotation(Token token) {
    Parser parser = new Parser(this);
    token = parser.parseMetadata(parser.syntheticPreviousToken(token));
    Expression annotation = pop() as Expression;
    checkEmpty(token.charOffset);
    return annotation;
  }

  void finishConstructor(
      ConstructorBuilder builder, AsyncMarker asyncModifier, Statement? body) {
    /// Quotes below are from [Dart Programming Language Specification, 4th
    /// Edition](
    /// https://ecma-international.org/publications/files/ECMA-ST/ECMA-408.pdf).
    assert(builder == member);
    Constructor constructor = builder.actualConstructor;
    List<FormalParameterBuilder>? formals = builder.formals;
    if (formals != null) {
      for (int i = 0; i < formals.length; i++) {
        FormalParameterBuilder parameter = formals[i];
        typeInferrer.flowAnalysis.declare(parameter.variable!, true);
      }
    }
    if (_initializers != null) {
      for (Initializer initializer in _initializers!) {
        typeInferrer.inferInitializer(this, initializer);
      }
      if (!builder.isExternal) {
        for (Initializer initializer in _initializers!) {
          builder.addInitializer(initializer, this);
        }
      }
    }
    if (asyncModifier != AsyncMarker.Sync) {
      constructor.initializers.add(buildInvalidInitializer(buildProblem(
          fasta.messageConstructorNotSync, body!.fileOffset, noLength)));
    }
    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.
      Constructor? superTarget = lookupConstructor(emptyName, isSuper: true);
      Initializer initializer;
      Arguments arguments = forest.createArgumentsEmpty(noLocation);
      if (superTarget == null ||
          checkArgumentsForFunction(superTarget.function, arguments,
                  builder.charOffset, const <TypeParameter>[]) !=
              null) {
        String superclass = classBuilder!.supertypeBuilder!.fullNameForErrors;
        int length = constructor.name.text.length;
        if (length == 0) {
          length = (constructor.parent as Class).name.length;
        }
        initializer = buildInvalidInitializer(
            buildProblem(
                fasta.templateSuperclassHasNoDefaultConstructor
                    .withArguments(superclass),
                builder.charOffset,
                length),
            builder.charOffset);
      } else {
        initializer = buildSuperInitializer(
            true, superTarget, arguments, builder.charOffset);
      }
      constructor.initializers.add(initializer);
    }
    setParents(constructor.initializers, constructor);
    libraryBuilder.loader.transformListPostInference(constructor.initializers,
        transformSetLiterals, transformCollections, libraryBuilder.library);
    if (body == null) {
      /// >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.
      constructor.function.body = new EmptyStatement()
        ..parent = constructor.function;
    }
  }

  @override
  void handleExpressionStatement(Token token) {
    debugEvent("ExpressionStatement");
    push(forest.createExpressionStatement(
        offsetForToken(token), 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;
    }
    int firstNamedArgumentIndex = arguments.length;
    for (int i = 0; i < arguments.length; i++) {
      Object? node = arguments[i];
      if (node is NamedExpression) {
        firstNamedArgumentIndex =
            i < firstNamedArgumentIndex ? i : firstNamedArgumentIndex;
      } else {
        Expression argument = toValue(node);
        arguments[i] = argument;
        if (i > firstNamedArgumentIndex) {
          arguments[i] = new NamedExpression(
              "#$i",
              buildProblem(fasta.messageExpectedNamedArgument,
                  argument.fileOffset, noLength))
            ..fileOffset = beginToken.charOffset;
        }
      }
    }
    if (firstNamedArgumentIndex < arguments.length) {
      List<Expression> positional = new List<Expression>.from(
          arguments.getRange(0, firstNamedArgumentIndex));
      List<NamedExpression> named = new List<NamedExpression>.from(
          arguments.getRange(firstNamedArgumentIndex, arguments.length));
      push(forest.createArguments(beginToken.offset, positional, named: named));
    } 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.
      push(forest.createArguments(
          beginToken.offset, new List<Expression>.from(arguments)));
    }
  }

  @override
  void handleParenthesizedCondition(Token token) {
    debugEvent("ParenthesizedCondition");
    push(popForValue());
  }

  @override
  void handleParenthesizedExpression(Token token) {
    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));
    }
  }

  @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,
        ValueKinds.ProblemBuilder
      ])
    ]));
    debugEvent("Send");
    Object? arguments = pop();
    List<UnresolvedType>? typeArguments = pop() as List<UnresolvedType>?;
    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 Arguments &&
        typeArguments != null &&
        (receiver is! TypeUseGenerator ||
            (receiver is TypeUseGenerator &&
                receiver.declaration is! TypeAliasBuilder));
    if (isInForest) {
      assert(forest.argumentsTypeArguments(arguments).isEmpty);
      forest.argumentsSetTypeArguments(
          arguments, buildDartTypeArguments(typeArguments));
    } else {
      assert(typeArguments == null ||
          (receiver is TypeUseGenerator &&
              receiver.declaration is TypeAliasBuilder));
    }
    if (receiver is ParserRecovery || arguments is ParserRecovery) {
      push(new ParserErrorGenerator(
          this, beginToken, fasta.messageSyntheticToken));
    } else if (receiver is Identifier) {
      Name name = new Name(receiver.name, libraryBuilder.nameOrigin);
      if (arguments == null) {
        push(new IncompletePropertyAccessGenerator(this, beginToken, name));
      } else {
        push(new SendAccessGenerator(
            this, beginToken, name, typeArguments, arguments as Arguments,
            isTypeArgumentsInForest: isInForest));
      }
    } else if (arguments == null) {
      push(receiver);
    } else {
      push(finishSend(receiver, typeArguments, arguments as Arguments,
          beginToken.charOffset,
          isTypeArgumentsInForest: isInForest));
    }
    assert(checkState(beginToken, [
      unionOfKinds([
        ValueKinds.Expression,
        ValueKinds.Generator,
        ValueKinds.Initializer,
        ValueKinds.ProblemBuilder
      ])
    ]));
  }

  @override
  /* Expression | Generator | Initializer */ finishSend(Object receiver,
      List<UnresolvedType>? typeArguments, Arguments 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) {
    debugEvent("beginCascade");
    Expression expression = popForValue();
    if (expression is Cascade) {
      push(expression);
      push(_createReadOnlyVariableAccess(expression.variable, token,
          expression.fileOffset, null, ReadOnlyAccessKind.LetVariable));
    } else {
      bool isNullAware = optional('?..', token);
      if (isNullAware && !libraryBuilder.isNonNullableByDefault) {
        reportMissingNonNullableSupport(token);
      }
      VariableDeclaration variable =
          createVariableDeclarationForValue(expression);
      push(new Cascade(variable, isNullAware: isNullAware)
        ..fileOffset = expression.fileOffset);
      push(_createReadOnlyVariableAccess(variable, token, expression.fileOffset,
          null, ReadOnlyAccessKind.LetVariable));
    }
  }

  @override
  void endCascade() {
    debugEvent("endCascade");
    Expression expression = popForEffect();
    Cascade cascadeReceiver = pop() as Cascade;
    cascadeReceiver.addCascadeExpression(expression);
    push(cascadeReceiver);
  }

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

  @override
  void endCaseExpression(Token colon) {
    debugEvent("endCaseExpression");
    Expression expression = popForValue();
    constantContext = pop() as ConstantContext;
    super.push(expression);
  }

  @override
  void beginBinaryExpression(Token token) {
    bool isAnd = optional("&&", token);
    if (isAnd || optional("||", token)) {
      Expression lhs = popForValue();
      // This is matched by the call to [endNode] in
      // [doLogicalExpression].
      if (isAnd) {
        typeInferrer.assignedVariables.beginNode();
      }
      push(lhs);
    }
  }

  @override
  void endBinaryExpression(Token token) {
    debugEvent("BinaryExpression");
    if (optional(".", token) ||
        optional("..", token) ||
        optional("?..", token)) {
      doDotOrCascadeExpression(token);
    } else if (optional("&&", token) || optional("||", token)) {
      doLogicalExpression(token);
    } else if (optional("??", token)) {
      doIfNull(token);
    } else if (optional("?.", token)) {
      doIfNotNull(token);
    } else {
      doBinaryExpression(token);
    }
  }

  void doBinaryExpression(Token token) {
    assert(checkState(token, <ValueKind>[
      unionOfKinds([
        ValueKinds.Expression,
        ValueKinds.Generator,
        ValueKinds.ProblemBuilder,
      ]),
      unionOfKinds([
        ValueKinds.Expression,
        ValueKinds.Generator,
        ValueKinds.ProblemBuilder,
      ]),
    ]));
    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 {
        if (left is ProblemBuilder) {
          ProblemBuilder problem = left;
          left = buildProblem(problem.message, problem.charOffset, noLength);
        }
        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(
              fasta.templateNotBinaryOperator.withArguments(token),
              token.charOffset,
              token.length));
        } else {
          push(buildProblem(fasta.templateInvalidOperator.withArguments(token),
              token.charOffset, token.length));
        }
      } else if (left is Generator) {
        push(left.buildBinaryOperation(token, name, right));
      } else {
        if (left is ProblemBuilder) {
          ProblemBuilder problem = left;
          left = buildProblem(problem.message, problem.charOffset, noLength);
        }
        assert(left is Expression);
        push(forest.createBinary(fileOffset, left as Expression, name, right));
      }
    }
  }

  /// Handle `a && b` and `a || b`.
  void doLogicalExpression(Token token) {
    Expression argument = popForValue();
    Expression receiver = pop() as Expression;
    Expression logicalExpression = forest.createLogicalExpression(
        offsetForToken(token), receiver, token.stringValue!, argument);
    push(logicalExpression);
    if (optional("&&", token)) {
      // This is matched by the call to [beginNode] in
      // [beginBinaryExpression].
      typeInferrer.assignedVariables.endNode(logicalExpression);
    }
  }

  /// Handle `a ?? b`.
  void doIfNull(Token token) {
    Expression b = popForValue();
    Expression a = popForValue();
    push(new IfNullExpression(a, b)..fileOffset = offsetForToken(token));
  }

  /// Handle `a?.b(...)`.
  void doIfNotNull(Token token) {
    Object? send = pop();
    if (send is IncompleteSendGenerator) {
      push(send.withReceiver(pop(), token.charOffset, isNullAware: true));
    } else {
      pop();
      token = token.next!;
      push(buildProblem(fasta.templateExpectedIdentifier.withArguments(token),
          offsetForToken(token), lengthForToken(token)));
    }
  }

  void doDotOrCascadeExpression(Token token) {
    Object? send = pop();
    if (send is IncompleteSendGenerator) {
      Object? receiver = optional(".", token) ? pop() : popForValue();
      push(send.withReceiver(receiver, token.charOffset));
    } else {
      pop();
      token = token.next!;
      push(buildProblem(fasta.templateExpectedIdentifier.withArguments(token),
          offsetForToken(token), lengthForToken(token)));
    }
  }

  bool areArgumentsCompatible(FunctionNode function, Arguments arguments) {
    // TODO(ahe): Implement this.
    return true;
  }

  @override
  Expression throwNoSuchMethodError(
      Expression receiver, String name, Arguments arguments, int charOffset,
      {Member? candidate,
      bool isSuper: false,
      bool isGetter: false,
      bool isSetter: false,
      bool isStatic: false,
      LocatedMessage? message}) {
    int length = name.length;
    int periodIndex = name.lastIndexOf(".");
    if (periodIndex != -1) {
      length -= periodIndex + 1;
    }
    Name kernelName = new Name(name, libraryBuilder.nameOrigin);
    List<LocatedMessage>? context;
    if (candidate != null && candidate.location != null) {
      Uri uri = candidate.location!.file;
      int offset = candidate.fileOffset;
      Message contextMessage;
      int length = noLength;
      if (candidate is Constructor && candidate.isSynthetic) {
        offset = candidate.enclosingClass.fileOffset;
        contextMessage = fasta.templateCandidateFoundIsDefaultConstructor
            .withArguments(candidate.enclosingClass.name);
      } else {
        if (candidate is Constructor) {
          if (candidate.name.text == '') {
            length = candidate.enclosingClass.name.length;
          } else {
            // Assume no spaces around the dot. Not perfect, but probably the
            // best we can do with the information available.
            length = candidate.enclosingClass.name.length + 1 + name.length;
          }
        } else {
          length = name.length;
        }
        contextMessage = fasta.messageCandidateFound;
      }
      context = [contextMessage.withLocation(uri, offset, length)];
    }
    if (message == null) {
      if (isGetter) {
        message = warnUnresolvedGet(kernelName, charOffset,
                isSuper: isSuper, reportWarning: false, context: context)
            .withLocation(uri, charOffset, length);
      } else if (isSetter) {
        message = warnUnresolvedSet(kernelName, charOffset,
                isSuper: isSuper, reportWarning: false, context: context)
            .withLocation(uri, charOffset, length);
      } else {
        message = warnUnresolvedMethod(kernelName, charOffset,
                isSuper: isSuper, reportWarning: false, context: context)
            .withLocation(uri, charOffset, length);
      }
    }
    return buildProblem(
        message.messageObject, message.charOffset, message.length,
        context: context);
  }

  @override
  Message warnUnresolvedGet(Name name, int charOffset,
      {bool isSuper: false,
      bool reportWarning: true,
      List<LocatedMessage>? context}) {
    Message message = isSuper
        ? fasta.templateSuperclassHasNoGetter.withArguments(name.text)
        : fasta.templateGetterNotFound.withArguments(name.text);
    if (reportWarning) {
      addProblemErrorIfConst(message, charOffset, name.text.length,
          context: context);
    }
    return message;
  }

  @override
  Message warnUnresolvedSet(Name name, int charOffset,
      {bool isSuper: false,
      bool reportWarning: true,
      List<LocatedMessage>? context}) {
    Message message = isSuper
        ? fasta.templateSuperclassHasNoSetter.withArguments(name.text)
        : fasta.templateSetterNotFound.withArguments(name.text);
    if (reportWarning) {
      addProblemErrorIfConst(message, charOffset, name.text.length,
          context: context);
    }
    return message;
  }

  @override
  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
        ? fasta.templateSuperclassHasNoMethod.withArguments(name.text)
        : fasta.templateMethodNotFound.withArguments(name.text);
    if (reportWarning) {
      addProblemErrorIfConst(message, charOffset, length, context: context);
    }
    return message;
  }

  @override
  void warnTypeArgumentsMismatch(String name, int expected, int charOffset) {
    addProblemErrorIfConst(
        fasta.templateTypeArgumentMismatch.withArguments(expected),
        charOffset,
        name.length);
  }

  @override
  Member? lookupInstanceMember(Name name,
      {bool isSetter: false, bool isSuper: false}) {
    return classBuilder!.lookupInstanceMember(hierarchy, name,
        isSetter: isSetter, isSuper: isSuper);
  }

  @override
  Constructor? lookupConstructor(Name name, {bool isSuper: false}) {
    return classBuilder!.lookupConstructor(name, isSuper: isSuper);
  }

  @override
  void handleIdentifier(Token token, IdentifierContext context) {
    debugEvent("handleIdentifier");
    String name = token.lexeme;
    if (context.isScopeReference) {
      assert(!inInitializer ||
          this.scope == enclosingScope ||
          this.scope.parent == enclosingScope);
      // This deals with this kind of initializer: `C(a) : a = a;`
      Scope scope = inInitializer ? enclosingScope : this.scope;
      push(scopeLookup(scope, name, token));
      return;
    } else if (context.inDeclaration) {
      if (context == IdentifierContext.topLevelVariableDeclaration ||
          context == IdentifierContext.fieldDeclaration) {
        constantContext = member.isConst
            ? ConstantContext.inferred
            : !member.isStatic &&
                    classBuilder != null &&
                    classBuilder!.declaresConstConstructor
                ? ConstantContext.required
                : ConstantContext.none;
      }
    } else if (constantContext != ConstantContext.none &&
        !context.allowedInConstantExpression) {
      addProblem(
          fasta.messageNotAConstantExpression, token.charOffset, token.length);
    }
    if (token.isSynthetic) {
      push(new ParserRecovery(offsetForToken(token)));
    } else {
      push(new Identifier(token));
    }
  }

  /// Helper method to create a [VariableGet] of the [variable] using
  /// [charOffset] as the file offset.
  @override
  VariableGet createVariableGet(VariableDeclaration variable, int charOffset,
      {bool forNullGuardedAccess: false}) {
    if (!(variable as VariableDeclarationImpl).isLocalFunction) {
      typeInferrer.assignedVariables.read(variable);
    }
    return new VariableGetImpl(variable,
        forNullGuardedAccess: forNullGuardedAccess)
      ..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);
  }

  /// Look up [name] in [scope] using [token] as location information (both to
  /// report problems and as the file offset in the generated kernel code).
  /// [isQualified] should be true if [name] is a qualified access (which
  /// implies that it shouldn't be turned into a [ThisPropertyAccessGenerator]
  /// if the name doesn't resolve in the scope).
  @override
  /*Generator|Expression|Builder*/ scopeLookup(
      Scope scope, String name, Token token,
      {bool isQualified: false, PrefixBuilder? prefix}) {
    int charOffset = offsetForToken(token);
    if (token.isSynthetic) {
      return new ParserErrorGenerator(this, token, fasta.messageSyntheticToken);
    }
    Builder? declaration = scope.lookup(name, charOffset, uri);
    if (declaration == null &&
        prefix == null &&
        (classBuilder?.isPatch ?? false)) {
      // The scope of a patched method includes the origin class.
      declaration = classBuilder!.origin
          .findStaticBuilder(name, charOffset, uri, libraryBuilder);
    }
    if (declaration != null &&
        declaration.isDeclarationInstanceMember &&
        (inFieldInitializer && !inLateFieldInitializer) &&
        !inInitializer) {
      // We cannot access a class instance member in an initializer of a
      // field.
      //
      // For instance
      //
      //     class M {
      //       int foo = bar;
      //       int bar;
      //     }
      //
      return new IncompleteErrorGenerator(this, token,
          fasta.templateThisAccessInFieldInitializer.withArguments(name));
    }
    if (declaration == null ||
        (!isDeclarationInstanceContext &&
            declaration.isDeclarationInstanceMember)) {
      // We either didn't find a declaration or found an instance member from
      // a non-instance context.
      Name n = new Name(name, libraryBuilder.nameOrigin);
      if (!isQualified && isDeclarationInstanceContext) {
        assert(declaration == null);
        if (constantContext != ConstantContext.none ||
            (inFieldInitializer && !inLateFieldInitializer) && !inInitializer) {
          return new UnresolvedNameGenerator(this, token, n);
        }
        if (extensionThis != null) {
          // If we are in an extension instance member we interpret this as an
          // implicit access on the 'this' parameter.
          return PropertyAccessGenerator.make(this, token,
              createVariableGet(extensionThis!, charOffset), n, false);
        } else {
          // This is an implicit access on 'this'.
          return new ThisPropertyAccessGenerator(this, token, n);
        }
      } else if (ignoreMainInGetMainClosure &&
          name == "main" &&
          member.name == "_getMainClosure") {
        return forest.createNullLiteral(charOffset);
      } else {
        return new UnresolvedNameGenerator(this, token, n);
      }
    } else if (declaration.isTypeDeclaration) {
      if (declaration is AccessErrorBuilder) {
        AccessErrorBuilder accessError = declaration;
        declaration = accessError.builder;
      }
      return new TypeUseGenerator(
          this, token, declaration as TypeDeclarationBuilder, name);
    } else if (declaration.isLocal) {
      VariableBuilder variableBuilder = declaration as VariableBuilder;
      if (constantContext != ConstantContext.none &&
          !variableBuilder.isConst &&
          !member.isConstructor &&
          !enableConstFunctionsInLibrary) {
        return new IncompleteErrorGenerator(
            this, token, fasta.messageNotAConstantExpression);
      }
      VariableDeclaration variable = variableBuilder.variable!;
      if (!variableBuilder.isAssignable) {
        return _createReadOnlyVariableAccess(
            variable,
            token,
            charOffset,
            name,
            variableBuilder.isConst
                ? ReadOnlyAccessKind.ConstVariable
                : ReadOnlyAccessKind.FinalVariable);
      } else {
        return new VariableUseGenerator(this, token, variable);
      }
    } else if (declaration.isClassInstanceMember) {
      if (constantContext != ConstantContext.none &&
          !inInitializer &&
          // TODO(ahe): This is a hack because Fasta sets up the scope
          // "this.field" parameters according to old semantics. Under the new
          // semantics, such parameters introduces a new parameter with that
          // name that should be resolved here.
          !member.isConstructor) {
        addProblem(
            fasta.messageNotAConstantExpression, charOffset, token.length);
      }
      Name n = new Name(name, libraryBuilder.nameOrigin);
      return new ThisPropertyAccessGenerator(this, token, n);
    } else if (declaration.isExtensionInstanceMember) {
      ExtensionBuilder extensionBuilder =
          declarationBuilder as ExtensionBuilder;
      MemberBuilder? setterBuilder =
          _getCorrespondingSetterBuilder(scope, declaration, name, charOffset);
      // TODO(johnniwinther): Check for constantContext like below?
      if (declaration.isField) {
        declaration = null;
      }
      if (setterBuilder != null &&
          (setterBuilder.isField || setterBuilder.isStatic)) {
        setterBuilder = null;
      }
      if (declaration == null && setterBuilder == null) {
        return new UnresolvedNameGenerator(
            this, token, new Name(name, libraryBuilder.nameOrigin));
      }
      MemberBuilder? getterBuilder =
          declaration is MemberBuilder ? declaration : null;
      return new ExtensionInstanceAccessGenerator.fromBuilder(
          this,
          token,
          extensionBuilder.extension,
          name,
          extensionThis!,
          extensionTypeParameters,
          getterBuilder,
          setterBuilder);
    } else if (declaration.isRegularMethod) {
      assert(declaration.isStatic || declaration.isTopLevel);
      MemberBuilder memberBuilder = declaration as MemberBuilder;
      return new StaticAccessGenerator(
          this, token, name, memberBuilder.member, null);
    } else if (declaration is PrefixBuilder) {
      assert(prefix == null);
      return new PrefixUseGenerator(this, token, declaration);
    } else if (declaration is LoadLibraryBuilder) {
      return new LoadLibraryGenerator(this, token, declaration);
    } else if (declaration.hasProblem && declaration is! AccessErrorBuilder) {
      return declaration;
    } else {
      MemberBuilder? setterBuilder =
          _getCorrespondingSetterBuilder(scope, declaration, name, charOffset);
      MemberBuilder? getterBuilder =
          declaration is MemberBuilder ? declaration : null;
      assert(getterBuilder != null || setterBuilder != null);
      StaticAccessGenerator generator = new StaticAccessGenerator.fromBuilder(
          this, name, token, getterBuilder, setterBuilder);
      if (constantContext != ConstantContext.none) {
        Member? readTarget = generator.readTarget;
        if (!(readTarget is Field && readTarget.isConst ||
            // Static tear-offs are also compile time constants.
            readTarget is Procedure)) {
          addProblem(
              fasta.messageNotAConstantExpression, charOffset, token.length);
        }
      }
      return generator;
    }
  }

  /// Returns the setter builder corresponding to [declaration] using the
  /// [name] and [charOffset] for the lookup into [scope] if necessary.
  MemberBuilder? _getCorrespondingSetterBuilder(
      Scope scope, Builder declaration, String name, int charOffset) {
    Builder? setter;
    if (declaration.isSetter) {
      setter = declaration;
    } else if (declaration.isGetter) {
      setter = scope.lookupSetter(name, charOffset, uri);
    } else if (declaration.isField) {
      MemberBuilder fieldBuilder = declaration as MemberBuilder;
      if (!fieldBuilder.isAssignable) {
        setter = scope.lookupSetter(name, charOffset, uri);
      } else {
        setter = declaration;
      }
    }
    return setter is MemberBuilder ? setter : null;
  }

  @override
  void handleQualified(Token period) {
    debugEvent("Qualified");
    Object? node = pop();
    Object? qualifier = pop();
    if (qualifier is ParserRecovery) {
      push(qualifier);
    } else if (node is ParserRecovery) {
      push(node);
    } else {
      Identifier identifier = node as Identifier;
      push(identifier.withQualifier(qualifier!));
    }
  }

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

  @override
  void handleStringPart(Token token) {
    debugEvent("StringPart");
    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) {
        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
  void handleScript(Token token) {
    debugEvent("Script");
  }

  @override
  void handleStringJuxtaposition(Token startToken, int literalCount) {
    debugEvent("StringJuxtaposition");
    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 = int.tryParse(token.lexeme);
    // 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));
    } 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(
          fasta.messageConstructorWithReturnType, beginToken.charOffset));
    } else {
      push(forest.createReturnStatement(offsetForToken(beginToken), expression,
          isArrow: !identical(beginToken.lexeme, "return")));
    }
  }

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

  @override
  void endThenStatement(Token token) {
    super.endThenStatement(token);
    // 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) {
    Statement? elsePart = popStatementIfNotNull(elseToken);
    AssignedVariablesNodeInfo<VariableDeclaration> assignedVariablesInfo =
        pop() as AssignedVariablesNodeInfo<VariableDeclaration>;
    Statement thenPart = popStatement();
    Expression condition = pop() as Expression;
    Statement node = forest.createIfStatement(
        offsetForToken(ifToken), condition, 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 & lateMask) != 0) {
      // This is matched by the call to [endNode] in [endVariableInitializer].
      typeInferrer.assignedVariables.beginNode();
    }
  }

  @override
  void endVariableInitializer(Token assignmentOperator) {
    debugEvent("VariableInitializer");
    assert(assignmentOperator.stringValue == "=");
    AssignedVariablesNodeInfo<VariableDeclaration>? assignedVariablesInfo;
    bool isLate = (currentLocalVariableModifiers & lateMask) != 0;
    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 & constMask) != 0;
    bool isFinal = (currentLocalVariableModifiers & finalMask) != 0;
    bool isLate = (currentLocalVariableModifiers & lateMask) != 0;
    Expression? initializer;
    if (!optional("in", token.next!)) {
      // 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(
              fasta.templateConstFieldWithoutInitializer
                  .withArguments(token.lexeme),
              token.charOffset,
              token.length);
        } else if (!libraryBuilder.isNonNullableByDefault &&
            isFinal &&
            !isLate) {
          initializer = buildProblem(
              fasta.templateFinalFieldWithoutInitializer
                  .withArguments(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 != -1);
    bool isConst = (currentLocalVariableModifiers & constMask) != 0;
    bool isFinal = (currentLocalVariableModifiers & finalMask) != 0;
    bool isLate = (currentLocalVariableModifiers & lateMask) != 0;
    bool isRequired = (currentLocalVariableModifiers & requiredMask) != 0;
    assert(isConst == (constantContext == ConstantContext.inferred));
    VariableDeclaration variable = new VariableDeclarationImpl(
        identifier.name, functionNestingLevel,
        forSyntheticToken: identifier.token.isSynthetic,
        initializer: initializer,
        type: currentLocalVariableType != null
            ? buildDartType(currentLocalVariableType!)
            : null,
        isFinal: isFinal,
        isConst: isConst,
        isLate: isLate,
        isRequired: isRequired,
        hasDeclaredInitializer: initializer != null,
        isStaticLate: libraryBuilder.isNonNullableByDefault &&
            isFinal &&
            initializer == null)
      ..fileOffset = identifier.charOffset
      ..fileEqualsOffset = offsetForToken(equalsToken);
    typeInferrer.assignedVariables.declare(variable);
    libraryBuilder.checkBoundsInVariableDeclaration(
        variable, typeEnvironment, uri);
    push(variable);
  }

  @override
  void beginFieldInitializer(Token token) {
    inFieldInitializer = true;
    if (member is FieldBuilder) {
      FieldBuilder fieldBuilder = member as FieldBuilder;
      inLateFieldInitializer = fieldBuilder.isLate;
      if (fieldBuilder.isAbstract) {
        addProblem(
            fasta.messageAbstractFieldInitializer, token.charOffset, noLength);
      } else if (fieldBuilder.isExternal) {
        addProblem(
            fasta.messageExternalFieldInitializer, token.charOffset, noLength);
      }
    } else {
      inLateFieldInitializer = false;
    }
  }

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

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

  @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);
    declareVariable(variable, scope);
  }

  @override
  void beginVariablesDeclaration(
      Token token, Token? lateToken, Token? varFinalOrConst) {
    debugEvent("beginVariablesDeclaration");
    if (!libraryBuilder.isNonNullableByDefault) {
      reportNonNullableModifierError(lateToken);
    }
    UnresolvedType? type = pop() as UnresolvedType?;
    int modifiers = (lateToken != null ? lateMask : 0) |
        Modifier.validateVarFinalOrConst(varFinalOrConst?.lexeme);
    _enterLocalState(inLateLocalInitializer: lateToken != null);
    super.push(currentLocalVariableModifiers);
    super.push(currentLocalVariableType ?? NullValue.Type);
    currentLocalVariableType = type;
    currentLocalVariableModifiers = modifiers;
    super.push(constantContext);
    constantContext = ((modifiers & constMask) != 0)
        ? 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() as UnresolvedType?;
      currentLocalVariableModifiers = pop() as int;
      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() as UnresolvedType?;
      currentLocalVariableModifiers = pop() as int;
      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<VariableDeclaration>> tryStatementInfoStack =
      const Link<AssignedVariablesNodeInfo<VariableDeclaration>>();

  @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());
    }
    super.beginBlock(token, blockKind);
  }

  @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);
    }
  }

  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) {
    assert(checkState(token, [
      unionOfKinds(<ValueKind>[
        ValueKinds.Expression,
        ValueKinds.Generator,
        // TODO(johnniwinther): Avoid problem builders here.
        ValueKinds.ProblemBuilder
      ]),
      unionOfKinds(<ValueKind>[
        ValueKinds.Expression, ValueKinds.Generator,
        // TODO(johnniwinther): Avoid problem builders here.
        ValueKinds.ProblemBuilder
      ])
    ]));
    debugEvent("AssignmentExpression");
    Expression value = popForValue();
    Object? generator = pop();
    if (generator is! Generator) {
      push(buildProblem(fasta.messageNotAnLvalue, offsetForToken(token),
          lengthForToken(token)));
    } else {
      push(new DelayedAssignment(
          this, token, generator, value, token.stringValue!));
    }
  }

  @override
  void enterLoop(int charOffset) {
    if (peek() is LabelTarget) {
      LabelTarget target = peek() as LabelTarget;
      enterBreakTarget(charOffset, target.breakTarget);
      enterContinueTarget(charOffset, target.continueTarget);
    } else {
      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) {
      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>) {
      List<VariableDeclaration> variables = <VariableDeclaration>[];
      for (Object v in variableOrExpression) {
        variables.addAll(_buildForLoopVariableDeclarations(v)!);
      }
      return variables;
    } else if (variableOrExpression == null) {
      return <VariableDeclaration>[];
    }
    return null;
  }

  @override
  void handleForInitializerEmptyStatement(Token token) {
    debugEvent("ForInitializerEmptyStatement");
    push(NullValue.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 handleForLoopParts(Token forKeyword, Token leftParen,
      Token leftSeparator, int updateExpressionCount) {
    push(forKeyword);
    push(leftParen);
    push(leftSeparator);
    push(updateExpressionCount);
  }

  @override
  void endForControlFlow(Token token) {
    debugEvent("ForControlFlow");
    Object? entry = pop();
    int updateExpressionCount = pop() as int;
    pop(); // left separator
    pop(); // left parenthesis
    Token forToken = pop() as Token;
    List<Expression> updates = popListForEffect(updateExpressionCount);
    Statement conditionStatement = popStatement(); // condition

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

      handleRecoverableError(
          fasta.templateCantUseControlFlowOrSpreadAsConstant
              .withArguments(forToken),
          forToken,
          forToken);
      push(invalidCollectionElement);
      return;
    }

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

    Object? variableOrExpression = pop();
    exitLocalScope();

    transformCollections = true;
    List<VariableDeclaration> variables =
        _buildForLoopVariableDeclarations(variableOrExpression)!;
    typeInferrer.assignedVariables.pushNode(assignedVariablesNodeInfo);
    Expression? condition;
    if (conditionStatement is ExpressionStatement) {
      condition = conditionStatement.expression;
    } else {
      assert(conditionStatement is EmptyStatement);
    }
    if (entry is MapLiteralEntry) {
      ForMapEntry result = forest.createForMapEntry(
          offsetForToken(forToken), variables, condition, updates, entry);
      typeInferrer.assignedVariables.endNode(result);
      push(result);
    } else {
      ForElement 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 */ ValueKinds.Statement,
      /* expression count */ ValueKinds.Integer,
      /* left separator */ ValueKinds.Token,
      /* left parenthesis */ ValueKinds.Token,
      /* for keyword */ ValueKinds.Token,
    ]));
    debugEvent("ForStatement");
    Statement body = popStatement();

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

    assert(checkState(endToken, <ValueKind>[
      /* expressions */ ...repeatedKinds(
          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();
    // This is matched by the call to [beginNode] in
    // [handleForInitializerEmptyStatement],
    // [handleForInitializerExpressionStatement], and
    // [handleForInitializerLocalVariableDeclaration].
    AssignedVariablesNodeInfo<VariableDeclaration> assignedVariablesNodeInfo =
        typeInferrer.assignedVariables.deferNode();

    Object? variableOrExpression = pop();
    List<VariableDeclaration>? 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 ParserRecovery) {
      problemInLoopOrSwitch ??= buildProblemStatement(
          fasta.messageSyntheticToken, variableOrExpression.charOffset,
          suppressMessage: true);
    }
    exitLoopOrSwitch(result);
  }

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

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

  @override
  void endInvalidYieldStatement(Token keyword, Token? starToken, Token endToken,
      fasta.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");

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

    // TODO(danrubel): Replace this with popListForValue
    // when control flow and spread collections have been enabled by default
    List<Expression> expressions =
        new List<Expression>.filled(count, dummyExpression, growable: true);
    for (int i = count - 1; i >= 0; i--) {
      Object? elem = pop();
      if (elem != invalidCollectionElement) {
        expressions[i] = toValue(elem);
      } else {
        expressions.removeAt(i);
      }
    }

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

    DartType typeArgument;
    if (typeArguments != null) {
      if (typeArguments.length > 1) {
        addProblem(
            fasta.messageListLiteralTooManyTypeArguments,
            offsetForToken(leftBracket),
            lengthOfSpan(leftBracket, leftBracket.endGroup));
        typeArgument = const InvalidType();
      } else {
        typeArgument = buildDartType(typeArguments.single);
        typeArgument = instantiateToBounds(
            typeArgument, coreTypes.objectClass, libraryBuilder.library);
      }
    } 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);
    libraryBuilder.checkBoundsInListLiteral(node, typeEnvironment, uri);
    push(node);
  }

  void buildLiteralSet(List<UnresolvedType>? typeArguments, Token? constKeyword,
      Token leftBrace, List<dynamic>? setOrMapEntries) {
    DartType typeArgument;
    if (typeArguments != null) {
      typeArgument = buildDartType(typeArguments.single);
      typeArgument = instantiateToBounds(
          typeArgument, coreTypes.objectClass, libraryBuilder.library);
    } 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(fasta.templateExpectedButGot.withArguments(','),
              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);
    libraryBuilder.checkBoundsInSetLiteral(node, typeEnvironment, uri);
    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");

    if (constantContext == ConstantContext.required && constKeyword == null) {
      addProblem(fasta.messageMissingExplicitConst, 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();
      // TODO(danrubel): Revise this to handle control flow and spread
      if (elem == invalidCollectionElement) {
        setOrMapEntries.removeAt(i);
      } else if (elem is MapLiteralEntry) {
        setOrMapEntries[i] = elem;
      } else {
        setOrMapEntries[i] = toValue(elem);
      }
    }
    List<UnresolvedType>? typeArguments = pop() as List<UnresolvedType>?;

    // 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 handleLiteralBool(Token token) {
    debugEvent("LiteralBool");
    bool value = optional("true", token);
    assert(value || optional("false", token));
    push(forest.createBoolLiteral(offsetForToken(token), value));
  }

  @override
  void handleLiteralDouble(Token token) {
    debugEvent("LiteralDouble");
    push(forest.createDoubleLiteral(
        offsetForToken(token), double.parse(token.lexeme)));
  }

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

  void buildLiteralMap(List<UnresolvedType>? 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]);
        valueType = buildDartType(typeArguments[1]);
        keyType = instantiateToBounds(
            keyType, coreTypes.objectClass, libraryBuilder.library);
        valueType = instantiateToBounds(
            valueType, coreTypes.objectClass, libraryBuilder.library);
      }
    } else {
      DartType implicitTypeArgument = this.implicitTypeArgument;
      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);
    libraryBuilder.checkBoundsInMapLiteral(node, typeEnvironment, uri);
    push(node);
  }

  @override
  void handleLiteralMapEntry(Token colon, Token endToken) {
    debugEvent("LiteralMapEntry");
    Expression value = popForValue();
    Expression key = popForValue();
    push(forest.createMapEntry(offsetForToken(colon), key, 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, fasta.messageSyntheticToken));
      } else {
        push(forest.createSymbolLiteral(
            offsetForToken(hashToken), symbolPartToString(part)));
      }
    } else {
      List<Identifier>? parts = const FixedNullableList<Identifier>()
          .popNonNullable(stack, identifierCount, dummyIdentifier);
      if (parts == null) {
        push(new ParserErrorGenerator(
            this, hashToken, fasta.messageSyntheticToken));
        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,
        ValueKinds.ProblemBuilder
      ])
    ]));
    if (!libraryBuilder.isNonNullableByDefault) {
      reportNonNullAssertExpressionNotEnabled(bang);
    }
    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");
    if (!libraryBuilder.isNonNullableByDefault) {
      reportErrorIfNullableType(questionMark);
    }
    bool isMarkedAsNullable = questionMark != null;
    List<UnresolvedType>? arguments = pop() as List<UnresolvedType>?;
    Object? name = pop();
    if (name is QualifiedName) {
      QualifiedName qualified = name;
      Object prefix = qualified.qualifier;
      Token suffix = qualified.suffix;
      if (prefix is Generator) {
        name = prefix.qualifiedLookup(suffix);
      } else {
        String name = getNodeName(prefix);
        String displayName = debugName(name, suffix.lexeme);
        int offset = offsetForToken(beginToken);
        Message message = fasta.templateNotAType.withArguments(displayName);
        libraryBuilder.addProblem(
            message, offset, lengthOfSpan(beginToken, suffix), uri);
        push(new UnresolvedType(
            new NamedTypeBuilder(
                name,
                libraryBuilder.nullableBuilderIfTrue(isMarkedAsNullable),
                null,
                uri,
                offset)
              ..bind(new InvalidTypeDeclarationBuilder(
                  name,
                  message.withLocation(
                      uri, offset, lengthOfSpan(beginToken, suffix)))),
            offset,
            uri));
        return;
      }
    }
    TypeBuilder? result;
    if (name is Generator) {
      result = name.buildTypeWithResolvedArguments(
          libraryBuilder.nullableBuilderIfTrue(isMarkedAsNullable), arguments);
      // ignore: unnecessary_null_comparison
      if (result == null) {
        unhandled("null", "result", beginToken.charOffset, uri);
      }
    } else if (name is ProblemBuilder) {
      // TODO(ahe): Arguments could be passed here.
      libraryBuilder.addProblem(
          name.message, name.charOffset, name.name.length, name.fileUri);
      result = new NamedTypeBuilder(
          name.name,
          libraryBuilder.nullableBuilderIfTrue(isMarkedAsNullable),
          /* arguments = */ null,
          name.fileUri,
          name.charOffset)
        ..bind(new InvalidTypeDeclarationBuilder(
            name.name,
            name.message.withLocation(
                name.fileUri, name.charOffset, name.name.length)));
    } else {
      unhandled(
          "${name.runtimeType}", "handleType", beginToken.charOffset, uri);
    }
    push(new UnresolvedType(result, beginToken.charOffset, uri));
  }

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

  void enterFunctionTypeScope(List<TypeVariableBuilder>? typeVariables) {
    debugEvent("enterFunctionTypeScope");
    enterLocalScope('FunctionTypeScope',
        scope.createNestedScope("function-type scope", isModifiable: true));
    if (typeVariables != null) {
      ScopeBuilder scopeBuilder = new ScopeBuilder(scope);
      for (TypeVariableBuilder builder in typeVariables) {
        String name = builder.name;
        TypeVariableBuilder? existing =
            scopeBuilder[name] as TypeVariableBuilder?;
        if (existing == null) {
          scopeBuilder.addMember(name, builder);
        } else {
          reportDuplicatedDeclaration(existing, name, builder.charOffset);
        }
      }
    }
  }

  @override
  void endFunctionType(Token functionToken, Token? questionMark) {
    debugEvent("FunctionType");
    if (!libraryBuilder.isNonNullableByDefault) {
      reportErrorIfNullableType(questionMark);
    }
    FormalParameters formals = pop() as FormalParameters;
    UnresolvedType? returnType = pop() as UnresolvedType?;
    List<TypeVariableBuilder>? typeVariables =
        pop() as List<TypeVariableBuilder>?;
    if (typeVariables != null) {
      for (TypeVariableBuilder builder in typeVariables) {
        if (builder.parameter.annotations.isNotEmpty) {
          if (!libraryBuilder.enableGenericMetadataInLibrary) {
            addProblem(fasta.messageAnnotationOnFunctionTypeTypeVariable,
                builder.charOffset, builder.name.length);
          }
          // Annotations on function types are not constant evaluated and are
          // not included in the generated AST so we clear them here.
          builder.parameter.annotations = const <Expression>[];
        }
      }
    }
    UnresolvedType type = formals.toFunctionType(
        returnType,
        libraryBuilder.nullableBuilderIfTrue(questionMark != null),
        typeVariables);
    exitLocalScope();
    push(type);
  }

  @override
  void handleVoidKeyword(Token token) {
    debugEvent("VoidKeyword");
    int offset = offsetForToken(token);
    // "void" is always nullable.
    push(new UnresolvedType(
        new NamedTypeBuilder(
            "void", const NullabilityBuilder.nullable(), null, uri, offset)
          ..bind(new VoidTypeDeclarationBuilder(
              const VoidType(), libraryBuilder, offset)),
        offset,
        uri));
  }

  @override
  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");
    DartType type = buildDartType(pop() as UnresolvedType,
        allowPotentiallyConstantType: libraryBuilder.isNonNullableByDefault);
    libraryBuilder.checkBoundsInType(
        type, typeEnvironment, uri, operator.charOffset);
    Expression expression = popForValue();
    Expression asExpression = forest.createAsExpression(
        offsetForToken(operator), expression, type,
        forNonNullableByDefault: libraryBuilder.isNonNullableByDefault);
    push(asExpression);
  }

  @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 UnresolvedType,
        allowPotentiallyConstantType: libraryBuilder.isNonNullableByDefault);
    Expression operand = popForValue();
    Expression isExpression = forest.createIsExpression(
        offsetForToken(isOperator), operand, type,
        forNonNullableByDefault: libraryBuilder.isNonNullableByDefault,
        notFileOffset: not != null ? offsetForToken(not) : null);
    libraryBuilder.checkBoundsInType(
        type, typeEnvironment, uri, isOperator.charOffset);
    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) {
    debugEvent("ConditionalExpression");
    Expression elseExpression = popForValue();
    Expression thenExpression = pop() as Expression;
    AssignedVariablesNodeInfo<VariableDeclaration> assignedVariablesInfo =
        pop() as AssignedVariablesNodeInfo<VariableDeclaration>;
    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(
          fasta.templateNotConstantExpression.withArguments('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) {
    // TODO(danrubel): handle required token
    if (!libraryBuilder.isNonNullableByDefault) {
      reportNonNullableModifierError(requiredToken);
    }
    push((covariantToken != null ? covariantMask : 0) |
        (requiredToken != null ? requiredMask : 0) |
        Modifier.validateVarFinalOrConst(varFinalOrConst?.lexeme));
  }

  @override
  void endFormalParameter(
      Token? thisKeyword,
      Token? periodAfterThis,
      Token nameToken,
      Token? initializerStart,
      Token? initializerEnd,
      FormalParameterKind kind,
      MemberKind memberKind) {
    debugEvent("FormalParameter");
    if (thisKeyword != null) {
      if (!inConstructor) {
        handleRecoverableError(fasta.messageFieldInitializerOutsideConstructor,
            thisKeyword, thisKeyword);
        thisKeyword = null;
      }
    }
    Object? nameNode = pop();
    UnresolvedType? type = pop() as UnresolvedType?;
    if (functionNestingLevel == 0 && type != null) {
      // 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/deferred_type_annotation.dart for an example
      // where not calling [buildDartType] leads to a missing compile-time
      // error. Also, notice that the type of the problematic parameter isn't
      // `invalid-type`.
      buildDartType(type);
    }
    int modifiers = pop() as int;
    if (inCatchClause) {
      modifiers |= finalMask;
    }
    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) {
      FunctionBuilder member = this.member as FunctionBuilder;
      parameter = member.getFormal(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 {
      parameter = new FormalParameterBuilder(null, modifiers, type?.builder,
          name?.name ?? '', libraryBuilder, offsetForToken(nameToken),
          fileUri: uri)
        ..hasDeclaredInitializer = (initializerStart != null);
    }
    VariableDeclaration variable = parameter.build(
        libraryBuilder, functionNestingLevel,
        nonInstanceContext: !isDeclarationInstanceContext);
    Expression? initializer = name?.initializer;
    if (initializer != null) {
      if (member is RedirectingFactoryBuilder) {
        RedirectingFactoryBuilder factory = member as RedirectingFactoryBuilder;
        addProblem(
            fasta.templateDefaultValueInRedirectingFactoryConstructor
                .withArguments(factory.redirectionTarget.fullNameForErrors),
            initializer.fileOffset,
            noLength);
      } else {
        if (!parameter.initializerWasInferred) {
          variable.initializer = initializer..parent = variable;
        }
      }
    } else if (kind != FormalParameterKind.mandatory) {
      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);
    typeInferrer.assignedVariables.declare(variable);
  }

  @override
  void endOptionalFormalParameters(
      int count, Token beginToken, Token endToken) {
    debugEvent("OptionalFormalParameters");
    FormalParameterKind kind = optional("{", beginToken)
        ? FormalParameterKind.optionalNamed
        : FormalParameterKind.optionalPositional;
    // 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.
    List<FormalParameterBuilder>? parameters =
        const FixedNullableList<FormalParameterBuilder>()
            .popNonNullable(stack, count, dummyFormalParameterBuilder);
    if (parameters == null) {
      push(new ParserRecovery(offsetForToken(beginToken)));
    } else {
      for (FormalParameterBuilder parameter in parameters) {
        parameter.kind = kind;
      }
      push(parameters);
    }
  }

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

  @override
  void endFunctionTypedFormalParameter(Token nameToken, Token? question) {
    debugEvent("FunctionTypedFormalParameter");
    if (inCatchClause || functionNestingLevel != 0) {
      exitLocalScope();
    }
    FormalParameters formals = pop() as FormalParameters;
    UnresolvedType? returnType = pop() as UnresolvedType?;
    List<TypeVariableBuilder>? typeVariables =
        pop() as List<TypeVariableBuilder>?;
    if (!libraryBuilder.isNonNullableByDefault) {
      reportErrorIfNullableType(question);
    }
    UnresolvedType type = formals.toFunctionType(returnType,
        libraryBuilder.nullableBuilderIfTrue(question != null), typeVariables);
    exitLocalScope();
    push(type);
    functionNestingLevel--;
  }

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

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

  @override
  void handleValuedFormalParameter(Token equals, Token token) {
    debugEvent("ValuedFormalParameter");
    Expression initializer = popForValue();
    Object? name = pop();
    if (name is ParserRecovery) {
      push(name);
    } else {
      push(new InitializedIdentifier(name as Identifier, initializer));
    }
  }

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

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

  @override
  void endFormalParameters(
      int count, Token beginToken, Token endToken, MemberKind kind) {
    debugEvent("FormalParameters");
    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);
    constantContext = pop() as ConstantContext;
    push(formals);
    if ((inCatchClause || functionNestingLevel != 0) &&
        kind != MemberKind.GeneralizedFunctionType) {
      enterLocalScope('formalParameters',
          formals.computeFormalParameterScope(scope, member, this));
    }
  }

  @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?;
    UnresolvedType? unresolvedExceptionType =
        popIfNotNull(onKeyword) as UnresolvedType?;
    DartType exceptionType;
    if (unresolvedExceptionType != null) {
      exceptionType = buildDartType(unresolvedExceptionType);
    } else {
      exceptionType = (libraryBuilder.isNonNullableByDefault
          ? coreTypes.objectNonNullableRawType
          : const DynamicType());
    }
    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, functionNestingLevel).type =
            exceptionType;
        if (parameterCount > 1) {
          stackTrace = catchParameters.parameters![1];
          stackTrace.build(libraryBuilder, functionNestingLevel).type =
              coreTypes.stackTraceRawType(libraryBuilder.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(
                fasta.messageCatchSyntaxExtraParameters, parameter.charOffset,
                length: parameter.name.length));
          }
        }
      }
    }
    push(forest.createCatch(
        offsetForToken(onKeyword ?? catchKeyword),
        exceptionType,
        exception?.variable,
        stackTrace?.variable,
        coreTypes.stackTraceRawType(libraryBuilder.nonNullable),
        body));
    if (compileTimeErrors == null) {
      push(NullValue.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) {
    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();
    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 (isNullAware && !libraryBuilder.isNonNullableByDefault) {
      reportMissingNonNullableSupport(openSquareBracket);
    }
    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,
        ValueKinds.ProblemBuilder
      ]),
    ]));
    debugEvent("UnaryPrefixExpression");
    Object? receiver = pop();
    if (optional("!", token)) {
      push(forest.createNot(offsetForToken(token), toValue(receiver)));
    } else {
      String operator = token.stringValue!;
      if (optional("-", token)) {
        operator = "unary-";
      }
      int fileOffset = offsetForToken(token);
      Name name = new Name(operator);
      if (receiver is Generator) {
        push(receiver.buildUnaryOperation(token, name));
      } else {
        assert(receiver is Expression);
        push(forest.createUnary(fileOffset, name, receiver as Expression));
      }
    }
  }

  Name incrementOperator(Token token) {
    if (optional("++", token)) return plusName;
    if (optional("--", token)) 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),
          offset: token.charOffset));
    } else {
      Expression value = toValue(generator);
      push(wrapInProblem(
          value, fasta.messageNotAnLvalue, 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, fasta.messageNotAnLvalue, value.fileOffset, noLength));
    }
  }

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

  /// 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) {
    assert(checkState(start, [
      /*suffix*/ if (periodBeforeName != null)
        unionOfKinds([ValueKinds.Identifier, ValueKinds.ParserRecovery]),
      /*type arguments*/ ValueKinds.TypeArgumentsOrNull,
      /*type*/ unionOfKinds([
        ValueKinds.Generator,
        ValueKinds.QualifiedName,
        ValueKinds.ProblemBuilder,
        ValueKinds.ParserRecovery
      ])
    ]));
    Object? suffixObject = popIfNotNull(periodBeforeName);
    Identifier? suffix;
    if (suffixObject is Identifier) {
      suffix = suffixObject;
    } else {
      assert(
          suffixObject == null || suffixObject is ParserRecovery,
          "Unexpected qualified name suffix $suffixObject "
          "(${suffixObject.runtimeType})");
      // There was a `.` without a suffix.
    }

    Identifier? identifier;
    List<UnresolvedType>? typeArguments = pop() as List<UnresolvedType>?;
    Object? type = pop();
    if (type is QualifiedName) {
      identifier = type;
      QualifiedName qualified = type;
      Object qualifier = qualified.qualifier;
      assert(checkValue(
          start,
          unionOfKinds([ValueKinds.Generator, ValueKinds.ProblemBuilder]),
          qualifier));
      if (qualifier is TypeUseGenerator) {
        type = qualifier;
        if (typeArguments != null) {
          // TODO(ahe): Point to the type arguments instead.
          addProblem(fasta.messageConstructorWithTypeArguments,
              identifier.charOffset, identifier.name.length);
        }
      } else if (qualifier is Generator) {
        type = qualifier.qualifiedLookup(identifier.token);
        identifier = null;
      } else if (qualifier is ProblemBuilder) {
        type = qualifier;
      } else {
        unhandled("${qualifier.runtimeType}", "pushQualifiedReference",
            start.charOffset, uri);
      }
    }
    String name;
    if (identifier != null && suffix != null) {
      name = "${identifier.name}.${suffix.name}";
    } else if (identifier != null) {
      name = identifier.name;
    } else if (suffix != null) {
      name = suffix.name;
    } else {
      name = "";
    }
    push(type);
    push(typeArguments ?? NullValue.TypeArguments);
    push(name);
    push(suffix ?? identifier ?? NullValue.Identifier);

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

  @override
  Expression buildStaticInvocation(Member target, Arguments arguments,
      {Constness constness: Constness.implicit,
      TypeAliasBuilder? typeAliasBuilder,
      int charOffset: -1,
      int charLength: noLength}) {
    // The argument checks for the initial target of redirecting factories
    // invocations are skipped in Dart 1.
    List<TypeParameter> typeParameters = target.function!.typeParameters;
    if (target is Constructor) {
      assert(!target.enclosingClass.isAbstract);
      typeParameters = target.enclosingClass.typeParameters;
    }
    LocatedMessage? argMessage = checkArgumentsForFunction(
        target.function!, arguments, charOffset, typeParameters);
    if (argMessage != null) {
      return throwNoSuchMethodError(forest.createNullLiteral(charOffset),
          target.name.text, arguments, charOffset,
          candidate: target, message: argMessage);
    }

    bool isConst = constness == Constness.explicitConst ||
        constantContext != ConstantContext.none;
    if (target is Constructor) {
      if (constantContext == ConstantContext.required &&
          constness == Constness.implicit) {
        addProblem(fasta.messageMissingExplicitConst, charOffset, charLength);
      }
      if (isConst && !target.isConst) {
        return buildProblem(
            fasta.messageNonConstConstructor, charOffset, charLength);
      }
      ConstructorInvocation node;
      if (typeAliasBuilder == null) {
        node = new ConstructorInvocation(target, arguments, isConst: isConst)
          ..fileOffset = charOffset;
        libraryBuilder.checkBoundsInConstructorInvocation(
            node, typeEnvironment, uri);
      } else {
        TypeAliasedConstructorInvocationJudgment constructorInvocation =
            node = new TypeAliasedConstructorInvocationJudgment(
                typeAliasBuilder, target, arguments,
                isConst: isConst)
              ..fileOffset = charOffset;
        // No type arguments were passed, so we need not check bounds.
        assert(arguments.types.isEmpty);
        typeAliasedConstructorInvocations.add(constructorInvocation);
      }
      return node;
    } else {
      Procedure procedure = target as Procedure;
      if (procedure.isFactory) {
        if (constantContext == ConstantContext.required &&
            constness == Constness.implicit) {
          addProblem(fasta.messageMissingExplicitConst, charOffset, charLength);
        }
        if (isConst && !procedure.isConst) {
          return buildProblem(
              fasta.messageNonConstFactory, charOffset, charLength);
        }
        StaticInvocation node;
        if (typeAliasBuilder == null) {
          node = new FactoryConstructorInvocationJudgment(target, arguments,
              isConst: isConst)
            ..fileOffset = charOffset;
          libraryBuilder.checkBoundsInFactoryInvocation(
              node, typeEnvironment, uri,
              inferred: !hasExplicitTypeArguments(arguments));
        } else {
          TypeAliasedFactoryInvocationJudgment constructorInvocation =
              new TypeAliasedFactoryInvocationJudgment(
                  typeAliasBuilder, target, arguments,
                  isConst: isConst)
                ..fileOffset = charOffset;
          // No type arguments were passed, so we need not check bounds.
          assert(arguments.types.isEmpty);
          typeAliasedFactoryInvocations.add(constructorInvocation);
          node = constructorInvocation;
        }
        return node;
      } else {
        assert(constness == Constness.implicit);
        return new StaticInvocation(target, arguments, isConst: false)
          ..fileOffset = charOffset;
      }
    }
  }

  Expression buildExtensionMethodInvocation(
      int fileOffset, Procedure target, Arguments arguments,
      {required bool isTearOff}) {
    List<TypeParameter> typeParameters = target.function.typeParameters;
    LocatedMessage? argMessage = checkArgumentsForFunction(
        target.function, arguments, fileOffset, typeParameters,
        isExtensionMemberInvocation: true);
    if (argMessage != null) {
      return throwNoSuchMethodError(forest.createNullLiteral(fileOffset),
          target.name.text, arguments, fileOffset,
          candidate: target, message: argMessage);
    }

    Expression node;
    if (isTearOff) {
      node = new ExtensionTearOff(target, arguments);
    } else {
      node = new StaticInvocation(target, arguments);
    }
    node.fileOffset = fileOffset;
    return node;
  }

  @override
  LocatedMessage? checkArgumentsForFunction(FunctionNode function,
      Arguments arguments, int offset, List<TypeParameter> typeParameters,
      {bool isExtensionMemberInvocation = false}) {
    int requiredPositionalParameterCountToReport =
        function.requiredParameterCount;
    int positionalParameterCountToReport = function.positionalParameters.length;
    int positionalArgumentCountToReport =
        forest.argumentsPositional(arguments).length;
    if (isExtensionMemberInvocation) {
      // Extension member invocations have additional synthetic parameter for
      // `this`.
      --requiredPositionalParameterCountToReport;
      --positionalParameterCountToReport;
      --positionalArgumentCountToReport;
    }
    if (forest.argumentsPositional(arguments).length <
        function.requiredParameterCount) {
      return fasta.templateTooFewArguments
          .withArguments(requiredPositionalParameterCountToReport,
              positionalArgumentCountToReport)
          .withLocation(uri, arguments.fileOffset, noLength);
    }
    if (forest.argumentsPositional(arguments).length >
        function.positionalParameters.length) {
      return fasta.templateTooManyArguments
          .withArguments(
              positionalParameterCountToReport, positionalArgumentCountToReport)
          .withLocation(uri, arguments.fileOffset, noLength);
    }
    List<NamedExpression> named = forest.argumentsNamed(arguments);
    if (named.isNotEmpty) {
      Set<String> parameterNames =
          new Set.from(function.namedParameters.map((a) => a.name));
      for (NamedExpression argument in named) {
        if (!parameterNames.contains(argument.name)) {
          return fasta.templateNoSuchNamedParameter
              .withArguments(argument.name)
              .withLocation(uri, argument.fileOffset, argument.name.length);
        }
      }
    }
    if (function.namedParameters.isNotEmpty) {
      if (libraryBuilder.isNonNullableByDefault) {
        Set<String> argumentNames = new Set.from(named.map((a) => a.name));
        for (VariableDeclaration parameter in function.namedParameters) {
          if (parameter.isRequired && !argumentNames.contains(parameter.name)) {
            return fasta.templateValueForRequiredParameterNotProvidedError
                .withArguments(parameter.name!)
                .withLocation(uri, arguments.fileOffset, fasta.noLength);
          }
        }
      }
    }

    List<DartType> types = forest.argumentsTypeArguments(arguments);
    if (typeParameters.length != 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 fasta.templateTypeArgumentMismatch
            .withArguments(typeParameters.length)
            .withLocation(uri, offset, noLength);
      }
    }

    return null;
  }

  @override
  LocatedMessage? checkArgumentsForType(
      FunctionType function, Arguments arguments, int offset,
      {bool isExtensionMemberInvocation = false}) {
    int requiredPositionalParameterCountToReport =
        function.requiredParameterCount;
    int positionalParameterCountToReport = function.positionalParameters.length;
    int positionalArgumentCountToReport =
        forest.argumentsPositional(arguments).length;
    if (isExtensionMemberInvocation) {
      // Extension member invocations have additional synthetic parameter for
      // `this`.
      --requiredPositionalParameterCountToReport;
      --positionalParameterCountToReport;
      --positionalArgumentCountToReport;
    }
    if (forest.argumentsPositional(arguments).length <
        function.requiredParameterCount) {
      return fasta.templateTooFewArguments
          .withArguments(requiredPositionalParameterCountToReport,
              positionalArgumentCountToReport)
          .withLocation(uri, arguments.fileOffset, noLength);
    }
    if (forest.argumentsPositional(arguments).length >
        function.positionalParameters.length) {
      return fasta.templateTooManyArguments
          .withArguments(
              positionalParameterCountToReport, positionalArgumentCountToReport)
          .withLocation(uri, arguments.fileOffset, noLength);
    }
    List<NamedExpression> named = forest.argumentsNamed(arguments);
    if (named.isNotEmpty) {
      Set<String> names =
          new Set.from(function.namedParameters.map((a) => a.name));
      for (NamedExpression argument in named) {
        if (!names.contains(argument.name)) {
          return fasta.templateNoSuchNamedParameter
              .withArguments(argument.name)
              .withLocation(uri, argument.fileOffset, argument.name.length);
        }
      }
    }
    if (function.namedParameters.isNotEmpty) {
      if (libraryBuilder.isNonNullableByDefault) {
        Set<String> argumentNames = new Set.from(named.map((a) => a.name));
        for (NamedType parameter in function.namedParameters) {
          if (parameter.isRequired && !argumentNames.contains(parameter.name)) {
            return fasta.templateValueForRequiredParameterNotProvidedError
                .withArguments(parameter.name)
                .withLocation(uri, arguments.fileOffset, fasta.noLength);
          }
        }
      }
    }
    List<Object> types = forest.argumentsTypeArguments(arguments);
    List<TypeParameter> 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 fasta.templateTypeArgumentMismatch
          .withArguments(typeParameters.length)
          .withLocation(uri, offset, noLength);
    }

    return null;
  }

  @override
  void beginNewExpression(Token token) {
    debugEvent("beginNewExpression");
    super.push(constantContext);
    if (constantContext != ConstantContext.none) {
      addProblem(
          fasta.templateNotConstantExpression.withArguments('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 token) {
    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);
  }

  void _buildConstructorReferenceInvocation(
      Token nameToken, int offset, Constness constness,
      {required bool inMetadata}) {
    assert(checkState(nameToken, [
      /*arguments*/ ValueKinds.Arguments,
      /*constructor name identifier*/ ValueKinds.IdentifierOrNull,
      /*constructor name*/ ValueKinds.Name,
      /*type arguments*/ ValueKinds.TypeArgumentsOrNull,
      /*class*/ unionOfKinds([
        ValueKinds.Generator,
        ValueKinds.ProblemBuilder,
        ValueKinds.ParserRecovery
      ]),
    ]));
    Arguments arguments = pop() as Arguments;
    Identifier? nameLastIdentifier = pop(NullValue.Identifier) as Identifier?;
    Token nameLastToken = nameLastIdentifier?.token ?? nameToken;
    String name = pop() as String;
    List<UnresolvedType>? typeArguments = pop() as List<UnresolvedType>?;
    if (inMetadata && typeArguments != null) {
      if (!libraryBuilder.enableGenericMetadataInLibrary) {
        handleRecoverableError(fasta.messageMetadataTypeArguments,
            nameLastToken.next!, nameLastToken.next!);
      }
    }

    Object? type = pop();

    ConstantContext savedConstantContext = pop() as ConstantContext;
    if (type is Generator) {
      push(type.invokeConstructor(
          typeArguments, name, arguments, nameToken, nameLastToken, constness));
    } else if (type is ParserRecovery) {
      push(new ParserErrorGenerator(
          this, nameToken, fasta.messageSyntheticToken));
    } else {
      String? typeName;
      if (type is ProblemBuilder) {
        typeName = type.fullNameForErrors;
      }
      push(throwNoSuchMethodError(forest.createNullLiteral(offset),
          debugName(typeName!, name), arguments, nameToken.charOffset));
    }
    constantContext = savedConstantContext;
  }

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

  @override
  Expression buildConstructorInvocation(
      TypeDeclarationBuilder? type,
      Token nameToken,
      Token nameLastToken,
      Arguments? arguments,
      String name,
      List<UnresolvedType>? typeArguments,
      int charOffset,
      Constness constness,
      {bool isTypeArgumentsInForest = false,
      TypeDeclarationBuilder? typeAliasBuilder}) {
    if (arguments == null) {
      return buildProblem(fasta.messageMissingArgumentList,
          nameToken.charOffset, nameToken.length);
    }
    if (name.isNotEmpty && arguments.types.isNotEmpty) {
      // TODO(ahe): Point to the type arguments instead.
      addProblem(fasta.messageConstructorWithTypeArguments,
          nameToken.charOffset, nameToken.length);
    }

    String? errorName;
    LocatedMessage? message;

    if (type is TypeAliasBuilder) {
      errorName = debugName(type.name, name);
      TypeAliasBuilder aliasBuilder = type;
      int numberOfTypeParameters = aliasBuilder.typeVariablesCount;
      int numberOfTypeArguments = typeArguments?.length ?? 0;
      if (typeArguments != null &&
          numberOfTypeParameters != numberOfTypeArguments) {
        // TODO(eernst): Use position of type arguments, not nameToken.
        return evaluateArgumentsBefore(
            arguments,
            buildProblem(
                fasta.templateTypeArgumentMismatch
                    .withArguments(numberOfTypeParameters),
                charOffset,
                noLength));
      }
      type = aliasBuilder.unaliasDeclaration(null,
          isUsedAsClass: true,
          usedAsClassCharOffset: nameToken.charOffset,
          usedAsClassFileUri: uri);
      List<TypeBuilder> typeArgumentBuilders = [];
      if (typeArguments != null) {
        for (UnresolvedType unresolvedType in typeArguments) {
          typeArgumentBuilders.add(unresolvedType.builder);
        }
      } else {
        if (aliasBuilder.typeVariablesCount > 0) {
          // Raw generic type alias used for instance creation, needs inference.
          ClassBuilder classBuilder;
          if (type is ClassBuilder) {
            classBuilder = type;
          } else {
            if (type is InvalidTypeDeclarationBuilder) {
              LocatedMessage message = type.message;
              return evaluateArgumentsBefore(
                  arguments,
                  buildProblem(message.messageObject, nameToken.charOffset,
                      nameToken.lexeme.length));
            }

            return throwNoSuchMethodError(forest.createNullLiteral(charOffset),
                errorName, arguments, nameLastToken.charOffset,
                message: message);
          }
          MemberBuilder? b = classBuilder.findConstructorOrFactory(
              name, charOffset, uri, libraryBuilder);
          Member? target = b?.member;
          if (b == null) {
            // Not found. Reported below.
          } else if (b is AmbiguousMemberBuilder) {
            message = b.message.withLocation(uri, charOffset, noLength);
          } else if (b.isConstructor) {
            if (classBuilder.isAbstract) {
              return evaluateArgumentsBefore(
                  arguments,
                  buildAbstractClassInstantiationError(
                      fasta.templateAbstractClassInstantiation
                          .withArguments(type.name),
                      type.name,
                      nameToken.charOffset));
            }
          }
          if (target is Constructor ||
              (target is Procedure && target.kind == ProcedureKind.Factory)) {
            Expression invocation;
            invocation = buildStaticInvocation(target!, arguments,
                constness: constness,
                typeAliasBuilder: aliasBuilder,
                charOffset: nameToken.charOffset,
                charLength: nameToken.length);
            return invocation;
          } else {
            return throwNoSuchMethodError(forest.createNullLiteral(charOffset),
                errorName, arguments, nameLastToken.charOffset,
                message: message);
          }
        } else {
          // Empty `typeArguments` and `aliasBuilder``is non-generic, but it
          // may still unalias to a class type with some type arguments.
          if (type is ClassBuilder) {
            List<TypeBuilder>? unaliasedTypeArgumentBuilders =
                aliasBuilder.unaliasTypeArguments(const []);
            if (unaliasedTypeArgumentBuilders == null) {
              // TODO(eernst): This is a wrong number of type arguments,
              // occurring indirectly (in an alias of an alias, etc.).
              return evaluateArgumentsBefore(
                  arguments,
                  buildProblem(
                      fasta.templateTypeArgumentMismatch
                          .withArguments(numberOfTypeParameters),
                      nameToken.charOffset,
                      nameToken.length,
                      suppressMessage: true));
            }
            List<DartType> dartTypeArguments = [];
            for (TypeBuilder typeBuilder in unaliasedTypeArgumentBuilders) {
              dartTypeArguments.add(typeBuilder.build(libraryBuilder));
            }
            assert(forest.argumentsTypeArguments(arguments).isEmpty);
            forest.argumentsSetTypeArguments(arguments, dartTypeArguments);
          }
        }
      }

      List<DartType> typeArgumentsToCheck = const <DartType>[];
      // ignore: unnecessary_null_comparison
      if (typeArgumentBuilders != null && 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);
        }
      }
      DartType typeToCheck = new TypedefType(
          aliasBuilder.typedef, Nullability.nonNullable, typeArgumentsToCheck);
      libraryBuilder.checkBoundsInType(
          typeToCheck, typeEnvironment, uri, charOffset,
          allowSuperBounded: false);

      if (type is ClassBuilder) {
        if (typeArguments != null) {
          int numberOfTypeParameters = aliasBuilder.typeVariables?.length ?? 0;
          if (numberOfTypeParameters != typeArgumentBuilders.length) {
            // TODO(eernst): Use position of type arguments, not nameToken.
            return evaluateArgumentsBefore(
                arguments,
                buildProblem(
                    fasta.templateTypeArgumentMismatch
                        .withArguments(numberOfTypeParameters),
                    nameToken.charOffset,
                    nameToken.length));
          }
          List<TypeBuilder>? unaliasedTypeArgumentBuilders =
              aliasBuilder.unaliasTypeArguments(typeArgumentBuilders);
          if (unaliasedTypeArgumentBuilders == null) {
            // TODO(eernst): This is a wrong number of type arguments,
            // occurring indirectly (in an alias of an alias, etc.).
            return evaluateArgumentsBefore(
                arguments,
                buildProblem(
                    fasta.templateTypeArgumentMismatch
                        .withArguments(numberOfTypeParameters),
                    nameToken.charOffset,
                    nameToken.length,
                    suppressMessage: true));
          }
          List<DartType> dartTypeArguments = [];
          for (TypeBuilder typeBuilder in unaliasedTypeArgumentBuilders) {
            dartTypeArguments.add(typeBuilder.build(libraryBuilder));
          }
          assert(forest.argumentsTypeArguments(arguments).isEmpty);
          forest.argumentsSetTypeArguments(arguments, dartTypeArguments);
        } else {
          ClassBuilder cls = type;
          if (cls.typeVariables?.isEmpty ?? true) {
            assert(forest.argumentsTypeArguments(arguments).isEmpty);
            forest.argumentsSetTypeArguments(arguments, []);
          } else {
            if (forest.argumentsTypeArguments(arguments).isEmpty) {
              // No type arguments provided to unaliased class, use defaults.
              List<DartType> result = new List<DartType>.generate(
                  cls.typeVariables!.length,
                  (int i) =>
                      cls.typeVariables![i].defaultType!.build(cls.library),
                  growable: true);
              forest.argumentsSetTypeArguments(arguments, result);
            }
          }
        }
      }
    } else {
      if (typeArguments != null && !isTypeArgumentsInForest) {
        assert(forest.argumentsTypeArguments(arguments).isEmpty);
        forest.argumentsSetTypeArguments(
            arguments, buildDartTypeArguments(typeArguments));
      }
    }
    if (type is ClassBuilder) {
      if (type is EnumBuilder) {
        return buildProblem(fasta.messageEnumInstantiation,
            nameToken.charOffset, nameToken.length);
      }
      MemberBuilder? b =
          type.findConstructorOrFactory(name, charOffset, uri, libraryBuilder);
      Member? target;
      if (b == null) {
        // Not found. Reported below.
      } else if (b is AmbiguousMemberBuilder) {
        message = b.message.withLocation(uri, charOffset, noLength);
      } else if (b.isConstructor) {
        if (type.isAbstract) {
          return evaluateArgumentsBefore(
              arguments,
              buildAbstractClassInstantiationError(
                  fasta.templateAbstractClassInstantiation
                      .withArguments(type.name),
                  type.name,
                  nameToken.charOffset));
        }
        target = b.member;
      } else {
        target = b.member;
      }
      if (target is Constructor ||
          (target is Procedure && target.kind == ProcedureKind.Factory)) {
        Expression invocation;

        invocation = buildStaticInvocation(target!, arguments,
            constness: constness,
            charOffset: nameToken.charOffset,
            charLength: nameToken.length,
            typeAliasBuilder: typeAliasBuilder as TypeAliasBuilder?);

        if (invocation is StaticInvocation &&
            isRedirectingFactory(target, helper: this)) {
          redirectingFactoryInvocations.add(invocation);
        }

        return invocation;
      } else {
        errorName ??= debugName(type.name, name);
      }
    } else if (type is InvalidTypeDeclarationBuilder) {
      LocatedMessage message = type.message;
      return evaluateArgumentsBefore(
          arguments,
          buildProblem(message.messageObject, nameToken.charOffset,
              nameToken.lexeme.length));
    } else {
      errorName ??= debugName(type!.fullNameForErrors, name);
    }

    return throwNoSuchMethodError(forest.createNullLiteral(charOffset),
        errorName, arguments, nameLastToken.charOffset,
        message: message);
  }

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

  @override
  void handleConstFactory(Token constKeyword) {
    debugEvent("ConstFactory");
    if (!libraryBuilder.enableConstFunctionsInLibrary) {
      handleRecoverableError(
          fasta.messageConstFactory, 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) {
    Expression condition = popForValue();
    // This is matched by the call to [deferNode] in
    // [handleElseControlFlow] and by the call to [endNode] in
    // [endIfControlFlow].
    typeInferrer.assignedVariables.beginNode();
    push(condition);
    super.handleThenControlFlow(token);
  }

  @override
  void handleElseControlFlow(Token elseToken) {
    // Resolve the top of the stack so that if it's a delayed assignment it
    // happens before we go into the else block.
    Object? node = pop();
    if (node is! MapLiteralEntry) node = toValue(node);
    // This is matched by the call to [beginNode] in
    // [handleThenControlFlow] and by the call to [storeInfo] in
    // [endIfElseControlFlow].
    push(typeInferrer.assignedVariables.deferNode());
    push(node);
  }

  @override
  void endIfControlFlow(Token token) {
    debugEvent("endIfControlFlow");
    Object? entry = pop();
    Object? condition = pop(); // parenthesized expression
    Token ifToken = pop() as Token;

    transformCollections = true;
    TreeNode node;
    if (entry is MapLiteralEntry) {
      node = forest.createIfMapEntry(
          offsetForToken(ifToken), toValue(condition), entry);
    } else {
      node = forest.createIfElement(
          offsetForToken(ifToken), toValue(condition), 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");
    Object? elseEntry = pop(); // else entry
    Object? thenEntry = pop(); // then entry
    AssignedVariablesNodeInfo<VariableDeclaration> assignedVariablesInfo =
        pop() as AssignedVariablesNodeInfo<VariableDeclaration>;
    Object? condition = pop(); // parenthesized expression
    Token ifToken = pop() as Token;

    transformCollections = true;
    TreeNode node;
    if (thenEntry is MapLiteralEntry) {
      if (elseEntry is MapLiteralEntry) {
        node = forest.createIfMapEntry(
            offsetForToken(ifToken), toValue(condition), thenEntry, elseEntry);
      } else if (elseEntry is ControlFlowElement) {
        MapLiteralEntry? elseMapEntry = elseEntry
            .toMapLiteralEntry(typeInferrer.assignedVariables.reassignInfo);
        if (elseMapEntry != null) {
          node = forest.createIfMapEntry(offsetForToken(ifToken),
              toValue(condition), thenEntry, elseMapEntry);
        } else {
          int offset = elseEntry is Expression
              ? elseEntry.fileOffset
              : offsetForToken(ifToken);
          node = new MapLiteralEntry(
              buildProblem(
                  fasta.messageCantDisambiguateAmbiguousInformation, offset, 1),
              new NullLiteral())
            ..fileOffset = offsetForToken(ifToken);
        }
      } else {
        int offset = elseEntry is Expression
            ? elseEntry.fileOffset
            : offsetForToken(ifToken);
        node = new MapLiteralEntry(
            buildProblem(fasta.templateExpectedAfterButGot.withArguments(':'),
                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) {
          node = forest.createIfMapEntry(offsetForToken(ifToken),
              toValue(condition), thenMapEntry, elseEntry);
        } else {
          int offset = thenEntry is Expression
              ? thenEntry.fileOffset
              : offsetForToken(ifToken);
          node = new MapLiteralEntry(
              buildProblem(
                  fasta.messageCantDisambiguateAmbiguousInformation, offset, 1),
              new NullLiteral())
            ..fileOffset = offsetForToken(ifToken);
        }
      } else {
        int offset = thenEntry is Expression
            ? thenEntry.fileOffset
            : offsetForToken(ifToken);
        node = new MapLiteralEntry(
            buildProblem(fasta.templateExpectedAfterButGot.withArguments(':'),
                offset, 1),
            new NullLiteral())
          ..fileOffset = offsetForToken(ifToken);
      }
    } else {
      node = forest.createIfElement(offsetForToken(ifToken), toValue(condition),
          toValue(thenEntry), toValue(elseEntry));
    }
    push(node);
    // This is matched by the call to [deferNode] in
    // [handleElseControlFlow].
    typeInferrer.assignedVariables.storeInfo(node, assignedVariablesInfo);
  }

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

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

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

  @override
  void handleThisExpression(Token token, IdentifierContext context) {
    debugEvent("ThisExpression");
    if (context.isScopeReference && isDeclarationInstanceContext) {
      if (extensionThis != null) {
        push(_createReadOnlyVariableAccess(extensionThis!, token,
            offsetForToken(token), 'this', ReadOnlyAccessKind.ExtensionThis));
      } else {
        push(new ThisAccessGenerator(this, token, inInitializer,
            inFieldInitializer, inLateFieldInitializer));
      }
    } else {
      push(new IncompleteErrorGenerator(
          this, token, fasta.messageThisAsIdentifier));
    }
  }

  @override
  void handleSuperExpression(Token token, IdentifierContext context) {
    debugEvent("SuperExpression");
    if (context.isScopeReference &&
        isDeclarationInstanceContext &&
        extensionThis == null) {
      MemberBuilder memberBuilder = member as MemberBuilder;
      memberBuilder.member.transformerFlags |= TransformerFlag.superCalls;
      push(new ThisAccessGenerator(this, token, inInitializer,
          inFieldInitializer, inLateFieldInitializer,
          isSuper: true));
    } else {
      push(new IncompleteErrorGenerator(
          this, token, fasta.messageSuperAsIdentifier));
    }
  }

  @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.charOffset);
    } else {
      assert(
          identifier is ParserRecovery,
          "Unexpected argument name: "
          "${identifier} (${identifier.runtimeType})");
      push(identifier);
    }
  }

  @override
  void endFunctionName(Token beginToken, Token token) {
    debugEvent("FunctionName");
    Identifier name = pop() as Identifier;
    Token nameToken = name.token;
    VariableDeclaration variable = new VariableDeclarationImpl(
        name.name, functionNestingLevel,
        forSyntheticToken: nameToken.isSynthetic,
        isFinal: true,
        isLocalFunction: true)
      ..fileOffset = name.charOffset;
    // TODO(ahe): Why are we looking up in local scope, but declaring in parent
    // scope?
    Builder? existing = scope.lookupLocalMember(name.name, setter: false);
    if (existing != null) {
      reportDuplicatedDeclaration(existing, name.name, name.charOffset);
    }
    push(new FunctionDeclarationImpl(
        variable,
        // The real function node is created later.
        dummyFunctionNode)
      ..fileOffset = beginToken.charOffset);
    declareVariable(variable, scope.parent!);
  }

  void enterFunction() {
    _enterLocalState();
    debugEvent("enterFunction");
    functionNestingLevel++;
    push(switchScope ?? NullValue.SwitchScope);
    switchScope = null;
    push(inCatchBlock);
    inCatchBlock = false;
    // This is matched by the call to [endNode] in [pushNamedFunction] or
    // [endFunctionExpression].
    typeInferrer.assignedVariables.beginNode();
  }

  void exitFunction() {
    debugEvent("exitFunction");
    functionNestingLevel--;
    inCatchBlock = pop() as bool;
    switchScope = pop() as Scope?;
    List<TypeVariableBuilder>? typeVariables =
        pop() as List<TypeVariableBuilder>?;
    exitLocalScope();
    push(typeVariables ?? NullValue.TypeVariables);
    _exitLocalState();
  }

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

  @override
  void beginNamedFunctionExpression(Token token) {
    debugEvent("beginNamedFunctionExpression");
    List<TypeVariableBuilder>? typeVariables =
        pop() as List<TypeVariableBuilder>?;
    // Create an additional scope in which the named function expression is
    // declared.
    enterLocalScope("named function");
    push(typeVariables ?? NullValue.TypeVariables);
    enterFunction();
  }

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

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

    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(libraryBuilder.nonNullable);
      if (isFunctionExpression) {
        Expression? oldInitializer = variable.initializer;
        variable.initializer = new FunctionExpression(function)
          ..parent = variable
          ..fileOffset = formals.charOffset;
        exitLocalScope();
        // This is matched by the call to [beginNode] in [enterFunction].
        typeInferrer.assignedVariables.endNode(variable.initializer!,
            isClosureOrLateVariableInitializer: true);
        Expression expression = new NamedFunctionExpressionJudgment(variable);
        if (oldInitializer != null) {
          // This must have been a compile-time error.
          Expression error = oldInitializer;
          assert(isErroneousNode(error));
          int offset = expression.fileOffset;
          push(new Let(
              new VariableDeclaration.forValue(error)..fileOffset = offset,
              expression)
            ..fileOffset = offset);
        } else {
          push(expression);
        }
      } else {
        declaration.function = function;
        function.parent = declaration;
        if (variable.initializer != null) {
          // This must have been a compile-time error.
          assert(isErroneousNode(variable.initializer!));

          push(forest
              .createBlock(declaration.fileOffset, noLocation, <Statement>[
            forest.createExpressionStatement(
                offsetForToken(token), variable.initializer!),
            declaration
          ]));
          variable.initializer = null;
        } else {
          push(declaration);
        }
        // This is matched by the call to [beginNode] in [enterFunction].
        typeInferrer.assignedVariables
            .endNode(declaration, isClosureOrLateVariableInitializer: true);
      }
    } 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 token) {
    debugEvent("FunctionExpression");
    Statement body = popStatement();
    AsyncMarker asyncModifier = pop() as AsyncMarker;
    exitLocalScope();
    FormalParameters formals = pop() as FormalParameters;
    exitFunction();
    List<TypeVariableBuilder>? typeParameters =
        pop() as List<TypeVariableBuilder>?;
    FunctionNode function = formals.buildFunctionNode(libraryBuilder, null,
        typeParameters, asyncModifier, body, token.charOffset,
        nonInstanceContext: !isDeclarationInstanceContext)
      ..fileOffset = beginToken.charOffset;

    Expression result;
    if (constantContext != ConstantContext.none) {
      result = buildProblem(fasta.messageNotAConstantExpression,
          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);
  }

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

  @override
  void endDoWhileStatement(
      Token doKeyword, Token whileKeyword, Token endToken) {
    debugEvent("DoWhileStatement");
    Expression condition = popForValue();
    Statement body = popStatement();
    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, condition);
    // 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) {
    enterLocalScope('forIn', scope.parent);
  }

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

  @override
  void handleForInLoopParts(Token? awaitToken, Token forToken,
      Token leftParenthesis, Token inKeyword) {
    push(awaitToken ?? NullValue.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(NullValue.AwaitToken) as Token?;

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

      handleRecoverableError(
          fasta.templateCantUseControlFlowOrSpreadAsConstant
              .withArguments(forToken),
          forToken,
          forToken);
      push(invalidCollectionElement);
      return;
    }

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

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

    transformCollections = true;
    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(
            fasta.messageForInLoopWithConstVariable,
            lvalue.fileOffset,
            lvalue.name!.length);
      }
    } else {
      VariableDeclaration variable = elements.syntheticVariableDeclaration =
          forest.createVariableDeclaration(
              offsetForToken(forToken), null, functionNestingLevel,
              isFinal: 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 VariableGetImpl(variable, forNullGuardedAccess: false)
              ..fileOffset = inToken.offset,
            voidContext: true);
      } else {
        Message message = forest.isVariablesDeclaration(lvalue)
            ? fasta.messageForInLoopExactlyOneVariable
            : fasta.messageForInLoopNotAssignable;
        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>.from(
                  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");
    Statement body = popStatement();

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

    // This is matched by the call to [beginNode] in [handleForInLoopParts].
    AssignedVariablesNodeInfo<VariableDeclaration> 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.charOffset));
  }

  @override
  void beginLabeledStatement(Token token, int labelCount) {
    debugEvent("beginLabeledStatement");
    List<Label>? labels = const FixedNullableList<Label>()
        .popNonNullable(stack, labelCount, dummyLabel);
    enterLocalScope('labeledStatement', scope.createNestedLabelScope());
    LabelTarget target = new LabelTarget(
        member as MemberBuilder, functionNestingLevel, token.charOffset);
    if (labels != null) {
      for (Label label in labels) {
        scope.declareLabel(label.name, target);
      }
    }
    push(target);
  }

  @override
  void endLabeledStatement(int labelCount) {
    debugEvent("LabeledStatement");
    Statement statement = pop() as Statement;
    LabelTarget target = pop() as LabelTarget;
    exitLocalScope();
    if (target.breakTarget.hasUsers || target.continueTarget.hasUsers) {
      if (forest.isVariablesDeclaration(statement)) {
        internalProblem(
            fasta.messageInternalProblemLabelUsageInVariablesDeclaration,
            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;
        }
      }
    }
    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(fasta.messageRethrowNotCatch,
          offsetForToken(rethrowToken), lengthForToken(rethrowToken)))
        ..fileOffset = offsetForToken(rethrowToken));
    }
  }

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

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

  @override
  void endWhileStatement(Token whileKeyword, Token endToken) {
    debugEvent("WhileStatement");
    Statement body = popStatement();
    Expression condition = popForValue();
    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), condition, 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.
    inInitializer = false;
  }

  @override
  void endAssert(Token assertKeyword, Assert kind, Token leftParenthesis,
      Token? commaToken, Token semicolonToken) {
    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 (optional(',', nextToken) &&
            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) {
        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(
            fasta.messageAssertAsExpression, 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();
    enterLocalScope("switch block");
    enterSwitchScope();
    enterBreakTarget(token.charOffset);
  }

  @override
  void beginSwitchCase(int labelCount, int expressionCount, Token firstToken) {
    debugEvent("beginSwitchCase");
    int count = labelCount + expressionCount;
    List<Object>? labelsAndExpressions = const FixedNullableList<Object>()
        .popNonNullable(stack, count, dummyLabel);
    List<Label>? labels =
        labelCount == 0 ? null : new List<Label>.filled(labelCount, dummyLabel);
    List<Expression> expressions = new List<Expression>.filled(
        expressionCount, dummyExpression,
        growable: true);
    int labelIndex = 0;
    int expressionIndex = 0;
    if (labelsAndExpressions != null) {
      for (Object labelOrExpression in labelsAndExpressions) {
        if (labelOrExpression is Label) {
          labels![labelIndex++] = labelOrExpression;
        } else {
          expressions[expressionIndex++] = labelOrExpression as Expression;
        }
      }
    }
    assert(scope == switchScope);
    if (labels != null) {
      for (Label label in labels) {
        String labelName = label.name;
        if (scope.hasLocalLabel(labelName)) {
          // TODO(ahe): Should validate this is a goto target.
          if (!scope.claimLabel(labelName)) {
            addProblem(
                fasta.templateDuplicateLabelInSwitchStatement
                    .withArguments(labelName),
                label.charOffset,
                labelName.length);
          }
        } else {
          scope.declareLabel(
              labelName, createGotoTarget(firstToken.charOffset));
        }
      }
    }
    push(expressions);
    push(labels ?? NullValue.Labels);
    enterLocalScope("switch case");
  }

  @override
  void endSwitchCase(
      int labelCount,
      int expressionCount,
      Token? defaultKeyword,
      Token? colonAfterDefault,
      int statementCount,
      Token firstToken,
      Token endToken) {
    debugEvent("SwitchCase");
    // 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, firstToken, null);
    exitLocalScope();
    List<Label>? labels = pop() as List<Label>?;
    List<Expression> expressions = pop() as List<Expression>;
    List<int> expressionOffsets = <int>[];
    for (Expression expression in expressions) {
      expressionOffsets.add(expression.fileOffset);
    }
    assert(labels == null || labels.isNotEmpty);
    push(new SwitchCaseImpl(expressions, expressionOffsets, block,
        isDefault: defaultKeyword != null, hasLabel: labels != null)
      ..fileOffset = firstToken.charOffset);
    push(labels ?? NullValue.Labels);
  }

  @override
  void endSwitchStatement(Token switchKeyword, Token endToken) {
    debugEvent("SwitchStatement");

    List<SwitchCase> cases = pop() as List<SwitchCase>;
    JumpTarget target = exitBreakTarget()!;
    exitSwitchScope();
    exitLocalScope();
    Expression expression = popForValue();
    Statement switchStatement = new SwitchStatement(expression, cases)
      ..fileOffset = switchKeyword.charOffset;
    Statement result = switchStatement;
    if (target.hasUsers) {
      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 endSwitchBlock(int caseCount, Token beginToken, Token endToken) {
    debugEvent("SwitchBlock");
    List<SwitchCase> cases =
        new List<SwitchCase>.filled(caseCount, dummySwitchCase, 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) as JumpTarget?;
          if (target != null) {
            target.resolveGotos(forest, current);
          }
        }
      }
    }
    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;
      }
      // The rule that every case block should end with one of the predefined
      // set of statements is specific to pre-NNBD code and is replaced with
      // another rule based on flow analysis for NNBD code.  For details, see
      // the following link:
      // https://github.com/dart-lang/language/blob/master/accepted/future-releases/nnbd/feature-specification.md#errors-and-warnings
      if (!libraryBuilder.isNonNullableByDefault) {
        if (lastNode is! BreakStatement &&
            lastNode is! ContinueSwitchStatement &&
            lastNode is! Rethrow &&
            lastNode is! ReturnStatement &&
            !forest.isThrow(lastNode)) {
          block.addStatement(new ExpressionStatement(
              buildFallThroughError(current.fileOffset)));
        }
      }
    }

    push(cases);
  }

  @override
  void handleCaseMatch(Token caseKeyword, Token colon) {
    debugEvent("CaseMatch");
    // Do nothing. Handled by [handleSwitchCase].
  }

  @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 = scope.lookupLabel(name) as JumpTarget?;
    }
    if (target == null && name == null) {
      push(problemInLoopOrSwitch = buildProblemStatement(
          fasta.messageBreakOutsideOfLoop, breakKeyword.charOffset));
    } else if (target == null ||
        target is! JumpTarget ||
        !target.isBreakTarget) {
      Token labelToken = breakKeyword.next!;
      push(problemInLoopOrSwitch = buildProblemStatement(
          fasta.templateInvalidBreakTarget.withArguments(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 = optional("break", keyword);
    if (name != null) {
      Template<Message Function(String)> template = isBreak
          ? fasta.templateBreakTargetOutsideFunction
          : fasta.templateContinueTargetOutsideFunction;
      problem = buildProblemStatement(
          template.withArguments(name), offsetForToken(keyword),
          length: lengthOfSpan(keyword, keyword.next));
    } else {
      Message message = isBreak
          ? fasta.messageAnonymousBreakTargetOutsideFunction
          : fasta.messageAnonymousContinueTargetOutsideFunction;
      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;
      Builder? namedTarget = scope.lookupLabel(identifier.name);
      if (namedTarget != null && namedTarget is! JumpTarget) {
        Token labelToken = continueKeyword.next!;
        push(problemInLoopOrSwitch = buildProblemStatement(
            fasta.messageContinueLabelNotTarget, labelToken.charOffset,
            length: labelToken.length));
        return;
      }
      target = namedTarget as JumpTarget?;
      if (target == null) {
        if (switchScope == null) {
          push(buildProblemStatement(
              fasta.templateLabelNotFound.withArguments(name),
              continueKeyword.next!.charOffset));
          return;
        }
        switchScope!.forwardDeclareLabel(
            identifier.name, target = createGotoTarget(identifier.charOffset));
      }
      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(
          fasta.messageContinueWithoutLabelInCase, continueKeyword.charOffset,
          length: continueKeyword.length));
    } else if (!target.isContinueTarget) {
      Token labelToken = continueKeyword.next!;
      push(problemInLoopOrSwitch = buildProblemStatement(
          fasta.templateInvalidContinueTarget.withArguments(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? typeVariableName;
    int typeVariableCharOffset;
    if (name is Identifier) {
      typeVariableName = name.name;
      typeVariableCharOffset = name.charOffset;
    } else if (name is ParserRecovery) {
      typeVariableName = TypeVariableBuilder.noNameSentinel;
      typeVariableCharOffset = name.charOffset;
    } else {
      unhandled("${name.runtimeType}", "beginTypeVariable.name",
          token.charOffset, uri);
    }
    TypeVariableBuilder variable = new TypeVariableBuilder(
        typeVariableName, libraryBuilder, typeVariableCharOffset, uri);
    if (annotations != null) {
      inferAnnotations(variable.parameter, annotations);
      for (Expression annotation in annotations) {
        variable.parameter.addAnnotation(annotation);
      }
    }
    push(variable);
  }

  @override
  void handleTypeVariablesDefined(Token token, int count) {
    debugEvent("handleTypeVariablesDefined");
    assert(count > 0);
    List<TypeVariableBuilder>? typeVariables =
        const FixedNullableList<TypeVariableBuilder>()
            .popNonNullable(stack, count, dummyTypeVariableBuilder);
    enterFunctionTypeScope(typeVariables);
    push(typeVariables);
  }

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

    TypeVariableBuilder variable = typeVariables[index];
    variable.bound = bound?.builder;
    if (variance != null) {
      if (!libraryBuilder.enableVarianceInLibrary) {
        reportVarianceModifierNotEnabled(variance);
      }
      variable.variance = Variance.fromString(variance.lexeme);
    }
  }

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

    List<TypeBuilder> unboundTypes = [];
    List<TypeVariableBuilder> unboundTypeVariables = [];
    List<TypeBuilder> calculatedBounds = calculateBounds(
        typeVariables,
        libraryBuilder.loader.target.dynamicType,
        libraryBuilder.loader.target.nullType,
        libraryBuilder.loader.target.objectClassBuilder,
        unboundTypes: unboundTypes,
        unboundTypeVariables: unboundTypeVariables);
    assert(unboundTypes.isEmpty,
        "Found a type not bound to a declaration in BodyBuilder.");
    for (int i = 0; i < typeVariables.length; ++i) {
      typeVariables[i].defaultType = calculatedBounds[i];
      typeVariables[i].defaultType!.resolveIn(
          scope,
          typeVariables[i].charOffset,
          typeVariables[i].fileUri!,
          libraryBuilder);
      typeVariables[i].finish(
          libraryBuilder,
          libraryBuilder.loader.target.objectClassBuilder,
          libraryBuilder.loader.target.dynamicType);
    }
    for (int i = 0; i < unboundTypeVariables.length; ++i) {
      unboundTypeVariables[i].finish(
          libraryBuilder,
          libraryBuilder.loader.target.objectClassBuilder,
          libraryBuilder.loader.target.dynamicType);
    }
    libraryBuilder.processPendingNullabilities();
  }

  @override
  void handleNoTypeVariables(Token token) {
    debugEvent("NoTypeVariables");
    enterFunctionTypeScope(null);
    push(NullValue.TypeVariables);
  }

  List<TypeParameter>? typeVariableBuildersToKernel(
      List<TypeVariableBuilder>? typeVariableBuilders) {
    if (typeVariableBuilders == null) return null;
    return new List<TypeParameter>.generate(typeVariableBuilders.length,
        (int i) => typeVariableBuilders[i].parameter,
        growable: true);
  }

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

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

  @override
  Expression wrapInProblem(
      Expression expression, Message message, int fileOffset, int length,
      {List<LocatedMessage>? context}) {
    Severity severity = message.code.severity;
    if (severity == Severity.error) {
      return wrapInLocatedProblem(
          expression, message.withLocation(uri, fileOffset, length),
          context: context);
    } else {
      addProblem(message, fileOffset, length, context: context);
      return expression;
    }
  }

  @override
  Expression wrapInLocatedProblem(Expression expression, LocatedMessage message,
      {List<LocatedMessage>? context}) {
    // 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: expression);
  }

  Expression buildFallThroughError(int charOffset) {
    addProblem(fasta.messageSwitchCaseFallThrough, charOffset, noLength);

    // TODO(ahe): The following doesn't make sense for the Analyzer. It should
    // be moved to [Forest] or conditional on `forest is Fangorn`.

    // TODO(ahe): Compute a LocatedMessage above instead?
    Location? location = messages.getLocationFromUri(uri, charOffset);

    return forest.createThrow(
        charOffset,
        buildStaticInvocation(
            libraryBuilder
                .loader.coreTypes.fallThroughErrorUrlAndLineConstructor,
            forest.createArguments(noLocation, <Expression>[
              forest.createStringLiteral(
                  charOffset, "${location?.file ?? uri}"),
              forest.createIntLiteral(charOffset, location?.line ?? 0),
            ]),
            constness: Constness.explicitNew,
            charOffset: charOffset));
  }

  Expression buildAbstractClassInstantiationError(
      Message message, String className,
      [int charOffset = -1]) {
    addProblemErrorIfConst(message, charOffset, className.length);
    // TODO(ahe): The following doesn't make sense to Analyzer AST.
    MemberBuilder constructor =
        libraryBuilder.loader.getAbstractClassInstantiationError();
    Expression invocation = buildStaticInvocation(
        constructor.member,
        forest.createArguments(charOffset,
            <Expression>[forest.createStringLiteral(charOffset, className)]),
        constness: Constness.explicitNew,
        charOffset: charOffset);
    return forest.createThrow(charOffset, invocation);
  }

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

  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(Field field, Expression value,
      String name, int offset, int previousInitializerOffset) {
    return new ShadowInvalidFieldInitializer(
        field,
        value,
        new VariableDeclaration.forValue(buildProblem(
            fasta.templateConstructorInitializeSameInstanceVariableSeveralTimes
                .withArguments(name),
            offset,
            noLength)))
      ..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}) {
    Builder? builder = declarationBuilder!.lookupLocalMember(name);
    if (builder?.next != null) {
      // Duplicated name, already reported.
      return <Initializer>[
        buildInvalidInitializer(
            buildProblem(
                fasta.templateDuplicatedDeclarationUse.withArguments(name),
                fieldNameOffset,
                name.length),
            fieldNameOffset)
      ];
    } else if (builder is FieldBuilder && builder.isDeclarationInstanceMember) {
      initializedFields ??= <String, int>{};
      if (initializedFields!.containsKey(name)) {
        return <Initializer>[
          buildDuplicatedInitializer(builder.field, expression, name,
              assignmentOffset, initializedFields![name]!)
        ];
      }
      initializedFields![name] = assignmentOffset;
      if (builder.isAbstract) {
        return <Initializer>[
          buildInvalidInitializer(
              buildProblem(fasta.messageAbstractFieldConstructorInitializer,
                  fieldNameOffset, name.length),
              fieldNameOffset)
        ];
      } else if (builder.isExternal) {
        return <Initializer>[
          buildInvalidInitializer(
              buildProblem(fasta.messageExternalFieldConstructorInitializer,
                  fieldNameOffset, name.length),
              fieldNameOffset)
        ];
      } else if (builder.isFinal && builder.hasInitializer) {
        addProblem(
            fasta.templateFieldAlreadyInitializedAtDeclaration
                .withArguments(name),
            assignmentOffset,
            noLength,
            context: [
              fasta.templateFieldAlreadyInitializedAtDeclarationCause
                  .withArguments(name)
                  .withLocation(uri, builder.charOffset, name.length)
            ]);
        MemberBuilder constructor =
            libraryBuilder.loader.getDuplicatedFieldInitializerError();
        Expression invocation = buildStaticInvocation(
            constructor.member,
            forest.createArguments(assignmentOffset, <Expression>[
              forest.createStringLiteral(assignmentOffset, name)
            ]),
            constness: Constness.explicitNew,
            charOffset: assignmentOffset);
        return <Initializer>[
          new ShadowInvalidFieldInitializer(
              builder.field,
              expression,
              new VariableDeclaration.forValue(
                  forest.createThrow(assignmentOffset, invocation)))
            ..fileOffset = assignmentOffset
        ];
      } else {
        if (formal != null && formal.type != null) {
          DartType formalType = formal.variable!.type;
          if (!typeEnvironment.isSubtypeOf(formalType, builder.fieldType,
              SubtypeCheckMode.withNullabilities)) {
            libraryBuilder.addProblem(
                fasta.templateInitializingFormalTypeMismatch.withArguments(
                    name,
                    formalType,
                    builder.fieldType,
                    libraryBuilder.isNonNullableByDefault),
                assignmentOffset,
                noLength,
                uri,
                context: [
                  fasta.messageInitializingFormalTypeMismatchField.withLocation(
                      builder.fileUri!, builder.charOffset, noLength)
                ]);
          }
        }
        ConstructorBuilder constructorBuilder = member as ConstructorBuilder;
        constructorBuilder.registerInitializedField(builder);
        return builder.buildInitializer(assignmentOffset, expression,
            isSynthetic: formal != null);
      }
    } else {
      return <Initializer>[
        buildInvalidInitializer(
            buildProblem(
                fasta.templateInitializerForStaticField.withArguments(name),
                fieldNameOffset,
                name.length),
            fieldNameOffset)
      ];
    }
  }

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

  @override
  Initializer buildRedirectingInitializer(
      Constructor constructor, Arguments arguments,
      [int charOffset = -1]) {
    if (classBuilder!
        .checkConstructorCyclic(member.name!, constructor.name.text)) {
      int length = constructor.name.text.length;
      if (length == 0) length = "this".length;
      addProblem(fasta.messageConstructorCyclic, charOffset, length);
      // TODO(askesc): Produce invalid initializer.
    }
    needsImplicitSuperInitializer = false;
    return new RedirectingInitializer(constructor, arguments)
      ..fileOffset = charOffset;
  }

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

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

  @override
  void handleInvalidFunctionBody(Token token) {
    if (member.isNative) {
      push(NullValue.FunctionBody);
    } else {
      push(forest.createBlock(offsetForToken(token), noLocation, <Statement>[
        buildProblemStatement(
            fasta.templateExpectedFunctionBody.withArguments(token),
            token.charOffset,
            length: token.length)
      ]));
    }
  }

  @override
  void handleTypeArgumentApplication(Token openAngleBracket) {
    assert(checkState(openAngleBracket, [
      ValueKinds.TypeArguments,
      unionOfKinds([ValueKinds.Generator, ValueKinds.Expression])
    ]));
    List<UnresolvedType>? typeArguments =
        pop() as List<UnresolvedType>?; // typeArguments
    if (libraryBuilder.enableConstructorTearOffsInLibrary) {
      Object? operand = pop();
      if (operand is Generator) {
        push(operand.applyTypeArguments(
            openAngleBracket.charOffset, typeArguments));
      } else {
        push(new Instantiation(
            toValue(operand), buildDartTypeArguments(typeArguments))
          ..fileOffset = openAngleBracket.charOffset);
      }
    } else {
      addProblem(
          templateExperimentNotEnabled.withArguments(
              'constructor-tearoffs',
              libraryBuilder.enableConstructorTearOffsVersionInLibrary
                  .toText()),
          openAngleBracket.charOffset,
          noLength);
    }
  }

  @override
  UnresolvedType validateTypeUse(UnresolvedType unresolved,
      {required bool nonInstanceAccessIsError,
      required bool allowPotentiallyConstantType}) {
    // ignore: unnecessary_null_comparison
    assert(nonInstanceAccessIsError != null);
    // ignore: unnecessary_null_comparison
    assert(allowPotentiallyConstantType != null);
    TypeBuilder builder = unresolved.builder;
    if (builder is NamedTypeBuilder && builder.declaration!.isTypeVariable) {
      TypeVariableBuilder typeParameterBuilder =
          builder.declaration as TypeVariableBuilder;
      TypeParameter typeParameter = typeParameterBuilder.parameter;
      LocatedMessage? message = _validateTypeUseIsInternal(
          builder, unresolved.fileUri, unresolved.charOffset,
          allowPotentiallyConstantType: allowPotentiallyConstantType);
      if (message == null) return unresolved;
      return new UnresolvedType(
          new NamedTypeBuilder(
              typeParameter.name!,
              builder.nullabilityBuilder,
              /* arguments = */ null,
              unresolved.fileUri,
              unresolved.charOffset)
            ..bind(new InvalidTypeDeclarationBuilder(
                typeParameter.name!, message)),
          unresolved.charOffset,
          unresolved.fileUri);
    } else if (builder is FunctionTypeBuilder) {
      LocatedMessage? message = _validateTypeUseIsInternal(
          builder, unresolved.fileUri, unresolved.charOffset,
          allowPotentiallyConstantType: allowPotentiallyConstantType);
      if (message == null) return unresolved;
      // TODO(johnniwinther): We should either remove this method completely and
      // fully handle this with `nonInstanceContext`, or fully handle all types
      // and remove `nonInstanceContext`.
      return new UnresolvedType(
          new FixedTypeBuilder(
              const InvalidType(), unresolved.fileUri, unresolved.charOffset),
          unresolved.charOffset,
          unresolved.fileUri);
    }
    return unresolved;
  }

  LocatedMessage? _validateTypeUseIsInternal(
      TypeBuilder? builder, Uri fileUri, int charOffset,
      {required bool allowPotentiallyConstantType}) {
    // ignore: unnecessary_null_comparison
    assert(allowPotentiallyConstantType != null);
    if (builder is NamedTypeBuilder && builder.declaration!.isTypeVariable) {
      TypeVariableBuilder typeParameterBuilder =
          builder.declaration as TypeVariableBuilder;
      TypeParameter typeParameter = typeParameterBuilder.parameter;
      LocatedMessage message;
      bool extensionField = member.isExtensionMember && member.isField;
      if ((extensionField || !isDeclarationInstanceContext) &&
          (typeParameter.parent is Class ||
              typeParameter.parent is Extension)) {
        message = fasta.messageTypeVariableInStaticContext.withLocation(
            builder.fileUri ?? fileUri,
            builder.charOffset ?? charOffset,
            typeParameter.name!.length);
      } else if (constantContext == ConstantContext.inferred &&
          !allowPotentiallyConstantType) {
        message = fasta.messageTypeVariableInConstantContext
            .withLocation(fileUri, charOffset, typeParameter.name!.length);
      } else {
        return null;
      }
      addProblem(message.messageObject, message.charOffset, message.length);
      return message;
    } else if (builder is FunctionTypeBuilder) {
      LocatedMessage? result = _validateTypeUseIsInternal(
          builder.returnType, fileUri, charOffset,
          allowPotentiallyConstantType: allowPotentiallyConstantType);
      if (result != null) {
        return result;
      }
      if (builder.formals != null) {
        for (FormalParameterBuilder formalParameterBuilder
            in builder.formals!) {
          result = _validateTypeUseIsInternal(
              formalParameterBuilder.type, fileUri, charOffset,
              allowPotentiallyConstantType: allowPotentiallyConstantType);
          if (result != null) {
            return result;
          }
        }
      }
    }
    return null;
  }

  @override
  Expression evaluateArgumentsBefore(
      Arguments? arguments, Expression expression) {
    if (arguments == null) return expression;
    List<Expression> expressions =
        new List<Expression>.from(forest.argumentsPositional(arguments));
    for (NamedExpression named in forest.argumentsNamed(arguments)) {
      expressions.add(named.value);
    }
    for (Expression argument in expressions.reversed) {
      expression = new Let(
          new VariableDeclaration.forValue(argument,
              isFinal: true,
              type: coreTypes.objectRawType(libraryBuilder.nullable)),
          expression);
    }
    return expression;
  }

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

  @override
  Expression buildMethodInvocation(
      Expression receiver, Name name, Arguments arguments, int offset,
      {bool isConstantExpression: false,
      bool isNullAware: false,
      bool isSuper: false}) {
    if (constantContext != ConstantContext.none &&
        !isConstantExpression &&
        !enableConstFunctionsInLibrary) {
      return buildProblem(
          fasta.templateNotConstantExpression
              .withArguments('Method invocation'),
          offset,
          name.text.length);
    }
    if (isSuper) {
      // We can ignore [isNullAware] on super sends.
      assert(forest.isThisExpression(receiver));
      Member? target = lookupInstanceMember(name, isSuper: true);

      if (target == null || (target is Procedure && !target.isAccessor)) {
        if (target == null) {
          warnUnresolvedMethod(name, offset, isSuper: true);
        } else if (!areArgumentsCompatible(target.function!, arguments)) {
          target = null;
          addProblemErrorIfConst(
              fasta.templateSuperclassMethodArgumentMismatch
                  .withArguments(name.text),
              offset,
              name.text.length);
        }
        return new SuperMethodInvocation(name, arguments, target as Procedure?)
          ..fileOffset = offset;
      }

      receiver = new SuperPropertyGet(name, target)..fileOffset = offset;
      return forest.createExpressionInvocation(
          arguments.fileOffset, receiver, arguments);
    }

    if (isNullAware) {
      VariableDeclarationImpl variable =
          createVariableDeclarationForValue(receiver);
      return new NullAwareMethodInvocation(
          variable,
          forest.createMethodInvocation(
              offset,
              createVariableGet(variable, receiver.fileOffset),
              name,
              arguments))
        ..fileOffset = receiver.fileOffset;
    } else {
      return forest.createMethodInvocation(offset, receiver, name, arguments);
    }
  }

  @override
  void addProblem(Message message, int charOffset, int length,
      {bool wasHandled: false,
      List<LocatedMessage>? context,
      Severity? 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.
    Severity severity = message.code.severity;
    if (constantContext != ConstantContext.none) {
      severity = Severity.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), Severity.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>[
            fasta.templateDuplicatedDeclarationCause
                .withArguments(name)
                .withLocation(
                    existing.fileUri!, existing.charOffset, name.length)
          ];
    addProblem(fasta.templateDuplicatedDeclaration.withArguments(name),
        charOffset, name.length,
        context: context);
  }

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

  @override
  StaticGet makeStaticGet(Member readTarget, Token token) {
    return new StaticGet(readTarget)..fileOffset = offsetForToken(token);
  }

  @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(UnresolvedType unresolvedType,
      {bool nonInstanceAccessIsError: false,
      bool allowPotentiallyConstantType: false}) {
    return validateTypeUse(unresolvedType,
            nonInstanceAccessIsError: nonInstanceAccessIsError,
            allowPotentiallyConstantType: allowPotentiallyConstantType)
        .builder
        .build(libraryBuilder);
  }

  @override
  DartType buildTypeLiteralDartType(UnresolvedType unresolvedType,
      {bool nonInstanceAccessIsError: false,
      bool allowPotentiallyConstantType: false}) {
    return validateTypeUse(unresolvedType,
            nonInstanceAccessIsError: nonInstanceAccessIsError,
            allowPotentiallyConstantType: allowPotentiallyConstantType)
        .builder
        .buildTypeLiteralType(libraryBuilder);
  }

  @override
  List<DartType> buildDartTypeArguments(List<UnresolvedType>? unresolvedTypes) {
    if (unresolvedTypes == null) return <DartType>[];
    return new List<DartType>.generate(
        unresolvedTypes.length, (int i) => buildDartType(unresolvedTypes[i]),
        growable: true);
  }

  @override
  String constructorNameForDiagnostics(String name,
      {String? className, bool isSuper: false}) {
    if (className == null) {
      Class cls = classBuilder!.cls;
      if (isSuper) {
        cls = cls.superclass!;
        while (cls.isMixinApplication) {
          cls = cls.superclass!;
        }
      }
      className = cls.name;
    }
    return name.isEmpty ? className : "$className.$name";
  }

  @override
  void handleNewAsIdentifier(Token token) {
    if (!libraryBuilder.enableConstructorTearOffsInLibrary) {
      addProblem(
          templateExperimentNotEnabled.withArguments(
              'constructor-tearoffs',
              libraryBuilder.enableConstructorTearOffsVersionInLibrary
                  .toText()),
          token.charOffset,
          token.length);
    }
  }
}

abstract class EnsureLoaded {
  void ensureLoaded(Member? member);
  bool isLoaded(Member? member);
}

class Operator {
  final Token token;
  String get name => token.stringValue!;

  final int charOffset;

  Operator(this.token, this.charOffset);

  String toString() => "operator($name)";
}

class JumpTarget extends BuilderImpl {
  final List<Statement> users = <Statement>[];

  final JumpTargetKind kind;

  final int functionNestingLevel;

  @override
  final MemberBuilder parent;

  @override
  final int charOffset;

  JumpTarget(
      this.kind, this.functionNestingLevel, this.parent, this.charOffset);

  @override
  Uri get fileUri => parent.fileUri!;

  bool get isBreakTarget => kind == JumpTargetKind.Break;

  bool get isContinueTarget => kind == JumpTargetKind.Continue;

  bool get isGotoTarget => kind == JumpTargetKind.Goto;

  bool get hasUsers => users.isNotEmpty;

  void addBreak(Statement statement) {
    assert(isBreakTarget);
    users.add(statement);
  }

  void addContinue(Statement statement) {
    assert(isContinueTarget);
    users.add(statement);
  }

  void addGoto(Statement statement) {
    assert(isGotoTarget);
    users.add(statement);
  }

  void resolveBreaks(
      Forest forest, LabeledStatement target, Statement targetStatement) {
    assert(isBreakTarget);
    for (Statement user in users) {
      BreakStatementImpl breakStatement = user as BreakStatementImpl;
      breakStatement.target = target;
      breakStatement.targetStatement = targetStatement;
    }
    users.clear();
  }

  List<BreakStatementImpl>? resolveContinues(
      Forest forest, LabeledStatement target) {
    assert(isContinueTarget);
    List<BreakStatementImpl> statements = <BreakStatementImpl>[];
    for (Statement user in users) {
      BreakStatementImpl breakStatement = user as BreakStatementImpl;
      breakStatement.target = target;
      statements.add(breakStatement);
    }
    users.clear();
    return statements;
  }

  void resolveGotos(Forest forest, SwitchCase target) {
    assert(isGotoTarget);
    for (Statement user in users) {
      ContinueSwitchStatement continueSwitchStatement =
          user as ContinueSwitchStatement;
      continueSwitchStatement.target = target;
    }
    users.clear();
  }

  @override
  String get fullNameForErrors => "<jump-target>";
}

class LabelTarget extends BuilderImpl implements JumpTarget {
  @override
  final MemberBuilder parent;

  final JumpTarget breakTarget;

  final JumpTarget continueTarget;

  final int functionNestingLevel;

  @override
  final int charOffset;

  LabelTarget(this.parent, this.functionNestingLevel, this.charOffset)
      : breakTarget = new JumpTarget(
            JumpTargetKind.Break, functionNestingLevel, parent, charOffset),
        continueTarget = new JumpTarget(
            JumpTargetKind.Continue, functionNestingLevel, parent, charOffset);

  @override
  Uri get fileUri => parent.fileUri!;

  bool get hasUsers => breakTarget.hasUsers || continueTarget.hasUsers;

  List<Statement> get users => unsupported("users", charOffset, fileUri);

  JumpTargetKind get kind => unsupported("kind", charOffset, fileUri);

  bool get isBreakTarget => true;

  bool get isContinueTarget => true;

  bool get isGotoTarget => false;

  void addBreak(Statement statement) {
    breakTarget.addBreak(statement);
  }

  void addContinue(Statement statement) {
    continueTarget.addContinue(statement);
  }

  void addGoto(Statement statement) {
    unsupported("addGoto", charOffset, fileUri);
  }

  void resolveBreaks(
      Forest forest, LabeledStatement target, Statement targetStatement) {
    breakTarget.resolveBreaks(forest, target, targetStatement);
  }

  List<BreakStatementImpl>? resolveContinues(
      Forest forest, LabeledStatement target) {
    return continueTarget.resolveContinues(forest, target);
  }

  void resolveGotos(Forest forest, SwitchCase target) {
    unsupported("resolveGotos", charOffset, fileUri);
  }

  @override
  String get fullNameForErrors => "<label-target>";
}

class FormalParameters {
  final List<FormalParameterBuilder>? parameters;
  final int charOffset;
  final int length;
  final Uri uri;

  FormalParameters(this.parameters, this.charOffset, this.length, this.uri) {
    if (parameters?.isEmpty ?? false) {
      throw "Empty parameters should be null";
    }
  }

  FunctionNode buildFunctionNode(
      SourceLibraryBuilder library,
      UnresolvedType? returnType,
      List<TypeVariableBuilder>? typeParameters,
      AsyncMarker asyncModifier,
      Statement body,
      int fileEndOffset,
      {required bool nonInstanceContext}) {
    FunctionType type = toFunctionType(
            returnType, const NullabilityBuilder.omitted(), typeParameters)
        .builder
        .build(library, nonInstanceContext: nonInstanceContext) as FunctionType;
    List<VariableDeclaration> positionalParameters = <VariableDeclaration>[];
    List<VariableDeclaration> namedParameters = <VariableDeclaration>[];
    if (parameters != null) {
      for (FormalParameterBuilder parameter in parameters!) {
        if (parameter.isNamed) {
          namedParameters.add(parameter.variable!);
        } else {
          positionalParameters.add(parameter.variable!);
        }
      }
      namedParameters.sort((VariableDeclaration a, VariableDeclaration b) {
        return a.name!.compareTo(b.name!);
      });
    }
    return new FunctionNode(body,
        typeParameters: type.typeParameters,
        positionalParameters: positionalParameters,
        namedParameters: namedParameters,
        requiredParameterCount: type.requiredParameterCount,
        returnType: type.returnType,
        asyncMarker: asyncModifier)
      ..fileOffset = charOffset
      ..fileEndOffset = fileEndOffset;
  }

  UnresolvedType toFunctionType(
      UnresolvedType? returnType, NullabilityBuilder nullabilityBuilder,
      [List<TypeVariableBuilder>? typeParameters]) {
    return new UnresolvedType(
        new FunctionTypeBuilder(returnType?.builder, typeParameters, parameters,
            nullabilityBuilder, uri, charOffset),
        charOffset,
        uri);
  }

  Scope computeFormalParameterScope(
      Scope parent, Builder declaration, ExpressionGeneratorHelper helper) {
    if (parameters == null) return parent;
    assert(parameters!.isNotEmpty);
    Map<String, Builder> local = <String, Builder>{};

    for (FormalParameterBuilder parameter in parameters!) {
      Builder? existing = local[parameter.name];
      if (existing != null) {
        helper.reportDuplicatedDeclaration(
            existing, parameter.name, parameter.charOffset);
      } else {
        local[parameter.name] = parameter;
      }
    }
    return new Scope(
        local: local,
        parent: parent,
        debugName: "formals",
        isModifiable: false);
  }

  String toString() {
    return "FormalParameters($parameters, $charOffset, $uri)";
  }
}

/// Returns a block like this:
///
///     {
///       statement;
///       body;
///     }
///
/// If [body] is a [Block], it's returned with [statement] prepended to it.
Block combineStatements(Statement statement, Statement body) {
  if (body is Block) {
    if (statement is Block) {
      body.statements.insertAll(0, statement.statements);
      setParents(statement.statements, body);
    } else {
      body.statements.insert(0, statement);
      statement.parent = body;
    }
    return body;
  } else {
    return new Block(<Statement>[statement, body])
      ..fileOffset = statement.fileOffset;
  }
}

/// DartDocTest(
///   debugName("myClassName", "myName", "myPrefix"),
///   "myPrefix.myClassName.myName"
/// )
/// DartDocTest(
///   debugName("myClassName", "myName"),
///   "myClassName.myName"
/// )
/// DartDocTest(
///   debugName("myClassName", ""),
///   "myClassName"
/// )
/// DartDocTest(
///   debugName("", ""),
///   ""
/// )
String debugName(String className, String name, [String? prefix]) {
  String result = name.isEmpty ? className : "$className.$name";
  return prefix == null ? result : "$prefix.$result";
}

// TODO(johnniwinther): This is a bit ad hoc. Call sites should know what kind
// of objects can be anticipated and handle these directly.
String getNodeName(Object node) {
  if (node is Identifier) {
    return node.name;
  } else if (node is Builder) {
    return node.fullNameForErrors;
  } else if (node is QualifiedName) {
    return flattenName(node, node.charOffset, null);
  } else {
    return unhandled("${node.runtimeType}", "getNodeName", -1, null);
  }
}

/// A data holder used to hold the information about a label that is pushed on
/// the stack.
class Label {
  String name;
  int charOffset;

  Label(this.name, this.charOffset);

  String toString() => "label($name)";
}

class ForInElements {
  VariableDeclaration? explicitVariableDeclaration;
  VariableDeclaration? syntheticVariableDeclaration;
  Expression? syntheticAssignment;
  Expression? expressionProblem;
  Statement? expressionEffects;

  VariableDeclaration get variable =>
      (explicitVariableDeclaration ?? syntheticVariableDeclaration)!;
}
