// Copyright (c) 2024, 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.

part of '../../ast.dart';

// ------------------------------------------------------------------------
//                                EXPRESSIONS
// ------------------------------------------------------------------------

sealed class Expression extends TreeNode {
  /// Returns the static type of the expression.
  ///
  /// This calls `StaticTypeContext.getExpressionType` which calls
  /// [getStaticTypeInternal] to compute the type of not already cached in
  /// [context].
  DartType getStaticType(StaticTypeContext context) {
    return context.getExpressionType(this);
  }

  /// Computes the static type of this expression.
  ///
  /// This is called by `StaticTypeContext.getExpressionType` if the static
  /// type of this expression is not already cached in [context].
  DartType getStaticTypeInternal(StaticTypeContext context);

  /// Returns the static type of the expression as an instantiation of
  /// [superclass].
  ///
  /// Shouldn't be used on code compiled in legacy mode, as this method assumes
  /// the IR is strongly typed.
  ///
  /// This method furthermore assumes that the type of the expression actually
  /// is a subtype of (some instantiation of) the given [superclass].
  /// If this is not the case, either an exception is thrown or the raw type of
  /// [superclass] is returned.
  InterfaceType getStaticTypeAsInstanceOf(
      Class superclass, StaticTypeContext context) {
    // This method assumes the program is correctly typed, so if the superclass
    // is not generic, we can just return its raw type without computing the
    // type of this expression.  It also ensures that all types are considered
    // subtypes of Object (not just interface types), and function types are
    // considered subtypes of Function.
    if (superclass.typeParameters.isEmpty) {
      return context.typeEnvironment.coreTypes
          .rawType(superclass, context.nonNullable);
    }
    DartType type = getStaticType(context).nonTypeParameterBound;
    if (type is NullType) {
      return context.typeEnvironment.coreTypes
          .bottomInterfaceType(superclass, context.nullable);
    } else if (type is NeverType) {
      return context.typeEnvironment.coreTypes
          .bottomInterfaceType(superclass, type.nullability);
    }
    if (type is TypeDeclarationType) {
      List<DartType>? upcastTypeArguments = context.typeEnvironment
          .getTypeArgumentsAsInstanceOf(type, superclass);
      if (upcastTypeArguments != null) {
        return new InterfaceType(
            superclass, type.nullability, upcastTypeArguments);
      }
    }

    // The static type of this expression is not a subtype of [superclass]. The
    // means that the static type of this expression is not the same as when
    // the parent [PropertyGet] or [MethodInvocation] was created.
    //
    // For instance when cloning generic mixin methods, the substitution can
    // render some of the code paths as dead code:
    //
    //     mixin M<T> {
    //       int method(T t) => t is String ? t.length : 0;
    //     }
    //     class C with M<int> {}
    //
    // The mixin transformation will clone the `M.method` method into the
    // unnamed mixin application for `Object&M<int>` as this:
    //
    //     int method(int t) => t is String ? t.length : 0;
    //
    // Now `t.length`, which was originally an access to `String.length` on a
    // receiver of type `T & String`, is an access to `String.length` on `int`.
    // When computing the static type of `t.length` we will try to compute the
    // type of `int` as an instance of `String`, and we do not find it to be
    // an instance of `String`.
    //
    // To resolve this case we compute the type of `t.length` to be the type
    // as if accessed on an unknown subtype `String`.
    return context.typeEnvironment.coreTypes
        .rawType(superclass, context.nonNullable);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg);

  int get precedence => astToText.Precedence.of(this);

  @override
  String toText(AstTextStrategy strategy) {
    AstPrinter printer = new AstPrinter(strategy);
    printer.writeExpression(this);
    return printer.getText();
  }
}

/// Abstract subclass of [Expression] that can be used to add [Expression]
/// subclasses from outside `package:kernel`.
abstract class AuxiliaryExpression extends Expression {
  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitAuxiliaryExpression(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitAuxiliaryExpression(this, arg);
}

/// An expression containing compile-time errors.
///
/// Should throw a runtime error when evaluated.
///
/// The [fileOffset] of an [InvalidExpression] indicates the location in the
/// tree where the expression occurs, rather than the location of the error.
class InvalidExpression extends Expression {
  // TODO(johnniwinther): Avoid using `null` as the empty string.
  String? message;

  /// The expression containing the error.
  Expression? expression;

  InvalidExpression(this.message, [this.expression]) {
    expression?.parent = this;
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      const NeverType.nonNullable();

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitInvalidExpression(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitInvalidExpression(this, arg);

  @override
  void visitChildren(Visitor v) {
    expression?.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    if (expression != null) {
      expression = v.transform(expression!);
      expression?.parent = this;
    }
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    if (expression != null) {
      expression = v.transformOrRemoveExpression(expression!);
      expression?.parent = this;
    }
  }

  @override
  String toString() {
    return "InvalidExpression(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('<invalid:');
    printer.write(message ?? '');
    if (expression != null) {
      printer.write(', ');
      printer.writeExpression(expression!);
    }
    printer.write('>');
  }
}

/// Read a local variable, a local function, or a function parameter.
class VariableGet extends Expression {
  VariableDeclaration variable;
  DartType? promotedType; // Null if not promoted.

  VariableGet(this.variable, [this.promotedType]);

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    return promotedType ?? variable.type;
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitVariableGet(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitVariableGet(this, arg);

  @override
  void visitChildren(Visitor v) {
    promotedType?.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    if (promotedType != null) {
      promotedType = v.visitDartType(promotedType!);
    }
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    if (promotedType != null) {
      DartType newPromotedType = v.visitDartType(promotedType!, dummyDartType);
      if (identical(newPromotedType, dummyDartType)) {
        promotedType = null;
      } else {
        promotedType = newPromotedType;
      }
    }
  }

  @override
  String toString() {
    return "VariableGet(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write(printer.getVariableName(variable));
    if (promotedType != null) {
      printer.write('{');
      printer.writeType(promotedType!);
      printer.write('}');
    }
  }
}

/// Assign a local variable or function parameter.
///
/// Evaluates to the value of [value].
class VariableSet extends Expression {
  VariableDeclaration variable;
  Expression value;

  VariableSet(this.variable, this.value) {
    value.parent = this;
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      value.getStaticType(context);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitVariableSet(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitVariableSet(this, arg);

  @override
  void visitChildren(Visitor v) {
    value.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    value = v.transform(value);
    value.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    value = v.transform(value);
    value.parent = this;
  }

  @override
  String toString() {
    return "VariableSet(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write(printer.getVariableName(variable));
    printer.write(' = ');
    printer.writeExpression(value);
  }
}

class RecordIndexGet extends Expression {
  Expression receiver;
  RecordType receiverType;
  final int index;

  RecordIndexGet(this.receiver, this.receiverType, this.index)
      : assert(0 <= index && index < receiverType.positional.length) {
    receiver.parent = this;
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    assert(index < receiverType.positional.length);
    return receiverType.positional[index];
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitRecordIndexGet(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitRecordIndexGet(this, arg);

  @override
  void visitChildren(Visitor v) {
    receiver.accept(v);
    receiverType.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    receiver = v.transform(receiver)..parent = this;
    receiverType = v.visitDartType(receiverType) as RecordType;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    receiver = v.transform(receiver)..parent = this;
    receiverType =
        v.visitDartType(receiverType, cannotRemoveSentinel) as RecordType;
  }

  @override
  String toString() {
    return "RecordIndexGet(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeExpression(receiver);
    printer.write(".\$${index + 1}");
  }
}

class RecordNameGet extends Expression {
  Expression receiver;
  RecordType receiverType;
  final String name;

  RecordNameGet(this.receiver, this.receiverType, this.name)
      : assert(receiverType.named
                .singleWhere((element) => element.name == name)
                .name ==
            name) {
    receiver.parent = this;
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    DartType? result;
    for (NamedType namedType in receiverType.named) {
      if (namedType.name == name) {
        result = namedType.type;
        break;
      }
    }
    assert(result != null);

    return result!;
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitRecordNameGet(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitRecordNameGet(this, arg);

  @override
  void visitChildren(Visitor v) {
    receiver.accept(v);
    receiverType.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    receiver = v.transform(receiver)..parent = this;
    receiverType = v.visitDartType(receiverType) as RecordType;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    receiver = v.transform(receiver)..parent = this;
    receiverType =
        v.visitDartType(receiverType, cannotRemoveSentinel) as RecordType;
  }

  @override
  String toString() {
    return "RecordNameGet(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeExpression(receiver);
    printer.write(".${name}");
  }
}

enum DynamicAccessKind {
  /// An access on a receiver of type dynamic.
  ///
  /// An access of this kind always results in a value of static type dynamic.
  ///
  /// Valid accesses to Object members on receivers of type dynamic are encoded
  /// as an [InstanceInvocation] of kind [InstanceAccessKind.Object].
  Dynamic,

  /// An access on a receiver of type Never.
  ///
  /// An access of this kind always results in a value of static type Never.
  ///
  /// Valid accesses to Object members on receivers of type Never are also
  /// encoded as [DynamicInvocation] of kind [DynamicAccessKind.Never] and _not_
  /// as an [InstanceInvocation] of kind [InstanceAccessKind.Object].
  Never,

  /// An access on a receiver of an invalid type.
  ///
  /// An access of this kind always results in a value of an invalid static
  /// type.
  Invalid,

  /// An access of an unresolved target.
  ///
  /// An access of this kind always results in a value of an invalid static
  /// type.
  Unresolved,
}

class DynamicGet extends Expression {
  final DynamicAccessKind kind;
  Expression receiver;
  Name name;

  DynamicGet(this.kind, this.receiver, this.name) {
    receiver.parent = this;
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitDynamicGet(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitDynamicGet(this, arg);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    switch (kind) {
      case DynamicAccessKind.Dynamic:
        return const DynamicType();
      case DynamicAccessKind.Never:
        return const NeverType.nonNullable();
      case DynamicAccessKind.Invalid:
      case DynamicAccessKind.Unresolved:
        return const InvalidType();
    }
  }

  @override
  void visitChildren(Visitor v) {
    receiver.accept(v);
    name.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    receiver = v.transform(receiver);
    receiver.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    receiver = v.transform(receiver);
    receiver.parent = this;
  }

  @override
  String toString() {
    return "DynamicGet($kind,${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeExpression(receiver,
        minimumPrecedence: astToText.Precedence.PRIMARY);
    printer.write('.');
    printer.writeName(name);
  }
}

/// A property read of an instance getter or field with a statically known
/// interface target.
class InstanceGet extends Expression {
  final InstanceAccessKind kind;
  Expression receiver;

  // TODO(johnniwinther): Can we pull this from the [interfaceTarget] instead?
  Name name;

  /// The static type of result of the property read.
  ///
  /// This includes substituted type parameters from the static receiver type.
  ///
  /// For instance
  ///
  ///    class A<T> {
  ///      T get t;
  ///    }
  ///    m(A<String> a) {
  ///      a.t; // The result type is `String`.
  ///    }
  ///
  DartType resultType;

  Reference interfaceTargetReference;

  InstanceGet(InstanceAccessKind kind, Expression receiver, Name name,
      {required Member interfaceTarget, required DartType resultType})
      : this.byReference(kind, receiver, name,
            interfaceTargetReference:
                getNonNullableMemberReferenceGetter(interfaceTarget),
            resultType: resultType);

  InstanceGet.byReference(this.kind, this.receiver, this.name,
      {required this.interfaceTargetReference, required this.resultType}) {
    receiver.parent = this;
  }

  Member get interfaceTarget => interfaceTargetReference.asMember;

  void set interfaceTarget(Member member) {
    interfaceTargetReference = getNonNullableMemberReferenceGetter(member);
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) => resultType;

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceGet(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitInstanceGet(this, arg);

  @override
  void visitChildren(Visitor v) {
    receiver.accept(v);
    interfaceTarget.acceptReference(v);
    name.accept(v);
    resultType.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    receiver = v.transform(receiver);
    receiver.parent = this;
    resultType = v.visitDartType(resultType);
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    receiver = v.transform(receiver);
    receiver.parent = this;
    resultType = v.visitDartType(resultType, cannotRemoveSentinel);
  }

  @override
  String toString() {
    return "InstanceGet($kind,${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeExpression(receiver,
        minimumPrecedence: astToText.Precedence.PRIMARY);
    printer.write('.');
    printer.writeInterfaceMemberName(interfaceTargetReference, name);
  }
}

/// A tear-off of the 'call' method on an expression whose static type is
/// a function type or the type 'Function'.
class FunctionTearOff extends Expression {
  Expression receiver;

  FunctionTearOff(this.receiver) {
    receiver.parent = this;
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      receiver.getStaticType(context);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitFunctionTearOff(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitFunctionTearOff(this, arg);

  @override
  void visitChildren(Visitor v) {
    receiver.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    receiver = v.transform(receiver);
    receiver.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    receiver = v.transform(receiver);
    receiver.parent = this;
  }

  @override
  String toString() {
    return "FunctionTearOff(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeExpression(receiver,
        minimumPrecedence: astToText.Precedence.PRIMARY);
    printer.write('.');
    printer.writeName(Name.callName);
  }
}

/// A tear-off of an instance method with a statically known interface target.
class InstanceTearOff extends Expression {
  final InstanceAccessKind kind;
  Expression receiver;

  // TODO(johnniwinther): Can we pull this from the [interfaceTarget] instead?
  Name name;

  /// The static type of result of the tear-off.
  ///
  /// This includes substituted type parameters from the static receiver type.
  ///
  /// For instance
  ///
  ///    class A<T, S> {
  ///      T method<U>(S s, U u) { ... }
  ///    }
  ///    m(A<String, int> a) {
  ///      a.method; // The result type is `String Function<U>(int, U)`.
  ///    }
  ///
  DartType resultType;

  Reference interfaceTargetReference;

  InstanceTearOff(InstanceAccessKind kind, Expression receiver, Name name,
      {required Procedure interfaceTarget, required DartType resultType})
      : this.byReference(kind, receiver, name,
            interfaceTargetReference:
                getNonNullableMemberReferenceGetter(interfaceTarget),
            resultType: resultType);

  InstanceTearOff.byReference(this.kind, this.receiver, this.name,
      {required this.interfaceTargetReference, required this.resultType}) {
    receiver.parent = this;
  }

  Procedure get interfaceTarget => interfaceTargetReference.asProcedure;

  void set interfaceTarget(Procedure procedure) {
    interfaceTargetReference = getNonNullableMemberReferenceGetter(procedure);
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) => resultType;

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceTearOff(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitInstanceTearOff(this, arg);

  @override
  void visitChildren(Visitor v) {
    receiver.accept(v);
    interfaceTarget.acceptReference(v);
    name.accept(v);
    resultType.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    receiver = v.transform(receiver);
    receiver.parent = this;
    resultType = v.visitDartType(resultType);
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    receiver = v.transform(receiver);
    receiver.parent = this;
    resultType = v.visitDartType(resultType, cannotRemoveSentinel);
  }

  @override
  String toString() {
    return "InstanceTearOff($kind, ${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeExpression(receiver,
        minimumPrecedence: astToText.Precedence.PRIMARY);
    printer.write('.');
    printer.writeInterfaceMemberName(interfaceTargetReference, name);
  }
}

class DynamicSet extends Expression {
  final DynamicAccessKind kind;
  Expression receiver;
  Name name;
  Expression value;

  DynamicSet(this.kind, this.receiver, this.name, this.value) {
    receiver.parent = this;
    value.parent = this;
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      value.getStaticType(context);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitDynamicSet(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitDynamicSet(this, arg);

  @override
  void visitChildren(Visitor v) {
    receiver.accept(v);
    name.accept(v);
    value.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    receiver = v.transform(receiver);
    receiver.parent = this;
    value = v.transform(value);
    value.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    receiver = v.transform(receiver);
    receiver.parent = this;
    value = v.transform(value);
    value.parent = this;
  }

  @override
  String toString() {
    return "DynamicSet($kind,${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeExpression(receiver,
        minimumPrecedence: astToText.Precedence.PRIMARY);
    printer.write('.');
    printer.writeName(name);
    printer.write(' = ');
    printer.writeExpression(value);
  }
}

/// An property write of an instance setter or field with a statically known
/// interface target.
class InstanceSet extends Expression {
  final InstanceAccessKind kind;
  Expression receiver;

  // TODO(johnniwinther): Can we pull this from the [interfaceTarget] instead?
  Name name;
  Expression value;

  Reference interfaceTargetReference;

  InstanceSet(
      InstanceAccessKind kind, Expression receiver, Name name, Expression value,
      {required Member interfaceTarget})
      : this.byReference(kind, receiver, name, value,
            interfaceTargetReference:
                getNonNullableMemberReferenceSetter(interfaceTarget));

  InstanceSet.byReference(this.kind, this.receiver, this.name, this.value,
      {required this.interfaceTargetReference}) {
    receiver.parent = this;
    value.parent = this;
  }

  Member get interfaceTarget => interfaceTargetReference.asMember;

  void set interfaceTarget(Member member) {
    interfaceTargetReference = getNonNullableMemberReferenceSetter(member);
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      value.getStaticType(context);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceSet(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitInstanceSet(this, arg);

  @override
  void visitChildren(Visitor v) {
    receiver.accept(v);
    interfaceTarget.acceptReference(v);
    name.accept(v);
    value.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    receiver = v.transform(receiver);
    receiver.parent = this;
    value = v.transform(value);
    value.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    receiver = v.transform(receiver);
    receiver.parent = this;
    value = v.transform(value);
    value.parent = this;
  }

  @override
  String toString() {
    return "InstanceSet(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeExpression(receiver,
        minimumPrecedence: astToText.Precedence.PRIMARY);
    printer.write('.');
    printer.writeInterfaceMemberName(interfaceTargetReference, name);
    printer.write(' = ');
    printer.writeExpression(value);
  }
}

/// Expression of form `super.foo` occurring in a mixin declaration.
///
/// In this setting, the target is looked up on the types in the mixin 'on'
/// clause and are therefore not necessary the runtime targets of the read. An
/// [AbstractSuperPropertyGet] must be converted into a [SuperPropertyGet] to
/// statically bind the target.
///
/// For instance
///
///    abstract class Interface {
///      get getter;
///    }
///    mixin Mixin on Interface {
///      get getter {
///        // This is an [AbstractSuperPropertyGet] with interface target
///        // `Interface.getter`.
///        return super.getter;
///      }
///    }
///    class Super implements Interface {
///      // This is the target when `Mixin` is applied to `Class`.
///      get getter => 42;
///    }
///    class Class extends Super with Mixin {}
///
/// This may invoke a getter, read a field, or tear off a method.
class AbstractSuperPropertyGet extends Expression {
  Name name;

  Reference interfaceTargetReference;

  AbstractSuperPropertyGet(Name name, Member interfaceTarget)
      : this.byReference(
            name, getNonNullableMemberReferenceGetter(interfaceTarget));

  AbstractSuperPropertyGet.byReference(
      this.name, this.interfaceTargetReference);

  Member get interfaceTarget => interfaceTargetReference.asMember;

  void set interfaceTarget(Member member) {
    interfaceTargetReference = getNonNullableMemberReferenceGetter(member);
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    Class declaringClass = interfaceTarget.enclosingClass!;
    if (declaringClass.typeParameters.isEmpty) {
      return interfaceTarget.getterType;
    }
    List<DartType>? receiverArguments = context.typeEnvironment
        .getTypeArgumentsAsInstanceOf(context.thisType!, declaringClass);
    return Substitution.fromPairs(
            declaringClass.typeParameters, receiverArguments!)
        .substituteType(interfaceTarget.getterType);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitAbstractSuperPropertyGet(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitAbstractSuperPropertyGet(this, arg);

  @override
  void visitChildren(Visitor v) {
    interfaceTarget.acceptReference(v);
    name.accept(v);
  }

  @override
  void transformChildren(Transformer v) {}

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {}

  @override
  String toString() {
    return "AbstractSuperPropertyGet(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('super.{abstract}');
    printer.writeInterfaceMemberName(interfaceTargetReference, name);
  }
}

/// Expression of form `super.field`.
///
/// This may invoke a getter, read a field, or tear off a method.
class SuperPropertyGet extends Expression {
  Name name;

  Reference interfaceTargetReference;

  SuperPropertyGet(Name name, Member interfaceTarget)
      : this.byReference(
            name, getNonNullableMemberReferenceGetter(interfaceTarget));

  SuperPropertyGet.byReference(this.name, this.interfaceTargetReference);

  Member get interfaceTarget => interfaceTargetReference.asMember;

  void set interfaceTarget(Member member) {
    interfaceTargetReference = getNonNullableMemberReferenceGetter(member);
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    Class declaringClass = interfaceTarget.enclosingClass!;
    if (declaringClass.typeParameters.isEmpty) {
      return interfaceTarget.getterType;
    }
    List<DartType>? receiverArguments = context.typeEnvironment
        .getTypeArgumentsAsInstanceOf(context.thisType!, declaringClass);
    return Substitution.fromPairs(
            declaringClass.typeParameters, receiverArguments!)
        .substituteType(interfaceTarget.getterType);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitSuperPropertyGet(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitSuperPropertyGet(this, arg);

  @override
  void visitChildren(Visitor v) {
    interfaceTarget.acceptReference(v);
    name.accept(v);
  }

  @override
  void transformChildren(Transformer v) {}

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {}

  @override
  String toString() {
    return "SuperPropertyGet(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('super.');
    printer.writeInterfaceMemberName(interfaceTargetReference, name);
  }
}

/// Expression of form `super.foo = x` occurring in a mixin declaration.
///
/// In this setting, the target is looked up on the types in the mixin 'on'
/// clause and are therefore not necessary the runtime targets of the
/// assignment. An [AbstractSuperPropertySet] must be converted into a
/// [SuperPropertySet] to statically bind the target.
///
/// For instance
///
///    abstract class Interface {
///      void set setter(value);
///    }
///    mixin Mixin on Interface {
///      void set setter(value) {
///        // This is an [AbstractSuperPropertySet] with interface target
///        // `Interface.setter`.
///        super.setter = value;
///      }
///    }
///    class Super implements Interface {
///      // This is the target when `Mixin` is applied to `Class`.
///      void set setter(value) {}
///    }
///    class Class extends Super with Mixin {}
///
/// This may invoke a setter or assign a field.
class AbstractSuperPropertySet extends Expression {
  Name name;
  Expression value;

  Reference interfaceTargetReference;

  AbstractSuperPropertySet(Name name, Expression value, Member interfaceTarget)
      : this.byReference(
            name, value, getNonNullableMemberReferenceSetter(interfaceTarget));

  AbstractSuperPropertySet.byReference(
      this.name, this.value, this.interfaceTargetReference) {
    value.parent = this;
  }

  Member get interfaceTarget => interfaceTargetReference.asMember;

  void set interfaceTarget(Member member) {
    interfaceTargetReference = getNonNullableMemberReferenceSetter(member);
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      value.getStaticType(context);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitAbstractSuperPropertySet(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitAbstractSuperPropertySet(this, arg);

  @override
  void visitChildren(Visitor v) {
    interfaceTarget.acceptReference(v);
    name.accept(v);
    value.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    value = v.transform(value);
    value.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    value = v.transform(value);
    value.parent = this;
  }

  @override
  String toString() {
    return "AbstractSuperPropertySet(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('super.{abstract}');
    printer.writeInterfaceMemberName(interfaceTargetReference, name);
    printer.write(' = ');
    printer.writeExpression(value);
  }
}

/// Expression of form `super.field = value`.
///
/// This may invoke a setter or assign a field.
///
/// Evaluates to the value of [value].
class SuperPropertySet extends Expression {
  Name name;
  Expression value;

  Reference interfaceTargetReference;

  SuperPropertySet(Name name, Expression value, Member interfaceTarget)
      : this.byReference(
            name, value, getNonNullableMemberReferenceSetter(interfaceTarget));

  SuperPropertySet.byReference(
      this.name, this.value, this.interfaceTargetReference) {
    value.parent = this;
  }

  Member get interfaceTarget => interfaceTargetReference.asMember;

  void set interfaceTarget(Member member) {
    interfaceTargetReference = getNonNullableMemberReferenceSetter(member);
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      value.getStaticType(context);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitSuperPropertySet(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitSuperPropertySet(this, arg);

  @override
  void visitChildren(Visitor v) {
    interfaceTarget.acceptReference(v);
    name.accept(v);
    value.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    value = v.transform(value);
    value.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    value = v.transform(value);
    value.parent = this;
  }

  @override
  String toString() {
    return "SuperPropertySet(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('super.');
    printer.writeInterfaceMemberName(interfaceTargetReference, name);
    printer.write(' = ');
    printer.writeExpression(value);
  }
}

/// Read a static field, call a static getter, or tear off a static method.
class StaticGet extends Expression {
  /// A static field, getter, or method (for tear-off).
  Reference targetReference;

  StaticGet(Member target)
      : assert(target is Field || (target is Procedure && target.isGetter)),
        this.targetReference = getNonNullableMemberReferenceGetter(target);

  StaticGet.byReference(this.targetReference);

  Member get target => targetReference.asMember;

  void set target(Member target) {
    targetReference = getNonNullableMemberReferenceGetter(target);
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      target.getterType;

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitStaticGet(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitStaticGet(this, arg);

  @override
  void visitChildren(Visitor v) {
    target.acceptReference(v);
  }

  @override
  void transformChildren(Transformer v) {}

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {}

  @override
  String toString() {
    return "StaticGet(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeMemberName(targetReference);
  }
}

/// Tear-off of a static method.
class StaticTearOff extends Expression {
  Reference targetReference;

  StaticTearOff(Procedure target)
      : assert(target.isStatic, "Unexpected static tear off target: $target"),
        assert(target.kind == ProcedureKind.Method,
            "Unexpected static tear off target: $target"),
        this.targetReference = getNonNullableMemberReferenceGetter(target);

  StaticTearOff.byReference(this.targetReference);

  Procedure get target => targetReference.asProcedure;

  void set target(Procedure target) {
    targetReference = getNonNullableMemberReferenceGetter(target);
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      target.getterType;

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitStaticTearOff(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitStaticTearOff(this, arg);

  @override
  void visitChildren(Visitor v) {
    target.acceptReference(v);
  }

  @override
  void transformChildren(Transformer v) {}

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {}

  @override
  String toString() {
    return "StaticTearOff(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeMemberName(targetReference);
  }
}

/// Assign a static field or call a static setter.
///
/// Evaluates to the value of [value].
class StaticSet extends Expression {
  /// A mutable static field or a static setter.
  Reference targetReference;
  Expression value;

  StaticSet(Member target, Expression value)
      : this.byReference(getNonNullableMemberReferenceSetter(target), value);

  StaticSet.byReference(this.targetReference, this.value) {
    value.parent = this;
  }

  Member get target => targetReference.asMember;

  void set target(Member target) {
    targetReference = getNonNullableMemberReferenceSetter(target);
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      value.getStaticType(context);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitStaticSet(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitStaticSet(this, arg);

  @override
  void visitChildren(Visitor v) {
    target.acceptReference(v);
    value.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    value = v.transform(value);
    value.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    value = v.transform(value);
    value.parent = this;
  }

  @override
  String toString() {
    return "StaticSet(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeMemberName(targetReference);
    printer.write(' = ');
    printer.writeExpression(value);
  }
}

/// The arguments to a function call, divided into type arguments,
/// positional arguments, and named arguments.
class Arguments extends TreeNode {
  final List<DartType> types;
  final List<Expression> positional;
  List<NamedExpression> named;

  Arguments(this.positional,
      {List<DartType>? types, List<NamedExpression>? named})
      : this.types = types ?? <DartType>[],
        this.named = named ?? <NamedExpression>[] {
    setParents(this.positional, this);
    setParents(this.named, this);
  }

  Arguments.empty()
      : types = <DartType>[],
        positional = <Expression>[],
        named = <NamedExpression>[];

  factory Arguments.forwarded(FunctionNode function, Library library) {
    return new Arguments(
        function.positionalParameters
            .map<Expression>((p) => new VariableGet(p))
            .toList(),
        named: function.namedParameters
            .map((p) => new NamedExpression(p.name!, new VariableGet(p)))
            .toList(),
        types: function.typeParameters
            .map<DartType>(
                (p) => new TypeParameterType.withDefaultNullability(p))
            .toList());
  }

  @override
  R accept<R>(TreeVisitor<R> v) => v.visitArguments(this);

  @override
  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) => v.visitArguments(this, arg);

  @override
  void visitChildren(Visitor v) {
    visitList(types, v);
    visitList(positional, v);
    visitList(named, v);
  }

  @override
  void transformChildren(Transformer v) {
    v.transformDartTypeList(types);
    v.transformList(positional, this);
    v.transformList(named, this);
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    v.transformDartTypeList(types);
    v.transformExpressionList(positional, this);
    v.transformNamedExpressionList(named, this);
  }

  @override
  String toString() {
    return "Arguments(${toStringInternal()})";
  }

  @override
  String toText(AstTextStrategy strategy) {
    AstPrinter printer = new AstPrinter(strategy);
    printer.writeArguments(this);
    return printer.getText();
  }

  @override
  void toTextInternal(AstPrinter printer, {bool includeTypeArguments = true}) {
    if (includeTypeArguments) {
      printer.writeTypeArguments(types);
    }
    printer.write('(');
    for (int index = 0; index < positional.length; index++) {
      if (index > 0) {
        printer.write(', ');
      }
      printer.writeExpression(positional[index]);
    }
    if (named.isNotEmpty) {
      if (positional.isNotEmpty) {
        printer.write(', ');
      }
      for (int index = 0; index < named.length; index++) {
        if (index > 0) {
          printer.write(', ');
        }
        printer.writeNamedExpression(named[index]);
      }
    }
    printer.write(')');
  }
}

/// A named argument, `name: value`.
class NamedExpression extends TreeNode {
  String name;
  Expression value;

  NamedExpression(this.name, this.value) {
    value.parent = this;
  }

  @override
  R accept<R>(TreeVisitor<R> v) => v.visitNamedExpression(this);

  @override
  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) =>
      v.visitNamedExpression(this, arg);

  @override
  void visitChildren(Visitor v) {
    value.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    value = v.transform(value);
    value.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    value = v.transform(value);
    value.parent = this;
  }

  @override
  String toString() {
    return "NamedExpression(${toStringInternal()})";
  }

  @override
  String toText(AstTextStrategy strategy) {
    AstPrinter printer = new AstPrinter(strategy);
    toTextInternal(printer);
    return printer.getText();
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write(name);
    printer.write(': ');
    printer.writeExpression(value);
  }
}

/// Common super class for [DirectMethodInvocation], [MethodInvocation],
/// [SuperMethodInvocation], [StaticInvocation], and [ConstructorInvocation].
abstract class InvocationExpression extends Expression {
  Arguments get arguments;

  /// Name of the invoked method.
  Name get name;
}

abstract class InstanceInvocationExpression extends InvocationExpression {
  Expression get receiver;
}

class DynamicInvocation extends InstanceInvocationExpression {
  // Must match serialized bit positions.
  static const int FlagImplicitCall = 1 << 0;

  final DynamicAccessKind kind;

  @override
  Expression receiver;

  @override
  Name name;

  @override
  Arguments arguments;

  int flags = 0;

  DynamicInvocation(this.kind, this.receiver, this.name, this.arguments) {
    receiver.parent = this;
    arguments.parent = this;
  }

  /// If `true` this is an implicit call to 'call'. For instance
  ///
  ///    method(dynamic d) {
  ///      d(); // Implicit call.
  ///      d.call(); // Explicit call.
  ///
  bool get isImplicitCall => flags & FlagImplicitCall != 0;

  void set isImplicitCall(bool value) {
    flags = value ? (flags | FlagImplicitCall) : (flags & ~FlagImplicitCall);
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    switch (kind) {
      case DynamicAccessKind.Dynamic:
        return const DynamicType();
      case DynamicAccessKind.Never:
        return const NeverType.nonNullable();
      case DynamicAccessKind.Invalid:
      case DynamicAccessKind.Unresolved:
        return const InvalidType();
    }
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitDynamicInvocation(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitDynamicInvocation(this, arg);

  @override
  void visitChildren(Visitor v) {
    receiver.accept(v);
    name.accept(v);
    arguments.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    receiver = v.transform(receiver);
    receiver.parent = this;
    arguments = v.transform(arguments);
    arguments.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    receiver = v.transform(receiver);
    receiver.parent = this;
    arguments = v.transform(arguments);
    arguments.parent = this;
  }

  @override
  String toString() {
    return "DynamicInvocation($kind,${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeExpression(receiver,
        minimumPrecedence: astToText.Precedence.PRIMARY);
    if (!isImplicitCall) {
      printer.write('.');
      printer.writeName(name);
    }
    printer.writeArguments(arguments);
  }
}

/// Access kind used by [InstanceInvocation], [InstanceGet], [InstanceSet],
/// and [InstanceTearOff].
enum InstanceAccessKind {
  /// An access to a member on a static receiver type which is an interface
  /// type.
  ///
  /// In null safe libraries the static receiver type is non-nullable.
  ///
  /// For instance:
  ///
  ///     class C { void method() {} }
  ///     main() => new C().method();
  ///
  Instance,

  /// An access to a member defined on Object on a static receiver type that
  /// is either a non-interface type or a nullable type.
  ///
  /// For instance:
  ///
  ///     test1(String? s) => s.toString();
  ///     test1(dynamic s) => s.hashCode;
  ///
  Object,

  /// An access to a method on a static receiver type which is an interface
  /// type which is inapplicable, that is, whose arguments don't match the
  /// required parameter structure.
  ///
  /// This is an error case which is only used on expression nested within
  /// [InvalidExpression]s.
  ///
  /// For instance:
  ///
  ///     class C { void method() {} }
  ///     main() => new C().method(0); // Too many arguments.
  ///
  Inapplicable,

  /// An access to a non-Object member on a static receiver type which is a
  /// nullable interface type.
  ///
  /// This is an error case which is only used on expression nested within
  /// [InvalidExpression]s.
  ///
  /// For instance:
  ///
  ///     class C { void method() {} }
  ///     test(C? c) => c.method(0); // 'c' is nullable.
  ///
  Nullable,
}

/// An invocation of an instance method with a statically known interface
/// target.
class InstanceInvocation extends InstanceInvocationExpression {
  // Must match serialized bit positions.
  static const int FlagInvariant = 1 << 0;
  static const int FlagBoundsSafe = 1 << 1;

  final InstanceAccessKind kind;

  @override
  Expression receiver;

  // TODO(johnniwinther): Can we pull this from the [interfaceTarget] instead?
  @override
  Name name;

  @override
  Arguments arguments;

  int flags = 0;

  /// The static type of the invocation.
  ///
  /// This includes substituted type parameters from the static receiver type
  /// and generic type arguments.
  ///
  /// For instance
  ///
  ///    class A<T> {
  ///      Map<T, S> map<S>(S s) { ... }
  ///    }
  ///    m(A<String> a) {
  ///      a.map(0); // The function type is `Map<String, int> Function(int)`.
  ///    }
  ///
  FunctionType functionType;

  Reference interfaceTargetReference;

  InstanceInvocation(InstanceAccessKind kind, Expression receiver, Name name,
      Arguments arguments,
      {required Procedure interfaceTarget, required FunctionType functionType})
      : this.byReference(kind, receiver, name, arguments,
            interfaceTargetReference:
                getNonNullableMemberReferenceGetter(interfaceTarget),
            functionType: functionType);

  InstanceInvocation.byReference(
      this.kind, this.receiver, this.name, this.arguments,
      {required this.interfaceTargetReference, required this.functionType})
      : assert(functionType.typeParameters.isEmpty) {
    receiver.parent = this;
    arguments.parent = this;
  }

  Procedure get interfaceTarget => interfaceTargetReference.asProcedure;

  void set interfaceTarget(Procedure target) {
    interfaceTargetReference = getNonNullableMemberReferenceGetter(target);
  }

  /// If `true`, this call is known to be safe wrt. parameter covariance checks.
  ///
  /// This is for instance the case in code patterns like this
  ///
  ///     List<int> list = <int>[];
  ///     list.add(0);
  ///
  /// where the `list` variable is known to hold a value of the same type as
  /// the static type. In contrast the would not be the case in code patterns
  /// like this
  ///
  ///     List<num> list = <double>[];
  ///     list.add(0); // Runtime error `int` is not a subtype of `double`.
  ///
  bool get isInvariant => flags & FlagInvariant != 0;

  void set isInvariant(bool value) {
    flags = value ? (flags | FlagInvariant) : (flags & ~FlagInvariant);
  }

  /// If `true`, this call is known to be safe wrt. parameter covariance checks.
  ///
  /// This is for instance the case in code patterns like this
  ///
  ///     List list = new List.filled(2, 0);
  ///     list[1] = 42;
  ///
  /// where the `list` is known to have a sufficient length for the update
  /// in `list[1] = 42`.
  bool get isBoundsSafe => flags & FlagBoundsSafe != 0;

  void set isBoundsSafe(bool value) {
    flags = value ? (flags | FlagBoundsSafe) : (flags & ~FlagBoundsSafe);
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      functionType.returnType;

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceInvocation(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitInstanceInvocation(this, arg);

  @override
  void visitChildren(Visitor v) {
    receiver.accept(v);
    interfaceTarget.acceptReference(v);
    name.accept(v);
    arguments.accept(v);
    functionType.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    receiver = v.transform(receiver);
    receiver.parent = this;
    arguments = v.transform(arguments);
    arguments.parent = this;
    functionType = v.visitDartType(functionType) as FunctionType;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    receiver = v.transform(receiver);
    receiver.parent = this;
    arguments = v.transform(arguments);
    arguments.parent = this;
    functionType =
        v.visitDartType(functionType, cannotRemoveSentinel) as FunctionType;
  }

  @override
  String toString() {
    return "InstanceInvocation($kind, ${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeExpression(receiver,
        minimumPrecedence: astToText.Precedence.PRIMARY);
    printer.write('.');
    printer.writeInterfaceMemberName(interfaceTargetReference, name);
    printer.writeArguments(arguments);
  }
}

/// An invocation of an instance getter or field with a statically known
/// interface target.
///
/// This is used only for web backend in order to support invocation of
/// native properties as functions. This node will be removed when this
/// invocation style is no longer supported.
class InstanceGetterInvocation extends InstanceInvocationExpression {
  // Must match serialized bit positions.
  static const int FlagInvariant = 1 << 0;
  static const int FlagBoundsSafe = 1 << 1;

  final InstanceAccessKind kind;

  @override
  Expression receiver;

  @override
  Name name;

  @override
  Arguments arguments;

  int flags = 0;

  /// The static type of the invocation, or `dynamic` is of the type is unknown.
  ///
  /// This includes substituted type parameters from the static receiver type
  /// and generic type arguments.
  ///
  /// For instance
  ///
  ///    class A<T> {
  ///      Map<T, S> Function<S>(S) get map => ...
  ///      dynamic get dyn => ...
  ///    }
  ///    m(A<String> a) {
  ///      a.map(0); // The function type is `Map<String, int> Function(int)`.
  ///      a.dyn(0); // The function type is `null`.
  ///    }
  ///
  FunctionType? functionType;

  Reference interfaceTargetReference;

  InstanceGetterInvocation(InstanceAccessKind kind, Expression receiver,
      Name name, Arguments arguments,
      {required Member interfaceTarget, required FunctionType? functionType})
      : this.byReference(kind, receiver, name, arguments,
            interfaceTargetReference:
                getNonNullableMemberReferenceGetter(interfaceTarget),
            functionType: functionType);

  InstanceGetterInvocation.byReference(
      this.kind, this.receiver, this.name, this.arguments,
      {required this.interfaceTargetReference, required this.functionType})
      : assert(functionType == null || functionType.typeParameters.isEmpty) {
    receiver.parent = this;
    arguments.parent = this;
  }

  Member get interfaceTarget => interfaceTargetReference.asMember;

  void set interfaceTarget(Member target) {
    interfaceTargetReference = getNonNullableMemberReferenceGetter(target);
  }

  /// If `true`, this call is known to be safe wrt. parameter covariance checks.
  ///
  /// This is for instance the case in code patterns like this
  ///
  ///     List<int> list = <int>[];
  ///     list.add(0);
  ///
  /// where the `list` variable is known to hold a value of the same type as
  /// the static type. In contrast the would not be the case in code patterns
  /// like this
  ///
  ///     List<num> list = <double>[];
  ///     list.add(0); // Runtime error `int` is not a subtype of `double`.
  ///
  bool get isInvariant => flags & FlagInvariant != 0;

  void set isInvariant(bool value) {
    flags = value ? (flags | FlagInvariant) : (flags & ~FlagInvariant);
  }

  /// If `true`, this call is known to be safe wrt. parameter covariance checks.
  ///
  /// This is for instance the case in code patterns like this
  ///
  ///     List list = new List.filled(2, 0);
  ///     list[1] = 42;
  ///
  /// where the `list` is known to have a sufficient length for the update
  /// in `list[1] = 42`.
  bool get isBoundsSafe => flags & FlagBoundsSafe != 0;

  void set isBoundsSafe(bool value) {
    flags = value ? (flags | FlagBoundsSafe) : (flags & ~FlagBoundsSafe);
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      functionType?.returnType ?? const DynamicType();

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceGetterInvocation(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitInstanceGetterInvocation(this, arg);

  @override
  void visitChildren(Visitor v) {
    receiver.accept(v);
    interfaceTarget.acceptReference(v);
    name.accept(v);
    arguments.accept(v);
    functionType?.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    receiver = v.transform(receiver);
    receiver.parent = this;
    arguments = v.transform(arguments);
    arguments.parent = this;

    if (functionType != null) {
      functionType = v.visitDartType(functionType!) as FunctionType;
    }
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    receiver = v.transform(receiver);
    receiver.parent = this;
    arguments = v.transform(arguments);
    arguments.parent = this;
    if (functionType != null) {
      functionType =
          v.visitDartType(functionType!, cannotRemoveSentinel) as FunctionType;
    }
  }

  @override
  String toString() {
    return "InstanceGetterInvocation($kind, ${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeExpression(receiver,
        minimumPrecedence: astToText.Precedence.PRIMARY);
    printer.write('.');
    printer.writeInterfaceMemberName(interfaceTargetReference, name);
    printer.writeArguments(arguments);
  }
}

/// Access kind used by [FunctionInvocation] and [FunctionTearOff].
enum FunctionAccessKind {
  /// An access to the 'call' method on an expression of static type `Function`.
  ///
  /// For instance
  ///
  ///     method(Function f) => f();
  ///
  Function,

  /// An access to the 'call' method on an expression whose static type is a
  /// function type.
  ///
  /// For instance
  ///
  ///     method(void Function() f) => f();
  ///
  FunctionType,

  /// An access to the 'call' method on an expression whose static type is a
  /// function type which is inapplicable, that is, whose arguments don't match
  /// the required parameter structure.
  ///
  /// This is an error case which is only used on expression nested within
  /// [InvalidExpression]s.
  ///
  /// For instance:
  ///
  ///     test(void Function() f) => f(0); // Too many arguments.
  ///
  Inapplicable,

  /// An access to the 'call' method on an expression whose static type is a
  /// nullable function type or `Function?`.
  ///
  /// This is an error case which is only used on expression nested within
  /// [InvalidExpression]s.
  ///
  /// For instance:
  ///
  ///     test(void Function()? f) => f(); // 'f' is nullable.
  ///
  Nullable,
}

/// An invocation of the 'call' method on an expression whose static type is
/// a function type or the type 'Function'.
class FunctionInvocation extends InstanceInvocationExpression {
  final FunctionAccessKind kind;

  @override
  Expression receiver;

  @override
  Arguments arguments;

  /// The static type of the invocation.
  ///
  /// This is `null` if the static type of the receiver is not a function type
  /// or is not bounded by a function type.
  ///
  /// For instance
  ///
  ///    m<T extends Function, S extends int Function()>(T t, S s, Function f) {
  ///      X local<X>(X t) => t;
  ///      t(); // The function type is `null`.
  ///      s(); // The function type is `int Function()`.
  ///      f(); // The function type is `null`.
  ///      local(0); // The function type is `int Function(int)`.
  ///    }
  ///
  FunctionType? functionType;

  FunctionInvocation(this.kind, this.receiver, this.arguments,
      {required this.functionType}) {
    receiver.parent = this;
    arguments.parent = this;
  }

  @override
  Name get name => Name.callName;

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      functionType?.returnType ?? const DynamicType();

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitFunctionInvocation(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitFunctionInvocation(this, arg);

  @override
  void visitChildren(Visitor v) {
    receiver.accept(v);
    name.accept(v);
    arguments.accept(v);
    functionType?.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    receiver = v.transform(receiver);
    receiver.parent = this;
    arguments = v.transform(arguments);
    arguments.parent = this;
    FunctionType? type = functionType;
    if (type != null) {
      functionType = v.visitDartType(type) as FunctionType;
    }
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    receiver = v.transform(receiver);
    receiver.parent = this;
    arguments = v.transform(arguments);
    arguments.parent = this;
    FunctionType? type = functionType;
    if (type != null) {
      functionType =
          v.visitDartType(type, cannotRemoveSentinel) as FunctionType;
    }
  }

  @override
  String toString() {
    return "FunctionInvocation(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeExpression(receiver,
        minimumPrecedence: astToText.Precedence.PRIMARY);
    printer.writeArguments(arguments);
  }
}

/// An invocation of a local function declaration.
class LocalFunctionInvocation extends InvocationExpression {
  /// The variable declaration for the function declaration.
  VariableDeclaration variable;

  @override
  Arguments arguments;

  /// The static type of the invocation.
  ///
  /// This might differ from the static type of [variable] for generic
  /// functions.
  ///
  /// For instance
  ///
  ///    m() {
  ///      T local<T>(T t) => t;
  ///      local(0); // The static type is `int Function(int)`.
  ///    }
  ///
  FunctionType functionType;

  LocalFunctionInvocation(this.variable, this.arguments,
      {required this.functionType}) {
    arguments.parent = this;
  }

  /// The declaration for the invoked local function.
  FunctionDeclaration get localFunction =>
      variable.parent as FunctionDeclaration;

  @override
  Name get name => Name.callName;

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      functionType.returnType;

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitLocalFunctionInvocation(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitLocalFunctionInvocation(this, arg);

  @override
  void visitChildren(Visitor v) {
    arguments.accept(v);
    functionType.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    arguments = v.transform(arguments);
    arguments.parent = this;
    functionType = v.visitDartType(functionType) as FunctionType;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    arguments = v.transform(arguments);
    arguments.parent = this;
    functionType =
        v.visitDartType(functionType, cannotRemoveSentinel) as FunctionType;
  }

  @override
  String toString() {
    return "LocalFunctionInvocation(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write(printer.getVariableName(variable));
    printer.writeArguments(arguments);
  }
}

/// Nullness test of an expression, that is `e == null`.
///
/// This is generated for code like `e1 == e2` where `e1` or `e2` is `null`.
class EqualsNull extends Expression {
  /// The expression tested for nullness.
  Expression expression;

  EqualsNull(this.expression) {
    expression.parent = this;
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitEqualsNull(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitEqualsNull(this, arg);

  @override
  void visitChildren(Visitor v) {
    expression.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    expression = v.transform(expression);
    expression.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    expression = v.transform(expression);
    expression.parent = this;
  }

  @override
  String toString() {
    return "EqualsNull(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeExpression(expression, minimumPrecedence: precedence);
    printer.write(' == null');
  }
}

/// A test of equality, that is `e1 == e2`.
///
/// This is generated for code like `e1 == e2` where neither `e1` nor `e2` is
/// `null`.
class EqualsCall extends Expression {
  Expression left;
  Expression right;

  /// The static type of the invocation.
  ///
  /// This might differ from the static type of [Object.==] for covariant
  /// parameters.
  ///
  /// For instance
  ///
  ///    class C<T> {
  ///      bool operator(covariant C<T> other) { ... }
  ///    }
  ///    // The function type is `bool Function(C<num>)`.
  ///    method(C<num> a, C<int> b) => a == b;
  ///
  FunctionType functionType;

  Reference interfaceTargetReference;

  EqualsCall(Expression left, Expression right,
      {required FunctionType functionType, required Procedure interfaceTarget})
      : this.byReference(left, right,
            functionType: functionType,
            interfaceTargetReference:
                getNonNullableMemberReferenceGetter(interfaceTarget));

  EqualsCall.byReference(this.left, this.right,
      {required this.functionType, required this.interfaceTargetReference}) {
    left.parent = this;
    right.parent = this;
  }

  Procedure get interfaceTarget => interfaceTargetReference.asProcedure;

  void set interfaceTarget(Procedure target) {
    interfaceTargetReference = getNonNullableMemberReferenceGetter(target);
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    return functionType.returnType;
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitEqualsCall(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitEqualsCall(this, arg);

  @override
  void visitChildren(Visitor v) {
    left.accept(v);
    interfaceTarget.acceptReference(v);
    right.accept(v);
    functionType.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    left = v.transform(left);
    left.parent = this;
    right = v.transform(right);
    right.parent = this;
    functionType = v.visitDartType(functionType) as FunctionType;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    left = v.transform(left);
    left.parent = this;
    right = v.transform(right);
    right.parent = this;
    functionType =
        v.visitDartType(functionType, cannotRemoveSentinel) as FunctionType;
  }

  @override
  String toString() {
    return "EqualsCall(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    int minimumPrecedence = precedence;
    printer.writeExpression(left, minimumPrecedence: minimumPrecedence);
    printer.write(' == ');
    printer.writeExpression(right, minimumPrecedence: minimumPrecedence + 1);
  }
}

/// Expression of form `super.foo(x)` occurring in a mixin declaration.
///
/// In this setting, the target is looked up on the types in the mixin 'on'
/// clause and are therefore not necessary the runtime targets of the
/// invocation. An [AbstractSuperMethodInvocation] must be converted into
/// a [SuperMethodInvocation] to statically bind the target.
///
/// For instance
///
///    abstract class Interface {
///      void method();
///    }
///    mixin Mixin on Interface {
///      void method() {
///        // This is an [AbstractSuperMethodInvocation] with interface target
///        // `Interface.method`.
///        super.method(); // This targets Super.method.
///      }
///    }
///    class Super implements Interface {
///      // This is the target when `Mixin` is applied to `Class`.
///      void method() {}
///    }
///    class Class extends Super with Mixin {}
///
class AbstractSuperMethodInvocation extends InvocationExpression {
  @override
  Name name;

  @override
  Arguments arguments;

  Reference interfaceTargetReference;

  AbstractSuperMethodInvocation(
      Name name, Arguments arguments, Procedure interfaceTarget)
      : this.byReference(
            name,
            arguments,
            // An invocation doesn't refer to the setter.
            getNonNullableMemberReferenceGetter(interfaceTarget));

  AbstractSuperMethodInvocation.byReference(
      this.name, this.arguments, this.interfaceTargetReference) {
    arguments.parent = this;
  }

  Procedure get interfaceTarget => interfaceTargetReference.asProcedure;

  void set interfaceTarget(Procedure target) {
    // An invocation doesn't refer to the setter.
    interfaceTargetReference = getNonNullableMemberReferenceGetter(target);
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    Class superclass = interfaceTarget.enclosingClass!;
    List<DartType>? receiverTypeArguments = context.typeEnvironment
        .getTypeArgumentsAsInstanceOf(context.thisType!, superclass);
    DartType returnType = Substitution.fromPairs(
            superclass.typeParameters, receiverTypeArguments!)
        .substituteType(interfaceTarget.function.returnType);
    return Substitution.fromPairs(
            interfaceTarget.function.typeParameters, arguments.types)
        .substituteType(returnType);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) =>
      v.visitAbstractSuperMethodInvocation(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitAbstractSuperMethodInvocation(this, arg);

  @override
  void visitChildren(Visitor v) {
    interfaceTarget.acceptReference(v);
    name.accept(v);
    arguments.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    arguments = v.transform(arguments);
    arguments.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    arguments = v.transform(arguments);
    arguments.parent = this;
  }

  @override
  String toString() {
    return "AbstractSuperMethodInvocation(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('super.{abstract}');
    printer.writeInterfaceMemberName(interfaceTargetReference, name);
    printer.writeArguments(arguments);
  }
}

/// Expression of form `super.foo(x)`.
///
/// The provided arguments might not match the parameters of the target.
class SuperMethodInvocation extends InvocationExpression {
  @override
  Name name;

  @override
  Arguments arguments;

  Reference interfaceTargetReference;

  SuperMethodInvocation(
      Name name, Arguments arguments, Procedure interfaceTarget)
      : this.byReference(
            name,
            arguments,
            // An invocation doesn't refer to the setter.
            getNonNullableMemberReferenceGetter(interfaceTarget));

  SuperMethodInvocation.byReference(
      this.name, this.arguments, this.interfaceTargetReference) {
    arguments.parent = this;
  }

  Procedure get interfaceTarget => interfaceTargetReference.asProcedure;

  void set interfaceTarget(Procedure target) {
    // An invocation doesn't refer to the setter.
    interfaceTargetReference = getNonNullableMemberReferenceGetter(target);
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    Class superclass = interfaceTarget.enclosingClass!;
    List<DartType>? receiverTypeArguments = context.typeEnvironment
        .getTypeArgumentsAsInstanceOf(context.thisType!, superclass);
    DartType returnType = Substitution.fromPairs(
            superclass.typeParameters, receiverTypeArguments!)
        .substituteType(interfaceTarget.function.returnType);
    return Substitution.fromPairs(
            interfaceTarget.function.typeParameters, arguments.types)
        .substituteType(returnType);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitSuperMethodInvocation(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitSuperMethodInvocation(this, arg);

  @override
  void visitChildren(Visitor v) {
    interfaceTarget.acceptReference(v);
    name.accept(v);
    arguments.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    arguments = v.transform(arguments);
    arguments.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    arguments = v.transform(arguments);
    arguments.parent = this;
  }

  @override
  String toString() {
    return "SuperMethodInvocation(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('super.');
    printer.writeInterfaceMemberName(interfaceTargetReference, name);
    printer.writeArguments(arguments);
  }
}

/// Expression of form `foo(x)`, or `const foo(x)` if the target is an
/// external constant factory.
///
/// The provided arguments might not match the parameters of the target.
class StaticInvocation extends InvocationExpression {
  Reference targetReference;

  @override
  Arguments arguments;

  /// True if this is a constant call to an external constant factory.
  bool isConst;

  @override
  Name get name => target.name;

  StaticInvocation(Procedure target, Arguments arguments,
      {bool isConst = false})
      : this.byReference(
            // An invocation doesn't refer to the setter.
            getNonNullableMemberReferenceGetter(target),
            arguments,
            isConst: isConst);

  StaticInvocation.byReference(this.targetReference, this.arguments,
      {this.isConst = false}) {
    arguments.parent = this;
  }

  Procedure get target => targetReference.asProcedure;

  void set target(Procedure target) {
    // An invocation doesn't refer to the setter.
    targetReference = getNonNullableMemberReferenceGetter(target);
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    return Substitution.fromPairs(
            target.function.typeParameters, arguments.types)
        .substituteType(target.function.returnType);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitStaticInvocation(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitStaticInvocation(this, arg);

  @override
  void visitChildren(Visitor v) {
    target.acceptReference(v);
    arguments.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    arguments = v.transform(arguments);
    arguments.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    arguments = v.transform(arguments);
    arguments.parent = this;
  }

  @override
  String toString() {
    return "StaticInvocation(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeMemberName(targetReference);
    printer.writeArguments(arguments);
  }
}

/// Expression of form `new Foo(x)` or `const Foo(x)`.
///
/// The provided arguments might not match the parameters of the target.
//
// DESIGN TODO: Should we pass type arguments in a separate field
// `classTypeArguments`? They are quite different from type arguments to
// generic functions.
class ConstructorInvocation extends InvocationExpression {
  Reference targetReference;

  @override
  Arguments arguments;

  bool isConst;

  @override
  Name get name => target.name;

  ConstructorInvocation(Constructor target, Arguments arguments,
      {bool isConst = false})
      : this.byReference(
            // A constructor doesn't refer to the setter.
            getNonNullableMemberReferenceGetter(target),
            arguments,
            isConst: isConst);

  ConstructorInvocation.byReference(this.targetReference, this.arguments,
      {this.isConst = false}) {
    arguments.parent = this;
  }

  Constructor get target => targetReference.asConstructor;

  void set target(Constructor target) {
    // A constructor doesn't refer to the setter.
    targetReference = getNonNullableMemberReferenceGetter(target);
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    return arguments.types.isEmpty
        ? context.typeEnvironment.coreTypes
            .rawType(target.enclosingClass, context.nonNullable)
        : new InterfaceType(
            target.enclosingClass, context.nonNullable, arguments.types);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitConstructorInvocation(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitConstructorInvocation(this, arg);

  @override
  void visitChildren(Visitor v) {
    target.acceptReference(v);
    arguments.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    arguments = v.transform(arguments);
    arguments.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    arguments = v.transform(arguments);
    arguments.parent = this;
  }

  // TODO(cstefantsova): Change the getter into a method that accepts a
  // CoreTypes.
  InterfaceType get constructedType {
    Class enclosingClass = target.enclosingClass;
    // TODO(cstefantsova): Get raw type from a CoreTypes object if arguments is
    // empty.
    return arguments.types.isEmpty
        ? new InterfaceType(enclosingClass, target.enclosingLibrary.nonNullable,
            const <DartType>[])
        : new InterfaceType(enclosingClass, target.enclosingLibrary.nonNullable,
            arguments.types);
  }

  @override
  String toString() {
    return "ConstructorInvocation(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    if (isConst) {
      printer.write('const ');
    } else {
      printer.write('new ');
    }
    printer.writeClassName(target.enclosingClass.reference);
    printer.writeTypeArguments(arguments.types);
    if (target.name.text.isNotEmpty) {
      printer.write('.');
      printer.write(target.name.text);
    }
    printer.writeArguments(arguments, includeTypeArguments: false);
  }
}

/// An explicit type instantiation of a generic function.
class Instantiation extends Expression {
  Expression expression;
  final List<DartType> typeArguments;

  Instantiation(this.expression, this.typeArguments) {
    expression.parent = this;
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    DartType type = expression.getStaticType(context);
    if (type is FunctionType) {
      return FunctionTypeInstantiator.instantiate(type, typeArguments);
    }
    assert(type is InvalidType || type is NeverType,
        "Unexpected operand type $type for $expression");
    return type;
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitInstantiation(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitInstantiation(this, arg);

  @override
  void visitChildren(Visitor v) {
    expression.accept(v);
    visitList(typeArguments, v);
  }

  @override
  void transformChildren(Transformer v) {
    expression = v.transform(expression);
    expression.parent = this;

    v.transformDartTypeList(typeArguments);
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    expression = v.transform(expression);
    expression.parent = this;

    v.transformDartTypeList(typeArguments);
  }

  @override
  String toString() {
    return "Instantiation(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeExpression(expression);
    printer.writeTypeArguments(typeArguments);
  }
}

/// Expression of form `!x`.
///
/// The `is!` and `!=` operators are desugared into [Not] nodes with `is` and
/// `==` expressions inside, respectively.
class Not extends Expression {
  Expression operand;

  Not(this.operand) {
    operand.parent = this;
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitNot(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) => v.visitNot(this, arg);

  @override
  void visitChildren(Visitor v) {
    operand.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    operand = v.transform(operand);
    operand.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    operand = v.transform(operand);
    operand.parent = this;
  }

  @override
  String toString() {
    return "Not(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('!');
    printer.writeExpression(operand,
        minimumPrecedence: astToText.Precedence.PREFIX);
  }
}

enum LogicalExpressionOperator { AND, OR }

String logicalExpressionOperatorToString(LogicalExpressionOperator operator) {
  switch (operator) {
    case LogicalExpressionOperator.AND:
      return "&&";
    case LogicalExpressionOperator.OR:
      return "||";
  }
}

/// Expression of form `x && y` or `x || y`
class LogicalExpression extends Expression {
  Expression left;
  LogicalExpressionOperator operatorEnum; // AND (&&) or OR (||).
  Expression right;

  LogicalExpression(this.left, this.operatorEnum, this.right) {
    left.parent = this;
    right.parent = this;
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitLogicalExpression(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitLogicalExpression(this, arg);

  @override
  void visitChildren(Visitor v) {
    left.accept(v);
    right.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    left = v.transform(left);
    left.parent = this;
    right = v.transform(right);
    right.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    left = v.transform(left);
    left.parent = this;
    right = v.transform(right);
    right.parent = this;
  }

  @override
  String toString() {
    return "LogicalExpression(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    int minimumPrecedence = precedence;
    printer.writeExpression(left, minimumPrecedence: minimumPrecedence);
    printer.write(' ${logicalExpressionOperatorToString(operatorEnum)} ');
    printer.writeExpression(right, minimumPrecedence: minimumPrecedence + 1);
  }
}

/// Expression of form `x ? y : z`.
class ConditionalExpression extends Expression {
  Expression condition;
  Expression then;
  Expression otherwise;

  /// The static type of the expression.
  DartType staticType;

  ConditionalExpression(
      this.condition, this.then, this.otherwise, this.staticType) {
    condition.parent = this;
    then.parent = this;
    otherwise.parent = this;
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) => staticType;

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitConditionalExpression(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitConditionalExpression(this, arg);

  @override
  void visitChildren(Visitor v) {
    condition.accept(v);
    then.accept(v);
    otherwise.accept(v);
    staticType.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    condition = v.transform(condition);
    condition.parent = this;
    then = v.transform(then);
    then.parent = this;
    otherwise = v.transform(otherwise);
    otherwise.parent = this;
    staticType = v.visitDartType(staticType);
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    condition = v.transform(condition);
    condition.parent = this;
    then = v.transform(then);
    then.parent = this;
    otherwise = v.transform(otherwise);
    otherwise.parent = this;
    staticType = v.visitDartType(staticType, cannotRemoveSentinel);
  }

  @override
  String toString() {
    return "ConditionalExpression(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeExpression(condition,
        minimumPrecedence: astToText.Precedence.LOGICAL_OR);
    printer.write(' ?');
    printer.write('{');
    printer.writeType(staticType);
    printer.write('}');
    printer.write(' ');
    printer.writeExpression(then);
    printer.write(' : ');
    printer.writeExpression(otherwise);
  }
}

/// Convert expressions to strings and concatenate them.  Semantically, calls
/// `toString` on every argument, checks that a string is returned, and returns
/// the concatenation of all the strings.
///
/// If [expressions] is empty then an empty string is returned.
///
/// These arise from string interpolations and adjacent string literals.
class StringConcatenation extends Expression {
  final List<Expression> expressions;

  StringConcatenation(this.expressions) {
    setParents(expressions, this);
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      context.typeEnvironment.coreTypes.stringRawType(context.nonNullable);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitStringConcatenation(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitStringConcatenation(this, arg);

  @override
  void visitChildren(Visitor v) {
    visitList(expressions, v);
  }

  @override
  void transformChildren(Transformer v) {
    v.transformList(expressions, this);
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    v.transformExpressionList(expressions, this);
  }

  @override
  String toString() {
    return "StringConcatenation(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('"');
    for (Expression part in expressions) {
      if (part is StringLiteral) {
        printer.write(escapeString(part.value));
      } else {
        printer.write(r'${');
        printer.writeExpression(part);
        printer.write('}');
      }
    }
    printer.write('"');
  }
}

/// Concatenate lists into a single list.
///
/// If [lists] is empty then an empty list is returned.
///
/// These arise from spread and control-flow elements in const list literals.
/// They are only present before constant evaluation, or within unevaluated
/// constants in constant expressions.
class ListConcatenation extends Expression {
  DartType typeArgument;
  final List<Expression> lists;

  ListConcatenation(this.lists, {this.typeArgument = const DynamicType()}) {
    setParents(lists, this);
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    return context.typeEnvironment.listType(typeArgument, context.nonNullable);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitListConcatenation(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitListConcatenation(this, arg);

  @override
  void visitChildren(Visitor v) {
    typeArgument.accept(v);
    visitList(lists, v);
  }

  @override
  void transformChildren(Transformer v) {
    typeArgument = v.visitDartType(typeArgument);
    v.transformList(lists, this);
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    typeArgument = v.visitDartType(typeArgument, cannotRemoveSentinel);
    v.transformExpressionList(lists, this);
  }

  @override
  String toString() {
    return "ListConcatenation(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    bool first = true;
    for (Expression part in lists) {
      if (!first) {
        printer.write(' + ');
      }
      printer.writeExpression(part);
      first = false;
    }
  }
}

/// Concatenate sets into a single set.
///
/// If [sets] is empty then an empty set is returned.
///
/// These arise from spread and control-flow elements in const set literals.
/// They are only present before constant evaluation, or within unevaluated
/// constants in constant expressions.
///
/// Duplicated values in or across the sets will result in a compile-time error
/// during constant evaluation.
class SetConcatenation extends Expression {
  DartType typeArgument;
  final List<Expression> sets;

  SetConcatenation(this.sets, {this.typeArgument = const DynamicType()}) {
    setParents(sets, this);
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    return context.typeEnvironment.setType(typeArgument, context.nonNullable);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitSetConcatenation(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitSetConcatenation(this, arg);

  @override
  void visitChildren(Visitor v) {
    typeArgument.accept(v);
    visitList(sets, v);
  }

  @override
  void transformChildren(Transformer v) {
    typeArgument = v.visitDartType(typeArgument);
    v.transformList(sets, this);
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    typeArgument = v.visitDartType(typeArgument, cannotRemoveSentinel);
    v.transformExpressionList(sets, this);
  }

  @override
  String toString() {
    return "SetConcatenation(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    bool first = true;
    for (Expression part in sets) {
      if (!first) {
        printer.write(' + ');
      }
      printer.writeExpression(part);
      first = false;
    }
  }
}

/// Concatenate maps into a single map.
///
/// If [maps] is empty then an empty map is returned.
///
/// These arise from spread and control-flow elements in const map literals.
/// They are only present before constant evaluation, or within unevaluated
/// constants in constant expressions.
///
/// Duplicated keys in or across the maps will result in a compile-time error
/// during constant evaluation.
class MapConcatenation extends Expression {
  DartType keyType;
  DartType valueType;
  final List<Expression> maps;

  MapConcatenation(this.maps,
      {this.keyType = const DynamicType(),
      this.valueType = const DynamicType()}) {
    setParents(maps, this);
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    return context.typeEnvironment
        .mapType(keyType, valueType, context.nonNullable);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitMapConcatenation(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitMapConcatenation(this, arg);

  @override
  void visitChildren(Visitor v) {
    keyType.accept(v);
    valueType.accept(v);
    visitList(maps, v);
  }

  @override
  void transformChildren(Transformer v) {
    keyType = v.visitDartType(keyType);
    valueType = v.visitDartType(valueType);
    v.transformList(maps, this);
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    keyType = v.visitDartType(keyType, cannotRemoveSentinel);
    valueType = v.visitDartType(valueType, cannotRemoveSentinel);
    v.transformExpressionList(maps, this);
  }

  @override
  String toString() {
    return "MapConcatenation(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    bool first = true;
    for (Expression part in maps) {
      if (!first) {
        printer.write(' + ');
      }
      printer.writeExpression(part);
      first = false;
    }
  }
}

/// Create an instance directly from the field values.
///
/// These expressions arise from const constructor calls when one or more field
/// initializing expressions, field initializers, assert initializers or unused
/// arguments contain unevaluated expressions. They only ever occur within
/// unevaluated constants in constant expressions.
class InstanceCreation extends Expression {
  final Reference classReference;
  final List<DartType> typeArguments;
  final Map<Reference, Expression> fieldValues;
  final List<AssertStatement> asserts;
  final List<Expression> unusedArguments;

  InstanceCreation(this.classReference, this.typeArguments, this.fieldValues,
      this.asserts, this.unusedArguments) {
    setParents(fieldValues.values.toList(), this);
    setParents(asserts, this);
    setParents(unusedArguments, this);
  }

  Class get classNode => classReference.asClass;

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    return typeArguments.isEmpty
        ? context.typeEnvironment.coreTypes
            .rawType(classNode, context.nonNullable)
        : new InterfaceType(classNode, context.nonNullable, typeArguments);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceCreation(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitInstanceCreation(this, arg);

  @override
  void visitChildren(Visitor v) {
    classReference.asClass.acceptReference(v);
    visitList(typeArguments, v);
    for (final Reference reference in fieldValues.keys) {
      reference.asField.acceptReference(v);
    }
    for (final Expression value in fieldValues.values) {
      value.accept(v);
    }
    visitList(asserts, v);
    visitList(unusedArguments, v);
  }

  @override
  void transformChildren(Transformer v) {
    fieldValues.forEach((Reference fieldRef, Expression value) {
      Expression transformed = v.transform(value);
      if (!identical(value, transformed)) {
        fieldValues[fieldRef] = transformed;
        transformed.parent = this;
      }
    });
    v.transformList(asserts, this);
    v.transformList(unusedArguments, this);
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    fieldValues.forEach((Reference fieldRef, Expression value) {
      Expression transformed = v.transform(value);
      if (!identical(value, transformed)) {
        fieldValues[fieldRef] = transformed;
        transformed.parent = this;
      }
    });
    v.transformList(asserts, this, dummyAssertStatement);
    v.transformExpressionList(unusedArguments, this);
  }

  @override
  String toString() {
    return "InstanceCreation(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeClassName(classReference);
    printer.writeTypeArguments(typeArguments);
    printer.write('{');
    bool first = true;
    fieldValues.forEach((Reference fieldRef, Expression value) {
      if (!first) {
        printer.write(', ');
      }
      printer.writeName(fieldRef.asField.name);
      printer.write(': ');
      printer.writeExpression(value);
      first = false;
    });
    for (AssertStatement assert_ in asserts) {
      if (!first) {
        printer.write(', ');
      }
      printer.write('assert(');
      printer.writeExpression(assert_.condition);
      if (assert_.message != null) {
        printer.write(', ');
        printer.writeExpression(assert_.message!);
      }
      printer.write(')');
      first = false;
    }
    for (Expression unusedArgument in unusedArguments) {
      if (!first) {
        printer.write(', ');
      }
      printer.writeExpression(unusedArgument);
      first = false;
    }
    printer.write('}');
  }
}

/// A marker indicating that a subexpression originates in a different source
/// file than the surrounding context.
///
/// These expressions arise from inlining of const variables during constant
/// evaluation. They only ever occur within unevaluated constants in constant
/// expressions.
class FileUriExpression extends Expression implements FileUriNode {
  /// The URI of the source file in which the subexpression is located.
  /// Can be different from the file containing the [FileUriExpression].
  @override
  Uri fileUri;

  Expression expression;

  FileUriExpression(this.expression, this.fileUri) {
    expression.parent = this;
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      expression.getStaticType(context);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitFileUriExpression(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitFileUriExpression(this, arg);

  @override
  void visitChildren(Visitor v) {
    expression.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    expression = v.transform(expression)..parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    expression = v.transform(expression)..parent = this;
  }

  @override
  Location? _getLocationInEnclosingFile(int offset) {
    return _getLocationInComponent(enclosingComponent, fileUri, offset,
        viaForErrorMessage: "File uri expression");
  }

  @override
  String toString() {
    return "FileUriExpression(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    if (printer.includeAuxiliaryProperties) {
      printer.write('{');
      printer.write(fileUri.toString());
      printer.write('}');
    }
    printer.writeExpression(expression);
  }
}

/// Expression of form `x is T`.
class IsExpression extends Expression {
  Expression operand;
  DartType type;

  IsExpression(this.operand, this.type) {
    operand.parent = this;
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitIsExpression(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitIsExpression(this, arg);

  @override
  void visitChildren(Visitor v) {
    operand.accept(v);
    type.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    operand = v.transform(operand);
    operand.parent = this;
    type = v.visitDartType(type);
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    operand = v.transform(operand);
    operand.parent = this;
    type = v.visitDartType(type, cannotRemoveSentinel);
  }

  @override
  String toString() {
    return "IsExpression(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeExpression(operand,
        minimumPrecedence: astToText.Precedence.BITWISE_OR);
    printer.write(' is ');
    printer.writeType(type);
  }
}

/// Expression of form `x as T`.
class AsExpression extends Expression {
  int flags = 0;
  Expression operand;
  DartType type;

  AsExpression(this.operand, this.type) {
    operand.parent = this;
  }

  // Must match serialized bit positions.
  static const int FlagTypeError = 1 << 0;
  static const int FlagCovarianceCheck = 1 << 1;
  static const int FlagForDynamic = 1 << 2;
  static const int FlagUnchecked = 1 << 3;

  /// If `true`, this test is an implicit down cast.
  ///
  /// If `true` a TypeError should be thrown. If `false` a CastError should be
  /// thrown.
  bool get isTypeError => flags & FlagTypeError != 0;

  void set isTypeError(bool value) {
    flags = value ? (flags | FlagTypeError) : (flags & ~FlagTypeError);
  }

  /// If `true`, this test is needed to ensure soundness of covariant type
  /// variables using in contravariant positions.
  ///
  /// For instance
  ///
  ///    class Class<T> {
  ///      void Function(T) field;
  ///      Class(this.field);
  ///    }
  ///    main() {
  ///      Class<num> c = new Class<int>((int i) {});
  ///      void Function<num> field = c.field; // Check needed on `c.field`
  ///      field(0.5);
  ///    }
  ///
  /// Here a covariant check `c.field as void Function(num)` is needed because
  /// the field could be (and indeed is) not a subtype of the static type of
  /// the expression.
  bool get isCovarianceCheck => flags & FlagCovarianceCheck != 0;

  void set isCovarianceCheck(bool value) {
    flags =
        value ? (flags | FlagCovarianceCheck) : (flags & ~FlagCovarianceCheck);
  }

  /// If `true`, this is an implicit down cast from an expression of type
  /// `dynamic`.
  bool get isForDynamic => flags & FlagForDynamic != 0;

  void set isForDynamic(bool value) {
    flags = value ? (flags | FlagForDynamic) : (flags & ~FlagForDynamic);
  }

  /// If `true`, this test is added to show the known static type of the
  /// expression and should not be performed at runtime.
  ///
  /// This is the case for instance for access to extension type representation
  /// fields on an extension type, where this node shows that the static type
  /// changes from the extension type of the declared representation type.
  ///
  /// This is also the case when a field access undergoes type promotion.
  bool get isUnchecked => flags & FlagUnchecked != 0;

  void set isUnchecked(bool value) {
    flags = value ? (flags | FlagUnchecked) : (flags & ~FlagUnchecked);
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) => type;

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitAsExpression(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitAsExpression(this, arg);

  @override
  void visitChildren(Visitor v) {
    operand.accept(v);
    type.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    operand = v.transform(operand);
    operand.parent = this;
    type = v.visitDartType(type);
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    operand = v.transform(operand);
    operand.parent = this;
    type = v.visitDartType(type, cannotRemoveSentinel);
  }

  @override
  String toString() {
    return "AsExpression(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeExpression(operand,
        minimumPrecedence: astToText.Precedence.BITWISE_OR);
    printer.write(' as');
    if (printer.includeAuxiliaryProperties) {
      List<String> flags = <String>[];
      if (isTypeError) {
        flags.add('TypeError');
      }
      if (isCovarianceCheck) {
        flags.add('CovarianceCheck');
      }
      if (isForDynamic) {
        flags.add('ForDynamic');
      }
      if (flags.isNotEmpty) {
        printer.write('{${flags.join(',')}}');
      }
    }
    printer.write(' ');
    printer.writeType(type);
  }
}

/// Null check expression of form `x!`.
///
/// This expression was added as part of NNBD and is currently only created when
/// the 'non-nullable' experimental feature is enabled.
class NullCheck extends Expression {
  Expression operand;

  NullCheck(this.operand) {
    operand.parent = this;
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    DartType operandType = operand.getStaticType(context);
    return operandType is NullType
        ? const NeverType.nonNullable()
        : operandType.withDeclaredNullability(Nullability.nonNullable);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitNullCheck(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitNullCheck(this, arg);

  @override
  void visitChildren(Visitor v) {
    operand.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    operand = v.transform(operand);
    operand.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    operand = v.transform(operand);
    operand.parent = this;
  }

  @override
  String toString() {
    return "NullCheck(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeExpression(operand,
        minimumPrecedence: astToText.Precedence.POSTFIX);
    printer.write('!');
  }
}

/// An integer, double, boolean, string, or null constant.
abstract class BasicLiteral extends Expression {
  Object? get value;

  @override
  void visitChildren(Visitor v) {}

  @override
  void transformChildren(Transformer v) {}

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {}
}

class StringLiteral extends BasicLiteral {
  @override
  String value;

  StringLiteral(this.value);

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      context.typeEnvironment.coreTypes.stringRawType(context.nonNullable);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitStringLiteral(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitStringLiteral(this, arg);

  @override
  String toString() {
    return "StringLiteral(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('"');
    printer.write(escapeString(value));
    printer.write('"');
  }
}

class IntLiteral extends BasicLiteral {
  /// Note that this value holds a uint64 value.
  /// E.g. "0x8000000000000000" will be saved as "-9223372036854775808" despite
  /// technically (on some platforms, particularly JavaScript) being positive.
  /// If the number is meant to be negative it will be wrapped in a "unary-".
  @override
  int value;

  IntLiteral(this.value);

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      context.typeEnvironment.coreTypes.intRawType(context.nonNullable);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitIntLiteral(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitIntLiteral(this, arg);

  @override
  String toString() {
    return "IntLiteral(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('$value');
  }
}

class DoubleLiteral extends BasicLiteral {
  @override
  double value;

  DoubleLiteral(this.value);

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      context.typeEnvironment.coreTypes.doubleRawType(context.nonNullable);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitDoubleLiteral(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitDoubleLiteral(this, arg);

  @override
  String toString() {
    return "DoubleLiteral(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('$value');
  }
}

class BoolLiteral extends BasicLiteral {
  @override
  bool value;

  BoolLiteral(this.value);

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitBoolLiteral(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitBoolLiteral(this, arg);

  @override
  String toString() {
    return "BoolLiteral(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('$value');
  }
}

class NullLiteral extends BasicLiteral {
  @override
  Object? get value => null;

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) => const NullType();

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitNullLiteral(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitNullLiteral(this, arg);

  @override
  String toString() {
    return "NullLiteral(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('null');
  }
}

class SymbolLiteral extends Expression {
  String value; // Everything strictly after the '#'.

  SymbolLiteral(this.value);

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      context.typeEnvironment.coreTypes.symbolRawType(context.nonNullable);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitSymbolLiteral(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitSymbolLiteral(this, arg);

  @override
  void visitChildren(Visitor v) {}

  @override
  void transformChildren(Transformer v) {}

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {}

  @override
  String toString() {
    return "SymbolLiteral(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('#');
    printer.write(value);
  }
}

class TypeLiteral extends Expression {
  DartType type;

  TypeLiteral(this.type);

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      context.typeEnvironment.coreTypes.typeRawType(context.nonNullable);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitTypeLiteral(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitTypeLiteral(this, arg);

  @override
  void visitChildren(Visitor v) {
    type.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    type = v.visitDartType(type);
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    type = v.visitDartType(type, cannotRemoveSentinel);
  }

  @override
  String toString() {
    return "TypeLiteral(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeType(type);
  }
}

class ThisExpression extends Expression {
  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      context.thisType!;

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitThisExpression(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitThisExpression(this, arg);

  @override
  void visitChildren(Visitor v) {}

  @override
  void transformChildren(Transformer v) {}

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {}

  @override
  String toString() {
    return "ThisExpression(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('this');
  }
}

class Rethrow extends Expression {
  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      const NeverType.nonNullable();

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitRethrow(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitRethrow(this, arg);

  @override
  void visitChildren(Visitor v) {}

  @override
  void transformChildren(Transformer v) {}

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {}

  @override
  String toString() {
    return "Rethrow(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('rethrow');
  }
}

class Throw extends Expression {
  Expression expression;
  int flags = 0;

  Throw(this.expression) {
    expression.parent = this;
  }

  // Must match serialized bit positions.
  static const int FlagForErrorHandling = 1 << 0;

  /// If `true`, this `throw` is *not* present in the source code but added
  /// to ensure correctness and/or soundness of the generated code.
  ///
  /// This is used for instance in the lowering for handling duplicate writes
  /// to a late final field or for pattern assignments that don't match.
  bool get forErrorHandling => flags & FlagForErrorHandling != 0;

  void set forErrorHandling(bool value) {
    flags = value
        ? (flags | FlagForErrorHandling)
        : (flags & ~FlagForErrorHandling);
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      const NeverType.nonNullable();

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitThrow(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) => v.visitThrow(this, arg);

  @override
  void visitChildren(Visitor v) {
    expression.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    expression = v.transform(expression);
    expression.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    expression = v.transform(expression);
    expression.parent = this;
  }

  @override
  String toString() {
    return "Throw(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('throw ');
    printer.writeExpression(expression);
  }
}

class ListLiteral extends Expression {
  bool isConst;
  DartType typeArgument; // Not null, defaults to DynamicType.
  final List<Expression> expressions;

  ListLiteral(this.expressions,
      {this.typeArgument = const DynamicType(), this.isConst = false}) {
    setParents(expressions, this);
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    return context.typeEnvironment.listType(typeArgument, context.nonNullable);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitListLiteral(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitListLiteral(this, arg);

  @override
  void visitChildren(Visitor v) {
    typeArgument.accept(v);
    visitList(expressions, v);
  }

  @override
  void transformChildren(Transformer v) {
    typeArgument = v.visitDartType(typeArgument);
    v.transformList(expressions, this);
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    typeArgument = v.visitDartType(typeArgument, cannotRemoveSentinel);
    v.transformExpressionList(expressions, this);
  }

  @override
  String toString() {
    return "ListLiteral(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    if (isConst) {
      printer.write('const ');
    }
    printer.write('<');
    printer.writeType(typeArgument);
    printer.write('>[');
    printer.writeExpressions(expressions);
    printer.write(']');
  }
}

class SetLiteral extends Expression {
  bool isConst;
  DartType typeArgument; // Not null, defaults to DynamicType.
  final List<Expression> expressions;

  SetLiteral(this.expressions,
      {this.typeArgument = const DynamicType(), this.isConst = false}) {
    setParents(expressions, this);
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    return context.typeEnvironment.setType(typeArgument, context.nonNullable);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitSetLiteral(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitSetLiteral(this, arg);

  @override
  void visitChildren(Visitor v) {
    typeArgument.accept(v);
    visitList(expressions, v);
  }

  @override
  void transformChildren(Transformer v) {
    typeArgument = v.visitDartType(typeArgument);
    v.transformList(expressions, this);
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    typeArgument = v.visitDartType(typeArgument, cannotRemoveSentinel);
    v.transformExpressionList(expressions, this);
  }

  @override
  String toString() {
    return "SetLiteral(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    if (isConst) {
      printer.write('const ');
    }
    printer.write('<');
    printer.writeType(typeArgument);
    printer.write('>{');
    printer.writeExpressions(expressions);
    printer.write('}');
  }
}

class MapLiteral extends Expression {
  bool isConst;
  DartType keyType; // Not null, defaults to DynamicType.
  DartType valueType; // Not null, defaults to DynamicType.
  final List<MapLiteralEntry> entries;

  MapLiteral(this.entries,
      {this.keyType = const DynamicType(),
      this.valueType = const DynamicType(),
      this.isConst = false}) {
    setParents(entries, this);
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    return context.typeEnvironment
        .mapType(keyType, valueType, context.nonNullable);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitMapLiteral(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitMapLiteral(this, arg);

  @override
  void visitChildren(Visitor v) {
    keyType.accept(v);
    valueType.accept(v);
    visitList(entries, v);
  }

  @override
  void transformChildren(Transformer v) {
    keyType = v.visitDartType(keyType);
    valueType = v.visitDartType(valueType);
    v.transformList(entries, this);
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    keyType = v.visitDartType(keyType, cannotRemoveSentinel);
    valueType = v.visitDartType(valueType, cannotRemoveSentinel);
    v.transformMapEntryList(entries, this);
  }

  @override
  String toString() {
    return "MapLiteral(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    if (isConst) {
      printer.write('const ');
    }
    printer.write('<');
    printer.writeType(keyType);
    printer.write(', ');
    printer.writeType(valueType);
    printer.write('>{');
    for (int index = 0; index < entries.length; index++) {
      if (index > 0) {
        printer.write(', ');
      }
      printer.writeMapEntry(entries[index]);
    }
    printer.write('}');
  }
}

class MapLiteralEntry extends TreeNode {
  Expression key;
  Expression value;

  MapLiteralEntry(this.key, this.value) {
    key.parent = this;
    value.parent = this;
  }

  @override
  R accept<R>(TreeVisitor<R> v) => v.visitMapLiteralEntry(this);

  @override
  R accept1<R, A>(TreeVisitor1<R, A> v, A arg) =>
      v.visitMapLiteralEntry(this, arg);

  @override
  void visitChildren(Visitor v) {
    key.accept(v);
    value.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    key = v.transform(key);
    key.parent = this;
    value = v.transform(value);
    value.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    key = v.transform(key);
    key.parent = this;
    value = v.transform(value);
    value.parent = this;
  }

  @override
  String toString() {
    return "MapEntry(${toStringInternal()})";
  }

  @override
  String toText(AstTextStrategy strategy) {
    AstPrinter printer = new AstPrinter(strategy);
    toTextInternal(printer);
    return printer.getText();
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeExpression(key);
    printer.write(': ');
    printer.writeExpression(value);
  }
}

class RecordLiteral extends Expression {
  bool isConst;
  final List<Expression> positional;
  final List<NamedExpression> named;
  RecordType recordType;

  RecordLiteral(this.positional, this.named, this.recordType,
      {this.isConst = false})
      : assert(positional.length == recordType.positional.length &&
            named.length == recordType.named.length &&
            recordType.named
                .map((f) => f.name)
                .toSet()
                .containsAll(named.map((f) => f.name))),
        assert(() {
          // Assert that the named fields are sorted.
          for (int i = 1; i < named.length; i++) {
            if (named[i].name.compareTo(named[i - 1].name) < 0) {
              return false;
            }
          }
          return true;
        }(),
            "Named fields of a RecordLiterals aren't sorted lexicographically: "
            "${named.map((f) => f.name).join(", ")}") {
    setParents(positional, this);
    setParents(named, this);
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    return recordType;
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitRecordLiteral(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitRecordLiteral(this, arg);

  @override
  void visitChildren(Visitor v) {
    visitList(positional, v);
    visitList(named, v);
    recordType.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    v.transformList(positional, this);
    v.transformList(named, this);
    recordType = v.visitDartType(recordType) as RecordType;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    v.transformExpressionList(positional, this);
    v.transformNamedExpressionList(named, this);
    recordType =
        v.visitDartType(recordType, cannotRemoveSentinel) as RecordType;
  }

  @override
  String toString() {
    return "RecordType(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    if (isConst) {
      printer.write("const ");
    }
    printer.write("(");
    for (int index = 0; index < positional.length; index++) {
      if (index > 0) {
        printer.write(", ");
      }
      printer.writeExpression(positional[index]);
    }
    if (named.isNotEmpty) {
      if (positional.isNotEmpty) {
        printer.write(", ");
      }
      for (int index = 0; index < named.length; index++) {
        if (index > 0) {
          printer.write(", ");
        }
        printer.writeNamedExpression(named[index]);
      }
    }
    printer.write(")");
  }
}

/// Expression of form `await x`.
class AwaitExpression extends Expression {
  Expression operand;

  /// If non-null, the runtime should check whether the value of [operand] is a
  /// subtype of [runtimeCheckType], and if _not_ so, wrap the value in a call
  /// to the `Future.value()` constructor.
  ///
  /// For instance
  ///
  ///     FutureOr<Object> future1 = Future<Object?>.value();
  ///     var x = await future1; // Check against `Future<Object>`.
  ///
  ///     Object object = Future<Object?>.value();
  ///     var y = await object; // Check against `Future<Object>`.
  ///
  ///     Future<Object?> future2 = Future<Object?>.value();
  ///     var z = await future2; // No check.
  ///
  /// This runtime checks is necessary to ensure that we don't evaluate the
  /// await expression to `null` when the static type of the expression is
  /// non-nullable.
  ///
  /// The [runtimeCheckType] is computed as `Future<T>` where `T = flatten(S)`
  /// and `S` is the static type of [operand]. To avoid unnecessary runtime
  /// checks, the [runtimeCheckType] is not set if the static type of the
  /// [operand] is a subtype of `Future<T>`.
  ///
  /// See https://github.com/dart-lang/sdk/issues/49396 for further discussion
  /// of which the check is needed.
  DartType? runtimeCheckType;

  AwaitExpression(this.operand) {
    operand.parent = this;
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    return context.typeEnvironment.flatten(operand.getStaticType(context));
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitAwaitExpression(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitAwaitExpression(this, arg);

  @override
  void visitChildren(Visitor v) {
    operand.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    operand = v.transform(operand);
    operand.parent = this;
    if (runtimeCheckType != null) {
      runtimeCheckType = v.visitDartType(runtimeCheckType!);
    }
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    operand = v.transform(operand);
    operand.parent = this;
    if (runtimeCheckType != null) {
      runtimeCheckType = v.visitDartType(runtimeCheckType!, null);
    }
  }

  @override
  String toString() {
    return "AwaitExpression(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('await ');
    printer.writeExpression(operand);
  }
}

/// Common super-interface for [FunctionExpression] and [FunctionDeclaration].
abstract class LocalFunction implements GenericFunction {
  @override
  FunctionNode get function;
}

/// Expression of form `(x,y) => ...` or `(x,y) { ... }`
///
/// The arrow-body form `=> e` is desugared into `return e;`.
class FunctionExpression extends Expression implements LocalFunction {
  @override
  FunctionNode function;

  FunctionExpression(this.function) {
    function.parent = this;
  }

  @override
  List<TypeParameter> get typeParameters => function.typeParameters;

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    return function.computeFunctionType(context.nonNullable);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitFunctionExpression(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitFunctionExpression(this, arg);

  @override
  void visitChildren(Visitor v) {
    function.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    function = v.transform(function);
    function.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    function = v.transform(function);
    function.parent = this;
  }

  @override
  String toString() {
    return "FunctionExpression(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeFunctionNode(function, '');
  }
}

class ConstantExpression extends Expression {
  Constant constant;
  DartType type;

  ConstantExpression(this.constant, [this.type = const DynamicType()]);

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) => type;

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitConstantExpression(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitConstantExpression(this, arg);

  @override
  void visitChildren(Visitor v) {
    constant.acceptReference(v);
    type.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    constant = v.visitConstant(constant);
    type = v.visitDartType(type);
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    constant = v.visitConstant(constant, cannotRemoveSentinel);
    type = v.visitDartType(type, cannotRemoveSentinel);
  }

  @override
  String toString() {
    return "ConstantExpression(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeConstant(constant);
  }
}

class FileUriConstantExpression extends ConstantExpression
    implements FileUriNode {
  @override
  Uri fileUri;

  FileUriConstantExpression(Constant constant,
      {DartType type = const DynamicType(), required this.fileUri})
      : super(constant, type);

  @override
  Location? _getLocationInEnclosingFile(int offset) {
    return _getLocationInComponent(enclosingComponent, fileUri, offset,
        viaForErrorMessage: "File uri constant expression");
  }
}

/// Synthetic expression of form `let v = x in y`
class Let extends Expression {
  VariableDeclaration variable; // Must have an initializer.
  Expression body;

  Let(this.variable, this.body) {
    variable.parent = this;
    body.parent = this;
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      body.getStaticType(context);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitLet(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) => v.visitLet(this, arg);

  @override
  void visitChildren(Visitor v) {
    variable.accept(v);
    body.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    variable = v.transform(variable);
    variable.parent = this;
    body = v.transform(body);
    body.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    variable = v.transform(variable);
    variable.parent = this;
    body = v.transform(body);
    body.parent = this;
  }

  @override
  String toString() {
    return "Let(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('let ');
    printer.writeVariableDeclaration(variable);
    printer.write(' in ');
    printer.writeExpression(body);
  }
}

class BlockExpression extends Expression {
  Block body;
  Expression value;

  BlockExpression(this.body, this.value) {
    body.parent = this;
    value.parent = this;
  }

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) =>
      value.getStaticType(context);

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitBlockExpression(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitBlockExpression(this, arg);

  @override
  void visitChildren(Visitor v) {
    body.accept(v);
    value.accept(v);
  }

  @override
  void transformChildren(Transformer v) {
    body = v.transform(body);
    body.parent = this;
    value = v.transform(value);
    value.parent = this;
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    body = v.transform(body);
    body.parent = this;
    value = v.transform(value);
    value.parent = this;
  }

  @override
  String toString() {
    return "BlockExpression(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write('block ');
    printer.writeBlock(body.statements);
    printer.write(' => ');
    printer.writeExpression(value);
  }
}

/// Attempt to load the library referred to by a deferred import.
///
/// This instruction is concerned with:
/// - keeping track whether the deferred import is marked as 'loaded'
/// - keeping track of whether the library code has already been downloaded
/// - actually downloading and linking the library
///
/// Should return a future.  The value in this future will be the same value
/// seen by callers of `loadLibrary` functions.
///
/// On backends that link the entire program eagerly, this instruction needs
/// to mark the deferred import as 'loaded' and return a future.
class LoadLibrary extends Expression {
  /// Reference to a deferred import in the enclosing library.
  LibraryDependency import;

  LoadLibrary(this.import);

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    return context.typeEnvironment
        .futureType(const DynamicType(), context.nonNullable);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitLoadLibrary(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitLoadLibrary(this, arg);

  @override
  void visitChildren(Visitor v) {}

  @override
  void transformChildren(Transformer v) {}

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {}

  @override
  String toString() {
    return "LoadLibrary(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write(import.name!);
    printer.write('.loadLibrary()');
  }
}

/// Checks that the given deferred import has been marked as 'loaded'.
class CheckLibraryIsLoaded extends Expression {
  /// Reference to a deferred import in the enclosing library.
  LibraryDependency import;

  CheckLibraryIsLoaded(this.import);

  @override
  DartType getStaticType(StaticTypeContext context) =>
      getStaticTypeInternal(context);

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    return context.typeEnvironment.coreTypes.objectRawType(context.nonNullable);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitCheckLibraryIsLoaded(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitCheckLibraryIsLoaded(this, arg);

  @override
  void visitChildren(Visitor v) {}

  @override
  void transformChildren(Transformer v) {}

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {}

  @override
  String toString() {
    return "CheckLibraryIsLoaded(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.write(import.name!);
    printer.write('.checkLibraryIsLoaded()');
  }
}

/// Tearing off a constructor of a class.
class ConstructorTearOff extends Expression {
  /// The reference to the constructor being torn off.
  Reference targetReference;

  ConstructorTearOff(Member target)
      : assert(
            target is Constructor || (target is Procedure && target.isFactory),
            "Unexpected constructor tear off target: $target"),
        this.targetReference = getNonNullableMemberReferenceGetter(target);

  ConstructorTearOff.byReference(this.targetReference);

  Member get target => targetReference.asMember;

  FunctionNode get function => target.function!;

  void set target(Member member) {
    assert(member is Constructor ||
        (member is Procedure && member.kind == ProcedureKind.Factory));
    targetReference = getNonNullableMemberReferenceGetter(member);
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    return target.function!.computeFunctionType(Nullability.nonNullable);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitConstructorTearOff(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitConstructorTearOff(this, arg);

  @override
  void visitChildren(Visitor v) {
    target.acceptReference(v);
  }

  @override
  void transformChildren(Transformer v) {}

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {}

  @override
  String toString() {
    return "ConstructorTearOff(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeMemberName(targetReference);
  }
}

/// Tearing off a redirecting factory constructor of a class.
class RedirectingFactoryTearOff extends Expression {
  /// The reference to the redirecting factory constructor being torn off.
  Reference targetReference;

  RedirectingFactoryTearOff(Procedure target)
      : assert(target.isRedirectingFactory),
        this.targetReference = getNonNullableMemberReferenceGetter(target);

  RedirectingFactoryTearOff.byReference(this.targetReference);

  Procedure get target => targetReference.asProcedure;

  void set target(Procedure target) {
    targetReference = getNonNullableMemberReferenceGetter(target);
  }

  FunctionNode get function => target.function;

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    return target.function.computeFunctionType(Nullability.nonNullable);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitRedirectingFactoryTearOff(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitRedirectingFactoryTearOff(this, arg);

  @override
  void visitChildren(Visitor v) {
    target.acceptReference(v);
  }

  @override
  void transformChildren(Transformer v) {}

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {}

  @override
  String toString() {
    return "RedirectingFactoryTearOff(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeMemberName(targetReference);
  }
}

class TypedefTearOff extends Expression {
  final List<StructuralParameter> structuralParameters;
  Expression expression;
  final List<DartType> typeArguments;

  TypedefTearOff(
      this.structuralParameters, this.expression, this.typeArguments) {
    expression.parent = this;
  }

  @override
  DartType getStaticTypeInternal(StaticTypeContext context) {
    FreshStructuralParameters freshTypeParameters =
        getFreshStructuralParameters(structuralParameters);
    FunctionType type = expression.getStaticType(context) as FunctionType;
    type = freshTypeParameters.substitute(
            FunctionTypeInstantiator.instantiate(type, typeArguments))
        as FunctionType;
    return new FunctionType(
        type.positionalParameters, type.returnType, type.declaredNullability,
        namedParameters: type.namedParameters,
        typeParameters: freshTypeParameters.freshTypeParameters,
        requiredParameterCount: type.requiredParameterCount);
  }

  @override
  R accept<R>(ExpressionVisitor<R> v) => v.visitTypedefTearOff(this);

  @override
  R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
      v.visitTypedefTearOff(this, arg);

  @override
  void visitChildren(Visitor v) {
    expression.accept(v);
    visitList(structuralParameters, v);
    visitList(typeArguments, v);
  }

  @override
  void transformChildren(Transformer v) {
    expression = v.transform(expression);
    expression.parent = this;
    v.transformDartTypeList(typeArguments);
  }

  @override
  void transformOrRemoveChildren(RemovingTransformer v) {
    expression = v.transform(expression);
    expression.parent = this;
    v.transformDartTypeList(typeArguments);
  }

  @override
  String toString() {
    return "TypedefTearOff(${toStringInternal()})";
  }

  @override
  void toTextInternal(AstPrinter printer) {
    printer.writeStructuralParameters(structuralParameters);
    printer.write(".(");
    printer.writeExpression(expression);
    printer.writeTypeArguments(typeArguments);
    printer.write(")");
  }
}
