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

import 'dart:math' as Math;

import '../common.dart';
import '../constants/values.dart';
import '../elements/entities.dart';
import '../js_model/jrecord_field_interface.dart' show JRecordFieldInterface;
import '../serialization/serialization.dart';
import '../util/enumset.dart';
import 'call_structure.dart';

abstract class AbstractUsage<T> {
  final EnumSet<T> _pendingUse;

  AbstractUsage.cloned(this._pendingUse);

  AbstractUsage() : this._pendingUse = EnumSet() {
    _pendingUse.addAll(_originalUse);
  }

  /// Returns the uses of [entity] that have been registered.
  EnumSet<T> get _appliedUse => _originalUse.minus(_pendingUse);

  EnumSet<T> get _originalUse;

  /// `true` if the [_appliedUse] is non-empty.
  bool get hasUse => _appliedUse.isNotEmpty;

  /// Returns `true` if [other] has the same original and pending usage as this.
  bool hasSameUsage(AbstractUsage<T> other) {
    if (identical(this, other)) return true;
    return _originalUse.value == other._originalUse.value &&
        _pendingUse.value == other._pendingUse.value;
  }
}

/// Registry for the observed use of a member [entity] in the open world.
abstract class MemberUsage extends AbstractUsage<MemberUse> {
  /// Constant empty access set used as the potential access set for impossible
  /// accesses, for instance writing to a final field or invoking a setter.
  static const EnumSet<Access> emptySet = EnumSet.fixed(0);

  final MemberEntity entity;

  MemberUsage.internal(this.entity) : super();

  MemberUsage.cloned(this.entity, EnumSet<MemberUse> pendingUse)
      : super.cloned(pendingUse);

  factory MemberUsage(MemberEntity member, {MemberAccess? potentialAccess}) {
    /// Create the set of potential accesses to [member], limited to [original]
    /// if provided.
    EnumSet<Access> createPotentialAccessSet(EnumSet<Access>? original) {
      if (original != null) {
        if (original.isEmpty) return emptySet;
        return original.clone();
      }
      if (member.isTopLevel || member.isStatic || member.isConstructor) {
        // TODO(johnniwinther): Track super constructor invocations?
        return EnumSet.fromValues([Access.staticAccess]);
      } else if (member.isInstanceMember) {
        return EnumSet.fromValues(Access.values);
      } else {
        assert(member is JRecordFieldInterface, "Unexpected member: $member");
        return EnumSet();
      }
    }

    /// Create the set of potential read accesses to [member], limited to reads
    /// in [potentialAccess] if provided.
    EnumSet<Access> createPotentialReads() {
      return createPotentialAccessSet(potentialAccess?.reads);
    }

    /// Create the set of potential write accesses to [member], limited to
    /// writes in [potentialAccess] if provided.
    EnumSet<Access> createPotentialWrites() {
      return createPotentialAccessSet(potentialAccess?.writes);
    }

    /// Create the set of potential invocation accesses to [member], limited to
    /// invocations in [potentialAccess] if provided.
    EnumSet<Access> createPotentialInvokes() {
      return createPotentialAccessSet(potentialAccess?.invokes);
    }

    if (member is FieldEntity) {
      if (member.isAssignable) {
        return FieldUsage(member,
            potentialReads: createPotentialReads(),
            potentialWrites: createPotentialWrites(),
            potentialInvokes: createPotentialInvokes());
      } else {
        return FieldUsage(member,
            potentialReads: createPotentialReads(),
            potentialWrites: emptySet,
            potentialInvokes: createPotentialInvokes());
      }
    } else if (member is FunctionEntity) {
      if (member.isGetter) {
        return PropertyUsage(member,
            potentialReads: createPotentialReads(),
            potentialWrites: emptySet,
            potentialInvokes: createPotentialInvokes());
      } else if (member.isSetter) {
        return PropertyUsage(member,
            potentialReads: emptySet,
            potentialWrites: createPotentialWrites(),
            potentialInvokes: emptySet);
      } else if (member.isConstructor) {
        return MethodUsage(member,
            potentialReads: emptySet,
            potentialInvokes: createPotentialInvokes());
      } else {
        return MethodUsage(member,
            potentialReads: createPotentialReads(),
            potentialInvokes: createPotentialInvokes());
      }
    }
    throw failedAt(member, "Unexpected member: $member");
  }

  /// `true` if [entity] has been initialized.
  bool get hasInit => true;

  /// The set of constant initial values for a field.
  Iterable<ConstantValue>? get initialConstants => null;

  /// `true` if [entity] has been read as a value. For a field this is a normal
  /// read access, for a function this is a closurization.
  bool get hasRead => reads.isNotEmpty;

  /// The set of potential read accesses to this member that have not yet
  /// been registered.
  EnumSet<Access> get potentialReads => const EnumSet.fixed(0);

  /// The set of registered read accesses to this member.
  EnumSet<Access> get reads => const EnumSet.fixed(0);

  /// `true` if a value has been written to [entity].
  bool get hasWrite => writes.isNotEmpty;

  /// The set of potential write accesses to this member that have not yet
  /// been registered.
  EnumSet<Access> get potentialWrites => const EnumSet.fixed(0);

  /// The set of registered write accesses to this member.
  EnumSet<Access> get writes => const EnumSet.fixed(0);

  /// `true` if an invocation has been performed on the value [entity]. For a
  /// function this is a normal invocation, for a field this is a read access
  /// followed by an invocation of the function-like value.
  bool get hasInvoke => invokes.isNotEmpty;

  /// The set of potential invocation accesses to this member that have not yet
  /// been registered.
  EnumSet<Access> get potentialInvokes => const EnumSet.fixed(0);

  /// The set of registered invocation accesses to this member.
  EnumSet<Access> get invokes => const EnumSet.fixed(0);

  /// Returns the [ParameterStructure] corresponding to the parameters that are
  /// used in invocations of [entity]. For a field, getter or setter this is
  /// always `null`.
  ParameterStructure? get invokedParameters => null;

  /// Whether this member has any potential but unregistered dynamic reads,
  /// writes or invocations.
  bool get hasPendingDynamicUse =>
      hasPendingDynamicInvoke ||
      hasPendingDynamicRead ||
      hasPendingDynamicWrite;

  /// Whether this member has any potential but unregistered dynamic
  /// invocations.
  bool get hasPendingDynamicInvoke =>
      potentialInvokes.contains(Access.dynamicAccess);

  /// Whether this member has any potential but unregistered dynamic reads.
  bool get hasPendingDynamicRead =>
      potentialReads.contains(Access.dynamicAccess);

  /// Whether this member has any potential but unregistered dynamic writes.
  bool get hasPendingDynamicWrite =>
      potentialWrites.contains(Access.dynamicAccess);

  /// Registers the [entity] has been initialized and returns the new
  /// [MemberUse]s that it caused.
  ///
  /// For a field this is the initial write access, for a function this is a
  /// no-op.
  EnumSet<MemberUse> init() => MemberUses.NONE;

  /// Registers the [entity] has been initialized with [constant] and returns
  /// the new [MemberUse]s that it caused.
  ///
  /// For a field this is the initial write access, for a function this is a
  /// no-op.
  EnumSet<MemberUse> constantInit(ConstantValue constant) => MemberUses.NONE;

  /// Registers a read of the value of [entity] and returns the new [MemberUse]s
  /// that it caused.
  ///
  /// For a field this is a normal read access, for a function this is a
  /// closurization.
  EnumSet<MemberUse> read(EnumSet<Access> accesses) => MemberUses.NONE;

  /// Registers a write of a value to [entity] and returns the new [MemberUse]s
  /// that it caused.
  EnumSet<MemberUse> write(EnumSet<Access> accesses) => MemberUses.NONE;

  /// Registers an invocation on the value of [entity] and returns the new
  /// [MemberUse]s that it caused.
  ///
  /// For a function this is a normal invocation, for a field this is a read
  /// access followed by an invocation of the function-like value.
  EnumSet<MemberUse> invoke(
          EnumSet<Access> accesses, CallStructure callStructure) =>
      MemberUses.NONE;

  @override
  EnumSet<MemberUse> get _originalUse => MemberUses.NORMAL_ONLY;

  @override
  int get hashCode => entity.hashCode;

  @override
  bool operator ==(other) {
    if (identical(this, other)) return true;
    if (other is! MemberUsage) return false;
    return entity == other.entity;
  }

  MemberUsage clone();

  bool dataEquals(MemberUsage other) {
    assert(entity == other.entity);
    return hasInit == other.hasInit &&
        hasRead == other.hasRead &&
        hasInvoke == other.hasInvoke &&
        hasWrite == other.hasWrite &&
        hasPendingDynamicRead == other.hasPendingDynamicRead &&
        hasPendingDynamicWrite == other.hasPendingDynamicWrite &&
        hasPendingDynamicInvoke == other.hasPendingDynamicInvoke &&
        hasPendingDynamicUse == other.hasPendingDynamicUse &&
        _pendingUse == other._pendingUse &&
        _appliedUse == other._appliedUse &&
        reads == other.reads &&
        writes == other.writes &&
        invokes == other.invokes &&
        potentialReads == other.potentialReads &&
        potentialWrites == other.potentialWrites &&
        potentialInvokes == other.potentialInvokes &&
        invokedParameters == other.invokedParameters;
  }
}

/// Member usage tracking for a getter or setter.
class PropertyUsage extends MemberUsage {
  @override
  final EnumSet<Access> potentialReads;

  @override
  final EnumSet<Access> potentialWrites;

  @override
  final EnumSet<Access> potentialInvokes;

  @override
  final EnumSet<Access> reads;

  @override
  final EnumSet<Access> writes;

  @override
  final EnumSet<Access> invokes;

  PropertyUsage.cloned(MemberEntity member, EnumSet<MemberUse> pendingUse,
      {required this.potentialReads,
      required this.potentialWrites,
      required this.potentialInvokes,
      required this.reads,
      required this.writes,
      required this.invokes})
      : // TODO(48820): Remove asserts when sound.
        assert((potentialReads as dynamic) != null),
        assert((potentialWrites as dynamic) != null),
        assert((potentialInvokes as dynamic) != null),
        assert((reads as dynamic) != null),
        assert((writes as dynamic) != null),
        assert((invokes as dynamic) != null),
        super.cloned(member, pendingUse);

  PropertyUsage(MemberEntity member,
      {required this.potentialReads,
      required this.potentialWrites,
      required this.potentialInvokes})
      : reads = EnumSet(),
        writes = EnumSet(),
        invokes = EnumSet(),
        // TODO(48820): Remove asserts when sound.
        assert((potentialReads as dynamic) != null),
        assert((potentialWrites as dynamic) != null),
        assert((potentialInvokes as dynamic) != null),
        super.internal(member);

  @override
  EnumSet<MemberUse> read(EnumSet<Access> accesses) {
    bool alreadyHasRead = hasRead;
    reads.addAll(potentialReads.removeAll(accesses));
    if (alreadyHasRead) {
      return MemberUses.NONE;
    }
    return _pendingUse.removeAll(MemberUses.NORMAL_ONLY);
  }

  @override
  EnumSet<MemberUse> write(EnumSet<Access> accesses) {
    bool alreadyHasWrite = hasWrite;
    writes.addAll(potentialWrites.removeAll(accesses));
    if (alreadyHasWrite) {
      return MemberUses.NONE;
    }
    return _pendingUse.removeAll(MemberUses.NORMAL_ONLY);
  }

  @override
  EnumSet<MemberUse> invoke(
      EnumSet<Access> accesses, CallStructure callStructure) {
    // We use `hasRead` here instead of `hasInvoke` because getters only have
    // 'normal use' (they cannot be closurized). This means that invoking an
    // already read getter does not result a new member use.
    bool alreadyHasRead = hasRead;
    reads.addAll(potentialReads.removeAll(Accesses.staticAccess));
    invokes.addAll(potentialInvokes.removeAll(accesses));
    if (alreadyHasRead) {
      return MemberUses.NONE;
    }
    return _pendingUse.removeAll(MemberUses.NORMAL_ONLY);
  }

  @override
  MemberUsage clone() {
    return PropertyUsage.cloned(entity, _pendingUse.clone(),
        potentialReads: potentialReads.clone(),
        potentialWrites: potentialWrites.clone(),
        potentialInvokes: potentialInvokes.clone(),
        reads: reads.clone(),
        writes: writes.clone(),
        invokes: invokes.clone());
  }

  @override
  String toString() => 'PropertyUsage($entity,'
      'reads=${reads.iterable(Access.values)},'
      'writes=${writes.iterable(Access.values)},'
      'invokes=${invokes.iterable(Access.values)},'
      'potentialReads=${potentialReads.iterable(Access.values)},'
      'potentialWrites=${potentialWrites.iterable(Access.values)},'
      'potentialInvokes=${potentialInvokes.iterable(Access.values)},'
      'pendingUse=${_pendingUse.iterable(MemberUse.values)},'
      'initialConstants=${initialConstants?.map((c) => c.toStructuredText(null))})';
}

/// Member usage tracking for a field.
class FieldUsage extends MemberUsage {
  @override
  bool hasInit;

  @override
  final EnumSet<Access> potentialReads;

  @override
  final EnumSet<Access> potentialWrites;

  @override
  final EnumSet<Access> potentialInvokes;

  @override
  final EnumSet<Access> reads;

  @override
  final EnumSet<Access> invokes;

  @override
  final EnumSet<Access> writes;

  List<ConstantValue>? _initialConstants;

  FieldUsage.cloned(FieldEntity field, EnumSet<MemberUse> pendingUse,
      {required this.potentialReads,
      required this.potentialWrites,
      required this.potentialInvokes,
      required this.hasInit,
      required this.reads,
      required this.writes,
      required this.invokes})
      : // TODO(48820): Remove asserts when sound.
        assert((potentialReads as dynamic) != null),
        assert((potentialWrites as dynamic) != null),
        assert((potentialInvokes as dynamic) != null),
        assert((reads as dynamic) != null),
        assert((writes as dynamic) != null),
        assert((invokes as dynamic) != null),
        super.cloned(field, pendingUse);

  FieldUsage(FieldEntity field,
      {required this.potentialReads,
      required this.potentialWrites,
      required this.potentialInvokes})
      : hasInit = false,
        reads = EnumSet(),
        writes = EnumSet(),
        invokes = EnumSet(),
        // TODO(48820): Remove asserts when sound.
        assert((potentialReads as dynamic) != null),
        assert((potentialWrites as dynamic) != null),
        assert((potentialInvokes as dynamic) != null),
        super.internal(field);

  @override
  Iterable<ConstantValue> get initialConstants => _initialConstants ?? const [];

  @override
  EnumSet<MemberUse> init() {
    if (hasInit) {
      return MemberUses.NONE;
    }
    hasInit = true;
    return _pendingUse.removeAll(MemberUses.NORMAL_ONLY);
  }

  @override
  EnumSet<MemberUse> constantInit(ConstantValue constant) {
    (_initialConstants ??= []).add(constant);
    return init();
  }

  @override
  bool get hasRead => reads.isNotEmpty;

  @override
  EnumSet<MemberUse> read(EnumSet<Access> accesses) {
    bool alreadyHasRead = hasRead;
    reads.addAll(potentialReads.removeAll(accesses));
    if (alreadyHasRead) {
      return MemberUses.NONE;
    }
    return _pendingUse.removeAll(MemberUses.NORMAL_ONLY);
  }

  @override
  bool get hasWrite => writes.isNotEmpty;

  @override
  EnumSet<MemberUse> write(EnumSet<Access> accesses) {
    bool alreadyHasWrite = hasWrite;
    writes.addAll(potentialWrites.removeAll(accesses));
    if (alreadyHasWrite) {
      return MemberUses.NONE;
    }
    return _pendingUse.removeAll(MemberUses.NORMAL_ONLY);
  }

  @override
  EnumSet<MemberUse> invoke(
      EnumSet<Access> accesses, CallStructure callStructure) {
    // We use `hasRead` here instead of `hasInvoke` because fields only have
    // 'normal use' (they cannot be closurized). This means that invoking an
    // already read field does not result a new member use.
    bool alreadyHasRead = hasRead;
    reads.addAll(potentialReads.removeAll(Accesses.staticAccess));
    invokes.addAll(potentialInvokes.removeAll(accesses));
    if (alreadyHasRead) {
      return MemberUses.NONE;
    }
    return _pendingUse.removeAll(MemberUses.NORMAL_ONLY);
  }

  @override
  MemberUsage clone() {
    return FieldUsage.cloned(entity as FieldEntity, _pendingUse.clone(),
        potentialReads: potentialReads.clone(),
        potentialWrites: potentialWrites.clone(),
        potentialInvokes: potentialInvokes.clone(),
        hasInit: hasInit,
        reads: reads.clone(),
        writes: writes.clone(),
        invokes: invokes.clone());
  }

  @override
  String toString() => 'FieldUsage($entity,hasInit=$hasInit,'
      'reads=${reads.iterable(Access.values)},'
      'writes=${writes.iterable(Access.values)},'
      'invokes=${invokes.iterable(Access.values)},'
      'potentialReads=${potentialReads.iterable(Access.values)},'
      'potentialWrites=${potentialWrites.iterable(Access.values)},'
      'potentialInvokes=${potentialInvokes.iterable(Access.values)},'
      'pendingUse=${_pendingUse.iterable(MemberUse.values)},'
      'initialConstants=${initialConstants.map((c) => c.toStructuredText(null))})';
}

/// Member usage tracking for a constructor or method.
class MethodUsage extends MemberUsage {
  @override
  final EnumSet<Access> potentialReads;

  @override
  final EnumSet<Access> potentialInvokes;

  @override
  final EnumSet<Access> reads;

  @override
  final EnumSet<Access> invokes;

  final ParameterUsage parameterUsage;

  MethodUsage.cloned(FunctionEntity function, this.parameterUsage,
      EnumSet<MemberUse> pendingUse,
      {required this.potentialReads,
      required this.reads,
      required this.potentialInvokes,
      required this.invokes})
      : assert((potentialReads as dynamic) != null),
        assert((potentialInvokes as dynamic) != null),
        assert((reads as dynamic) != null),
        assert((invokes as dynamic) != null),
        super.cloned(function, pendingUse);

  MethodUsage(FunctionEntity function,
      {required this.potentialReads, required this.potentialInvokes})
      : reads = EnumSet(),
        invokes = EnumSet(),
        parameterUsage = ParameterUsage(function.parameterStructure),
        assert((potentialReads as dynamic) != null),
        assert((potentialInvokes as dynamic) != null),
        super.internal(function);

  @override
  bool get hasInvoke => invokes.isNotEmpty && parameterUsage.hasInvoke;

  @override
  EnumSet<MemberUse> get _originalUse =>
      entity.isInstanceMember ? MemberUses.ALL_INSTANCE : MemberUses.ALL_STATIC;

  @override
  EnumSet<MemberUse> read(EnumSet<Access> accesses) {
    bool alreadyHasInvoke = hasInvoke;
    bool alreadyHasRead = hasRead;
    reads.addAll(potentialReads.removeAll(accesses));
    invokes.addAll(potentialInvokes.removeAll(Accesses.dynamicAccess));
    parameterUsage.fullyUse();
    if (alreadyHasInvoke) {
      if (alreadyHasRead) {
        return MemberUses.NONE;
      }
      return _pendingUse.removeAll(entity.isInstanceMember
          ? MemberUses.CLOSURIZE_INSTANCE_ONLY
          : MemberUses.CLOSURIZE_STATIC_ONLY);
    } else if (alreadyHasRead) {
      return _pendingUse.removeAll(MemberUses.NORMAL_ONLY);
    } else {
      return _pendingUse.removeAll(entity.isInstanceMember
          ? MemberUses.ALL_INSTANCE
          : MemberUses.ALL_STATIC);
    }
  }

  @override
  EnumSet<MemberUse> invoke(
      EnumSet<Access> accesses, CallStructure callStructure) {
    bool alreadyHasInvoke = hasInvoke;
    parameterUsage.invoke(callStructure);
    invokes.addAll(potentialInvokes.removeAll(accesses));
    if (alreadyHasInvoke) {
      return MemberUses.NONE;
    } else {
      return _pendingUse
          .removeAll(hasRead ? MemberUses.NONE : MemberUses.NORMAL_ONLY);
    }
  }

  @override
  ParameterStructure? get invokedParameters => parameterUsage.invokedParameters;

  @override
  bool get hasPendingDynamicInvoke =>
      potentialInvokes.contains(Access.dynamicAccess) ||
      (invokes.contains(Access.dynamicAccess) && !parameterUsage.isFullyUsed);

  @override
  MemberUsage clone() {
    return MethodUsage.cloned(
        entity as FunctionEntity, parameterUsage.clone(), _pendingUse.clone(),
        reads: reads.clone(),
        potentialReads: potentialReads.clone(),
        invokes: invokes.clone(),
        potentialInvokes: potentialInvokes.clone());
  }

  @override
  String toString() => 'MethodUsage($entity,'
      'reads=${reads.iterable(Access.values)},'
      'invokes=${invokes.iterable(Access.values)},'
      'parameterUsage=${parameterUsage},'
      'potentialReads=${potentialReads.iterable(Access.values)},'
      'potentialInvokes=${potentialInvokes.iterable(Access.values)},'
      'pendingUse=${_pendingUse.iterable(MemberUse.values)})';
}

/// Enum class for the possible kind of use of [MemberEntity] objects.
enum MemberUse {
  /// Read or write of a field, or invocation of a method.
  NORMAL,

  /// Tear-off of an instance method.
  CLOSURIZE_INSTANCE,

  /// Tear-off of a static method.
  CLOSURIZE_STATIC,
}

/// Common [EnumSet]s used for [MemberUse].
class MemberUses {
  static const EnumSet<MemberUse> NONE = EnumSet.fixed(0);
  static const EnumSet<MemberUse> NORMAL_ONLY = EnumSet.fixed(1);
  static const EnumSet<MemberUse> CLOSURIZE_INSTANCE_ONLY = EnumSet.fixed(2);
  static const EnumSet<MemberUse> CLOSURIZE_STATIC_ONLY = EnumSet.fixed(4);
  static const EnumSet<MemberUse> ALL_INSTANCE = EnumSet.fixed(3);
  static const EnumSet<MemberUse> ALL_STATIC = EnumSet.fixed(5);
}

typedef MemberUsedCallback = void Function(
    MemberEntity member, EnumSet<MemberUse> useSet);

/// Registry for the observed use of a class [entity] in the open world.
// TODO(johnniwinther): Merge this with [InstantiationInfo].
class ClassUsage extends AbstractUsage<ClassUse> {
  bool isInstantiated = false;
  bool isImplemented = false;

  final ClassEntity cls;

  ClassUsage(this.cls) : super();

  EnumSet<ClassUse> instantiate() {
    if (isInstantiated) {
      return ClassUses.NONE;
    }
    isInstantiated = true;
    return _pendingUse.removeAll(ClassUses.INSTANTIATED_ONLY);
  }

  EnumSet<ClassUse> implement() {
    if (isImplemented) {
      return ClassUses.NONE;
    }
    isImplemented = true;
    return _pendingUse.removeAll(ClassUses.IMPLEMENTED_ONLY);
  }

  @override
  EnumSet<ClassUse> get _originalUse => ClassUses.ALL;

  @override
  String toString() => '$cls:${_appliedUse.iterable(ClassUse.values)}';
}

/// Enum class for the possible kind of use of [ClassEntity] objects.
enum ClassUse { INSTANTIATED, IMPLEMENTED }

/// Common [EnumSet]s used for [ClassUse].
class ClassUses {
  static const EnumSet<ClassUse> NONE = EnumSet.fixed(0);
  static const EnumSet<ClassUse> INSTANTIATED_ONLY = EnumSet.fixed(1);
  static const EnumSet<ClassUse> IMPLEMENTED_ONLY = EnumSet.fixed(2);
  static const EnumSet<ClassUse> ALL = EnumSet.fixed(3);
}

typedef ClassUsedCallback = void Function(
    ClassEntity cls, EnumSet<ClassUse> useSet);

/// Object used for tracking parameter use in constructor and method
/// invocations.
class ParameterUsage {
  /// The original parameter structure of the method or constructor.
  final ParameterStructure _parameterStructure;

  /// `true` if the method or constructor has at least one invocation.
  bool _hasInvoke = false;

  /// The maximum number of (optional) positional parameters provided in
  /// invocations of the method or constructor.
  ///
  /// If all positional parameters having been provided this is set to `null`.
  int? _providedPositionalParameters;

  /// `true` if all type parameters have been provided in at least one
  /// invocation of the method or constructor.
  late bool _areAllTypeParametersProvided;

  /// The set of named parameters that have not yet been provided in any
  /// invocation of the method or constructor.
  ///
  /// If all named parameters have been provided this is set to `null`.
  Set<String>? _unprovidedNamedParameters;

  ParameterUsage(this._parameterStructure) {
    _areAllTypeParametersProvided = _parameterStructure.typeParameters == 0;
    _providedPositionalParameters = _parameterStructure.positionalParameters ==
            _parameterStructure.requiredPositionalParameters
        ? null
        : 0;
    if (!_parameterStructure.namedParameters.isEmpty) {
      _unprovidedNamedParameters =
          Set<String>.from(_parameterStructure.namedParameters);
    }
  }

  ParameterUsage.cloned(this._parameterStructure,
      {required bool hasInvoke,
      required providedPositionalParameters,
      required bool areAllTypeParametersProvided,
      required Set<String>? unprovidedNamedParameters})
      : _hasInvoke = hasInvoke,
        _providedPositionalParameters = providedPositionalParameters,
        _areAllTypeParametersProvided = areAllTypeParametersProvided,
        _unprovidedNamedParameters = unprovidedNamedParameters;

  bool invoke(CallStructure callStructure) {
    if (isFullyUsed) return false;
    _hasInvoke = true;
    bool changed = false;
    if (_providedPositionalParameters != null) {
      int newProvidedPositionalParameters = Math.max(
          _providedPositionalParameters!,
          callStructure.positionalArgumentCount);
      changed |=
          newProvidedPositionalParameters != _providedPositionalParameters;
      _providedPositionalParameters = newProvidedPositionalParameters;
      if (_providedPositionalParameters! >=
          _parameterStructure.positionalParameters) {
        _providedPositionalParameters = null;
      }
    }
    if (_unprovidedNamedParameters != null &&
        callStructure.namedArguments.isNotEmpty) {
      int _providedNamedParametersCount = _unprovidedNamedParameters!.length;
      _unprovidedNamedParameters!.removeAll(callStructure.namedArguments);
      changed |=
          _providedNamedParametersCount != _unprovidedNamedParameters!.length;
      if (_unprovidedNamedParameters!.isEmpty) {
        _unprovidedNamedParameters = null;
      }
    }
    if (!_areAllTypeParametersProvided && callStructure.typeArgumentCount > 0) {
      _areAllTypeParametersProvided = true;
      changed = true;
    }
    return changed;
  }

  bool get hasInvoke => _hasInvoke;

  bool get isFullyUsed =>
      _hasInvoke &&
      _providedPositionalParameters == null &&
      _unprovidedNamedParameters == null &&
      _areAllTypeParametersProvided;

  void fullyUse() {
    _hasInvoke = true;
    _providedPositionalParameters = null;
    _unprovidedNamedParameters = null;
    _areAllTypeParametersProvided = true;
  }

  ParameterStructure? get invokedParameters {
    if (!_hasInvoke) return null;
    if (isFullyUsed) return _parameterStructure;
    return ParameterStructure(
        _parameterStructure.requiredPositionalParameters,
        _providedPositionalParameters ??
            _parameterStructure.positionalParameters,
        _unprovidedNamedParameters == null
            ? _parameterStructure.namedParameters
            : _parameterStructure.namedParameters
                .where((n) => !_unprovidedNamedParameters!.contains(n))
                .toList(),
        _parameterStructure.requiredNamedParameters,
        _areAllTypeParametersProvided ? _parameterStructure.typeParameters : 0);
  }

  ParameterUsage clone() {
    return ParameterUsage.cloned(_parameterStructure,
        hasInvoke: _hasInvoke,
        providedPositionalParameters: _providedPositionalParameters,
        areAllTypeParametersProvided: _areAllTypeParametersProvided,
        unprovidedNamedParameters: _unprovidedNamedParameters?.toSet());
  }

  @override
  String toString() {
    return 'ParameterUsage('
        '_hasInvoke=$_hasInvoke,'
        '_providedPositionalParameters=$_providedPositionalParameters,'
        '_areAllTypeParametersProvided=$_areAllTypeParametersProvided,'
        '_unprovidedNamedParameters=$_unprovidedNamedParameters)';
  }
}

/// Enum for member access kinds use in [MemberUsage] computation during
/// resolution or codegen enqueueing.
enum Access {
  /// Statically bound access of a member.
  staticAccess,

  /// Dynamically bound access of a member.
  dynamicAccess,

  /// Direct access of a super class member.
  superAccess,
}

/// Access sets used for registration of member usage.
class Accesses {
  /// Statically bound access of a member.
  static const EnumSet<Access> staticAccess = EnumSet.fixed(1);

  /// Dynamically bound access of a member. This implies the statically bound
  /// access of the member.
  static const EnumSet<Access> dynamicAccess = EnumSet.fixed(3);

  /// Direct access of a super class member. This implies the statically bound
  /// access of the member.
  static const EnumSet<Access> superAccess = EnumSet.fixed(5);
}

/// The accesses of a member collected during closed world computation.
class MemberAccess {
  static const String tag = 'MemberAccess';

  final EnumSet<Access> reads;
  final EnumSet<Access> writes;
  final EnumSet<Access> invokes;

  MemberAccess(this.reads, this.writes, this.invokes);

  factory MemberAccess.readFromDataSource(DataSourceReader source) {
    source.begin(tag);
    EnumSet<Access> reads = EnumSet.fixed(source.readInt());
    EnumSet<Access> writes = EnumSet.fixed(source.readInt());
    EnumSet<Access> invokes = EnumSet.fixed(source.readInt());
    source.end(tag);
    return MemberAccess(reads, writes, invokes);
  }

  void writeToDataSink(DataSinkWriter sink) {
    sink.begin(tag);
    sink.writeInt(reads.value);
    sink.writeInt(writes.value);
    sink.writeInt(invokes.value);
    sink.end(tag);
  }
}
