Skip to content

Commit

Permalink
Fix arity in overloaded function argument error (#883)
Browse files Browse the repository at this point in the history
When overloaded functions receive an incorrect number of positional
arguments, determine which overload has the most similar number of
arguments, and then correctly display that number in the error.

Closes #520
sass/sass-spec#1496
  • Loading branch information
Awjin committed Nov 15, 2019
1 parent 3d1dab3 commit 07b5c84
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 12 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## 1.23.5

* When an overloaded function receives the wrong number of arguments, guess
which overload the user actually meant to invoke, and display the invalid
argument error for that overload.

* When `@error` is used in a function or mixin, print the call site rather than
the location of the `@error` itself to better match the behavior of calling a
built-in function that throws an error.
Expand Down
33 changes: 27 additions & 6 deletions lib/src/callable/async_built_in.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,32 @@ class AsyncBuiltInCallable implements AsyncCallable {
/// Returns the argument declaration and Dart callback for the given
/// positional and named arguments.
///
/// Note that this doesn't guarantee that [positional] and [names] are valid
/// for the returned [ArgumentDeclaration].
/// If no exact match is found, finds the closest approximation. Note that this
/// doesn't guarantee that [positional] and [names] are valid for the returned
/// [ArgumentDeclaration].
Tuple2<ArgumentDeclaration, _Callback> callbackFor(
int positional, Set<String> names) =>
_overloads.take(_overloads.length - 1).firstWhere(
(overload) => overload.item1.matches(positional, names),
orElse: () => _overloads.last);
int positional, Set<String> names) {
Tuple2<ArgumentDeclaration, _Callback> fuzzyMatch;
int minMismatchDistance;

for (var overload in _overloads) {
// Ideally, find an exact match.
if (overload.item1.matches(positional, names)) return overload;

var mismatchDistance = overload.item1.arguments.length - positional;

if (minMismatchDistance != null) {
if (mismatchDistance.abs() > minMismatchDistance.abs()) continue;
// If two overloads have the same mismatch distance, favor the overload
// that has more arguments.
if (mismatchDistance.abs() == minMismatchDistance.abs() &&
mismatchDistance < 0) continue;
}

minMismatchDistance = mismatchDistance;
fuzzyMatch = overload;
}

return fuzzyMatch;
}
}
33 changes: 27 additions & 6 deletions lib/src/callable/built_in.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,34 @@ class BuiltInCallable implements Callable, AsyncBuiltInCallable {
/// Returns the argument declaration and Dart callback for the given
/// positional and named arguments.
///
/// Note that this doesn't guarantee that [positional] and [names] are valid
/// for the returned [ArgumentDeclaration].
/// If no exact match is found, finds the closest approximation. Note that this
/// doesn't guarantee that [positional] and [names] are valid for the returned
/// [ArgumentDeclaration].
Tuple2<ArgumentDeclaration, _Callback> callbackFor(
int positional, Set<String> names) =>
_overloads.take(_overloads.length - 1).firstWhere(
(overload) => overload.item1.matches(positional, names),
orElse: () => _overloads.last);
int positional, Set<String> names) {
Tuple2<ArgumentDeclaration, _Callback> fuzzyMatch;
int minMismatchDistance;

for (var overload in _overloads) {
// Ideally, find an exact match.
if (overload.item1.matches(positional, names)) return overload;

var mismatchDistance = overload.item1.arguments.length - positional;

if (minMismatchDistance != null) {
if (mismatchDistance.abs() > minMismatchDistance.abs()) continue;
// If two overloads have the same mismatch distance, favor the overload
// that has more arguments.
if (mismatchDistance.abs() == minMismatchDistance.abs() &&
mismatchDistance < 0) continue;
}

minMismatchDistance = mismatchDistance;
fuzzyMatch = overload;
}

return fuzzyMatch;
}

/// Returns a copy of this callable with the given [name].
BuiltInCallable withName(String name) =>
Expand Down

0 comments on commit 07b5c84

Please sign in to comment.