checkArity static method

void checkArity(
  1. List<Object?> positional,
  2. String memberDescription, {
  3. int? exactly,
  4. int? atMost,
  5. int? atLeast,
})

SCC85: reject positional arguments the adapter would silently discard.

The companion to describeArityError, which covers the too-FEW half generically: an unguarded adapter that reads past the end of the argument list raises a RangeError the dispatcher recognises and restates. Too MANY arguments raise nothing at all — the adapter reads the slots it wants, the surplus is dropped, and a typo stays invisible:

UriData.parse('data:,a', 'extra')   // returns the parsed value

That half cannot be recognised at the dispatch boundary the same way, because BridgedClass stores an adapter as an untyped closure and nothing on the dispatch path knows how many arguments it wants. The count is known only inside the adapter, so the check has to live there — but it does NOT have to be written out 443 times across two trees, which is what this is for.

atMost is the bound to prefer, and the one a sweep can derive mechanically: it is one past the highest index the adapter ever reads, so anything beyond it is provably ignored. exactly and atLeast are for adapters whose minimum is known by hand — the minimum is not derivable in general, because an adapter reading positionalArgs[1] behind a length test takes one argument or two.

Ordering note: once an adapter carries this, its message wins over describeArityError's, because the check runs before any index is read. That is intended — an explicit guard can name the expected shape — but it means a test asserting the generic wording must not point at a guarded bridge.

This is the HAND-WRITTEN stdlib entry point, and the counterpart to getRequiredArg, which is the generated one. The two throw different exception types on purpose — see getRequiredArg for why the split exists and why it was not collapsed. stdlib_d4_boundary_test keeps it stated.

memberDescription is the Class.member the script author called.

Implementation

static void checkArity(
  List<Object?> positional,
  String memberDescription, {
  int? exactly,
  int? atMost,
  int? atLeast,
}) {
  assert(
    exactly != null || atMost != null || atLeast != null,
    'checkArity was given no bound, so it would accept anything. Pass '
    'exactly:, atMost: or atLeast:.',
  );
  final int actual = positional.length;

  if (exactly != null && actual != exactly) {
    throw RuntimeD4rtException(
      '$memberDescription expects exactly $exactly positional '
      '${_arguments(exactly)}, but was called with $actual.',
    );
  }
  if (atLeast != null && actual < atLeast) {
    throw RuntimeD4rtException(
      '$memberDescription expects at least $atLeast positional '
      '${_arguments(atLeast)}, but was called with $actual.',
    );
  }
  if (atMost != null && actual > atMost) {
    throw RuntimeD4rtException(
      '$memberDescription accepts at most $atMost positional '
      '${_arguments(atMost)}, but was called with $actual. The extra '
      '${actual - atMost == 1 ? 'argument is' : 'arguments are'} not used by '
      'this member — check for a typo or a misremembered signature.',
    );
  }
}