Fix arity in overloaded function argument error (#883)

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
This commit is contained in:
Awjin Ahn 2019-11-15 14:26:11 -08:00 committed by GitHub
parent 3d1dab3563
commit 07b5c84b7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 12 deletions

View File

@ -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.

View File

@ -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;
}
}

View File

@ -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) =>