Issue 19220 function parameter arity (#24031)

* Added reference test case and diagnostics message

* Adjusted arity checks to account for non-contiguous overloads

* Code cleanup, baseline not yet commited

* Accepted test baselines and minor implementation changes

* Cleaned up baseline tracking the now renamed arity check test

* Add range response when range contains only 2 values

* Added recent baseline

* Refined arity error messages when available overloads can be grouped

* Rolled back code formatting

* WIP cleanup needed in a few edge cases

* Finished adding new more descriptive error messages

* Code cleanup

* Added simplified version of bugfix for #19220

* Rebased onto master

* Removed whitespace after type assertion

* Code review simplifications

* Use correct diagnostic name

* Code review changes and simplification of diagnostic message

* Revert formatting changes
This commit is contained in:
rflorian 2018-07-12 02:19:56 +02:00 committed by Nathan Shively-Sanders
parent 5f4a03c408
commit 66e9aaac18
7 changed files with 249 additions and 10 deletions

View file

@ -19052,24 +19052,40 @@ namespace ts {
else if (args) {
let min = Number.POSITIVE_INFINITY;
let max = Number.NEGATIVE_INFINITY;
let belowArgCount = Number.NEGATIVE_INFINITY;
let aboveArgCount = Number.POSITIVE_INFINITY;
let argCount = args.length;
for (const sig of signatures) {
min = Math.min(min, getMinArgumentCount(sig));
max = Math.max(max, getParameterCount(sig));
const minCount = getMinArgumentCount(sig);
const maxCount = getParameterCount(sig);
if (minCount < argCount && minCount > belowArgCount) belowArgCount = minCount;
if (argCount < maxCount && maxCount < aboveArgCount) aboveArgCount = maxCount;
min = Math.min(min, minCount);
max = Math.max(max, maxCount);
}
const hasRestParameter = some(signatures, hasEffectiveRestParameter);
const hasSpreadArgument = getSpreadArgumentIndex(args) > -1;
const paramCount = hasRestParameter ? min :
const paramRange = hasRestParameter ? min :
min < max ? min + "-" + max :
min;
let argCount = args.length;
const hasSpreadArgument = getSpreadArgumentIndex(args) > -1;
if (argCount <= max && hasSpreadArgument) {
argCount--;
}
const error = hasRestParameter && hasSpreadArgument ? Diagnostics.Expected_at_least_0_arguments_but_got_1_or_more :
hasRestParameter ? Diagnostics.Expected_at_least_0_arguments_but_got_1 :
hasSpreadArgument ? Diagnostics.Expected_0_arguments_but_got_1_or_more :
Diagnostics.Expected_0_arguments_but_got_1;
diagnostics.add(createDiagnosticForNode(node, error, paramCount, argCount));
if (hasRestParameter || hasSpreadArgument) {
const error = hasRestParameter && hasSpreadArgument ? Diagnostics.Expected_at_least_0_arguments_but_got_1_or_more :
hasRestParameter ? Diagnostics.Expected_at_least_0_arguments_but_got_1 :
Diagnostics.Expected_0_arguments_but_got_1_or_more;
diagnostics.add(createDiagnosticForNode(node, error, paramRange, argCount));
}
else if (min < argCount && argCount < max) {
diagnostics.add(createDiagnosticForNode(node, Diagnostics.No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments, argCount, belowArgCount, aboveArgCount));
}
else {
diagnostics.add(createDiagnosticForNode(node, Diagnostics.Expected_0_arguments_but_got_1, paramRange, argCount));
}
}
else if (fallbackError) {
diagnostics.add(createDiagnosticForNode(node, fallbackError));

View file

@ -2056,6 +2056,10 @@
"category": "Error",
"code": 2574
},
"No overload expects {0} arguments, but overloads do exist that expect either {1} or {2} arguments.": {
"category": "Error",
"code": 2575
},
"JSX element attributes type '{0}' may not be a union type.": {
"category": "Error",
"code": 2600

View file

@ -0,0 +1,39 @@
tests/cases/compiler/functionParameterArityMismatch.ts(3,1): error TS2554: Expected 1-3 arguments, but got 0.
tests/cases/compiler/functionParameterArityMismatch.ts(4,1): error TS2575: No overload expects 2 arguments, but overloads do exist that expect either 1 or 3 arguments.
tests/cases/compiler/functionParameterArityMismatch.ts(5,1): error TS2554: Expected 1-3 arguments, but got 4.
tests/cases/compiler/functionParameterArityMismatch.ts(11,1): error TS2575: No overload expects 1 arguments, but overloads do exist that expect either 0 or 2 arguments.
tests/cases/compiler/functionParameterArityMismatch.ts(12,1): error TS2575: No overload expects 3 arguments, but overloads do exist that expect either 2 or 4 arguments.
tests/cases/compiler/functionParameterArityMismatch.ts(13,1): error TS2575: No overload expects 5 arguments, but overloads do exist that expect either 4 or 6 arguments.
tests/cases/compiler/functionParameterArityMismatch.ts(14,1): error TS2554: Expected 0-6 arguments, but got 7.
==== tests/cases/compiler/functionParameterArityMismatch.ts (7 errors) ====
declare function f1(a: number);
declare function f1(a: number, b: number, c: number);
f1();
~~~~
!!! error TS2554: Expected 1-3 arguments, but got 0.
f1(1, 2);
~~~~~~~~
!!! error TS2575: No overload expects 2 arguments, but overloads do exist that expect either 1 or 3 arguments.
f1(1, 2, 3, 4);
~~~~~~~~~~~~~~
!!! error TS2554: Expected 1-3 arguments, but got 4.
declare function f2();
declare function f2(a: number, b: number);
declare function f2(a: number, b: number, c: number, d: number);
declare function f2(a: number, b: number, c: number, d: number, e: number, f: number);
f2(1);
~~~~~
!!! error TS2575: No overload expects 1 arguments, but overloads do exist that expect either 0 or 2 arguments.
f2(1, 2, 3);
~~~~~~~~~~~
!!! error TS2575: No overload expects 3 arguments, but overloads do exist that expect either 2 or 4 arguments.
f2(1, 2, 3, 4, 5);
~~~~~~~~~~~~~~~~~
!!! error TS2575: No overload expects 5 arguments, but overloads do exist that expect either 4 or 6 arguments.
f2(1, 2, 3, 4, 5, 6, 7);
~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2554: Expected 0-6 arguments, but got 7.

View file

@ -0,0 +1,25 @@
//// [functionParameterArityMismatch.ts]
declare function f1(a: number);
declare function f1(a: number, b: number, c: number);
f1();
f1(1, 2);
f1(1, 2, 3, 4);
declare function f2();
declare function f2(a: number, b: number);
declare function f2(a: number, b: number, c: number, d: number);
declare function f2(a: number, b: number, c: number, d: number, e: number, f: number);
f2(1);
f2(1, 2, 3);
f2(1, 2, 3, 4, 5);
f2(1, 2, 3, 4, 5, 6, 7);
//// [functionParameterArityMismatch.js]
f1();
f1(1, 2);
f1(1, 2, 3, 4);
f2(1);
f2(1, 2, 3);
f2(1, 2, 3, 4, 5);
f2(1, 2, 3, 4, 5, 6, 7);

View file

@ -0,0 +1,56 @@
=== tests/cases/compiler/functionParameterArityMismatch.ts ===
declare function f1(a: number);
>f1 : Symbol(f1, Decl(functionParameterArityMismatch.ts, 0, 0), Decl(functionParameterArityMismatch.ts, 0, 31))
>a : Symbol(a, Decl(functionParameterArityMismatch.ts, 0, 20))
declare function f1(a: number, b: number, c: number);
>f1 : Symbol(f1, Decl(functionParameterArityMismatch.ts, 0, 0), Decl(functionParameterArityMismatch.ts, 0, 31))
>a : Symbol(a, Decl(functionParameterArityMismatch.ts, 1, 20))
>b : Symbol(b, Decl(functionParameterArityMismatch.ts, 1, 30))
>c : Symbol(c, Decl(functionParameterArityMismatch.ts, 1, 41))
f1();
>f1 : Symbol(f1, Decl(functionParameterArityMismatch.ts, 0, 0), Decl(functionParameterArityMismatch.ts, 0, 31))
f1(1, 2);
>f1 : Symbol(f1, Decl(functionParameterArityMismatch.ts, 0, 0), Decl(functionParameterArityMismatch.ts, 0, 31))
f1(1, 2, 3, 4);
>f1 : Symbol(f1, Decl(functionParameterArityMismatch.ts, 0, 0), Decl(functionParameterArityMismatch.ts, 0, 31))
declare function f2();
>f2 : Symbol(f2, Decl(functionParameterArityMismatch.ts, 4, 15), Decl(functionParameterArityMismatch.ts, 6, 22), Decl(functionParameterArityMismatch.ts, 7, 42), Decl(functionParameterArityMismatch.ts, 8, 64))
declare function f2(a: number, b: number);
>f2 : Symbol(f2, Decl(functionParameterArityMismatch.ts, 4, 15), Decl(functionParameterArityMismatch.ts, 6, 22), Decl(functionParameterArityMismatch.ts, 7, 42), Decl(functionParameterArityMismatch.ts, 8, 64))
>a : Symbol(a, Decl(functionParameterArityMismatch.ts, 7, 20))
>b : Symbol(b, Decl(functionParameterArityMismatch.ts, 7, 30))
declare function f2(a: number, b: number, c: number, d: number);
>f2 : Symbol(f2, Decl(functionParameterArityMismatch.ts, 4, 15), Decl(functionParameterArityMismatch.ts, 6, 22), Decl(functionParameterArityMismatch.ts, 7, 42), Decl(functionParameterArityMismatch.ts, 8, 64))
>a : Symbol(a, Decl(functionParameterArityMismatch.ts, 8, 20))
>b : Symbol(b, Decl(functionParameterArityMismatch.ts, 8, 30))
>c : Symbol(c, Decl(functionParameterArityMismatch.ts, 8, 41))
>d : Symbol(d, Decl(functionParameterArityMismatch.ts, 8, 52))
declare function f2(a: number, b: number, c: number, d: number, e: number, f: number);
>f2 : Symbol(f2, Decl(functionParameterArityMismatch.ts, 4, 15), Decl(functionParameterArityMismatch.ts, 6, 22), Decl(functionParameterArityMismatch.ts, 7, 42), Decl(functionParameterArityMismatch.ts, 8, 64))
>a : Symbol(a, Decl(functionParameterArityMismatch.ts, 9, 20))
>b : Symbol(b, Decl(functionParameterArityMismatch.ts, 9, 30))
>c : Symbol(c, Decl(functionParameterArityMismatch.ts, 9, 41))
>d : Symbol(d, Decl(functionParameterArityMismatch.ts, 9, 52))
>e : Symbol(e, Decl(functionParameterArityMismatch.ts, 9, 63))
>f : Symbol(f, Decl(functionParameterArityMismatch.ts, 9, 74))
f2(1);
>f2 : Symbol(f2, Decl(functionParameterArityMismatch.ts, 4, 15), Decl(functionParameterArityMismatch.ts, 6, 22), Decl(functionParameterArityMismatch.ts, 7, 42), Decl(functionParameterArityMismatch.ts, 8, 64))
f2(1, 2, 3);
>f2 : Symbol(f2, Decl(functionParameterArityMismatch.ts, 4, 15), Decl(functionParameterArityMismatch.ts, 6, 22), Decl(functionParameterArityMismatch.ts, 7, 42), Decl(functionParameterArityMismatch.ts, 8, 64))
f2(1, 2, 3, 4, 5);
>f2 : Symbol(f2, Decl(functionParameterArityMismatch.ts, 4, 15), Decl(functionParameterArityMismatch.ts, 6, 22), Decl(functionParameterArityMismatch.ts, 7, 42), Decl(functionParameterArityMismatch.ts, 8, 64))
f2(1, 2, 3, 4, 5, 6, 7);
>f2 : Symbol(f2, Decl(functionParameterArityMismatch.ts, 4, 15), Decl(functionParameterArityMismatch.ts, 6, 22), Decl(functionParameterArityMismatch.ts, 7, 42), Decl(functionParameterArityMismatch.ts, 8, 64))

View file

@ -0,0 +1,85 @@
=== tests/cases/compiler/functionParameterArityMismatch.ts ===
declare function f1(a: number);
>f1 : { (a: number): any; (a: number, b: number, c: number): any; }
>a : number
declare function f1(a: number, b: number, c: number);
>f1 : { (a: number): any; (a: number, b: number, c: number): any; }
>a : number
>b : number
>c : number
f1();
>f1() : any
>f1 : { (a: number): any; (a: number, b: number, c: number): any; }
f1(1, 2);
>f1(1, 2) : any
>f1 : { (a: number): any; (a: number, b: number, c: number): any; }
>1 : 1
>2 : 2
f1(1, 2, 3, 4);
>f1(1, 2, 3, 4) : any
>f1 : { (a: number): any; (a: number, b: number, c: number): any; }
>1 : 1
>2 : 2
>3 : 3
>4 : 4
declare function f2();
>f2 : { (): any; (a: number, b: number): any; (a: number, b: number, c: number, d: number): any; (a: number, b: number, c: number, d: number, e: number, f: number): any; }
declare function f2(a: number, b: number);
>f2 : { (): any; (a: number, b: number): any; (a: number, b: number, c: number, d: number): any; (a: number, b: number, c: number, d: number, e: number, f: number): any; }
>a : number
>b : number
declare function f2(a: number, b: number, c: number, d: number);
>f2 : { (): any; (a: number, b: number): any; (a: number, b: number, c: number, d: number): any; (a: number, b: number, c: number, d: number, e: number, f: number): any; }
>a : number
>b : number
>c : number
>d : number
declare function f2(a: number, b: number, c: number, d: number, e: number, f: number);
>f2 : { (): any; (a: number, b: number): any; (a: number, b: number, c: number, d: number): any; (a: number, b: number, c: number, d: number, e: number, f: number): any; }
>a : number
>b : number
>c : number
>d : number
>e : number
>f : number
f2(1);
>f2(1) : any
>f2 : { (): any; (a: number, b: number): any; (a: number, b: number, c: number, d: number): any; (a: number, b: number, c: number, d: number, e: number, f: number): any; }
>1 : 1
f2(1, 2, 3);
>f2(1, 2, 3) : any
>f2 : { (): any; (a: number, b: number): any; (a: number, b: number, c: number, d: number): any; (a: number, b: number, c: number, d: number, e: number, f: number): any; }
>1 : 1
>2 : 2
>3 : 3
f2(1, 2, 3, 4, 5);
>f2(1, 2, 3, 4, 5) : any
>f2 : { (): any; (a: number, b: number): any; (a: number, b: number, c: number, d: number): any; (a: number, b: number, c: number, d: number, e: number, f: number): any; }
>1 : 1
>2 : 2
>3 : 3
>4 : 4
>5 : 5
f2(1, 2, 3, 4, 5, 6, 7);
>f2(1, 2, 3, 4, 5, 6, 7) : any
>f2 : { (): any; (a: number, b: number): any; (a: number, b: number, c: number, d: number): any; (a: number, b: number, c: number, d: number, e: number, f: number): any; }
>1 : 1
>2 : 2
>3 : 3
>4 : 4
>5 : 5
>6 : 6
>7 : 7

View file

@ -0,0 +1,14 @@
declare function f1(a: number);
declare function f1(a: number, b: number, c: number);
f1();
f1(1, 2);
f1(1, 2, 3, 4);
declare function f2();
declare function f2(a: number, b: number);
declare function f2(a: number, b: number, c: number, d: number);
declare function f2(a: number, b: number, c: number, d: number, e: number, f: number);
f2(1);
f2(1, 2, 3);
f2(1, 2, 3, 4, 5);
f2(1, 2, 3, 4, 5, 6, 7);