// 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/closure.dart';
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 JRecordField, "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.isField) {
      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.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 {
      assert(member is FunctionEntity,
          failedAt(member, "Unexpected member: $member"));
      return MethodUsage(member,
          potentialReads: createPotentialReads(),
          potentialInvokes: createPotentialInvokes());
    }
  }

  /// `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,
      {this.potentialReads,
      this.potentialWrites,
      this.potentialInvokes,
      this.reads,
      this.writes,
      this.invokes})
      : assert(potentialReads != null),
        assert(potentialWrites != null),
        assert(potentialInvokes != null),
        assert(reads != null),
        assert(writes != null),
        assert(invokes != null),
        super.cloned(member, pendingUse);

  PropertyUsage(MemberEntity member,
      {this.potentialReads, this.potentialWrites, this.potentialInvokes})
      : reads = EnumSet(),
        writes = EnumSet(),
        invokes = EnumSet(),
        assert(potentialReads != null),
        assert(potentialWrites != null),
        assert(potentialInvokes != 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,
      {this.potentialReads,
      this.potentialWrites,
      this.potentialInvokes,
      this.hasInit,
      this.reads,
      this.writes,
      this.invokes})
      : assert(potentialReads != null),
        assert(potentialWrites != null),
        assert(potentialInvokes != null),
        assert(reads != null),
        assert(writes != null),
        assert(invokes != null),
        super.cloned(field, pendingUse);

  FieldUsage(FieldEntity field,
      {this.potentialReads, this.potentialWrites, this.potentialInvokes})
      : hasInit = false,
        reads = EnumSet(),
        writes = EnumSet(),
        invokes = EnumSet(),
        assert(potentialReads != null),
        assert(potentialWrites != null),
        assert(potentialInvokes != 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 ??= [];
    _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, _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,
      {this.potentialReads, this.reads, this.potentialInvokes, this.invokes})
      : assert(potentialReads != null),
        assert(potentialInvokes != null),
        assert(reads != null),
        assert(invokes != null),
        super.cloned(function, pendingUse);

  MethodUsage(FunctionEntity function,
      {this.potentialReads, this.potentialInvokes})
      : reads = EnumSet(),
        invokes = EnumSet(),
        parameterUsage = ParameterUsage(function.parameterStructure),
        assert(potentialReads != null),
        assert(potentialInvokes != 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, 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;

  /// 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.
  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) {
    _hasInvoke = false;
    _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,
      {bool hasInvoke,
      int providedPositionalParameters,
      bool areAllTypeParametersProvided,
      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);
  }
}
