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

/// A library to help generate expression.
library fasta.expression_generator;

import 'package:_fe_analyzer_shared/src/parser/parser.dart'
    show lengthForToken, lengthOfSpan;

import 'package:_fe_analyzer_shared/src/scanner/token.dart' show Token;

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

import '../builder/builder.dart';
import '../builder/class_builder.dart';
import '../builder/declaration_builder.dart';
import '../builder/extension_builder.dart';
import '../builder/invalid_type_declaration_builder.dart';
import '../builder/member_builder.dart';
import '../builder/named_type_builder.dart';
import '../builder/nullability_builder.dart';
import '../builder/prefix_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 '../constant_context.dart' show ConstantContext;

import '../fasta_codes.dart';

import '../names.dart'
    show
        ampersandName,
        barName,
        callName,
        caretName,
        divisionName,
        equalsName,
        indexGetName,
        indexSetName,
        leftShiftName,
        lengthName,
        minusName,
        multiplyName,
        mustacheName,
        percentName,
        plusName,
        rightShiftName,
        tripleShiftName;

import '../problems.dart';

import '../scope.dart';

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

import 'body_builder.dart' show noLocation;

import 'constness.dart' show Constness;

import 'expression_generator_helper.dart' show ExpressionGeneratorHelper;

import 'forest.dart';

import 'kernel_api.dart' show NameSystem, printNodeOn, printQualifiedNameOn;

import 'kernel_builder.dart' show LoadLibraryBuilder;

import 'internal_ast.dart';

/// A generator represents a subexpression for which we can't yet build an
/// expression because we don't yet know the context in which it's used.
///
/// Once the context is known, a generator can be converted into an expression
/// by calling a `build` method.
///
/// For example, when building a kernel representation for `a[x] = b`, after
/// parsing `a[x]` but before parsing `= b`, we don't yet know whether to
/// generate an invocation of `operator[]` or `operator[]=`, so we create a
/// [Generator] object.  Later, after `= b` is parsed, [buildAssignment] will
/// be called.
abstract class Generator {
  /// Helper that provides access to contextual information.
  final ExpressionGeneratorHelper _helper;

  /// A token that defines a position subexpression that being built.
  final Token token;

  final int fileOffset;

  Generator(this._helper, this.token) : fileOffset = offsetForToken(token);

  /// Easy access to the [Forest] factory object.
  Forest get _forest => _helper.forest;

  // TODO(johnniwinther): Improve the semantic precision of this property or
  // remove it. It's unclear if the semantics is inconsistent. It's for instance
  // used both for the name of a variable in [VariableUseGenerator] and for
  // `[]` in [IndexedAccessGenerator], and while the former text occurs in the
  // underlying source code, the latter doesn't.
  String get _plainNameForRead;

  /// Internal name used for debugging.
  String get _debugName;

  /// The source uri for use in error messaging.
  Uri get _uri => _helper.uri;

  /// Builds a [Expression] representing a read from the generator.
  ///
  /// The read of this subexpression does _not_ need to support a simultaneous
  /// write of the same subexpression.
  Expression buildSimpleRead();

  /// Builds a [Expression] representing an assignment with the generator on
  /// the LHS and [value] on the RHS.
  ///
  /// The returned expression evaluates to the assigned value, unless
  /// [voidContext] is true, in which case it may evaluate to anything.
  Expression buildAssignment(Expression value, {bool voidContext: false});

  /// Returns a [Expression] representing a null-aware assignment (`??=`) with
  /// the generator on the LHS and [value] on the RHS.
  ///
  /// The returned expression evaluates to the assigned value, unless
  /// [voidContext] is true, in which case it may evaluate to anything.
  ///
  /// [type] is the static type of the RHS.
  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false});

  /// Returns a [Expression] representing a compound assignment (e.g. `+=`)
  /// with the generator on the LHS and [value] on the RHS.
  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false});

  /// Returns a [Expression] representing a pre-increment or pre-decrement of
  /// the generator.
  Expression buildPrefixIncrement(Name binaryOperator,
      {int offset: TreeNode.noOffset, bool voidContext: false}) {
    return buildCompoundAssignment(
        binaryOperator, _forest.createIntLiteral(offset, 1),
        offset: offset,
        // TODO(johnniwinther): We are missing some void contexts here. For
        // instance `++a?.b;` is not providing a void context making it default
        // `true`.
        voidContext: voidContext,
        isPreIncDec: true);
  }

  /// Returns a [Expression] representing a post-increment or post-decrement of
  /// the generator.
  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset: TreeNode.noOffset, bool voidContext: false});

  /// Returns a [Generator] or [Expression] representing an index access
  /// (e.g. `a[b]`) with the generator on the receiver and [index] as the
  /// index expression.
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware});

  /// Returns a [Expression] representing a compile-time error.
  ///
  /// At runtime, an exception will be thrown.
  Expression _makeInvalidRead() {
    return _helper.throwNoSuchMethodError(_forest.createNullLiteral(fileOffset),
        _plainNameForRead, _forest.createArgumentsEmpty(noLocation), fileOffset,
        isGetter: true);
  }

  /// Returns a [Expression] representing a compile-time error wrapping
  /// [value].
  ///
  /// At runtime, [value] will be evaluated before throwing an exception.
  Expression _makeInvalidWrite(Expression value) {
    return _helper.throwNoSuchMethodError(
        _forest.createNullLiteral(fileOffset),
        _plainNameForRead,
        _forest.createArguments(noLocation, <Expression>[value]),
        fileOffset,
        isSetter: true);
  }

  Expression buildForEffect() => buildSimpleRead();

  List<Initializer> buildFieldInitializer(Map<String, int>? initializedFields) {
    return <Initializer>[
      _helper.buildInvalidInitializer(
          _helper.buildProblem(
              messageInvalidInitializer, fileOffset, lengthForToken(token)),
          fileOffset)
    ];
  }

  /// Returns an expression, generator or initializer for an invocation of this
  /// subexpression with [typeArguments] and [arguments] at [offset]. Callers
  /// must pass `isInForest: true` iff [typeArguments] have already been added
  /// to [forest].
  ///
  /// For instance:
  /// * If this is a [PropertyAccessGenerator] for `a.b`, this will create
  ///   a [MethodInvocation] for `a.b(...)`.
  /// * If this is a [ThisAccessGenerator] for `this` in an initializer list,
  ///   this will create a [RedirectingInitializer] for `this(...)`.
  /// * If this is an [IncompleteErrorGenerator], this will return the error
  ///   generator itself.
  ///
  /// If the invocation has explicit type arguments
  /// [buildTypeWithResolvedArguments] called instead.
  /* Expression | Generator | Initializer */ doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false});

  /* Expression | Generator */ buildPropertyAccess(
      IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
    if (send is SendAccessGenerator) {
      return _helper.buildMethodInvocation(buildSimpleRead(), send.name,
          send.arguments, offsetForToken(send.token),
          isNullAware: isNullAware,
          isConstantExpression: send.isPotentiallyConstant);
    } else {
      if (_helper.constantContext != ConstantContext.none &&
          send.name != lengthName) {
        _helper.addProblem(
            messageNotAConstantExpression, fileOffset, token.length);
      }
      return PropertyAccessGenerator.make(
          _helper, send.token, buildSimpleRead(), send.name, isNullAware);
    }
  }

  /*Expression | Generator*/ buildEqualsOperation(Token token, Expression right,
      {required bool isNot}) {
    // ignore: unnecessary_null_comparison
    assert(isNot != null);
    return _forest.createEquals(offsetForToken(token), buildSimpleRead(), right,
        isNot: isNot);
  }

  /*Expression | Generator*/ buildBinaryOperation(
      Token token, Name binaryName, Expression right) {
    return _forest.createBinary(
        offsetForToken(token), buildSimpleRead(), binaryName, right);
  }

  /*Expression | Generator*/ buildUnaryOperation(Token token, Name unaryName) {
    return _forest.createUnary(
        offsetForToken(token), unaryName, buildSimpleRead());
  }

  /*Expression|Generator*/ applyTypeArguments(
      int fileOffset, List<UnresolvedType>? typeArguments) {
    return new Instantiation(
        buildSimpleRead(), _helper.buildDartTypeArguments(typeArguments))
      ..fileOffset = fileOffset;
  }

  /// Returns a [TypeBuilder] for this subexpression instantiated with the
  /// type [arguments]. If no type arguments are provided [arguments] is `null`.
  ///
  /// The type arguments have not been resolved and should be resolved to
  /// create a [TypeBuilder] for a valid type.
  TypeBuilder buildTypeWithResolvedArguments(
      NullabilityBuilder nullabilityBuilder, List<UnresolvedType>? arguments) {
    // TODO(johnniwinther): Could we use a FixedTypeBuilder(InvalidType()) here?
    NamedTypeBuilder result = new NamedTypeBuilder(
        token.lexeme,
        nullabilityBuilder,
        /* arguments = */ null,
        /* fileUri = */ null,
        /* charOffset = */ null);
    Message message = templateNotAType.withArguments(token.lexeme);
    _helper.libraryBuilder
        .addProblem(message, fileOffset, lengthForToken(token), _uri);
    result.bind(result.buildInvalidTypeDeclarationBuilder(
        message.withLocation(_uri, fileOffset, lengthForToken(token))));
    return result;
  }

  /* Expression | Generator */ Object qualifiedLookup(Token name) {
    return new UnexpectedQualifiedUseGenerator(_helper, name, this, false);
  }

  Expression invokeConstructor(
      List<UnresolvedType>? typeArguments,
      String name,
      Arguments arguments,
      Token nameToken,
      Token nameLastToken,
      Constness constness) {
    if (typeArguments != null) {
      assert(_forest.argumentsTypeArguments(arguments).isEmpty);
      _forest.argumentsSetTypeArguments(
          arguments, _helper.buildDartTypeArguments(typeArguments));
    }
    return _helper.throwNoSuchMethodError(
        _forest.createNullLiteral(fileOffset),
        _helper.constructorNameForDiagnostics(name,
            className: _plainNameForRead),
        arguments,
        nameToken.charOffset);
  }

  void printOn(StringSink sink);

  String toString() {
    StringBuffer buffer = new StringBuffer();
    buffer.write(_debugName);
    buffer.write("(offset: ");
    buffer.write("${fileOffset}");
    printOn(buffer);
    buffer.write(")");
    return "$buffer";
  }
}

/// [VariableUseGenerator] represents the subexpression whose prefix is a
/// local variable or parameter name.
///
/// For instance:
///
///   method(a) {
///     var b;
///     a;         // a VariableUseGenerator is created for `a`.
///     b = a[];   // a VariableUseGenerator is created for `a` and `b`.
///     b();       // a VariableUseGenerator is created for `b`.
///     b.c = a.d; // a VariableUseGenerator is created for `a` and `b`.
///   }
///
/// If the variable is final or read-only (like a parameter in a catch clause) a
/// [ReadOnlyAccessGenerator] is created instead.
class VariableUseGenerator extends Generator {
  final VariableDeclaration variable;

  final DartType? promotedType;

  VariableUseGenerator(
      ExpressionGeneratorHelper helper, Token token, this.variable,
      [this.promotedType])
      : assert(variable.isAssignable, 'Variable $variable is not assignable'),
        super(helper, token);

  @override
  String get _debugName => "VariableUseGenerator";

  @override
  String get _plainNameForRead => variable.name!;

  @override
  Expression buildSimpleRead() {
    return _createRead();
  }

  Expression _createRead() {
    return _helper.createVariableGet(variable, fileOffset);
  }

  @override
  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return _createWrite(fileOffset, value);
  }

  Expression _createWrite(int offset, Expression value) {
    _helper.registerVariableAssignment(variable);
    return new VariableSet(variable, value)..fileOffset = offset;
  }

  @override
  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    Expression read = _createRead();
    Expression write = _createWrite(fileOffset, value);
    return new IfNullSet(read, write, forEffect: voidContext)
      ..fileOffset = offset;
  }

  @override
  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    Expression binary = _helper.forest
        .createBinary(offset, _createRead(), binaryOperator, value);
    return _createWrite(fileOffset, binary);
  }

  @override
  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset = TreeNode.noOffset, bool voidContext = false}) {
    Expression value = _forest.createIntLiteral(offset, 1);
    if (voidContext) {
      return buildCompoundAssignment(binaryOperator, value,
          offset: offset, voidContext: voidContext, isPostIncDec: true);
    }
    VariableDeclarationImpl read =
        _helper.createVariableDeclarationForValue(_createRead());
    Expression binary = _helper.forest.createBinary(offset,
        _helper.createVariableGet(read, fileOffset), binaryOperator, value);
    VariableDeclarationImpl write =
        _helper.createVariableDeclarationForValue(_createWrite(offset, binary));
    return new LocalPostIncDec(read, write)..fileOffset = offset;
  }

  @override
  Expression doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    return _helper.forest.createExpressionInvocation(
        adjustForImplicitCall(_plainNameForRead, offset),
        buildSimpleRead(),
        arguments);
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
        isNullAware: isNullAware);
  }

  @override
  void printOn(StringSink sink) {
    NameSystem syntheticNames = new NameSystem();
    sink.write(", variable: ");
    printNodeOn(variable, sink, syntheticNames: syntheticNames);
    sink.write(", promotedType: ");
    printNodeOn(promotedType, sink, syntheticNames: syntheticNames);
  }
}

/// A [PropertyAccessGenerator] represents a subexpression whose prefix is
/// an explicit property access.
///
/// For instance
///
///   method(a) {
///     a.b;      // a PropertyAccessGenerator is created for `a.b`.
///     a.b();    // a PropertyAccessGenerator is created for `a.b`.
///     a.b = c;  // a PropertyAccessGenerator is created for `a.b`.
///     a.b += c; // a PropertyAccessGenerator is created for `a.b`.
///   }
///
/// If the receiver is `this`, a [ThisPropertyAccessGenerator] is created
/// instead. If the access is null-aware, e.g. `a?.b`, a
/// [NullAwarePropertyAccessGenerator] is created instead.
class PropertyAccessGenerator extends Generator {
  /// The receiver expression. `a` in the examples in the class documentation.
  final Expression receiver;

  /// The name for the accessed property. `b` in the examples in the class
  /// documentation.
  final Name name;

  PropertyAccessGenerator(
      ExpressionGeneratorHelper helper, Token token, this.receiver, this.name)
      : super(helper, token);

  @override
  String get _debugName => "PropertyAccessGenerator";

  @override
  String get _plainNameForRead => name.text;

  @override
  Expression doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    return _helper.buildMethodInvocation(receiver, name, arguments, offset);
  }

  @override
  void printOn(StringSink sink) {
    NameSystem syntheticNames = new NameSystem();
    sink.write(", receiver: ");
    printNodeOn(receiver, sink, syntheticNames: syntheticNames);
    sink.write(", name: ");
    sink.write(name.text);
  }

  @override
  Expression buildSimpleRead() {
    return _forest.createPropertyGet(fileOffset, receiver, name);
  }

  @override
  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return _helper.forest.createPropertySet(fileOffset, receiver, name, value,
        forEffect: voidContext);
  }

  @override
  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext = false}) {
    return new IfNullPropertySet(receiver, name, value,
        forEffect: voidContext, readOffset: fileOffset, writeOffset: fileOffset)
      ..fileOffset = offset;
  }

  @override
  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    return new CompoundPropertySet(receiver, name, binaryOperator, value,
        forEffect: voidContext,
        readOffset: fileOffset,
        binaryOffset: offset,
        writeOffset: fileOffset)
      ..fileOffset = offset;
  }

  @override
  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset = TreeNode.noOffset, bool voidContext = false}) {
    Expression value = _forest.createIntLiteral(offset, 1);
    if (voidContext) {
      return buildCompoundAssignment(binaryOperator, value,
          offset: offset, voidContext: voidContext, isPostIncDec: true);
    }
    VariableDeclarationImpl variable =
        _helper.createVariableDeclarationForValue(receiver);
    VariableDeclarationImpl read = _helper.createVariableDeclarationForValue(
        _forest.createPropertyGet(fileOffset,
            _helper.createVariableGet(variable, receiver.fileOffset), name));
    Expression binary = _helper.forest.createBinary(offset,
        _helper.createVariableGet(read, fileOffset), binaryOperator, value);
    VariableDeclarationImpl write = _helper.createVariableDeclarationForValue(
        _helper.forest.createPropertySet(
            fileOffset,
            _helper.createVariableGet(variable, receiver.fileOffset),
            name,
            binary,
            forEffect: true));
    return new PropertyPostIncDec(variable, read, write)..fileOffset = offset;
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
        isNullAware: isNullAware);
  }

  /// Creates a [Generator] for the access of property [name] on [receiver].
  static Generator make(ExpressionGeneratorHelper helper, Token token,
      Expression receiver, Name name, bool isNullAware) {
    if (helper.forest.isThisExpression(receiver)) {
      return new ThisPropertyAccessGenerator(helper, token, name,
          thisOffset: receiver.fileOffset, isNullAware: isNullAware);
    } else {
      return isNullAware
          ? new NullAwarePropertyAccessGenerator(helper, token, receiver, name)
          : new PropertyAccessGenerator(helper, token, receiver, name);
    }
  }
}

/// A [ThisPropertyAccessGenerator] represents a subexpression whose prefix is
/// an implicit or explicit access on `this`.
///
/// For instance
///
///   class C {
///     var b;
///     method() {
///       b;           // a ThisPropertyAccessGenerator is created for `b`.
///       b();         // a ThisPropertyAccessGenerator is created for `b`.
///       b = c;       // a ThisPropertyAccessGenerator is created for `b`.
///       b += c;      // a ThisPropertyAccessGenerator is created for `b`.
///       this.b;      // a ThisPropertyAccessGenerator is created for `this.b`.
///       this.b();    // a ThisPropertyAccessGenerator is created for `this.b`.
///       this.b = c;  // a ThisPropertyAccessGenerator is created for `this.b`.
///       this.b += c; // a ThisPropertyAccessGenerator is created for `this.b`.
///     }
///   }
///
/// This is a special case of [PropertyAccessGenerator] to avoid creating an
/// indirect access to 'this' in for instance `this.b += c` which by
/// [PropertyAccessGenerator] would have been created as
///
///     let #1 = this in #.b = #.b + c
///
/// instead of
///
///     this.b = this.b + c
///
class ThisPropertyAccessGenerator extends Generator {
  /// The name for the accessed property. `b` in the examples in the class
  /// documentation.
  final Name name;

  /// The offset of `this` if explicit. Otherwise `null`.
  final int? thisOffset;
  final bool isNullAware;

  ThisPropertyAccessGenerator(
      ExpressionGeneratorHelper helper, Token token, this.name,
      {this.thisOffset, this.isNullAware: false})
      : super(helper, token);

  @override
  String get _debugName => "ThisPropertyAccessGenerator";

  @override
  String get _plainNameForRead => name.text;

  void _reportNonNullableInNullAwareWarningIfNeeded() {
    if (isNullAware && _helper.libraryBuilder.isNonNullableByDefault) {
      _helper.libraryBuilder.addProblem(
          messageThisInNullAwareReceiver,
          thisOffset ?? fileOffset,
          thisOffset != null ? 4 : noLength,
          _helper.uri);
    }
  }

  @override
  Expression buildSimpleRead() {
    return _createRead();
  }

  Expression _createRead() {
    _reportNonNullableInNullAwareWarningIfNeeded();
    return _forest.createPropertyGet(
        fileOffset, _forest.createThisExpression(fileOffset), name);
  }

  @override
  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    _reportNonNullableInNullAwareWarningIfNeeded();
    return _createWrite(fileOffset, value, forEffect: voidContext);
  }

  Expression _createWrite(int offset, Expression value,
      {required bool forEffect}) {
    return _helper.forest.createPropertySet(
        fileOffset, _forest.createThisExpression(fileOffset), name, value,
        forEffect: forEffect);
  }

  @override
  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    return new IfNullSet(
        _createRead(), _createWrite(offset, value, forEffect: voidContext),
        forEffect: voidContext)
      ..fileOffset = offset;
  }

  @override
  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    _reportNonNullableInNullAwareWarningIfNeeded();
    _helper.forest.createBinary(
        offset,
        _forest.createPropertyGet(
            fileOffset, _forest.createThisExpression(fileOffset), name),
        binaryOperator,
        value);
    Expression binary = _helper.forest.createBinary(
        offset,
        _forest.createPropertyGet(
            fileOffset, _forest.createThisExpression(fileOffset), name),
        binaryOperator,
        value);
    return _createWrite(fileOffset, binary, forEffect: voidContext);
  }

  @override
  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset = TreeNode.noOffset, bool voidContext = false}) {
    Expression value = _forest.createIntLiteral(offset, 1);
    if (voidContext) {
      return buildCompoundAssignment(binaryOperator, value,
          offset: offset, voidContext: voidContext, isPostIncDec: true);
    }
    _reportNonNullableInNullAwareWarningIfNeeded();
    VariableDeclarationImpl read = _helper.createVariableDeclarationForValue(
        _forest.createPropertyGet(
            fileOffset, _forest.createThisExpression(fileOffset), name));
    Expression binary = _helper.forest.createBinary(offset,
        _helper.createVariableGet(read, fileOffset), binaryOperator, value);
    VariableDeclarationImpl write = _helper.createVariableDeclarationForValue(
        _createWrite(fileOffset, binary, forEffect: true));
    return new PropertyPostIncDec.onReadOnly(read, write)..fileOffset = offset;
  }

  @override
  Expression doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    return _helper.buildMethodInvocation(
        _forest.createThisExpression(fileOffset), name, arguments, offset);
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
        isNullAware: isNullAware);
  }

  @override
  void printOn(StringSink sink) {
    sink.write(", name: ");
    sink.write(name.text);
  }
}

class NullAwarePropertyAccessGenerator extends Generator {
  final VariableDeclaration receiver;

  final Expression receiverExpression;

  final Name name;

  NullAwarePropertyAccessGenerator(ExpressionGeneratorHelper helper,
      Token token, this.receiverExpression, this.name)
      : this.receiver =
            helper.createVariableDeclarationForValue(receiverExpression),
        super(helper, token);

  @override
  String get _debugName => "NullAwarePropertyAccessGenerator";

  Expression receiverAccess() => new VariableGet(receiver);

  @override
  String get _plainNameForRead => name.text;

  @override
  Expression buildSimpleRead() {
    VariableDeclarationImpl variable =
        _helper.createVariableDeclarationForValue(receiverExpression);
    PropertyGet read = _forest.createPropertyGet(
        fileOffset,
        _helper.createVariableGet(variable, receiverExpression.fileOffset,
            forNullGuardedAccess: true),
        name);
    return new NullAwarePropertyGet(variable, read)
      ..fileOffset = receiverExpression.fileOffset;
  }

  @override
  Expression buildAssignment(Expression value, {bool voidContext = false}) {
    VariableDeclarationImpl variable =
        _helper.createVariableDeclarationForValue(receiverExpression);
    PropertySet read = _helper.forest.createPropertySet(
        fileOffset,
        _helper.createVariableGet(variable, receiverExpression.fileOffset,
            forNullGuardedAccess: true),
        name,
        value,
        forEffect: voidContext,
        readOnlyReceiver: true);
    return new NullAwarePropertySet(variable, read)
      ..fileOffset = receiverExpression.fileOffset;
  }

  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    return new NullAwareIfNullSet(receiverExpression, name, value,
        forEffect: voidContext,
        readOffset: fileOffset,
        testOffset: offset,
        writeOffset: fileOffset)
      ..fileOffset = offset;
  }

  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    return new NullAwareCompoundSet(
        receiverExpression, name, binaryOperator, value,
        readOffset: fileOffset,
        binaryOffset: offset,
        writeOffset: fileOffset,
        forEffect: voidContext,
        forPostIncDec: isPostIncDec);
  }

  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset: TreeNode.noOffset, bool voidContext: false}) {
    return buildCompoundAssignment(
        binaryOperator, _forest.createIntLiteral(offset, 1),
        offset: offset, voidContext: voidContext, isPostIncDec: true);
  }

  @override
  Expression doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    return unsupported("doInvocation", offset, _uri);
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
        isNullAware: isNullAware);
  }

  @override
  void printOn(StringSink sink) {
    NameSystem syntheticNames = new NameSystem();
    sink.write(", receiver: ");
    printNodeOn(receiver, sink, syntheticNames: syntheticNames);
    sink.write(", receiverExpression: ");
    printNodeOn(receiverExpression, sink, syntheticNames: syntheticNames);
    sink.write(", name: ");
    sink.write(name.text);
  }
}

class SuperPropertyAccessGenerator extends Generator {
  final Name name;

  final Member? getter;

  final Member? setter;

  SuperPropertyAccessGenerator(ExpressionGeneratorHelper helper, Token token,
      this.name, this.getter, this.setter)
      : super(helper, token);

  @override
  String get _debugName => "SuperPropertyAccessGenerator";

  @override
  String get _plainNameForRead => name.text;

  @override
  Expression buildSimpleRead() {
    return _createRead();
  }

  Expression _createRead() {
    if (getter == null) {
      _helper.warnUnresolvedGet(name, fileOffset, isSuper: true);
    }
    return new SuperPropertyGet(name, getter)..fileOffset = fileOffset;
  }

  @override
  Expression buildAssignment(Expression value, {bool voidContext = false}) {
    return _createWrite(fileOffset, value);
  }

  Expression _createWrite(int offset, Expression value) {
    if (setter == null) {
      _helper.warnUnresolvedSet(name, offset, isSuper: true);
    }
    SuperPropertySet write = new SuperPropertySet(name, value, setter)
      ..fileOffset = offset;
    return write;
  }

  @override
  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset = TreeNode.noOffset,
      bool voidContext = false,
      bool isPreIncDec = false,
      bool isPostIncDec = false}) {
    Expression binary = _helper.forest
        .createBinary(offset, _createRead(), binaryOperator, value);
    return _createWrite(fileOffset, binary);
  }

  @override
  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset = TreeNode.noOffset, bool voidContext = false}) {
    Expression value = _forest.createIntLiteral(offset, 1);
    if (voidContext) {
      return buildCompoundAssignment(binaryOperator, value,
          offset: offset, voidContext: voidContext, isPostIncDec: true);
    }
    VariableDeclarationImpl read =
        _helper.createVariableDeclarationForValue(_createRead());
    Expression binary = _helper.forest.createBinary(offset,
        _helper.createVariableGet(read, fileOffset), binaryOperator, value);
    VariableDeclarationImpl write = _helper
        .createVariableDeclarationForValue(_createWrite(fileOffset, binary));
    return new StaticPostIncDec(read, write)..fileOffset = offset;
  }

  @override
  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    return new IfNullSet(_createRead(), _createWrite(fileOffset, value),
        forEffect: voidContext)
      ..fileOffset = offset;
  }

  @override
  Expression doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    if (_helper.constantContext != ConstantContext.none) {
      // TODO(brianwilkerson) Fix the length
      _helper.addProblem(messageNotAConstantExpression, offset, 1);
    }
    if (getter == null || isFieldOrGetter(getter)) {
      return _helper.forest
          .createExpressionInvocation(offset, buildSimpleRead(), arguments);
    } else {
      // TODO(ahe): This could be something like "super.property(...)" where
      // property is a setter.
      return unhandled("${getter.runtimeType}", "doInvocation", offset, _uri);
    }
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
        isNullAware: isNullAware);
  }

  @override
  void printOn(StringSink sink) {
    sink.write(", name: ");
    sink.write(name.text);
    sink.write(", getter: ");
    printQualifiedNameOn(getter, sink);
    sink.write(", setter: ");
    printQualifiedNameOn(setter, sink);
  }
}

class IndexedAccessGenerator extends Generator {
  final Expression receiver;

  final Expression index;

  final bool isNullAware;

  IndexedAccessGenerator(
      ExpressionGeneratorHelper helper, Token token, this.receiver, this.index,
      {required this.isNullAware})
      // ignore: unnecessary_null_comparison
      : assert(isNullAware != null),
        super(helper, token);

  @override
  String get _plainNameForRead => "[]";

  @override
  String get _debugName => "IndexedAccessGenerator";

  @override
  Expression buildSimpleRead() {
    VariableDeclarationImpl? variable;
    Expression receiverValue;
    if (isNullAware) {
      variable = _helper.createVariableDeclarationForValue(receiver);
      receiverValue = _helper.createVariableGet(variable, fileOffset,
          forNullGuardedAccess: true);
    } else {
      receiverValue = receiver;
    }
    Expression result =
        _forest.createIndexGet(fileOffset, receiverValue, index);
    if (isNullAware) {
      result = new NullAwareMethodInvocation(variable!, result)
        ..fileOffset = fileOffset;
    }
    return result;
  }

  @override
  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    VariableDeclarationImpl? variable;
    Expression receiverValue;
    if (isNullAware) {
      variable = _helper.createVariableDeclarationForValue(receiver);
      receiverValue = _helper.createVariableGet(variable, fileOffset,
          forNullGuardedAccess: true);
    } else {
      receiverValue = receiver;
    }
    Expression result = _forest.createIndexSet(
        fileOffset, receiverValue, index, value,
        forEffect: voidContext);
    if (isNullAware) {
      result = new NullAwareMethodInvocation(variable!, result)
        ..fileOffset = fileOffset;
    }
    return result;
  }

  @override
  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    VariableDeclarationImpl? variable;
    Expression receiverValue;
    if (isNullAware) {
      variable = _helper.createVariableDeclarationForValue(receiver);
      receiverValue = _helper.createVariableGet(variable, fileOffset,
          forNullGuardedAccess: true);
    } else {
      receiverValue = receiver;
    }

    Expression result = new IfNullIndexSet(receiverValue, index, value,
        readOffset: fileOffset,
        testOffset: offset,
        writeOffset: fileOffset,
        forEffect: voidContext)
      ..fileOffset = offset;
    if (isNullAware) {
      result = new NullAwareMethodInvocation(variable!, result)
        ..fileOffset = fileOffset;
    }
    return result;
  }

  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    VariableDeclarationImpl? variable;
    Expression receiverValue;
    if (isNullAware) {
      variable = _helper.createVariableDeclarationForValue(receiver);
      receiverValue = _helper.createVariableGet(variable, fileOffset,
          forNullGuardedAccess: true);
    } else {
      receiverValue = receiver;
    }

    Expression result = new CompoundIndexSet(
        receiverValue, index, binaryOperator, value,
        readOffset: fileOffset,
        binaryOffset: offset,
        writeOffset: fileOffset,
        forEffect: voidContext,
        forPostIncDec: isPostIncDec);
    if (isNullAware) {
      result = new NullAwareMethodInvocation(variable!, result)
        ..fileOffset = fileOffset;
    }
    return result;
  }

  @override
  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset = TreeNode.noOffset, bool voidContext = false}) {
    Expression value = _forest.createIntLiteral(offset, 1);
    return buildCompoundAssignment(binaryOperator, value,
        offset: offset, voidContext: voidContext, isPostIncDec: true);
  }

  @override
  Expression doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    return _helper.forest.createExpressionInvocation(
        arguments.fileOffset, buildSimpleRead(), arguments);
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
        isNullAware: isNullAware);
  }

  @override
  void printOn(StringSink sink) {
    NameSystem syntheticNames = new NameSystem();
    sink.write(", receiver: ");
    printNodeOn(receiver, sink, syntheticNames: syntheticNames);
    sink.write(", index: ");
    printNodeOn(index, sink, syntheticNames: syntheticNames);
    sink.write(", isNullAware: ${isNullAware}");
  }

  static Generator make(ExpressionGeneratorHelper helper, Token token,
      Expression receiver, Expression index,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    if (helper.forest.isThisExpression(receiver)) {
      return new ThisIndexedAccessGenerator(helper, token, index,
          thisOffset: receiver.fileOffset, isNullAware: isNullAware);
    } else {
      return new IndexedAccessGenerator(helper, token, receiver, index,
          isNullAware: isNullAware);
    }
  }
}

/// Special case of [IndexedAccessGenerator] to avoid creating an indirect
/// access to 'this'.
class ThisIndexedAccessGenerator extends Generator {
  final Expression index;

  final int? thisOffset;
  final bool isNullAware;

  ThisIndexedAccessGenerator(
      ExpressionGeneratorHelper helper, Token token, this.index,
      {this.thisOffset, this.isNullAware: false})
      : super(helper, token);

  @override
  String get _plainNameForRead => "[]";

  @override
  String get _debugName => "ThisIndexedAccessGenerator";

  void _reportNonNullableInNullAwareWarningIfNeeded() {
    if (isNullAware && _helper.libraryBuilder.isNonNullableByDefault) {
      _helper.libraryBuilder.addProblem(
          messageThisInNullAwareReceiver,
          thisOffset ?? fileOffset,
          thisOffset != null ? 4 : noLength,
          _helper.uri);
    }
  }

  @override
  Expression buildSimpleRead() {
    _reportNonNullableInNullAwareWarningIfNeeded();
    Expression receiver = _helper.forest.createThisExpression(fileOffset);
    return _forest.createIndexGet(fileOffset, receiver, index);
  }

  @override
  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    _reportNonNullableInNullAwareWarningIfNeeded();
    Expression receiver = _helper.forest.createThisExpression(fileOffset);
    return _forest.createIndexSet(fileOffset, receiver, index, value,
        forEffect: voidContext);
  }

  @override
  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    _reportNonNullableInNullAwareWarningIfNeeded();
    Expression receiver = _helper.forest.createThisExpression(fileOffset);
    return new IfNullIndexSet(receiver, index, value,
        readOffset: fileOffset,
        testOffset: offset,
        writeOffset: fileOffset,
        forEffect: voidContext)
      ..fileOffset = offset;
  }

  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    _reportNonNullableInNullAwareWarningIfNeeded();
    Expression receiver = _helper.forest.createThisExpression(fileOffset);
    return new CompoundIndexSet(receiver, index, binaryOperator, value,
        readOffset: fileOffset,
        binaryOffset: offset,
        writeOffset: fileOffset,
        forEffect: voidContext,
        forPostIncDec: isPostIncDec);
  }

  @override
  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset = TreeNode.noOffset, bool voidContext = false}) {
    Expression value = _forest.createIntLiteral(offset, 1);
    return buildCompoundAssignment(binaryOperator, value,
        offset: offset, voidContext: voidContext, isPostIncDec: true);
  }

  @override
  Expression doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    return _helper.forest
        .createExpressionInvocation(offset, buildSimpleRead(), arguments);
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
        isNullAware: isNullAware);
  }

  @override
  void printOn(StringSink sink) {
    NameSystem syntheticNames = new NameSystem();
    sink.write(", index: ");
    printNodeOn(index, sink, syntheticNames: syntheticNames);
  }
}

class SuperIndexedAccessGenerator extends Generator {
  final Expression index;

  final Procedure? getter;

  final Procedure? setter;

  SuperIndexedAccessGenerator(ExpressionGeneratorHelper helper, Token token,
      this.index, this.getter, this.setter)
      : super(helper, token);

  String get _plainNameForRead => "[]";

  String get _debugName => "SuperIndexedAccessGenerator";

  @override
  Expression buildSimpleRead() {
    if (getter == null) {
      _helper.warnUnresolvedMethod(indexGetName, fileOffset, isSuper: true);
    }
    return _helper.forest.createSuperMethodInvocation(
        fileOffset,
        indexGetName,
        getter,
        _helper.forest.createArguments(fileOffset, <Expression>[index]));
  }

  @override
  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    if (voidContext) {
      if (setter == null) {
        _helper.warnUnresolvedMethod(indexSetName, fileOffset, isSuper: true);
      }
      return _helper.forest.createSuperMethodInvocation(
          fileOffset,
          indexSetName,
          setter,
          _helper.forest
              .createArguments(fileOffset, <Expression>[index, value]));
    } else {
      return new SuperIndexSet(setter, index, value)..fileOffset = fileOffset;
    }
  }

  @override
  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    return new IfNullSuperIndexSet(getter, setter, index, value,
        readOffset: fileOffset,
        testOffset: offset,
        writeOffset: fileOffset,
        forEffect: voidContext)
      ..fileOffset = offset;
  }

  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    return new CompoundSuperIndexSet(
        getter, setter, index, binaryOperator, value,
        readOffset: fileOffset,
        binaryOffset: offset,
        writeOffset: fileOffset,
        forEffect: voidContext,
        forPostIncDec: isPostIncDec);
  }

  @override
  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset = TreeNode.noOffset, bool voidContext = false}) {
    Expression value = _forest.createIntLiteral(offset, 1);
    return buildCompoundAssignment(binaryOperator, value,
        offset: offset, voidContext: voidContext, isPostIncDec: true);
  }

  @override
  Expression doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    return _helper.forest
        .createExpressionInvocation(offset, buildSimpleRead(), arguments);
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
        isNullAware: isNullAware);
  }

  @override
  void printOn(StringSink sink) {
    NameSystem syntheticNames = new NameSystem();
    sink.write(", index: ");
    printNodeOn(index, sink, syntheticNames: syntheticNames);
    sink.write(", getter: ");
    printQualifiedNameOn(getter, sink);
    sink.write(", setter: ");
    printQualifiedNameOn(setter, sink);
  }
}

/// A [StaticAccessGenerator] represents a subexpression whose prefix is
/// a static or top-level member, including static extension members.
///
/// For instance
///
///   get property => 0;
///   set property(_) {}
///   var field;
///   method() {}
///
///   main() {
///     property;     // a StaticAccessGenerator is created for `property`.
///     property = 0; // a StaticAccessGenerator is created for `property`.
///     field = 0;    // a StaticAccessGenerator is created for `field`.
///     method;       // a StaticAccessGenerator is created for `method`.
///     method();     // a StaticAccessGenerator is created for `method`.
///   }
///
///   class A {}
///   extension B on A {
///     static get property => 0;
///     static set property(_) {}
///     static var field;
///     static method() {
///       property;     // this StaticAccessGenerator is created for `property`.
///       property = 0; // this StaticAccessGenerator is created for `property`.
///       field = 0;    // this StaticAccessGenerator is created for `field`.
///       method;       // this StaticAccessGenerator is created for `method`.
///       method();     // this StaticAccessGenerator is created for `method`.
///     }
///   }
///
class StaticAccessGenerator extends Generator {
  /// The name of the original target;
  final String targetName;

  /// The static [Member] used for performing a read or invocation on this
  /// subexpression.
  ///
  /// This can be `null` if the subexpression doesn't have a readable target.
  /// For instance if the subexpression is a setter without a corresponding
  /// getter.
  final Member? readTarget;

  /// The static [Member] used for performing a write on this subexpression.
  ///
  /// This can be `null` if the subexpression doesn't have a writable target.
  /// For instance if the subexpression is a final field, a method, or a getter
  /// without a corresponding setter.
  final Member? writeTarget;

  /// The offset of the type name if explicit. Otherwise `null`.
  final int? typeOffset;
  final bool isNullAware;

  StaticAccessGenerator(ExpressionGeneratorHelper helper, Token token,
      this.targetName, this.readTarget, this.writeTarget,
      {this.typeOffset, this.isNullAware: false})
      // ignore: unnecessary_null_comparison
      : assert(targetName != null),
        assert(readTarget != null || writeTarget != null),
        super(helper, token);

  factory StaticAccessGenerator.fromBuilder(
      ExpressionGeneratorHelper helper,
      String targetName,
      Token token,
      MemberBuilder? getterBuilder,
      MemberBuilder? setterBuilder,
      {int? typeOffset,
      bool isNullAware: false}) {
    return new StaticAccessGenerator(helper, token, targetName,
        getterBuilder?.readTarget, setterBuilder?.writeTarget,
        typeOffset: typeOffset, isNullAware: isNullAware);
  }

  void _reportNonNullableInNullAwareWarningIfNeeded() {
    if (isNullAware && _helper.libraryBuilder.isNonNullableByDefault) {
      String className = (readTarget ?? writeTarget)!.enclosingClass!.name;
      _helper.libraryBuilder.addProblem(
          templateClassInNullAwareReceiver.withArguments(className),
          typeOffset ?? fileOffset,
          typeOffset != null ? className.length : noLength,
          _helper.uri);
    }
  }

  @override
  String get _debugName => "StaticAccessGenerator";

  @override
  String get _plainNameForRead => targetName;

  @override
  Expression buildSimpleRead() {
    return _createRead();
  }

  Expression _createRead() {
    Expression read;
    if (readTarget == null) {
      read = _makeInvalidRead();
    } else {
      _reportNonNullableInNullAwareWarningIfNeeded();
      read = _helper.makeStaticGet(readTarget!, token);
    }
    return read;
  }

  @override
  Expression buildAssignment(Expression value, {bool voidContext = false}) {
    _reportNonNullableInNullAwareWarningIfNeeded();
    return _createWrite(fileOffset, value);
  }

  Expression _createWrite(int offset, Expression value) {
    Expression write;
    if (writeTarget == null) {
      write = _makeInvalidWrite(value);
    } else {
      _reportNonNullableInNullAwareWarningIfNeeded();
      write = new StaticSet(writeTarget!, value)..fileOffset = offset;
    }
    return write;
  }

  @override
  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    return new IfNullSet(_createRead(), _createWrite(offset, value),
        forEffect: voidContext)
      ..fileOffset = offset;
  }

  @override
  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset = TreeNode.noOffset,
      bool voidContext = false,
      bool isPreIncDec = false,
      bool isPostIncDec = false}) {
    Expression binary = _helper.forest
        .createBinary(offset, _createRead(), binaryOperator, value);
    return _createWrite(fileOffset, binary);
  }

  @override
  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset = TreeNode.noOffset, bool voidContext = false}) {
    Expression value = _forest.createIntLiteral(offset, 1);
    if (voidContext) {
      return buildCompoundAssignment(binaryOperator, value,
          offset: offset, voidContext: voidContext, isPostIncDec: true);
    }
    VariableDeclarationImpl read =
        _helper.createVariableDeclarationForValue(_createRead());
    Expression binary = _helper.forest.createBinary(offset,
        _helper.createVariableGet(read, fileOffset), binaryOperator, value);
    VariableDeclarationImpl write =
        _helper.createVariableDeclarationForValue(_createWrite(offset, binary));
    return new StaticPostIncDec(read, write)..fileOffset = offset;
  }

  @override
  Expression doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    if (_helper.constantContext != ConstantContext.none &&
        !_helper.isIdentical(readTarget) &&
        !_helper.enableConstFunctionsInLibrary) {
      return _helper.buildProblem(
          templateNotConstantExpression.withArguments('Method invocation'),
          offset,
          readTarget?.name.text.length ?? 0);
    }
    if (readTarget == null || isFieldOrGetter(readTarget!)) {
      return _helper.forest.createExpressionInvocation(
          offset + (readTarget?.name.text.length ?? 0),
          buildSimpleRead(),
          arguments);
    } else {
      return _helper.buildStaticInvocation(readTarget as Procedure, arguments,
          charOffset: offset);
    }
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
        isNullAware: isNullAware);
  }

  @override
  void printOn(StringSink sink) {
    sink.write(", targetName: ");
    sink.write(targetName);
    sink.write(", readTarget: ");
    printQualifiedNameOn(readTarget, sink);
    sink.write(", writeTarget: ");
    printQualifiedNameOn(writeTarget, sink);
  }
}

/// An [ExtensionInstanceAccessGenerator] represents a subexpression whose
/// prefix is an extension instance member.
///
/// For instance
///
///   class A {}
///   extension B on A {
///     get property => 0;
///     set property(_) {}
///     method() {
///       property;     // this generator is created for `property`.
///       property = 0; // this generator is created for `property`.
///       method;       // this generator is created for `method`.
///       method();     // this generator is created for `method`.
///     }
///   }
///
/// These can only occur within an extension instance member.
class ExtensionInstanceAccessGenerator extends Generator {
  final Extension extension;

  /// The original name of the target.
  final String targetName;

  /// The static [Member] generated for an instance extension member which is
  /// used for performing a read on this subexpression.
  ///
  /// This can be `null` if the subexpression doesn't have a readable target.
  /// For instance if the subexpression is a setter without a corresponding
  /// getter.
  final Procedure? readTarget;

  /// The static [Member] generated for an instance extension member which is
  /// used for performing an invocation on this subexpression.
  ///
  /// This can be `null` if the subexpression doesn't have an invokable target.
  /// For instance if the subexpression is a getter or setter.
  final Procedure? invokeTarget;

  /// The static [Member] generated for an instance extension member which is
  /// used for performing a write on this subexpression.
  ///
  /// This can be `null` if the subexpression doesn't have a writable target.
  /// For instance if the subexpression is a final field, a method, or a getter
  /// without a corresponding setter.
  final Procedure? writeTarget;

  /// The parameter holding the value for `this` within the current extension
  /// instance method.
  // TODO(johnniwinther): Handle static access to extension instance members,
  // in which case the access is erroneous and [extensionThis] is `null`.
  final VariableDeclaration extensionThis;

  /// The type parameters synthetically added to  the current extension
  /// instance method.
  final List<TypeParameter>? extensionTypeParameters;

  ExtensionInstanceAccessGenerator(
      ExpressionGeneratorHelper helper,
      Token token,
      this.extension,
      this.targetName,
      this.readTarget,
      this.invokeTarget,
      this.writeTarget,
      this.extensionThis,
      this.extensionTypeParameters)
      // ignore: unnecessary_null_comparison
      : assert(targetName != null),
        assert(
            readTarget != null || invokeTarget != null || writeTarget != null),
        // ignore: unnecessary_null_comparison
        assert(extensionThis != null),
        super(helper, token);

  factory ExtensionInstanceAccessGenerator.fromBuilder(
      ExpressionGeneratorHelper helper,
      Token token,
      Extension extension,
      String? targetName,
      VariableDeclaration extensionThis,
      List<TypeParameter>? extensionTypeParameters,
      MemberBuilder? getterBuilder,
      MemberBuilder? setterBuilder) {
    Procedure? readTarget;
    Procedure? invokeTarget;
    if (getterBuilder != null) {
      if (getterBuilder.isGetter) {
        assert(!getterBuilder.isStatic);
        readTarget = getterBuilder.readTarget as Procedure?;
      } else if (getterBuilder.isRegularMethod) {
        assert(!getterBuilder.isStatic);
        readTarget = getterBuilder.readTarget as Procedure?;
        invokeTarget = getterBuilder.invokeTarget as Procedure?;
      } else if (getterBuilder.isOperator) {
        assert(!getterBuilder.isStatic);
        invokeTarget = getterBuilder.invokeTarget as Procedure?;
      }
    }
    Procedure? writeTarget;
    if (setterBuilder != null) {
      if (setterBuilder.isSetter) {
        assert(!setterBuilder.isStatic);
        writeTarget = setterBuilder.writeTarget as Procedure?;
        targetName ??= setterBuilder.name;
      } else {
        return unhandled(
            "${setterBuilder.runtimeType}",
            "ExtensionInstanceAccessGenerator.fromBuilder",
            offsetForToken(token),
            helper.uri);
      }
    }
    return new ExtensionInstanceAccessGenerator(
        helper,
        token,
        extension,
        targetName!,
        readTarget,
        invokeTarget,
        writeTarget,
        extensionThis,
        extensionTypeParameters);
  }

  @override
  String get _debugName => "InstanceExtensionAccessGenerator";

  @override
  String get _plainNameForRead => targetName;

  int get _extensionTypeParameterCount => extensionTypeParameters?.length ?? 0;

  List<DartType> _createExtensionTypeArguments() {
    List<DartType> extensionTypeArguments = const <DartType>[];
    if (extensionTypeParameters != null) {
      extensionTypeArguments = [];
      for (TypeParameter typeParameter in extensionTypeParameters!) {
        extensionTypeArguments.add(
            _forest.createTypeParameterTypeWithDefaultNullabilityForLibrary(
                typeParameter, extension.enclosingLibrary));
      }
    }
    return extensionTypeArguments;
  }

  @override
  Expression buildSimpleRead() {
    return _createRead();
  }

  Expression _createRead() {
    Expression read;
    if (readTarget == null) {
      read = _makeInvalidRead();
    } else {
      read = _helper.buildExtensionMethodInvocation(
          fileOffset,
          readTarget!,
          _helper.forest.createArgumentsForExtensionMethod(
              fileOffset,
              _extensionTypeParameterCount,
              0,
              _helper.createVariableGet(extensionThis, fileOffset),
              extensionTypeArguments: _createExtensionTypeArguments()),
          isTearOff: invokeTarget != null);
    }
    return read;
  }

  @override
  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return _createWrite(fileOffset, value, forEffect: voidContext);
  }

  Expression _createWrite(int offset, Expression value,
      {required bool forEffect}) {
    Expression write;
    if (writeTarget == null) {
      write = _makeInvalidWrite(value);
    } else {
      write = new ExtensionSet(
          extension,
          _createExtensionTypeArguments(),
          _helper.createVariableGet(extensionThis, fileOffset),
          writeTarget!,
          value,
          forEffect: forEffect);
    }
    write.fileOffset = offset;
    return write;
  }

  @override
  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    return new IfNullSet(
        _createRead(), _createWrite(fileOffset, value, forEffect: voidContext),
        forEffect: voidContext)
      ..fileOffset = offset;
  }

  @override
  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    Expression binary = _helper.forest
        .createBinary(offset, _createRead(), binaryOperator, value);
    return _createWrite(fileOffset, binary, forEffect: voidContext);
  }

  @override
  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset = TreeNode.noOffset, bool voidContext = false}) {
    Expression value = _forest.createIntLiteral(offset, 1);
    if (voidContext) {
      return buildCompoundAssignment(binaryOperator, value,
          offset: offset, voidContext: voidContext, isPostIncDec: true);
    }
    VariableDeclarationImpl read =
        _helper.createVariableDeclarationForValue(_createRead());
    Expression binary = _helper.forest.createBinary(offset,
        _helper.createVariableGet(read, fileOffset), binaryOperator, value);
    VariableDeclarationImpl write = _helper.createVariableDeclarationForValue(
        _createWrite(fileOffset, binary, forEffect: true));
    return new PropertyPostIncDec.onReadOnly(read, write)..fileOffset = offset;
  }

  @override
  Expression doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    if (invokeTarget != null) {
      return _helper.buildExtensionMethodInvocation(
          offset,
          invokeTarget!,
          _forest.createArgumentsForExtensionMethod(
              fileOffset,
              _extensionTypeParameterCount,
              invokeTarget!.function.typeParameters.length -
                  _extensionTypeParameterCount,
              _helper.createVariableGet(extensionThis, offset),
              extensionTypeArguments: _createExtensionTypeArguments(),
              typeArguments: arguments.types,
              positionalArguments: arguments.positional,
              namedArguments: arguments.named),
          isTearOff: false);
    } else {
      return _helper.forest.createExpressionInvocation(
          adjustForImplicitCall(_plainNameForRead, offset),
          buildSimpleRead(),
          arguments);
    }
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
        isNullAware: isNullAware);
  }

  @override
  void printOn(StringSink sink) {
    sink.write(", targetName: ");
    sink.write(targetName);
    sink.write(", readTarget: ");
    printQualifiedNameOn(readTarget, sink);
    sink.write(", writeTarget: ");
    printQualifiedNameOn(writeTarget, sink);
  }
}

/// A [ExplicitExtensionInstanceAccessGenerator] represents a subexpression
/// whose prefix is a forced extension instance member access.
///
/// For instance
///
///   class A<T> {}
///   extension B on A<int> {
///     method() {}
///   }
///   extension C<T> {
///     T get field => 0;
///     set field(T _) {}
///   }
///
///   method(A a) {
///     B(a).method;     // this generator is created for `B(a).method`.
///     B(a).method();   // this generator is created for `B(a).method`.
///     C<int>(a).field; // this generator is created for `C<int>(a).field`.
///     C(a).field = 0;  // this generator is created for `C(a).field`.
///   }
///
class ExplicitExtensionInstanceAccessGenerator extends Generator {
  /// The file offset used for the explicit extension application type
  /// arguments.
  final int extensionTypeArgumentOffset;

  final Extension extension;

  /// The name of the original target;
  final Name targetName;

  /// The static [Member] generated for an instance extension member which is
  /// used for performing a read on this subexpression.
  ///
  /// This can be `null` if the subexpression doesn't have a readable target.
  /// For instance if the subexpression is a setter without a corresponding
  /// getter.
  final Procedure? readTarget;

  /// The static [Member] generated for an instance extension member which is
  /// used for performing an invocation on this subexpression.
  ///
  /// This can be `null` if the subexpression doesn't have an invokable target.
  /// For instance if the subexpression is a getter or setter.
  final Procedure? invokeTarget;

  /// The static [Member] generated for an instance extension member which is
  /// used for performing a write on this subexpression.
  ///
  /// This can be `null` if the subexpression doesn't have a writable target.
  /// For instance if the subexpression is a final field, a method, or a getter
  /// without a corresponding setter.
  final Procedure? writeTarget;

  /// The expression holding the receiver value for the explicit extension
  /// access, that is, `a` in `Extension<int>(a).method<String>()`.
  final Expression receiver;

  /// The type arguments explicitly passed to the explicit extension access,
  /// like `<int>` in `Extension<int>(a).method<String>()`.
  final List<DartType>? explicitTypeArguments;

  /// The number of type parameters declared on the extension declaration.
  final int extensionTypeParameterCount;

  /// If `true` the access is null-aware, like `Extension(c)?.foo`.
  final bool isNullAware;

  ExplicitExtensionInstanceAccessGenerator(
      ExpressionGeneratorHelper helper,
      Token token,
      this.extensionTypeArgumentOffset,
      this.extension,
      this.targetName,
      this.readTarget,
      this.invokeTarget,
      this.writeTarget,
      this.receiver,
      this.explicitTypeArguments,
      this.extensionTypeParameterCount,
      {required this.isNullAware})
      // ignore: unnecessary_null_comparison
      : assert(targetName != null),
        assert(
            readTarget != null || invokeTarget != null || writeTarget != null),
        // ignore: unnecessary_null_comparison
        assert(receiver != null),
        // ignore: unnecessary_null_comparison
        assert(isNullAware != null),
        super(helper, token);

  factory ExplicitExtensionInstanceAccessGenerator.fromBuilder(
      ExpressionGeneratorHelper helper,
      Token token,
      int extensionTypeArgumentOffset,
      Extension extension,
      Name targetName,
      Builder? getterBuilder,
      Builder? setterBuilder,
      Expression receiver,
      List<DartType>? explicitTypeArguments,
      int extensionTypeParameterCount,
      {required bool isNullAware}) {
    assert(getterBuilder != null || setterBuilder != null);
    Procedure? readTarget;
    Procedure? invokeTarget;
    if (getterBuilder != null) {
      assert(!getterBuilder.isStatic);
      if (getterBuilder is AccessErrorBuilder) {
        AccessErrorBuilder error = getterBuilder;
        getterBuilder = error.builder;
        // We should only see an access error here if we've looked up a setter
        // when not explicitly looking for a setter.
        assert(getterBuilder.isSetter);
      } else if (getterBuilder.isGetter) {
        assert(!getterBuilder.isStatic);
        MemberBuilder memberBuilder = getterBuilder as MemberBuilder;
        readTarget = memberBuilder.readTarget as Procedure?;
      } else if (getterBuilder.isRegularMethod) {
        assert(!getterBuilder.isStatic);
        MemberBuilder procedureBuilder = getterBuilder as MemberBuilder;
        readTarget = procedureBuilder.readTarget as Procedure?;
        invokeTarget = procedureBuilder.invokeTarget as Procedure?;
      } else if (getterBuilder.isOperator) {
        assert(!getterBuilder.isStatic);
        MemberBuilder memberBuilder = getterBuilder as MemberBuilder;
        invokeTarget = memberBuilder.invokeTarget as Procedure?;
      } else {
        return unhandled(
            "$getterBuilder (${getterBuilder.runtimeType})",
            "InstanceExtensionAccessGenerator.fromBuilder",
            offsetForToken(token),
            helper.uri);
      }
    }
    Procedure? writeTarget;
    if (setterBuilder != null) {
      assert(!setterBuilder.isStatic);
      if (setterBuilder is AccessErrorBuilder) {
        // No setter.
      } else if (setterBuilder.isSetter) {
        assert(!setterBuilder.isStatic);
        MemberBuilder memberBuilder = setterBuilder as MemberBuilder;
        writeTarget = memberBuilder.writeTarget as Procedure?;
      } else {
        return unhandled(
            "$setterBuilder (${setterBuilder.runtimeType})",
            "InstanceExtensionAccessGenerator.fromBuilder",
            offsetForToken(token),
            helper.uri);
      }
    }
    return new ExplicitExtensionInstanceAccessGenerator(
        helper,
        token,
        extensionTypeArgumentOffset,
        extension,
        targetName,
        readTarget,
        invokeTarget,
        writeTarget,
        receiver,
        explicitTypeArguments,
        extensionTypeParameterCount,
        isNullAware: isNullAware);
  }

  @override
  String get _debugName => "ExplicitExtensionIndexedAccessGenerator";

  @override
  String get _plainNameForRead => targetName.text;

  List<DartType> _createExtensionTypeArguments() {
    return explicitTypeArguments ?? const <DartType>[];
  }

  /// Returns `true` if performing a read operation is a tear off.
  ///
  /// This is the case if [invokeTarget] is non-null, since extension methods
  /// have both a [readTarget] and an [invokeTarget], whereas extension getters
  /// only have a [readTarget].
  bool get isReadTearOff => invokeTarget != null;

  @override
  Expression buildSimpleRead() {
    if (isNullAware) {
      VariableDeclarationImpl variable =
          _helper.createVariableDeclarationForValue(receiver);
      return new NullAwareExtension(
          variable,
          _createRead(_helper.createVariableGet(variable, variable.fileOffset,
              forNullGuardedAccess: true)))
        ..fileOffset = fileOffset;
    } else {
      return _createRead(receiver);
    }
  }

  Expression _createRead(Expression receiver) {
    Expression read;
    if (readTarget == null) {
      read = _makeInvalidRead();
    } else {
      read = _helper.buildExtensionMethodInvocation(
          fileOffset,
          readTarget!,
          _helper.forest.createArgumentsForExtensionMethod(
              fileOffset, extensionTypeParameterCount, 0, receiver,
              extensionTypeArguments: _createExtensionTypeArguments(),
              extensionTypeArgumentOffset: extensionTypeArgumentOffset),
          isTearOff: isReadTearOff);
    }
    return read;
  }

  @override
  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    if (isNullAware) {
      VariableDeclarationImpl variable =
          _helper.createVariableDeclarationForValue(receiver);
      return new NullAwareExtension(
          variable,
          _createWrite(
              fileOffset,
              _helper.createVariableGet(variable, variable.fileOffset,
                  forNullGuardedAccess: true),
              value,
              forEffect: voidContext))
        ..fileOffset = fileOffset;
    } else {
      return _createWrite(fileOffset, receiver, value, forEffect: voidContext);
    }
  }

  Expression _createWrite(int offset, Expression receiver, Expression value,
      {required bool forEffect}) {
    Expression write;
    if (writeTarget == null) {
      write = _makeInvalidWrite(value);
    } else {
      write = new ExtensionSet(
          extension, explicitTypeArguments, receiver, writeTarget!, value,
          forEffect: forEffect);
    }
    write.fileOffset = offset;
    return write;
  }

  @override
  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    if (isNullAware) {
      VariableDeclarationImpl variable =
          _helper.createVariableDeclarationForValue(receiver);
      Expression read = _createRead(_helper.createVariableGet(
          variable, receiver.fileOffset,
          forNullGuardedAccess: true));
      Expression write = _createWrite(
          fileOffset,
          _helper.createVariableGet(variable, receiver.fileOffset,
              forNullGuardedAccess: true),
          value,
          forEffect: voidContext);
      return new NullAwareExtension(
          variable,
          new IfNullSet(read, write, forEffect: voidContext)
            ..fileOffset = offset)
        ..fileOffset = fileOffset;
    } else {
      return new IfNullPropertySet(receiver, targetName, value,
          forEffect: voidContext,
          readOffset: fileOffset,
          writeOffset: fileOffset)
        ..fileOffset = offset;
    }
  }

  @override
  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    if (isNullAware) {
      VariableDeclarationImpl variable =
          _helper.createVariableDeclarationForValue(receiver);
      Expression binary = _helper.forest.createBinary(
          offset,
          _createRead(_helper.createVariableGet(variable, receiver.fileOffset,
              forNullGuardedAccess: true)),
          binaryOperator,
          value);
      Expression write = _createWrite(
          fileOffset,
          _helper.createVariableGet(variable, receiver.fileOffset,
              forNullGuardedAccess: true),
          binary,
          forEffect: voidContext);
      return new NullAwareExtension(variable, write)..fileOffset = offset;
    } else {
      return new CompoundExtensionSet(extension, explicitTypeArguments,
          receiver, targetName, readTarget, binaryOperator, value, writeTarget,
          forEffect: voidContext,
          readOffset: fileOffset,
          binaryOffset: offset,
          writeOffset: fileOffset)
        ..fileOffset = offset;
    }
  }

  @override
  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset = TreeNode.noOffset, bool voidContext = false}) {
    Expression value = _forest.createIntLiteral(offset, 1);
    if (voidContext) {
      return buildCompoundAssignment(binaryOperator, value,
          offset: offset, voidContext: voidContext, isPostIncDec: true);
    } else if (isNullAware) {
      VariableDeclarationImpl variable =
          _helper.createVariableDeclarationForValue(receiver);
      VariableDeclarationImpl read = _helper.createVariableDeclarationForValue(
          _createRead(_helper.createVariableGet(variable, receiver.fileOffset,
              forNullGuardedAccess: true)));
      Expression binary = _helper.forest.createBinary(offset,
          _helper.createVariableGet(read, fileOffset), binaryOperator, value);
      VariableDeclarationImpl write = _helper.createVariableDeclarationForValue(
          _createWrite(
              fileOffset,
              _helper.createVariableGet(variable, receiver.fileOffset,
                  forNullGuardedAccess: true),
              binary,
              forEffect: voidContext)
            ..fileOffset = fileOffset);
      return new NullAwareExtension(
          variable, new LocalPostIncDec(read, write)..fileOffset = offset)
        ..fileOffset = fileOffset;
    } else {
      VariableDeclarationImpl variable =
          _helper.createVariableDeclarationForValue(receiver);
      VariableDeclarationImpl read = _helper.createVariableDeclarationForValue(
          _createRead(
              _helper.createVariableGet(variable, receiver.fileOffset)));
      Expression binary = _helper.forest.createBinary(offset,
          _helper.createVariableGet(read, fileOffset), binaryOperator, value);
      VariableDeclarationImpl write = _helper.createVariableDeclarationForValue(
          _createWrite(fileOffset,
              _helper.createVariableGet(variable, receiver.fileOffset), binary,
              forEffect: voidContext)
            ..fileOffset = fileOffset);
      return new PropertyPostIncDec(variable, read, write)..fileOffset = offset;
    }
  }

  @override
  Expression doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    VariableDeclarationImpl? receiverVariable;
    Expression receiverExpression = receiver;
    if (isNullAware) {
      receiverVariable = _helper.createVariableDeclarationForValue(receiver);
      receiverExpression = _helper.createVariableGet(
          receiverVariable, receiverVariable.fileOffset,
          forNullGuardedAccess: true);
    }
    Expression invocation;
    if (invokeTarget != null) {
      invocation = _helper.buildExtensionMethodInvocation(
          fileOffset,
          invokeTarget!,
          _forest.createArgumentsForExtensionMethod(
              fileOffset,
              extensionTypeParameterCount,
              invokeTarget!.function.typeParameters.length -
                  extensionTypeParameterCount,
              receiverExpression,
              extensionTypeArguments: _createExtensionTypeArguments(),
              extensionTypeArgumentOffset: extensionTypeArgumentOffset,
              typeArguments: arguments.types,
              positionalArguments: arguments.positional,
              namedArguments: arguments.named),
          isTearOff: false);
    } else {
      invocation = _helper.forest.createExpressionInvocation(
          adjustForImplicitCall(_plainNameForRead, offset),
          _createRead(receiverExpression),
          arguments);
    }
    if (isNullAware) {
      assert(receiverVariable != null);
      return new NullAwareExtension(receiverVariable!, invocation)
        ..fileOffset = fileOffset;
    } else {
      return invocation;
    }
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
        isNullAware: isNullAware);
  }

  @override
  void printOn(StringSink sink) {
    sink.write(", targetName: ");
    sink.write(targetName);
    sink.write(", readTarget: ");
    printQualifiedNameOn(readTarget, sink);
    sink.write(", writeTarget: ");
    printQualifiedNameOn(writeTarget, sink);
  }
}

class ExplicitExtensionIndexedAccessGenerator extends Generator {
  /// The file offset used for the explicit extension application type
  /// arguments.
  final int extensionTypeArgumentOffset;

  final Extension extension;

  /// The static [Member] generated for the [] operation.
  ///
  /// This can be `null` if the extension doesn't have an [] method.
  final Procedure? readTarget;

  /// The static [Member] generated for the []= operation.
  ///
  /// This can be `null` if the extension doesn't have an []= method.
  final Procedure? writeTarget;

  /// The expression holding the receiver value for the explicit extension
  /// access, that is, `a` in `Extension<int>(a)[index]`.
  final Expression receiver;

  /// The index expression;
  final Expression index;

  /// The type arguments explicitly passed to the explicit extension access,
  /// like `<int>` in `Extension<int>(a)[b]`.
  final List<DartType>? explicitTypeArguments;

  /// The number of type parameters declared on the extension declaration.
  final int extensionTypeParameterCount;

  final bool isNullAware;

  ExplicitExtensionIndexedAccessGenerator(
      ExpressionGeneratorHelper helper,
      Token token,
      this.extensionTypeArgumentOffset,
      this.extension,
      this.readTarget,
      this.writeTarget,
      this.receiver,
      this.index,
      this.explicitTypeArguments,
      this.extensionTypeParameterCount,
      {required this.isNullAware})
      : assert(readTarget != null || writeTarget != null),
        // ignore: unnecessary_null_comparison
        assert(receiver != null),
        // ignore: unnecessary_null_comparison
        assert(isNullAware != null),
        super(helper, token);

  factory ExplicitExtensionIndexedAccessGenerator.fromBuilder(
      ExpressionGeneratorHelper helper,
      Token token,
      int extensionTypeArgumentOffset,
      Extension extension,
      Builder? getterBuilder,
      Builder? setterBuilder,
      Expression receiver,
      Expression index,
      List<DartType>? explicitTypeArguments,
      int extensionTypeParameterCount,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    Procedure? readTarget;
    if (getterBuilder != null) {
      if (getterBuilder is AccessErrorBuilder) {
        AccessErrorBuilder error = getterBuilder;
        getterBuilder = error.builder;
        // We should only see an access error here if we've looked up a setter
        // when not explicitly looking for a setter.
        assert(getterBuilder is MemberBuilder);
      } else if (getterBuilder is MemberBuilder) {
        MemberBuilder procedureBuilder = getterBuilder;
        readTarget = procedureBuilder.member as Procedure?;
      } else {
        return unhandled(
            "${getterBuilder.runtimeType}",
            "InstanceExtensionAccessGenerator.fromBuilder",
            offsetForToken(token),
            helper.uri);
      }
    }
    Procedure? writeTarget;
    if (setterBuilder is MemberBuilder) {
      MemberBuilder memberBuilder = setterBuilder;
      writeTarget = memberBuilder.member as Procedure?;
    }
    return new ExplicitExtensionIndexedAccessGenerator(
        helper,
        token,
        extensionTypeArgumentOffset,
        extension,
        readTarget,
        writeTarget,
        receiver,
        index,
        explicitTypeArguments,
        extensionTypeParameterCount,
        isNullAware: isNullAware);
  }

  List<DartType> _createExtensionTypeArguments() {
    return explicitTypeArguments ?? const <DartType>[];
  }

  String get _plainNameForRead => "[]";

  String get _debugName => "ExplicitExtensionIndexedAccessGenerator";

  @override
  Expression buildSimpleRead() {
    if (readTarget == null) {
      return _makeInvalidRead();
    }
    VariableDeclarationImpl? variable;
    Expression receiverValue;
    if (isNullAware) {
      variable = _helper.createVariableDeclarationForValue(receiver);
      receiverValue = _helper.createVariableGet(variable, fileOffset,
          forNullGuardedAccess: true);
    } else {
      receiverValue = receiver;
    }
    Expression result = _helper.buildExtensionMethodInvocation(
        fileOffset,
        readTarget!,
        _forest.createArgumentsForExtensionMethod(
            fileOffset, extensionTypeParameterCount, 0, receiverValue,
            extensionTypeArguments: _createExtensionTypeArguments(),
            extensionTypeArgumentOffset: extensionTypeArgumentOffset,
            positionalArguments: <Expression>[index]),
        isTearOff: false);
    if (isNullAware) {
      result = new NullAwareMethodInvocation(variable!, result)
        ..fileOffset = fileOffset;
    }
    return result;
  }

  @override
  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    if (writeTarget == null) {
      return _makeInvalidWrite(value);
    }
    VariableDeclarationImpl? variable;
    Expression receiverValue;
    if (isNullAware) {
      variable = _helper.createVariableDeclarationForValue(receiver);
      receiverValue = _helper.createVariableGet(variable, fileOffset,
          forNullGuardedAccess: true);
    } else {
      receiverValue = receiver;
    }
    Expression result;
    if (voidContext) {
      result = _helper.buildExtensionMethodInvocation(
          fileOffset,
          writeTarget!,
          _forest.createArgumentsForExtensionMethod(
              fileOffset, extensionTypeParameterCount, 0, receiverValue,
              extensionTypeArguments: _createExtensionTypeArguments(),
              extensionTypeArgumentOffset: extensionTypeArgumentOffset,
              positionalArguments: <Expression>[index, value]),
          isTearOff: false);
    } else {
      result = new ExtensionIndexSet(extension, explicitTypeArguments,
          receiverValue, writeTarget!, index, value)
        ..fileOffset = fileOffset;
    }
    if (isNullAware) {
      result = new NullAwareMethodInvocation(variable!, result)
        ..fileOffset = fileOffset;
    }
    return result;
  }

  @override
  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    VariableDeclarationImpl? variable;
    Expression receiverValue;
    if (isNullAware) {
      variable = _helper.createVariableDeclarationForValue(receiver);
      receiverValue = _helper.createVariableGet(variable, fileOffset,
          forNullGuardedAccess: true);
    } else {
      receiverValue = receiver;
    }
    Expression result = new IfNullExtensionIndexSet(
        extension,
        explicitTypeArguments,
        receiverValue,
        readTarget,
        writeTarget,
        index,
        value,
        readOffset: fileOffset,
        testOffset: offset,
        writeOffset: fileOffset,
        forEffect: voidContext)
      ..fileOffset = offset;
    if (isNullAware) {
      result = new NullAwareMethodInvocation(variable!, result)
        ..fileOffset = fileOffset;
    }
    return result;
  }

  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    VariableDeclarationImpl? variable;
    Expression receiverValue;
    if (isNullAware) {
      variable = _helper.createVariableDeclarationForValue(receiver);
      receiverValue = _helper.createVariableGet(variable, fileOffset,
          forNullGuardedAccess: true);
    } else {
      receiverValue = receiver;
    }
    Expression result = new CompoundExtensionIndexSet(
        extension,
        explicitTypeArguments,
        receiverValue,
        readTarget,
        writeTarget,
        index,
        binaryOperator,
        value,
        readOffset: fileOffset,
        binaryOffset: offset,
        writeOffset: fileOffset,
        forEffect: voidContext,
        forPostIncDec: isPostIncDec);
    if (isNullAware) {
      result = new NullAwareMethodInvocation(variable!, result)
        ..fileOffset = fileOffset;
    }
    return result;
  }

  @override
  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset = TreeNode.noOffset, bool voidContext = false}) {
    Expression value = _forest.createIntLiteral(offset, 1);
    return buildCompoundAssignment(binaryOperator, value,
        offset: offset, voidContext: voidContext, isPostIncDec: true);
  }

  @override
  Expression doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    return _helper.forest
        .createExpressionInvocation(offset, buildSimpleRead(), arguments);
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
        isNullAware: isNullAware);
  }

  @override
  void printOn(StringSink sink) {
    NameSystem syntheticNames = new NameSystem();
    sink.write(", index: ");
    printNodeOn(index, sink, syntheticNames: syntheticNames);
    sink.write(", readTarget: ");
    printQualifiedNameOn(readTarget, sink);
    sink.write(", writeTarget: ");
    printQualifiedNameOn(writeTarget, sink);
  }
}

/// A [ExplicitExtensionAccessGenerator] represents a subexpression whose
/// prefix is an explicit extension application.
///
/// For instance
///
///   class A<T> {}
///   extension B on A<int> {
///     method() {}
///   }
///   extension C<T> on A<T> {
///     T get field => 0;
///     set field(T _) {}
///   }
///
///   method(A a) {
///     B(a).method;     // this generator is created for `B(a)`.
///     B(a).method();   // this generator is created for `B(a)`.
///     C<int>(a).field; // this generator is created for `C<int>(a)`.
///     C(a).field = 0;  // this generator is created for `C(a)`.
///   }
///
/// When an access is performed on this generator a
/// [ExplicitExtensionInstanceAccessGenerator] is created.
class ExplicitExtensionAccessGenerator extends Generator {
  final ExtensionBuilder extensionBuilder;
  final Expression receiver;
  final List<DartType>? explicitTypeArguments;

  ExplicitExtensionAccessGenerator(
      ExpressionGeneratorHelper helper,
      Token token,
      this.extensionBuilder,
      this.receiver,
      this.explicitTypeArguments)
      : super(helper, token);

  @override
  String get _plainNameForRead {
    return unsupported(
        "ExplicitExtensionAccessGenerator.plainNameForRead", fileOffset, _uri);
  }

  @override
  String get _debugName => "ExplicitExtensionAccessGenerator";

  @override
  Expression buildSimpleRead() {
    return _makeInvalidRead();
  }

  @override
  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return _makeInvalidWrite(value);
  }

  @override
  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    return _makeInvalidRead();
  }

  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    return _makeInvalidRead();
  }

  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset: TreeNode.noOffset, bool voidContext: false}) {
    return _makeInvalidRead();
  }

  Generator _createInstanceAccess(Token token, Name name,
      {bool isNullAware: false}) {
    Builder? getter = extensionBuilder.lookupLocalMemberByName(name);
    if (getter != null && (getter.isStatic || getter.isField)) {
      getter = null;
    }
    Builder? setter =
        extensionBuilder.lookupLocalMemberByName(name, setter: true);
    if (setter != null && setter.isStatic) {
      setter = null;
    }
    if (getter == null && setter == null) {
      return new UnresolvedNameGenerator(_helper, token, name);
    }
    return new ExplicitExtensionInstanceAccessGenerator.fromBuilder(
        _helper,
        token,
        // TODO(johnniwinther): Improve this. This is the name of the extension
        // and not the type arguments (or arguments if type arguments are
        // omitted).
        fileOffset,
        extensionBuilder.extension,
        name,
        getter,
        setter,
        receiver,
        explicitTypeArguments,
        extensionBuilder.typeParameters?.length ?? 0,
        isNullAware: isNullAware);
  }

  /* Expression | Generator */ buildPropertyAccess(
      IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
    if (_helper.constantContext != ConstantContext.none) {
      _helper.addProblem(
          messageNotAConstantExpression, fileOffset, token.length);
    }
    Generator generator =
        _createInstanceAccess(send.token, send.name, isNullAware: isNullAware);
    if (send.arguments != null) {
      return generator.doInvocation(
          offsetForToken(send.token), send.typeArguments, send.arguments!,
          isTypeArgumentsInForest: send.isTypeArgumentsInForest);
    } else {
      return generator;
    }
  }

  @override
  buildBinaryOperation(Token token, Name binaryName, Expression right) {
    int fileOffset = offsetForToken(token);
    Generator generator = _createInstanceAccess(token, binaryName);
    return generator.doInvocation(fileOffset, null,
        _forest.createArguments(fileOffset, <Expression>[right]));
  }

  @override
  buildUnaryOperation(Token token, Name unaryName) {
    int fileOffset = offsetForToken(token);
    Generator generator = _createInstanceAccess(token, unaryName);
    return generator.doInvocation(
        fileOffset, null, _forest.createArgumentsEmpty(fileOffset));
  }

  @override
  doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    Generator generator = _createInstanceAccess(token, callName);
    return generator.doInvocation(offset, typeArguments, arguments,
        isTypeArgumentsInForest: isTypeArgumentsInForest);
  }

  @override
  Expression _makeInvalidRead() {
    return _helper.buildProblem(messageExplicitExtensionAsExpression,
        fileOffset, lengthForToken(token));
  }

  @override
  Expression _makeInvalidWrite(Expression value) {
    return _helper.buildProblem(
        messageExplicitExtensionAsLvalue, fileOffset, lengthForToken(token));
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    Builder? getter = extensionBuilder.lookupLocalMemberByName(indexGetName);
    Builder? setter = extensionBuilder.lookupLocalMemberByName(indexSetName);
    if (getter == null && setter == null) {
      return new UnresolvedNameGenerator(_helper, token, indexGetName);
    }

    return new ExplicitExtensionIndexedAccessGenerator.fromBuilder(
        _helper,
        token,
        // TODO(johnniwinther): Improve this. This is the name of the extension
        // and not the type arguments (or arguments if type arguments are
        // omitted).
        fileOffset,
        extensionBuilder.extension,
        getter,
        setter,
        receiver,
        index,
        explicitTypeArguments,
        extensionBuilder.typeParameters?.length ?? 0,
        isNullAware: isNullAware);
  }

  @override
  void printOn(StringSink sink) {
    sink.write(", extensionBuilder: ");
    sink.write(extensionBuilder);
    sink.write(", receiver: ");
    sink.write(receiver);
  }
}

class LoadLibraryGenerator extends Generator {
  final LoadLibraryBuilder builder;

  LoadLibraryGenerator(
      ExpressionGeneratorHelper helper, Token token, this.builder)
      : super(helper, token);

  @override
  String get _plainNameForRead => 'loadLibrary';

  @override
  String get _debugName => "LoadLibraryGenerator";

  @override
  Expression buildSimpleRead() {
    builder.importDependency.targetLibrary;
    LoadLibraryTearOff read = new LoadLibraryTearOff(
        builder.importDependency, builder.createTearoffMethod(_helper.forest))
      ..fileOffset = fileOffset;
    return read;
  }

  @override
  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return _makeInvalidWrite(value);
  }

  @override
  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    Expression read = buildSimpleRead();
    Expression write = _makeInvalidWrite(value);
    return new IfNullSet(read, write, forEffect: voidContext)
      ..fileOffset = offset;
  }

  @override
  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    Expression binary = _helper.forest
        .createBinary(offset, buildSimpleRead(), binaryOperator, value);
    return _makeInvalidWrite(binary);
  }

  @override
  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset = TreeNode.noOffset, bool voidContext = false}) {
    Expression value = _forest.createIntLiteral(offset, 1);
    return buildCompoundAssignment(binaryOperator, value,
        offset: offset, voidContext: voidContext, isPostIncDec: true);
  }

  @override
  Expression doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    if (_forest.argumentsPositional(arguments).length > 0 ||
        _forest.argumentsNamed(arguments).length > 0) {
      _helper.addProblemErrorIfConst(
          messageLoadLibraryTakesNoArguments, offset, 'loadLibrary'.length);
    }
    return builder.createLoadLibrary(offset, _forest, arguments);
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
        isNullAware: isNullAware);
  }

  @override
  void printOn(StringSink sink) {
    sink.write(", builder: ");
    sink.write(builder);
  }
}

class DeferredAccessGenerator extends Generator {
  final PrefixUseGenerator prefixGenerator;

  final Generator suffixGenerator;

  DeferredAccessGenerator(ExpressionGeneratorHelper helper, Token token,
      this.prefixGenerator, this.suffixGenerator)
      : super(helper, token);

  @override
  Expression buildSimpleRead() {
    return _helper.wrapInDeferredCheck(suffixGenerator.buildSimpleRead(),
        prefixGenerator.prefix, token.charOffset);
  }

  @override
  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return _helper.wrapInDeferredCheck(
        suffixGenerator.buildAssignment(value, voidContext: voidContext),
        prefixGenerator.prefix,
        token.charOffset);
  }

  @override
  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    return _helper.wrapInDeferredCheck(
        suffixGenerator.buildIfNullAssignment(value, type, offset,
            voidContext: voidContext),
        prefixGenerator.prefix,
        token.charOffset);
  }

  @override
  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    return _helper.wrapInDeferredCheck(
        suffixGenerator.buildCompoundAssignment(binaryOperator, value,
            offset: offset,
            voidContext: voidContext,
            isPreIncDec: isPreIncDec,
            isPostIncDec: isPostIncDec),
        prefixGenerator.prefix,
        token.charOffset);
  }

  @override
  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset: TreeNode.noOffset, bool voidContext: false}) {
    return _helper.wrapInDeferredCheck(
        suffixGenerator.buildPostfixIncrement(binaryOperator,
            offset: offset, voidContext: voidContext),
        prefixGenerator.prefix,
        token.charOffset);
  }

  @override
  buildPropertyAccess(
      IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
    Object propertyAccess =
        suffixGenerator.buildPropertyAccess(send, operatorOffset, isNullAware);
    if (propertyAccess is Generator) {
      return new DeferredAccessGenerator(
          _helper, token, prefixGenerator, propertyAccess);
    } else {
      Expression expression = propertyAccess as Expression;
      return _helper.wrapInDeferredCheck(
          expression, prefixGenerator.prefix, token.charOffset);
    }
  }

  @override
  String get _plainNameForRead {
    return unsupported("deferredAccessor.plainNameForRead", fileOffset, _uri);
  }

  @override
  String get _debugName => "DeferredAccessGenerator";

  @override
  TypeBuilder buildTypeWithResolvedArguments(
      NullabilityBuilder nullabilityBuilder, List<UnresolvedType>? arguments) {
    String name = "${prefixGenerator._plainNameForRead}."
        "${suffixGenerator._plainNameForRead}";
    TypeBuilder type = suffixGenerator.buildTypeWithResolvedArguments(
        nullabilityBuilder, arguments);
    LocatedMessage message;
    if (type is NamedTypeBuilder &&
        type.declaration is InvalidTypeDeclarationBuilder) {
      InvalidTypeDeclarationBuilder declaration =
          type.declaration as InvalidTypeDeclarationBuilder;
      message = declaration.message;
    } else {
      int charOffset = offsetForToken(prefixGenerator.token);
      message = templateDeferredTypeAnnotation
          .withArguments(
              _helper.buildDartType(new UnresolvedType(type, charOffset, _uri)),
              prefixGenerator._plainNameForRead,
              _helper.libraryBuilder.isNonNullableByDefault)
          .withLocation(
              _uri, charOffset, lengthOfSpan(prefixGenerator.token, token));
    }
    // TODO(johnniwinther): Could we use a FixedTypeBuilder(InvalidType()) here?
    NamedTypeBuilder result = new NamedTypeBuilder(
        name,
        nullabilityBuilder,
        /* arguments = */ null,
        /* fileUri = */ null,
        /* charOffset = */ null);
    _helper.libraryBuilder.addProblem(
        message.messageObject, message.charOffset, message.length, message.uri);
    result.bind(result.buildInvalidTypeDeclarationBuilder(message));
    return result;
  }

  @override
  doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    Object suffix = suffixGenerator.doInvocation(
        offset, typeArguments, arguments,
        isTypeArgumentsInForest: isTypeArgumentsInForest);
    if (suffix is Expression) {
      return _helper.wrapInDeferredCheck(
          suffix, prefixGenerator.prefix, fileOffset);
    } else {
      return new DeferredAccessGenerator(
          _helper, token, prefixGenerator, suffix as Generator);
    }
  }

  @override
  Expression invokeConstructor(
      List<UnresolvedType>? typeArguments,
      String name,
      Arguments arguments,
      Token nameToken,
      Token nameLastToken,
      Constness constness) {
    return _helper.wrapInDeferredCheck(
        suffixGenerator.invokeConstructor(typeArguments, name, arguments,
            nameToken, nameLastToken, constness),
        prefixGenerator.prefix,
        offsetForToken(suffixGenerator.token));
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
        isNullAware: isNullAware);
  }

  @override
  void printOn(StringSink sink) {
    sink.write(", prefixGenerator: ");
    sink.write(prefixGenerator);
    sink.write(", suffixGenerator: ");
    sink.write(suffixGenerator);
  }
}

/// [TypeUseGenerator] represents the subexpression whose prefix is the name of
/// a class, enum, type variable, typedef, mixin declaration, extension
/// declaration or built-in type, like dynamic and void.
///
/// For instance:
///
///   class A<T> {}
///   typedef B = Function();
///   mixin C<T> on A<T> {}
///   extension D<T> on A<T> {}
///
///   method<T>() {
///     C<B>        // a TypeUseGenerator is created for `C` and `B`.
///     B b;        // a TypeUseGenerator is created for `B`.
///     D.foo();    // a TypeUseGenerator is created for `D`.
///     new A<T>(); // a TypeUseGenerator is created for `A` and `T`.
///     T();        // a TypeUseGenerator is created for `T`.
///   }
///
class TypeUseGenerator extends AbstractReadOnlyAccessGenerator {
  final TypeDeclarationBuilder declaration;
  List<UnresolvedType>? typeArguments;

  final String targetName;

  Expression? _expression;

  TypeUseGenerator(ExpressionGeneratorHelper helper, Token token,
      this.declaration, this.targetName)
      : super(
            helper,
            token,
            // TODO(johnniwinther): InvalidTypeDeclarationBuilder is currently
            // misused for import conflict.
            declaration is InvalidTypeDeclarationBuilder
                ? ReadOnlyAccessKind.InvalidDeclaration
                : ReadOnlyAccessKind.TypeLiteral);

  @override
  String get _debugName => "TypeUseGenerator";

  @override
  TypeBuilder buildTypeWithResolvedArguments(
      NullabilityBuilder nullabilityBuilder, List<UnresolvedType>? arguments) {
    if (declaration.isExtension && !_helper.enableExtensionTypesInLibrary) {
      // Extension declarations cannot be used as types.
      return super
          .buildTypeWithResolvedArguments(nullabilityBuilder, arguments);
    }
    if (arguments != null) {
      int expected = declaration.typeVariablesCount;
      if (arguments.length != expected) {
        // Build the type arguments to report any errors they may have.
        _helper.buildDartTypeArguments(arguments);
        _helper.warnTypeArgumentsMismatch(
            declaration.name, expected, fileOffset);
        // We ignore the provided arguments, which will in turn return the
        // raw type below.
        // TODO(sigmund): change to use an InvalidType and include the raw type
        // as a recovery node once the IR can represent it (Issue #29840).
        arguments = null;
      }
    }

    List<TypeBuilder>? argumentBuilders;
    if (arguments != null) {
      argumentBuilders =
          new List<TypeBuilder>.generate(arguments.length, (int i) {
        return _helper
            .validateTypeUse(arguments![i],
                nonInstanceAccessIsError: false,
                allowPotentiallyConstantType:
                    _helper.libraryBuilder.isNonNullableByDefault &&
                        _helper.inIsOrAsOperatorType)
            .builder;
      }, growable: false);
    }
    return new NamedTypeBuilder(
        targetName, nullabilityBuilder, argumentBuilders, _uri, fileOffset)
      ..bind(declaration);
  }

  @override
  Expression invokeConstructor(
      List<UnresolvedType>? typeArguments,
      String name,
      Arguments arguments,
      Token nameToken,
      Token nameLastToken,
      Constness constness) {
    return _helper.buildConstructorInvocation(
        declaration,
        nameToken,
        nameLastToken,
        arguments,
        name,
        typeArguments,
        offsetForToken(nameToken),
        constness);
  }

  @override
  void printOn(StringSink sink) {
    sink.write(", declaration: ");
    sink.write(declaration);
    sink.write(", plainNameForRead: ");
    sink.write(_plainNameForRead);
  }

  @override
  Expression get expression {
    if (_expression == null) {
      if (declaration is InvalidTypeDeclarationBuilder) {
        InvalidTypeDeclarationBuilder declaration =
            this.declaration as InvalidTypeDeclarationBuilder;
        _expression = _helper.buildProblemErrorIfConst(
            declaration.message.messageObject, fileOffset, token.length);
      } else {
        _expression = _forest.createTypeLiteral(
            offsetForToken(token),
            _helper.buildTypeLiteralDartType(
                new UnresolvedType(
                    buildTypeWithResolvedArguments(
                        _helper.libraryBuilder.nonNullableBuilder,
                        typeArguments),
                    fileOffset,
                    _uri),
                nonInstanceAccessIsError: true));
      }
    }
    return _expression!;
  }

  @override
  buildPropertyAccess(
      IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
    int nameOffset = offsetForToken(send.token);
    Name name = send.name;
    Arguments? arguments = send.arguments;

    TypeDeclarationBuilder? declarationBuilder = declaration;
    TypeAliasBuilder? aliasBuilder;
    List<TypeBuilder>? unaliasedTypeArguments;
    bool isGenericTypedefTearOff = false;
    if (declarationBuilder is TypeAliasBuilder) {
      aliasBuilder = declarationBuilder;
      declarationBuilder = aliasBuilder.unaliasDeclaration(null,
          isUsedAsClass: true,
          usedAsClassCharOffset: this.fileOffset,
          usedAsClassFileUri: _uri);
      List<TypeBuilder>? aliasedTypeArguments =
          typeArguments?.map((unknownType) => unknownType.builder).toList();
      if (aliasedTypeArguments != null &&
          aliasedTypeArguments.length != aliasBuilder.typeVariablesCount) {
        _helper.libraryBuilder.addProblem(
            templateTypeArgumentMismatch
                .withArguments(aliasBuilder.typeVariablesCount),
            fileOffset,
            noLength,
            _uri);
      } else {
        if (declarationBuilder is DeclarationBuilder) {
          unaliasedTypeArguments =
              aliasBuilder.unaliasTypeArguments(aliasedTypeArguments);
          if (aliasedTypeArguments != null) {
            _helper.libraryBuilder.uncheckedTypedefTypes.add(
                new UncheckedTypedefType(new TypedefType(
                    aliasBuilder.typedef,
                    _helper.libraryBuilder.nonNullable,
                    aliasBuilder.buildTypeArguments(
                        _helper.libraryBuilder, aliasedTypeArguments)))
                  ..fileUri = _uri
                  ..offset = fileOffset);
          }
          if (aliasedTypeArguments == null &&
              aliasBuilder.typeVariablesCount != 0) {
            isGenericTypedefTearOff = true;
            aliasedTypeArguments = <TypeBuilder>[];
            for (TypeVariableBuilder typeVariable
                in aliasBuilder.typeVariables!) {
              aliasedTypeArguments.add(new NamedTypeBuilder(typeVariable.name,
                  const NullabilityBuilder.omitted(), null, _uri, fileOffset)
                ..bind(typeVariable));
            }
          }
          unaliasedTypeArguments =
              aliasBuilder.unaliasTypeArguments(aliasedTypeArguments);
        }
      }
    }
    if (declarationBuilder is DeclarationBuilder) {
      DeclarationBuilder declaration = declarationBuilder;
      Builder? member = declaration.findStaticBuilder(
          name.text, nameOffset, _uri, _helper.libraryBuilder);
      Generator generator;
      if (member == null) {
        // If we find a setter, [member] is an [AccessErrorBuilder], not null.
        if (send is IncompletePropertyAccessGenerator) {
          assert(
              send.typeArguments == null,
              "Unexpected non-null typeArguments of "
              "an IncompletePropertyAccessGenerator object: "
              "'${send.typeArguments.runtimeType}'.");
          if (_helper.enableConstructorTearOffsInLibrary &&
              declarationBuilder is ClassBuilder) {
            MemberBuilder? constructor =
                declarationBuilder.findConstructorOrFactory(
                    name.text, nameOffset, _uri, _helper.libraryBuilder);
            Member? tearOff = constructor?.readTarget;
            Expression? tearOffExpression;
            if (tearOff is Constructor) {
              if (declarationBuilder.isAbstract) {
                return _helper.buildProblem(
                    messageAbstractClassConstructorTearOff,
                    nameOffset,
                    name.text.length);
              }
              tearOffExpression = _helper.forest
                  .createConstructorTearOff(token.charOffset, tearOff);
            } else if (tearOff is Procedure) {
              if (tearOff.isRedirectingFactory) {
                tearOffExpression = _helper.forest
                    .createRedirectingFactoryTearOff(token.charOffset, tearOff);
              } else {
                tearOffExpression = _helper.forest
                    .createStaticTearOff(token.charOffset, tearOff);
              }
            } else if (tearOff != null) {
              unhandled("${tearOff.runtimeType}", "buildPropertyAccess",
                  operatorOffset, _helper.uri);
            }
            if (tearOffExpression != null) {
              List<DartType>? builtTypeArguments;
              if (unaliasedTypeArguments != null) {
                builtTypeArguments = declarationBuilder.buildTypeArguments(
                    _helper.libraryBuilder, unaliasedTypeArguments);
              } else if (typeArguments != null) {
                builtTypeArguments =
                    _helper.buildDartTypeArguments(typeArguments);
              }
              if (isGenericTypedefTearOff) {
                FreshTypeParameters freshTypeParameters =
                    getFreshTypeParameters(
                        aliasBuilder!.typedef.typeParameters);
                List<DartType>? substitutedTypeArguments;
                if (builtTypeArguments != null) {
                  substitutedTypeArguments = <DartType>[];
                  for (DartType builtTypeArgument in builtTypeArguments) {
                    substitutedTypeArguments
                        .add(freshTypeParameters.substitute(builtTypeArgument));
                  }
                }
                tearOffExpression = _helper.forest.createTypedefTearOff(
                    token.charOffset,
                    freshTypeParameters.freshTypeParameters,
                    tearOffExpression,
                    substitutedTypeArguments ?? const <DartType>[]);
              } else {
                if (builtTypeArguments != null &&
                    builtTypeArguments.isNotEmpty) {
                  tearOffExpression = _helper.forest.createInstantiation(
                      token.charOffset, tearOffExpression, builtTypeArguments);
                }
              }
              return tearOffExpression;
            }
          }
          generator = new UnresolvedNameGenerator(_helper, send.token, name);
        } else {
          return _helper.buildConstructorInvocation(
              declaration,
              send.token,
              send.token,
              arguments!,
              name.text,
              send.typeArguments,
              token.charOffset,
              Constness.implicit,
              isTypeArgumentsInForest: send.isTypeArgumentsInForest,
              typeAliasBuilder: aliasBuilder);
        }
      } else if (member is AmbiguousBuilder) {
        return _helper.buildProblem(
            member.message, member.charOffset, name.text.length);
      } else {
        Builder? setter;
        if (member.isSetter) {
          setter = member;
          member = null;
        } else if (member.isGetter) {
          setter = declaration.findStaticBuilder(
              name.text, fileOffset, _uri, _helper.libraryBuilder,
              isSetter: true);
        } else if (member.isField) {
          MemberBuilder fieldBuilder = member as MemberBuilder;
          if (!fieldBuilder.isAssignable) {
            setter = declaration.findStaticBuilder(
                name.text, fileOffset, _uri, _helper.libraryBuilder,
                isSetter: true);
          } else {
            setter = member;
          }
        }
        generator = new StaticAccessGenerator.fromBuilder(
            _helper,
            name.text,
            send.token,
            member is MemberBuilder ? member : null,
            setter is MemberBuilder ? setter : null,
            typeOffset: fileOffset,
            isNullAware: isNullAware);
      }

      return arguments == null
          ? generator
          : generator.doInvocation(
              offsetForToken(send.token), send.typeArguments, arguments,
              isTypeArgumentsInForest: send.isTypeArgumentsInForest);
    } else {
      // `SomeType?.toString` is the same as `SomeType.toString`, not
      // `(SomeType).toString`.
      return super.buildPropertyAccess(send, operatorOffset, isNullAware);
    }
  }

  @override
  doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    if (declaration.isExtension) {
      ExtensionBuilder extensionBuilder = declaration as ExtensionBuilder;
      if (arguments.positional.length != 1 || arguments.named.isNotEmpty) {
        return _helper.buildProblem(messageExplicitExtensionArgumentMismatch,
            fileOffset, lengthForToken(token));
      }
      List<DartType>? explicitTypeArguments =
          getExplicitTypeArguments(arguments);
      if (explicitTypeArguments != null) {
        int typeParameterCount = extensionBuilder.typeParameters?.length ?? 0;
        if (explicitTypeArguments.length != typeParameterCount) {
          return _helper.buildProblem(
              templateExplicitExtensionTypeArgumentMismatch.withArguments(
                  extensionBuilder.name, typeParameterCount),
              fileOffset,
              lengthForToken(token));
        }
      }
      // TODO(johnniwinther): Check argument and type argument count.
      return new ExplicitExtensionAccessGenerator(
          _helper,
          token,
          declaration as ExtensionBuilder,
          arguments.positional.single,
          explicitTypeArguments);
    } else {
      return _helper.buildConstructorInvocation(declaration, token, token,
          arguments, "", typeArguments, token.charOffset, Constness.implicit,
          isTypeArgumentsInForest: isTypeArgumentsInForest);
    }
  }

  @override
  applyTypeArguments(int fileOffset, List<UnresolvedType>? typeArguments) {
    return new TypeUseGenerator(_helper, token, declaration, targetName)
      ..typeArguments = typeArguments;
  }
}

enum ReadOnlyAccessKind {
  ConstVariable,
  FinalVariable,
  ExtensionThis,
  LetVariable,
  TypeLiteral,
  ParenthesizedExpression,
  InvalidDeclaration,
}

/// [ReadOnlyAccessGenerator] represents the subexpression whose prefix is the
/// name of final local variable, final parameter, or catch clause variable or
/// `this` in an instance method in an extension declaration.
///
/// For instance:
///
///   method(final a) {
///     final b = null;
///     a;         // a ReadOnlyAccessGenerator is created for `a`.
///     a[];       // a ReadOnlyAccessGenerator is created for `a`.
///     b();       // a ReadOnlyAccessGenerator is created for `b`.
///     b.c = a.d; // a ReadOnlyAccessGenerator is created for `a` and `b`.
///
///     try {
///     } catch (a) {
///       a;       // a ReadOnlyAccessGenerator is created for `a`.
///     }
///   }
///
///   extension on Foo {
///     method() {
///       this;         // a ReadOnlyAccessGenerator is created for `this`.
///       this.a;       // a ReadOnlyAccessGenerator is created for `this`.
///       this.b();     // a ReadOnlyAccessGenerator is created for `this`.
///     }
///   }
///
class ReadOnlyAccessGenerator extends AbstractReadOnlyAccessGenerator {
  final String targetName;

  Expression expression;

  ReadOnlyAccessGenerator(ExpressionGeneratorHelper helper, Token token,
      this.expression, this.targetName, ReadOnlyAccessKind kind)
      : super(helper, token, kind);
}

abstract class AbstractReadOnlyAccessGenerator extends Generator {
  final ReadOnlyAccessKind kind;

  AbstractReadOnlyAccessGenerator(
      ExpressionGeneratorHelper helper, Token token, this.kind)
      : super(helper, token);

  String get targetName;

  Expression get expression;

  @override
  String get _debugName => "ReadOnlyAccessGenerator";

  @override
  String get _plainNameForRead => targetName;

  @override
  Expression buildSimpleRead() => _createRead();

  Expression _createRead() => expression;

  Expression _makeInvalidWrite(Expression value) {
    switch (kind) {
      case ReadOnlyAccessKind.ConstVariable:
        // ignore: unnecessary_null_comparison
        assert(targetName != null);
        return _helper.buildProblem(
            templateCannotAssignToConstVariable.withArguments(targetName),
            fileOffset,
            lengthForToken(token));
      case ReadOnlyAccessKind.FinalVariable:
        // ignore: unnecessary_null_comparison
        assert(targetName != null);
        return _helper.buildProblem(
            templateCannotAssignToFinalVariable.withArguments(targetName),
            fileOffset,
            lengthForToken(token));
      case ReadOnlyAccessKind.ExtensionThis:
        return _helper.buildProblem(messageCannotAssignToExtensionThis,
            fileOffset, lengthForToken(token));
      case ReadOnlyAccessKind.TypeLiteral:
        return _helper.buildProblem(messageCannotAssignToTypeLiteral,
            fileOffset, lengthForToken(token));
      case ReadOnlyAccessKind.ParenthesizedExpression:
        return _helper.buildProblem(
            messageCannotAssignToParenthesizedExpression,
            fileOffset,
            lengthForToken(token));
      case ReadOnlyAccessKind.LetVariable:
      case ReadOnlyAccessKind.InvalidDeclaration:
        break;
    }
    return super._makeInvalidWrite(value);
  }

  @override
  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return _makeInvalidWrite(value);
  }

  @override
  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    Expression read = _createRead();
    Expression write = _makeInvalidWrite(value);
    return new IfNullSet(read, write, forEffect: voidContext)
      ..fileOffset = offset;
  }

  @override
  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    Expression binary = _helper.forest
        .createBinary(offset, _createRead(), binaryOperator, value);
    return _makeInvalidWrite(binary);
  }

  @override
  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset = TreeNode.noOffset, bool voidContext = false}) {
    Expression value = _forest.createIntLiteral(offset, 1);
    return buildCompoundAssignment(binaryOperator, value,
        offset: offset, voidContext: voidContext, isPostIncDec: true);
  }

  @override
  doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    return _helper.forest.createExpressionInvocation(
        adjustForImplicitCall(targetName, offset), _createRead(), arguments);
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    // TODO(johnniwinther): The read-only quality of the variable should be
    // passed on to the generator.
    return new IndexedAccessGenerator(_helper, token, _createRead(), index,
        isNullAware: isNullAware);
  }

  @override
  void printOn(StringSink sink) {
    NameSystem syntheticNames = new NameSystem();
    sink.write(", expression: ");
    printNodeOn(expression, sink, syntheticNames: syntheticNames);
    sink.write(", plainNameForRead: ");
    sink.write(targetName);
    sink.write(", kind: ");
    sink.write(kind);
  }
}

abstract class ErroneousExpressionGenerator extends Generator {
  ErroneousExpressionGenerator(ExpressionGeneratorHelper helper, Token token)
      : super(helper, token);

  /// Pass [arguments] that must be evaluated before throwing an error.  At
  /// most one of [isGetter] and [isSetter] should be true and they're passed
  /// to [ExpressionGeneratorHelper.throwNoSuchMethodError] if it is used.
  Expression buildError(Arguments arguments,
      {bool isGetter: false, bool isSetter: false, int offset});

  Name get name => unsupported("name", fileOffset, _uri);

  @override
  String get _plainNameForRead => name.text;

  withReceiver(Object? receiver, int operatorOffset,
          {bool isNullAware: false}) =>
      this;

  @override
  List<Initializer> buildFieldInitializer(Map<String, int>? initializedFields) {
    return <Initializer>[
      _helper.buildInvalidInitializer(
          buildError(_forest.createArgumentsEmpty(fileOffset), isSetter: true))
    ];
  }

  @override
  doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    return buildError(arguments, offset: offset);
  }

  @override
  buildPropertyAccess(
      IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
    return send.withReceiver(buildSimpleRead(), operatorOffset,
        isNullAware: isNullAware);
  }

  @override
  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return buildError(_forest.createArguments(fileOffset, <Expression>[value]),
        isSetter: true);
  }

  @override
  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: -1,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    return buildError(_forest.createArguments(fileOffset, <Expression>[value]),
        isGetter: true);
  }

  @override
  Expression buildPrefixIncrement(Name binaryOperator,
      {int offset: -1, bool voidContext: false}) {
    return buildError(
        _forest.createArguments(
            fileOffset, <Expression>[_forest.createIntLiteral(offset, 1)]),
        isGetter: true)
      ..fileOffset = offset;
  }

  @override
  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset: -1, bool voidContext: false}) {
    return buildError(
        _forest.createArguments(
            fileOffset, <Expression>[_forest.createIntLiteral(offset, 1)]),
        isGetter: true)
      ..fileOffset = offset;
  }

  @override
  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    return buildError(_forest.createArguments(fileOffset, <Expression>[value]),
        isSetter: true);
  }

  @override
  Expression buildSimpleRead() {
    return buildError(_forest.createArgumentsEmpty(fileOffset), isGetter: true);
  }

  @override
  Expression _makeInvalidRead() {
    return buildError(_forest.createArgumentsEmpty(fileOffset), isGetter: true);
  }

  @override
  Expression _makeInvalidWrite(Expression value) {
    return buildError(_forest.createArguments(fileOffset, <Expression>[value]),
        isSetter: true);
  }

  @override
  Expression invokeConstructor(
      List<UnresolvedType>? typeArguments,
      String name,
      Arguments arguments,
      Token nameToken,
      Token nameLastToken,
      Constness constness) {
    if (typeArguments != null) {
      assert(_forest.argumentsTypeArguments(arguments).isEmpty);
      _forest.argumentsSetTypeArguments(
          arguments, _helper.buildDartTypeArguments(typeArguments));
    }
    return buildError(arguments);
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
        isNullAware: isNullAware);
  }
}

class UnresolvedNameGenerator extends ErroneousExpressionGenerator {
  @override
  final Name name;

  factory UnresolvedNameGenerator(
      ExpressionGeneratorHelper helper, Token token, Name name) {
    if (name.text.isEmpty) {
      unhandled("empty", "name", offsetForToken(token), helper.uri);
    }
    return new UnresolvedNameGenerator.internal(helper, token, name);
  }

  UnresolvedNameGenerator.internal(
      ExpressionGeneratorHelper helper, Token token, this.name)
      : super(helper, token);

  @override
  String get _debugName => "UnresolvedNameGenerator";

  @override
  Expression doInvocation(
      int charOffset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    return buildError(arguments, offset: charOffset);
  }

  @override
  Expression buildError(Arguments arguments,
      {bool isGetter: false, bool isSetter: false, int? offset}) {
    offset ??= fileOffset;
    return _helper.throwNoSuchMethodError(
        _forest.createNullLiteral(offset), _plainNameForRead, arguments, offset,
        isGetter: isGetter, isSetter: isSetter);
  }

  @override
  /* Expression | Generator */ Object qualifiedLookup(Token name) {
    return new UnexpectedQualifiedUseGenerator(_helper, name, this, true);
  }

  @override
  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return _buildUnresolvedVariableAssignment(false, value);
  }

  @override
  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    return _buildUnresolvedVariableAssignment(true, value);
  }

  @override
  Expression buildSimpleRead() {
    return buildError(_forest.createArgumentsEmpty(fileOffset), isGetter: true)
      ..fileOffset = fileOffset;
  }

  @override
  void printOn(StringSink sink) {
    sink.write(", name: ");
    sink.write(name.text);
  }

  Expression _buildUnresolvedVariableAssignment(
      bool isCompound, Expression value) {
    return buildError(_forest.createArguments(fileOffset, <Expression>[value]),
        isSetter: true);
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
        isNullAware: isNullAware);
  }
}

abstract class ContextAwareGenerator extends Generator {
  final Generator generator;

  ContextAwareGenerator(
      ExpressionGeneratorHelper helper, Token token, this.generator)
      : super(helper, token);

  @override
  String get _plainNameForRead {
    return unsupported("plainNameForRead", token.charOffset, _helper.uri);
  }

  @override
  Expression doInvocation(
      int charOffset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    return unhandled("${runtimeType}", "doInvocation", charOffset, _uri);
  }

  @override
  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return _makeInvalidWrite(value);
  }

  @override
  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    return _makeInvalidWrite(value);
  }

  @override
  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: -1,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    return _makeInvalidWrite(value);
  }

  @override
  Expression buildPrefixIncrement(Name binaryOperator,
      {int offset: -1, bool voidContext: false}) {
    return _makeInvalidWrite(null);
  }

  @override
  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset: -1, bool voidContext: false}) {
    return _makeInvalidWrite(null);
  }

  @override
  _makeInvalidRead() {
    return unsupported("makeInvalidRead", token.charOffset, _helper.uri);
  }

  @override
  Expression _makeInvalidWrite(Expression? value) {
    return _helper.buildProblem(messageIllegalAssignmentToNonAssignable,
        fileOffset, lengthForToken(token));
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
        isNullAware: isNullAware);
  }
}

class DelayedAssignment extends ContextAwareGenerator {
  final Expression value;

  String assignmentOperator;

  DelayedAssignment(ExpressionGeneratorHelper helper, Token token,
      Generator generator, this.value, this.assignmentOperator)
      : super(helper, token, generator);

  @override
  String get _debugName => "DelayedAssignment";

  @override
  Expression buildSimpleRead() {
    return handleAssignment(false);
  }

  @override
  Expression buildForEffect() {
    return handleAssignment(true);
  }

  Expression handleAssignment(bool voidContext) {
    if (_helper.constantContext != ConstantContext.none) {
      return _helper.buildProblem(
          messageNotAConstantExpression, fileOffset, token.length);
    }
    if (identical("=", assignmentOperator)) {
      return generator.buildAssignment(value, voidContext: voidContext);
    } else if (identical("+=", assignmentOperator)) {
      return generator.buildCompoundAssignment(plusName, value,
          offset: fileOffset, voidContext: voidContext);
    } else if (identical("-=", assignmentOperator)) {
      return generator.buildCompoundAssignment(minusName, value,
          offset: fileOffset, voidContext: voidContext);
    } else if (identical("*=", assignmentOperator)) {
      return generator.buildCompoundAssignment(multiplyName, value,
          offset: fileOffset, voidContext: voidContext);
    } else if (identical("%=", assignmentOperator)) {
      return generator.buildCompoundAssignment(percentName, value,
          offset: fileOffset, voidContext: voidContext);
    } else if (identical("&=", assignmentOperator)) {
      return generator.buildCompoundAssignment(ampersandName, value,
          offset: fileOffset, voidContext: voidContext);
    } else if (identical("/=", assignmentOperator)) {
      return generator.buildCompoundAssignment(divisionName, value,
          offset: fileOffset, voidContext: voidContext);
    } else if (identical("<<=", assignmentOperator)) {
      return generator.buildCompoundAssignment(leftShiftName, value,
          offset: fileOffset, voidContext: voidContext);
    } else if (identical(">>=", assignmentOperator)) {
      return generator.buildCompoundAssignment(rightShiftName, value,
          offset: fileOffset, voidContext: voidContext);
    } else if (identical(">>>=", assignmentOperator)) {
      return generator.buildCompoundAssignment(tripleShiftName, value,
          offset: fileOffset, voidContext: voidContext);
    } else if (identical("??=", assignmentOperator)) {
      return generator.buildIfNullAssignment(
          value, const DynamicType(), fileOffset,
          voidContext: voidContext);
    } else if (identical("^=", assignmentOperator)) {
      return generator.buildCompoundAssignment(caretName, value,
          offset: fileOffset, voidContext: voidContext);
    } else if (identical("|=", assignmentOperator)) {
      return generator.buildCompoundAssignment(barName, value,
          offset: fileOffset, voidContext: voidContext);
    } else if (identical("~/=", assignmentOperator)) {
      return generator.buildCompoundAssignment(mustacheName, value,
          offset: fileOffset, voidContext: voidContext);
    } else {
      return unhandled(assignmentOperator, "handleAssignment", token.charOffset,
          _helper.uri);
    }
  }

  @override
  List<Initializer> buildFieldInitializer(Map<String, int>? initializedFields) {
    if (!identical("=", assignmentOperator) ||
        generator is! ThisPropertyAccessGenerator) {
      return generator.buildFieldInitializer(initializedFields);
    }
    return _helper.buildFieldInitializer(generator._plainNameForRead,
        offsetForToken(generator.token), fileOffset, value);
  }

  @override
  void printOn(StringSink sink) {
    sink.write(", value: ");
    printNodeOn(value, sink);
    sink.write(", assignmentOperator: ");
    sink.write(assignmentOperator);
  }
}

class DelayedPostfixIncrement extends ContextAwareGenerator {
  final Name binaryOperator;

  DelayedPostfixIncrement(ExpressionGeneratorHelper helper, Token token,
      Generator generator, this.binaryOperator)
      : super(helper, token, generator);

  @override
  String get _debugName => "DelayedPostfixIncrement";

  @override
  Expression buildSimpleRead() {
    return generator.buildPostfixIncrement(binaryOperator,
        offset: fileOffset, voidContext: false);
  }

  @override
  Expression buildForEffect() {
    return generator.buildPostfixIncrement(binaryOperator,
        offset: fileOffset, voidContext: true);
  }

  @override
  void printOn(StringSink sink) {
    sink.write(", binaryOperator: ");
    sink.write(binaryOperator.text);
  }
}

class PrefixUseGenerator extends Generator {
  final PrefixBuilder prefix;

  PrefixUseGenerator(ExpressionGeneratorHelper helper, Token token, this.prefix)
      : super(helper, token);

  @override
  String get _plainNameForRead => prefix.name;

  @override
  String get _debugName => "PrefixUseGenerator";

  @override
  Expression buildSimpleRead() => _makeInvalidRead();

  @override
  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return _makeInvalidWrite(value);
  }

  @override
  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    return _makeInvalidRead();
  }

  @override
  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    return _makeInvalidRead();
  }

  @override
  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset: TreeNode.noOffset, bool voidContext: false}) {
    return _makeInvalidRead();
  }

  @override
  /* Expression | Generator */ Object qualifiedLookup(Token name) {
    if (_helper.constantContext != ConstantContext.none && prefix.deferred) {
      _helper.addProblem(
          templateCantUseDeferredPrefixAsConstant.withArguments(token),
          fileOffset,
          lengthForToken(token));
    }
    Object result = _helper.scopeLookup(prefix.exportScope, name.lexeme, name,
        isQualified: true, prefix: prefix);
    if (prefix.deferred) {
      if (result is Generator) {
        if (result is! LoadLibraryGenerator) {
          result = new DeferredAccessGenerator(_helper, name, this, result);
        }
      } else {
        _helper.wrapInDeferredCheck(result as Expression, prefix, fileOffset);
      }
    }
    return result;
  }

  @override
  /* Expression | Generator | Initializer */ doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    return _helper.wrapInLocatedProblem(
        _helper.evaluateArgumentsBefore(
            arguments, _forest.createNullLiteral(fileOffset)),
        messageCantUsePrefixAsExpression.withLocation(
            _helper.uri, fileOffset, lengthForToken(token)));
  }

  @override
  /* Expression | Generator */ buildPropertyAccess(
      IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
    if (send is IncompleteSendGenerator) {
      assert(send.name.text == send.token.lexeme,
          "'${send.name.text}' != ${send.token.lexeme}");
      Object result = qualifiedLookup(send.token);
      if (send is SendAccessGenerator) {
        result = _helper.finishSend(
            result, send.typeArguments, send.arguments, fileOffset,
            isTypeArgumentsInForest: send.isTypeArgumentsInForest);
      }
      if (isNullAware) {
        result = _helper.wrapInLocatedProblem(
            _helper.toValue(result),
            messageCantUsePrefixWithNullAware.withLocation(
                _helper.uri, fileOffset, lengthForToken(token)));
      }
      return result;
    } else {
      return buildSimpleRead();
    }
  }

  @override
  Expression _makeInvalidRead() {
    return _helper.buildProblem(
        messageCantUsePrefixAsExpression, fileOffset, lengthForToken(token));
  }

  @override
  Expression _makeInvalidWrite(Expression value) => _makeInvalidRead();

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
        isNullAware: isNullAware);
  }

  @override
  void printOn(StringSink sink) {
    sink.write(", prefix: ");
    sink.write(prefix.name);
    sink.write(", deferred: ");
    sink.write(prefix.deferred);
  }
}

class UnexpectedQualifiedUseGenerator extends Generator {
  final Generator prefixGenerator;

  final bool isUnresolved;

  UnexpectedQualifiedUseGenerator(ExpressionGeneratorHelper helper, Token token,
      this.prefixGenerator, this.isUnresolved)
      : super(helper, token);

  @override
  String get _plainNameForRead =>
      "${prefixGenerator._plainNameForRead}.${token.lexeme}";

  @override
  String get _debugName => "UnexpectedQualifiedUseGenerator";

  @override
  Expression buildSimpleRead() => _makeInvalidRead();

  @override
  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return _makeInvalidWrite(value);
  }

  @override
  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    return _makeInvalidRead();
  }

  @override
  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    return _makeInvalidRead();
  }

  @override
  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset = TreeNode.noOffset, bool voidContext = false}) {
    return _makeInvalidRead();
  }

  @override
  Expression doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    return _helper.throwNoSuchMethodError(_forest.createNullLiteral(offset),
        _plainNameForRead, arguments, fileOffset);
  }

  @override
  TypeBuilder buildTypeWithResolvedArguments(
      NullabilityBuilder nullabilityBuilder, List<UnresolvedType>? arguments) {
    Template<Message Function(String, String)> template = isUnresolved
        ? templateUnresolvedPrefixInTypeAnnotation
        : templateNotAPrefixInTypeAnnotation;
    // TODO(johnniwinther): Could we use a FixedTypeBuilder(InvalidType()) here?
    NamedTypeBuilder result = new NamedTypeBuilder(
        _plainNameForRead,
        nullabilityBuilder,
        /* arguments = */ null,
        /* fileUri = */ null,
        /* charOffset = */ null);
    Message message =
        template.withArguments(prefixGenerator.token.lexeme, token.lexeme);
    _helper.libraryBuilder.addProblem(
        message,
        offsetForToken(prefixGenerator.token),
        lengthOfSpan(prefixGenerator.token, token),
        _uri);
    result.bind(result.buildInvalidTypeDeclarationBuilder(message.withLocation(
        _uri,
        offsetForToken(prefixGenerator.token),
        lengthOfSpan(prefixGenerator.token, token))));
    return result;
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
        isNullAware: isNullAware);
  }

  @override
  void printOn(StringSink sink) {
    sink.write(", prefixGenerator: ");
    prefixGenerator.printOn(sink);
  }
}

class ParserErrorGenerator extends Generator {
  final Message message;

  ParserErrorGenerator(
      ExpressionGeneratorHelper helper, Token token, this.message)
      : super(helper, token);

  @override
  String get _plainNameForRead => "#parser-error";

  @override
  String get _debugName => "ParserErrorGenerator";

  @override
  void printOn(StringSink sink) {}

  Expression buildProblem() {
    return _helper.buildProblem(message, fileOffset, noLength,
        suppressMessage: true);
  }

  Expression buildSimpleRead() => buildProblem();

  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return buildProblem();
  }

  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    return buildProblem();
  }

  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    return buildProblem();
  }

  Expression buildPrefixIncrement(Name binaryOperator,
      {int offset: TreeNode.noOffset, bool voidContext: false}) {
    return buildProblem();
  }

  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset: TreeNode.noOffset, bool voidContext: false}) {
    return buildProblem();
  }

  Expression _makeInvalidRead() => buildProblem();

  Expression _makeInvalidWrite(Expression value) => buildProblem();

  List<Initializer> buildFieldInitializer(Map<String, int>? initializedFields) {
    return <Initializer>[_helper.buildInvalidInitializer(buildProblem())];
  }

  Expression doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    return buildProblem();
  }

  Expression buildPropertyAccess(
      IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
    return buildProblem();
  }

  TypeBuilder buildTypeWithResolvedArguments(
      NullabilityBuilder nullabilityBuilder, List<UnresolvedType>? arguments) {
    // TODO(johnniwinther): Could we use a FixedTypeBuilder(InvalidType()) here?
    NamedTypeBuilder result = new NamedTypeBuilder(
        token.lexeme,
        nullabilityBuilder,
        /* arguments = */ null,
        /* fileUri = */ null,
        /* charOffset = */ null);
    _helper.libraryBuilder.addProblem(message, fileOffset, noLength, _uri);
    result.bind(result.buildInvalidTypeDeclarationBuilder(
        message.withLocation(_uri, fileOffset, noLength)));
    return result;
  }

  Expression qualifiedLookup(Token name) {
    return buildProblem();
  }

  Expression invokeConstructor(
      List<UnresolvedType>? typeArguments,
      String name,
      Arguments arguments,
      Token nameToken,
      Token nameLastToken,
      Constness constness) {
    return buildProblem();
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
        isNullAware: isNullAware);
  }
}

/// A [ThisAccessGenerator] represents a subexpression whose prefix is `this`
/// or `super`.
///
/// For instance
///
///   class C {
///     var b = this.c; // a ThisAccessGenerator is created for `this`.
///     var c;
///     C(this.c) :     // a ThisAccessGenerator is created for `this`.
///       this.b = c;   // a ThisAccessGenerator is created for `this`.
///     method() {
///       this.b;       // a ThisAccessGenerator is created for `this`.
///       super.b();    // a ThisAccessGenerator is created for `super`.
///       this.b = c;   // a ThisAccessGenerator is created for `this`.
///       this.b += c;  // a ThisAccessGenerator is created for `this`.
///     }
///   }
///
/// If this `this` occurs in an instance member on an extension declaration,
/// a [ReadOnlyAccessGenerator] is created instead.
///
class ThisAccessGenerator extends Generator {
  /// `true` if this access is in an initializer list.
  ///
  /// For instance in `<init>` in
  ///
  ///    class Class {
  ///      Class() : <init>;
  ///    }
  ///
  final bool isInitializer;

  /// `true` if this access is in 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>;
  ///    }
  ///
  final bool inFieldInitializer;

  /// `true` if this access is 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;
  ///    }
  ///
  final bool inLateFieldInitializer;

  /// `true` if this subexpression represents a `super` prefix.
  final bool isSuper;

  ThisAccessGenerator(ExpressionGeneratorHelper helper, Token token,
      this.isInitializer, this.inFieldInitializer, this.inLateFieldInitializer,
      {this.isSuper: false})
      : super(helper, token);

  String get _plainNameForRead {
    return unsupported(
        "${isSuper ? 'super' : 'this'}.plainNameForRead", fileOffset, _uri);
  }

  String get _debugName => "ThisAccessGenerator";

  Expression buildSimpleRead() {
    if (!isSuper) {
      if (inFieldInitializer && !inLateFieldInitializer) {
        return buildFieldInitializerError(null);
      } else {
        return _forest.createThisExpression(fileOffset);
      }
    } else {
      return _helper.buildProblem(
          messageSuperAsExpression, fileOffset, lengthForToken(token));
    }
  }

  Expression buildFieldInitializerError(Map<String, int>? initializedFields) {
    String keyword = isSuper ? "super" : "this";
    return _helper.buildProblem(
        templateThisOrSuperAccessInFieldInitializer.withArguments(keyword),
        fileOffset,
        keyword.length);
  }

  @override
  List<Initializer> buildFieldInitializer(Map<String, int>? initializedFields) {
    Expression error = buildFieldInitializerError(initializedFields);
    return <Initializer>[
      _helper.buildInvalidInitializer(error, error.fileOffset)
    ];
  }

  void _reportNonNullableInNullAwareWarningIfNeeded() {
    if (_helper.libraryBuilder.isNonNullableByDefault) {
      _helper.libraryBuilder.addProblem(
          messageThisInNullAwareReceiver, fileOffset, 4, _helper.uri);
    }
  }

  buildPropertyAccess(
      IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
    Name name = send.name;
    Arguments? arguments = send.arguments;
    int offset = offsetForToken(send.token);
    if (isInitializer && send is SendAccessGenerator) {
      if (isNullAware) {
        _helper.addProblem(
            messageInvalidUseOfNullAwareAccess, operatorOffset, 2);
      }
      return buildConstructorInitializer(offset, name, arguments!);
    }
    if (inFieldInitializer && !inLateFieldInitializer && !isInitializer) {
      return buildFieldInitializerError(null);
    }
    if (send is SendAccessGenerator) {
      // Notice that 'this' or 'super' can't be null. So we can ignore the
      // value of [isNullAware].
      if (isNullAware) {
        _reportNonNullableInNullAwareWarningIfNeeded();
      }
      return _helper.buildMethodInvocation(
          _forest.createThisExpression(fileOffset),
          name,
          send.arguments,
          offsetForToken(send.token),
          isSuper: isSuper);
    } else {
      if (isSuper) {
        Member? getter = _helper.lookupInstanceMember(name, isSuper: isSuper);
        Member? setter = _helper.lookupInstanceMember(name,
            isSuper: isSuper, isSetter: true);
        return new SuperPropertyAccessGenerator(
            _helper,
            // TODO(ahe): This is not the 'super' token.
            send.token,
            name,
            getter,
            setter);
      } else {
        return new ThisPropertyAccessGenerator(
            _helper,
            // TODO(ahe): This is not the 'this' token.
            send.token,
            name,
            thisOffset: fileOffset,
            isNullAware: isNullAware);
      }
    }
  }

  doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    if (isInitializer) {
      return buildConstructorInitializer(offset, new Name(""), arguments);
    } else if (isSuper) {
      return _helper.buildProblem(messageSuperAsExpression, offset, noLength);
    } else {
      return _helper.forest.createExpressionInvocation(
          offset, _forest.createThisExpression(fileOffset), arguments);
    }
  }

  @override
  buildEqualsOperation(Token token, Expression right, {required bool isNot}) {
    // ignore: unnecessary_null_comparison
    assert(isNot != null);
    if (isSuper) {
      int offset = offsetForToken(token);
      Expression result = _helper.buildMethodInvocation(
          _forest.createThisExpression(fileOffset),
          equalsName,
          _forest.createArguments(offset, <Expression>[right]),
          offset,
          isSuper: true);
      if (isNot) {
        result = _forest.createNot(offset, result);
      }
      return result;
    }
    return super.buildEqualsOperation(token, right, isNot: isNot);
  }

  @override
  buildBinaryOperation(Token token, Name binaryName, Expression right) {
    if (isSuper) {
      int offset = offsetForToken(token);
      return _helper.buildMethodInvocation(
          _forest.createThisExpression(fileOffset),
          binaryName,
          _forest.createArguments(offset, <Expression>[right]),
          offset,
          isSuper: true);
    }
    return super.buildBinaryOperation(token, binaryName, right);
  }

  @override
  buildUnaryOperation(Token token, Name unaryName) {
    if (isSuper) {
      int offset = offsetForToken(token);
      return _helper.buildMethodInvocation(
          _forest.createThisExpression(fileOffset),
          unaryName,
          _forest.createArgumentsEmpty(offset),
          offset,
          isSuper: true);
    }
    return super.buildUnaryOperation(token, unaryName);
  }

  Initializer buildConstructorInitializer(
      int offset, Name name, Arguments arguments) {
    Constructor? constructor =
        _helper.lookupConstructor(name, isSuper: isSuper);
    LocatedMessage? message;
    if (constructor != null) {
      message = _helper.checkArgumentsForFunction(
          constructor.function, arguments, offset, <TypeParameter>[]);
    } else {
      String fullName =
          _helper.constructorNameForDiagnostics(name.text, isSuper: isSuper);
      message = (isSuper
              ? templateSuperclassHasNoConstructor
              : templateConstructorNotFound)
          .withArguments(fullName)
          .withLocation(_uri, fileOffset, lengthForToken(token));
    }
    if (message != null) {
      return _helper.buildInvalidInitializer(
          _helper.throwNoSuchMethodError(
              _forest.createNullLiteral(offset),
              _helper.constructorNameForDiagnostics(name.text,
                  isSuper: isSuper),
              arguments,
              offset,
              isSuper: isSuper,
              message: message),
          offset);
    } else if (isSuper) {
      return _helper.buildSuperInitializer(
          false, constructor!, arguments, offset);
    } else {
      return _helper.buildRedirectingInitializer(
          constructor!, arguments, offset);
    }
  }

  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return buildAssignmentError();
  }

  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    return buildAssignmentError();
  }

  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    return buildAssignmentError();
  }

  Expression buildPrefixIncrement(Name binaryOperator,
      {int offset: TreeNode.noOffset, bool voidContext: false}) {
    return buildAssignmentError();
  }

  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset: TreeNode.noOffset, bool voidContext: false}) {
    return buildAssignmentError();
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    if (isSuper) {
      return new SuperIndexedAccessGenerator(
          _helper,
          token,
          index,
          _helper.lookupInstanceMember(indexGetName, isSuper: true)
              as Procedure?,
          _helper.lookupInstanceMember(indexSetName, isSuper: true)
              as Procedure?);
    } else {
      return new ThisIndexedAccessGenerator(_helper, token, index,
          thisOffset: fileOffset, isNullAware: isNullAware);
    }
  }

  Expression buildAssignmentError() {
    return _helper.buildProblem(
        isSuper ? messageCannotAssignToSuper : messageNotAnLvalue,
        fileOffset,
        token.length);
  }

  @override
  void printOn(StringSink sink) {
    sink.write(", isInitializer: ");
    sink.write(isInitializer);
    sink.write(", inFieldInitializer: ");
    sink.write(inFieldInitializer);
    sink.write(", inLateFieldInitializer: ");
    sink.write(inLateFieldInitializer);
    sink.write(", isSuper: ");
    sink.write(isSuper);
  }
}

abstract class IncompleteSendGenerator implements Generator {
  Name get name;

  withReceiver(Object? receiver, int operatorOffset, {bool isNullAware: false});

  List<UnresolvedType>? get typeArguments => null;

  bool get isTypeArgumentsInForest => true;

  Arguments? get arguments => null;
}

class IncompleteErrorGenerator extends ErroneousExpressionGenerator
    with IncompleteSendGenerator {
  final Message message;

  IncompleteErrorGenerator(
      ExpressionGeneratorHelper helper, Token token, this.message)
      : super(helper, token);

  String get _plainNameForRead => token.lexeme;

  String get _debugName => "IncompleteErrorGenerator";

  @override
  Expression buildError(Arguments arguments,
      {bool isGetter: false, bool isSetter: false, int? offset}) {
    int length = noLength;
    if (offset == null) {
      offset = fileOffset;
      length = lengthForToken(token);
    }
    return _helper.buildProblem(message, offset, length);
  }

  @override
  doInvocation(
          int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
          {bool isTypeArgumentsInForest = false}) =>
      this;

  @override
  Expression buildSimpleRead() {
    return buildError(_forest.createArgumentsEmpty(fileOffset), isGetter: true)
      ..fileOffset = fileOffset;
  }

  @override
  void printOn(StringSink sink) {
    sink.write(", message: ");
    sink.write(message.code.name);
  }
}

// TODO(ahe): Rename to SendGenerator.
class SendAccessGenerator extends Generator with IncompleteSendGenerator {
  @override
  final Name name;

  @override
  final List<UnresolvedType>? typeArguments;

  @override
  final bool isTypeArgumentsInForest;

  @override
  final Arguments arguments;

  final bool isPotentiallyConstant;

  SendAccessGenerator(ExpressionGeneratorHelper helper, Token token, this.name,
      this.typeArguments, this.arguments,
      {this.isPotentiallyConstant = false, this.isTypeArgumentsInForest = true})
      : super(helper, token) {
    // ignore: unnecessary_null_comparison
    assert(arguments != null);
  }

  String get _plainNameForRead => name.text;

  String get _debugName => "SendAccessGenerator";

  Expression buildSimpleRead() {
    return unsupported("buildSimpleRead", fileOffset, _uri);
  }

  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return unsupported("buildAssignment", fileOffset, _uri);
  }

  withReceiver(Object? receiver, int operatorOffset,
      {bool isNullAware: false}) {
    if (receiver is Generator) {
      return receiver.buildPropertyAccess(this, operatorOffset, isNullAware);
    }
    return _helper.buildMethodInvocation(
        _helper.toValue(receiver), name, arguments, fileOffset,
        isNullAware: isNullAware);
  }

  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    return unsupported("buildNullAwareAssignment", offset, _uri);
  }

  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    return unsupported("buildCompoundAssignment", offset, _uri);
  }

  Expression buildPrefixIncrement(Name binaryOperator,
      {int offset: TreeNode.noOffset, bool voidContext: false}) {
    return unsupported("buildPrefixIncrement", offset, _uri);
  }

  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset: TreeNode.noOffset, bool voidContext: false}) {
    return unsupported("buildPostfixIncrement", offset, _uri);
  }

  Expression doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    return unsupported("doInvocation", offset, _uri);
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return unsupported("buildIndexedAccess", offsetForToken(token), _uri);
  }

  @override
  void printOn(StringSink sink) {
    sink.write(", name: ");
    sink.write(name.text);
    sink.write(", arguments: ");
    Arguments node = arguments;
    if (node is Node) {
      printNodeOn(node, sink);
    } else {
      sink.write(node);
    }
  }
}

class IncompletePropertyAccessGenerator extends Generator
    with IncompleteSendGenerator {
  final Name name;

  IncompletePropertyAccessGenerator(
      ExpressionGeneratorHelper helper, Token token, this.name)
      : super(helper, token);

  String get _plainNameForRead => name.text;

  String get _debugName => "IncompletePropertyAccessGenerator";

  Expression buildSimpleRead() {
    return unsupported("buildSimpleRead", fileOffset, _uri);
  }

  Expression buildAssignment(Expression value, {bool voidContext: false}) {
    return unsupported("buildAssignment", fileOffset, _uri);
  }

  withReceiver(Object? receiver, int operatorOffset,
      {bool isNullAware: false}) {
    if (receiver is Generator) {
      return receiver.buildPropertyAccess(this, operatorOffset, isNullAware);
    }
    return PropertyAccessGenerator.make(
        _helper, token, _helper.toValue(receiver), name, isNullAware);
  }

  Expression buildIfNullAssignment(Expression value, DartType type, int offset,
      {bool voidContext: false}) {
    return unsupported("buildNullAwareAssignment", offset, _uri);
  }

  Expression buildCompoundAssignment(Name binaryOperator, Expression value,
      {int offset: TreeNode.noOffset,
      bool voidContext: false,
      bool isPreIncDec: false,
      bool isPostIncDec: false}) {
    return unsupported("buildCompoundAssignment", offset, _uri);
  }

  Expression buildPrefixIncrement(Name binaryOperator,
      {int offset: TreeNode.noOffset, bool voidContext: false}) {
    return unsupported("buildPrefixIncrement", offset, _uri);
  }

  Expression buildPostfixIncrement(Name binaryOperator,
      {int offset: TreeNode.noOffset, bool voidContext: false}) {
    return unsupported("buildPostfixIncrement", offset, _uri);
  }

  Expression doInvocation(
      int offset, List<UnresolvedType>? typeArguments, Arguments arguments,
      {bool isTypeArgumentsInForest = false}) {
    return unsupported("doInvocation", offset, _uri);
  }

  @override
  Generator buildIndexedAccess(Expression index, Token token,
      {required bool isNullAware}) {
    // ignore: unnecessary_null_comparison
    assert(isNullAware != null);
    return unsupported("buildIndexedAccess", offsetForToken(token), _uri);
  }

  @override
  void printOn(StringSink sink) {
    sink.write(", name: ");
    sink.write(name.text);
  }
}

/// [ParenthesizedExpressionGenerator] represents the subexpression whose prefix
/// is a parenthesized expression.
///
/// For instance:
///
///   method(final a) {
///     final b = null;
///     (a);           // this generator is created for `(a)`.
///     (a)[];         // this generator is created for `(a)`.
///     (b)();         // this generator is created for `(b)`.
///     (b).c = (a.d); // this generator is created for `(a.d)` and `(b)`.
///   }
///
// TODO(johnniwinther): Remove this in favor of [ParenthesizedExpression] when
// the [TypePromoter] is replaced by [FlowAnalysis].
class ParenthesizedExpressionGenerator extends AbstractReadOnlyAccessGenerator {
  final Expression expression;

  ParenthesizedExpressionGenerator(
      ExpressionGeneratorHelper helper, Token token, this.expression)
      : super(helper, token, ReadOnlyAccessKind.ParenthesizedExpression);

  @override
  String get targetName => '';

  @override
  Expression buildSimpleRead() => expression;

  @override
  Expression _createRead() =>
      _helper.forest.createParenthesized(fileOffset, expression);

  String get _debugName => "ParenthesizedExpressionGenerator";

  /* Expression | Generator */ buildPropertyAccess(
      IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
    if (send is SendAccessGenerator) {
      return _helper.buildMethodInvocation(
          _createRead(), send.name, send.arguments, offsetForToken(send.token),
          isNullAware: isNullAware,
          isConstantExpression: send.isPotentiallyConstant);
    } else {
      if (_helper.constantContext != ConstantContext.none &&
          send.name != lengthName) {
        _helper.addProblem(
            messageNotAConstantExpression, fileOffset, token.length);
      }
      return PropertyAccessGenerator.make(
          _helper, send.token, _createRead(), send.name, isNullAware);
    }
  }
}

int adjustForImplicitCall(String? name, int offset) {
  // Normally the offset is at the start of the token, but in this case,
  // because we insert a '.call', we want it at the end instead.
  return offset + (name?.length ?? 0);
}

bool isFieldOrGetter(Member? member) {
  return member is Field || (member is Procedure && member.isGetter);
}
