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

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(UnresolvedKind unresolvedKind) {
    return _helper.buildUnresolvedError(_forest.createNullLiteral(fileOffset),
        _plainNameForRead, _forest.createArgumentsEmpty(noLocation), fileOffset,
        kind: unresolvedKind);
  }

  /// 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.buildUnresolvedError(
        _forest.createNullLiteral(fileOffset),
        _plainNameForRead,
        _forest.createArguments(noLocation, <Expression>[value]),
        fileOffset,
        kind: UnresolvedKind.Setter);
  }

  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 buildSelectorAccess(
      Selector send, int operatorOffset, bool isNullAware) {
    if (send is InvocationSelector) {
      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,
      {required bool inImplicitCreationContext}) {
    return _helper.createInstantiationAndInvocation(() => buildSimpleRead(),
        typeArguments, _plainNameForRead, name, arguments,
        instantiationOffset: fileOffset,
        invocationOffset: nameLastToken.charOffset,
        inImplicitCreationContext: inImplicitCreationContext);
  }

  void printOn(StringSink sink);

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

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

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

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

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

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

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

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

  @override
  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(UnresolvedKind.Getter);
    } 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(UnresolvedKind.Getter);
    } 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(UnresolvedKind.Getter);
    } 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>[];
  }

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

  @override
  String get _debugName => "ExplicitExtensionIndexedAccessGenerator";

  @override
  Expression buildSimpleRead() {
    if (readTarget == null) {
      return _makeInvalidRead(UnresolvedKind.Method);
    }
    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;
  }

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

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

  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,
          unresolvedReadKind: UnresolvedKind.Member);
    }
    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);
  }

  @override
  Expression_Generator buildSelectorAccess(
      Selector 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
  Expression_Generator 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
  Expression_Generator buildUnaryOperation(Token token, Name unaryName) {
    int fileOffset = offsetForToken(token);
    Generator generator = _createInstanceAccess(token, unaryName);
    return generator.doInvocation(
        fileOffset, null, _forest.createArgumentsEmpty(fileOffset));
  }

  @override
  Expression_Generator_Initializer 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([UnresolvedKind? unresolvedKind]) {
    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,
          unresolvedReadKind: UnresolvedKind.Method);
    }

    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
  Expression_Generator buildSelectorAccess(
      Selector send, int operatorOffset, bool isNullAware) {
    Object propertyAccess =
        suffixGenerator.buildSelectorAccess(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
  Expression_Generator_Initializer 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,
      {required bool inImplicitCreationContext}) {
    return _helper.wrapInDeferredCheck(
        suffixGenerator.invokeConstructor(
            typeArguments, name, arguments, nameToken, nameLastToken, constness,
            inImplicitCreationContext: inImplicitCreationContext),
        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;

  @override
  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,
      {required bool inImplicitCreationContext}) {
    return _helper.buildConstructorInvocation(
        declaration,
        nameToken,
        nameLastToken,
        arguments,
        name,
        typeArguments,
        offsetForToken(nameToken),
        constness,
        unresolvedKind: UnresolvedKind.Constructor);
  }

  @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
  Expression_Generator buildSelectorAccess(
      Selector 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) {
          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 the arguments weren't supplied, the tear off is treated as
          // generic, and the aliased type arguments match type parameters of
          // the type alias.
          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 PropertySelector) {
          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) {
                if (unaliasedTypeArguments.length !=
                    declarationBuilder.typeVariablesCount) {
                  // The type arguments are either aren't provided or mismatch
                  // in number with the type variables of the RHS declaration.
                  // We substitute them with the default types here: in the
                  // first case that would be exactly what type inference fills
                  // in for the RHS, and in the second case it's a reasonable
                  // fallback, as the error is reported during a check on the
                  // typedef.
                  builtTypeArguments = <DartType>[];
                  for (TypeParameter typeParameter
                      in declarationBuilder.cls.typeParameters) {
                    builtTypeArguments.add(typeParameter.defaultType);
                  }
                } else {
                  builtTypeArguments = declarationBuilder.buildTypeArguments(
                      _helper.libraryBuilder, unaliasedTypeArguments);
                }
              } else if (typeArguments != null) {
                builtTypeArguments =
                    _helper.buildDartTypeArguments(typeArguments);
              }
              if (isGenericTypedefTearOff) {
                if (isProperRenameForClass(_helper.typeEnvironment,
                    aliasBuilder!.typedef, aliasBuilder.library.library)) {
                  return tearOffExpression;
                }
                Procedure? tearOffLowering =
                    aliasBuilder.findConstructorOrFactory(
                        name.text, nameOffset, _uri, _helper.libraryBuilder);
                if (tearOffLowering != null) {
                  return _helper.forest
                      .createStaticTearOff(token.charOffset, tearOffLowering);
                }
                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,
              unresolvedReadKind: UnresolvedKind.Member);
        } else {
          return _helper.buildConstructorInvocation(
              declaration,
              send.token,
              send.token,
              arguments!,
              name.text,
              send.typeArguments,
              token.charOffset,
              Constness.implicit,
              isTypeArgumentsInForest: send.isTypeArgumentsInForest,
              typeAliasBuilder: aliasBuilder,
              unresolvedKind:
                  isNullAware ? UnresolvedKind.Method : UnresolvedKind.Member);
        }
      } else if (member is AmbiguousBuilder) {
        return _helper.buildProblem(
            member.message, member.charOffset, name.text.length);
      } else if (member.isStatic &&
          !member.isFactory &&
          typeArguments != null) {
        return _helper.buildProblem(messageStaticTearOffFromInstantiatedClass,
            send.fileOffset, send.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.buildSelectorAccess(send, operatorOffset, isNullAware);
    }
  }

  @override
  Expression_Generator_Builder 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,
          unresolvedKind: UnresolvedKind.Constructor);
    }
  }

  @override
  Expression_Generator 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 {
  @override
  final String targetName;

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

  @override
  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
  Expression_Generator_Initializer 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.buildUnresolvedError] if it is used.
  Expression buildError(Arguments arguments,
      {required UnresolvedKind kind, int? charOffset});

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

  @override
  String get _plainNameForRead => name.text;

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

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

  @override
  Expression_Generator buildSelectorAccess(
      Selector 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]),
        kind: UnresolvedKind.Setter);
  }

  @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]),
        kind: UnresolvedKind.Getter);
  }

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

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

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

  @override
  Expression buildSimpleRead() {
    return buildError(_forest.createArgumentsEmpty(fileOffset),
        kind: UnresolvedKind.Member);
  }

  @override
  Expression _makeInvalidRead(UnresolvedKind unresolvedKind) {
    return buildError(_forest.createArgumentsEmpty(fileOffset),
        kind: unresolvedKind);
  }

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

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

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

  final UnresolvedKind unresolvedReadKind;

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

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

  @override
  String get _debugName => "UnresolvedNameGenerator";

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

  @override
  Expression buildError(Arguments arguments,
      {required UnresolvedKind kind, int? charOffset}) {
    charOffset ??= fileOffset;
    return _helper.buildUnresolvedError(_forest.createNullLiteral(charOffset),
        _plainNameForRead, arguments, charOffset,
        kind: kind);
  }

  @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),
        kind: unresolvedReadKind)
      ..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]),
        kind: UnresolvedKind.Setter);
  }

  @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
  Never 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
  Never _makeInvalidRead([UnresolvedKind? unresolvedKind]) {
    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 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 buildSelectorAccess(
      Selector send, int operatorOffset, bool isNullAware) {
    assert(send.name.text == send.token.lexeme,
        "'${send.name.text}' != ${send.token.lexeme}");
    Object result = qualifiedLookup(send.token);
    if (send is InvocationSelector) {
      result = _helper.finishSend(
          result, send.typeArguments, send.arguments, send.fileOffset,
          isTypeArgumentsInForest: send.isTypeArgumentsInForest);
    }
    if (isNullAware) {
      result = _helper.wrapInLocatedProblem(
          _helper.toValue(result),
          messageCantUsePrefixWithNullAware.withLocation(
              _helper.uri, fileOffset, lengthForToken(token)));
    }
    return result;
  }

  @override
  Expression _makeInvalidRead([UnresolvedKind? unresolvedKind]) {
    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(UnresolvedKind.Member);

  @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(UnresolvedKind.Member);
  }

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

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

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

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

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

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

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

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

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

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

  @override
  Expression _makeInvalidRead([UnresolvedKind? unresolvedKind]) =>
      buildProblem();

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

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

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

  @override
  Expression buildSelectorAccess(
      Selector send, int operatorOffset, bool isNullAware) {
    return buildProblem();
  }

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

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

  @override
  Expression invokeConstructor(
      List<UnresolvedType>? typeArguments,
      String name,
      Arguments arguments,
      Token nameToken,
      Token nameLastToken,
      Constness constness,
      {required bool inImplicitCreationContext}) {
    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);

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

  @override
  String get _debugName => "ThisAccessGenerator";

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

  @override
  Expression_Generator buildSelectorAccess(
      Selector send, int operatorOffset, bool isNullAware) {
    Name name = send.name;
    Arguments? arguments = send.arguments;
    int offset = offsetForToken(send.token);
    if (isInitializer && send is InvocationSelector) {
      if (isNullAware) {
        _helper.addProblem(
            messageInvalidUseOfNullAwareAccess, operatorOffset, 2);
      }
      return buildConstructorInitializer(offset, name, arguments!);
    }
    if (inFieldInitializer && !inLateFieldInitializer && !isInitializer) {
      return buildFieldInitializerError(null);
    }
    if (send is InvocationSelector) {
      // 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);
      }
    }
  }

  @override
  Expression_Generator_Initializer 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
  Expression_Generator 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
  Expression_Generator 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
  Expression_Generator 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.buildUnresolvedError(
              _forest.createNullLiteral(offset),
              _helper.constructorNameForDiagnostics(name.text,
                  isSuper: isSuper),
              arguments,
              offset,
              isSuper: isSuper,
              message: message,
              kind: UnresolvedKind.Constructor),
          offset);
    } else if (isSuper) {
      return _helper.buildSuperInitializer(
          false, constructor!, arguments, offset);
    } else {
      return _helper.buildRedirectingInitializer(
          constructor!, arguments, offset);
    }
  }

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

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

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

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

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

class IncompleteErrorGenerator extends ErroneousExpressionGenerator {
  final Message message;

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

  @override
  String get _plainNameForRead => token.lexeme;

  @override
  String get _debugName => "IncompleteErrorGenerator";

  @override
  Expression buildError(Arguments arguments,
      {required UnresolvedKind kind,
      String? name,
      int? charOffset,
      int? charLength}) {
    if (charOffset == null) {
      charOffset = fileOffset;
      charLength ??= lengthForToken(token);
    }
    charLength ??= noLength;
    return _helper.buildProblem(message, charOffset, charLength);
  }

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

  @override
  Expression buildSimpleRead() {
    return buildError(_forest.createArgumentsEmpty(fileOffset),
        kind: UnresolvedKind.Member)
      ..fileOffset = fileOffset;
  }

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

/// [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 {
  @override
  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);

  @override
  String get _debugName => "ParenthesizedExpressionGenerator";

  @override
  Expression_Generator buildSelectorAccess(
      Selector send, int operatorOffset, bool isNullAware) {
    if (send is InvocationSelector) {
      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);
}

/// A [Selector] is a part of an object access after `.` or `..` or `?.`,
/// including arguments, if present.
///
/// For instance, an [InvocationSelector] is created for `b()` in
///
///    a.b();
///    a..b();
///    a?.b();
///
/// and a [PropertySelector] is created for `b` in
///
///    a.b;
///    a.b = c;
///    a..b;
///    a..b = c;
///    a?.b;
///    a?.b = c;
///
abstract class Selector {
  final ExpressionGeneratorHelper _helper;
  final Token token;

  Selector(this._helper, this.token);

  int get fileOffset => offsetForToken(token);

  Name get name;

  /// Applies this selector to [receiver].
  Expression_Generator withReceiver(Object? receiver, int operatorOffset,
      {bool isNullAware: false});

  List<UnresolvedType>? get typeArguments => null;

  bool get isTypeArgumentsInForest => true;

  Arguments? get arguments => null;

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

  void printOn(StringSink sink);

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

/// An [InvocationSelector] is the part of an object invocation after `.` or
/// `..` or `?.` including arguments.
///
/// For instance, an [InvocationSelector] is created for `b()` in
///
///    a.b();
///    a..b();
///    a?.b();
///
class InvocationSelector extends Selector {
  @override
  final Name name;

  @override
  final List<UnresolvedType>? typeArguments;

  @override
  final bool isTypeArgumentsInForest;

  @override
  final Arguments arguments;

  final bool isPotentiallyConstant;

  InvocationSelector(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);
  }

  @override
  String get _debugName => 'InvocationSelector';

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

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

/// A [PropertySelector] is the part of an object access after `.` or `..` or
/// `?.`.
///
/// For instance a [PropertySelector] is created for `b` in
///
///    a.b;
///    a.b = c;
///    a..b;
///    a..b = c;
///    a?.b;
///    a?.b = c;
///
class PropertySelector extends Selector {
  @override
  final Name name;

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

  @override
  String get _debugName => 'PropertySelector';

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

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