From 76bc82bf53194bb36c8da55845ec0d660bdc792a Mon Sep 17 00:00:00 2001 From: Jack Williams Date: Mon, 2 Dec 2019 07:30:24 +0000 Subject: [PATCH 1/3] Make never rest type top-like --- src/compiler/checker.ts | 2 +- tests/baselines/reference/genericRestTypes.js | 15 +++++++++++++++ .../reference/genericRestTypes.symbols | 19 +++++++++++++++++++ .../reference/genericRestTypes.types | 18 ++++++++++++++++++ tests/cases/compiler/genericRestTypes.ts | 5 +++++ 5 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3f550efce4051..9c1b6e3e493cd 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25632,7 +25632,7 @@ namespace ts { function getNonArrayRestType(signature: Signature) { const restType = getEffectiveRestType(signature); - return restType && !isArrayType(restType) && !isTypeAny(restType) ? restType : undefined; + return restType && !isArrayType(restType) && !isTypeAny(restType) && (restType.flags & TypeFlags.Never) === 0 ? restType : undefined; } function getTypeOfFirstParameterOfSignature(signature: Signature) { diff --git a/tests/baselines/reference/genericRestTypes.js b/tests/baselines/reference/genericRestTypes.js index 5abf8113f388c..e902a56ea8a14 100644 --- a/tests/baselines/reference/genericRestTypes.js +++ b/tests/baselines/reference/genericRestTypes.js @@ -11,8 +11,23 @@ type Explicit = (...args: Tail>) => ReturnType any> = (...args: Tail>) => ReturnType; type Generic = Bind1; // (bar: string) => boolean + +function assignmentWithComplexRest() { + const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; + const fn2: (...args: never) => void = fn1; +} //// [genericRestTypes.js] "use strict"; // Repro from #25793 +function assignmentWithComplexRest() { + var fn1 = function (x) { + var _ = []; + for (var _i = 1; _i < arguments.length; _i++) { + _[_i - 1] = arguments[_i]; + } + return x; + }; + var fn2 = fn1; +} diff --git a/tests/baselines/reference/genericRestTypes.symbols b/tests/baselines/reference/genericRestTypes.symbols index c8ab347609cb9..b687a2a467fbd 100644 --- a/tests/baselines/reference/genericRestTypes.symbols +++ b/tests/baselines/reference/genericRestTypes.symbols @@ -44,3 +44,22 @@ type Generic = Bind1; // (bar: string) => boolean >Bind1 : Symbol(Bind1, Decl(genericRestTypes.ts, 8, 90)) >MyFunctionType : Symbol(MyFunctionType, Decl(genericRestTypes.ts, 4, 110)) +function assignmentWithComplexRest() { +>assignmentWithComplexRest : Symbol(assignmentWithComplexRest, Decl(genericRestTypes.ts, 11, 37)) +>T : Symbol(T, Decl(genericRestTypes.ts, 13, 35)) + + const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; +>fn1 : Symbol(fn1, Decl(genericRestTypes.ts, 14, 9)) +>x : Symbol(x, Decl(genericRestTypes.ts, 14, 16)) +>rest : Symbol(rest, Decl(genericRestTypes.ts, 14, 26)) +>T : Symbol(T, Decl(genericRestTypes.ts, 13, 35)) +>x : Symbol(x, Decl(genericRestTypes.ts, 14, 50)) +>_ : Symbol(_, Decl(genericRestTypes.ts, 14, 52)) +>x : Symbol(x, Decl(genericRestTypes.ts, 14, 50)) + + const fn2: (...args: never) => void = fn1; +>fn2 : Symbol(fn2, Decl(genericRestTypes.ts, 15, 9)) +>args : Symbol(args, Decl(genericRestTypes.ts, 15, 16)) +>fn1 : Symbol(fn1, Decl(genericRestTypes.ts, 14, 9)) +} + diff --git a/tests/baselines/reference/genericRestTypes.types b/tests/baselines/reference/genericRestTypes.types index b2fb37871bd23..f102330f5a0ae 100644 --- a/tests/baselines/reference/genericRestTypes.types +++ b/tests/baselines/reference/genericRestTypes.types @@ -27,3 +27,21 @@ type Bind1 any> = (...args: Tail; // (bar: string) => boolean >Generic : Bind1 +function assignmentWithComplexRest() { +>assignmentWithComplexRest : () => void + + const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; +>fn1 : (x: string, ...rest: T) => void +>x : string +>rest : T +>(x, ..._) => x : (x: string, ..._: T) => string +>x : string +>_ : T +>x : string + + const fn2: (...args: never) => void = fn1; +>fn2 : (...args: never) => void +>args : never +>fn1 : (x: string, ...rest: T) => void +} + diff --git a/tests/cases/compiler/genericRestTypes.ts b/tests/cases/compiler/genericRestTypes.ts index 78eb9b53f7010..f0e053187537a 100644 --- a/tests/cases/compiler/genericRestTypes.ts +++ b/tests/cases/compiler/genericRestTypes.ts @@ -12,3 +12,8 @@ type Explicit = (...args: Tail>) => ReturnType any> = (...args: Tail>) => ReturnType; type Generic = Bind1; // (bar: string) => boolean + +function assignmentWithComplexRest() { + const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; + const fn2: (...args: never) => void = fn1; +} From a02b63dbc2bb7b09e3dce7b243e8dfadb7e75b6a Mon Sep 17 00:00:00 2001 From: Jack Williams Date: Mon, 2 Dec 2019 20:16:29 +0000 Subject: [PATCH 2/3] Add higher-order test --- .../reference/genericRestTypes.errors.txt | 35 +++++++++++++++++++ tests/baselines/reference/genericRestTypes.js | 9 +++++ .../reference/genericRestTypes.symbols | 19 ++++++++++ .../reference/genericRestTypes.types | 18 ++++++++++ tests/cases/compiler/genericRestTypes.ts | 5 +++ 5 files changed, 86 insertions(+) create mode 100644 tests/baselines/reference/genericRestTypes.errors.txt diff --git a/tests/baselines/reference/genericRestTypes.errors.txt b/tests/baselines/reference/genericRestTypes.errors.txt new file mode 100644 index 0000000000000..f44b77525dfce --- /dev/null +++ b/tests/baselines/reference/genericRestTypes.errors.txt @@ -0,0 +1,35 @@ +tests/cases/compiler/genericRestTypes.ts(21,11): error TS2322: Type '(cb: (x: string, ...rest: T) => void) => void' is not assignable to type '(cb: (...args: never) => void) => void'. + Types of parameters 'cb' and 'cb' are incompatible. + Types of parameters 'args' and 'x' are incompatible. + Type '[string, ...T[number][]]' is not assignable to type 'never'. + + +==== tests/cases/compiler/genericRestTypes.ts (1 errors) ==== + // Repro from #25793 + + // Gets the parameters of a function type as a tuple + // Removes the first element from a tuple + type Tail = ((...args: T) => any) extends ((head: any, ...tail: infer U) => any) ? U : never; + + type MyFunctionType = (foo: number, bar: string) => boolean; + + type Explicit = (...args: Tail>) => ReturnType; // (bar: string) => boolean + + type Bind1 any> = (...args: Tail>) => ReturnType; + type Generic = Bind1; // (bar: string) => boolean + + function assignmentWithComplexRest() { + const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; + const fn2: (...args: never) => void = fn1; + } + + function assignmentWithComplexRest2() { + const fn1: (cb: (x: string, ...rest: T) => void) => void = (cb) => {}; + const fn2: (cb: (...args: never) => void) => void = fn1; + ~~~ +!!! error TS2322: Type '(cb: (x: string, ...rest: T) => void) => void' is not assignable to type '(cb: (...args: never) => void) => void'. +!!! error TS2322: Types of parameters 'cb' and 'cb' are incompatible. +!!! error TS2322: Types of parameters 'args' and 'x' are incompatible. +!!! error TS2322: Type '[string, ...T[number][]]' is not assignable to type 'never'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/genericRestTypes.js b/tests/baselines/reference/genericRestTypes.js index e902a56ea8a14..6f4ffcac989b4 100644 --- a/tests/baselines/reference/genericRestTypes.js +++ b/tests/baselines/reference/genericRestTypes.js @@ -16,6 +16,11 @@ function assignmentWithComplexRest() { const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; const fn2: (...args: never) => void = fn1; } + +function assignmentWithComplexRest2() { + const fn1: (cb: (x: string, ...rest: T) => void) => void = (cb) => {}; + const fn2: (cb: (...args: never) => void) => void = fn1; +} //// [genericRestTypes.js] @@ -31,3 +36,7 @@ function assignmentWithComplexRest() { }; var fn2 = fn1; } +function assignmentWithComplexRest2() { + var fn1 = function (cb) { }; + var fn2 = fn1; +} diff --git a/tests/baselines/reference/genericRestTypes.symbols b/tests/baselines/reference/genericRestTypes.symbols index b687a2a467fbd..c30f2317c8ccf 100644 --- a/tests/baselines/reference/genericRestTypes.symbols +++ b/tests/baselines/reference/genericRestTypes.symbols @@ -63,3 +63,22 @@ function assignmentWithComplexRest() { >fn1 : Symbol(fn1, Decl(genericRestTypes.ts, 14, 9)) } +function assignmentWithComplexRest2() { +>assignmentWithComplexRest2 : Symbol(assignmentWithComplexRest2, Decl(genericRestTypes.ts, 16, 1)) +>T : Symbol(T, Decl(genericRestTypes.ts, 18, 36)) + + const fn1: (cb: (x: string, ...rest: T) => void) => void = (cb) => {}; +>fn1 : Symbol(fn1, Decl(genericRestTypes.ts, 19, 9)) +>cb : Symbol(cb, Decl(genericRestTypes.ts, 19, 16)) +>x : Symbol(x, Decl(genericRestTypes.ts, 19, 21)) +>rest : Symbol(rest, Decl(genericRestTypes.ts, 19, 31)) +>T : Symbol(T, Decl(genericRestTypes.ts, 18, 36)) +>cb : Symbol(cb, Decl(genericRestTypes.ts, 19, 64)) + + const fn2: (cb: (...args: never) => void) => void = fn1; +>fn2 : Symbol(fn2, Decl(genericRestTypes.ts, 20, 9)) +>cb : Symbol(cb, Decl(genericRestTypes.ts, 20, 16)) +>args : Symbol(args, Decl(genericRestTypes.ts, 20, 21)) +>fn1 : Symbol(fn1, Decl(genericRestTypes.ts, 19, 9)) +} + diff --git a/tests/baselines/reference/genericRestTypes.types b/tests/baselines/reference/genericRestTypes.types index f102330f5a0ae..04b6499cffef6 100644 --- a/tests/baselines/reference/genericRestTypes.types +++ b/tests/baselines/reference/genericRestTypes.types @@ -45,3 +45,21 @@ function assignmentWithComplexRest() { >fn1 : (x: string, ...rest: T) => void } +function assignmentWithComplexRest2() { +>assignmentWithComplexRest2 : () => void + + const fn1: (cb: (x: string, ...rest: T) => void) => void = (cb) => {}; +>fn1 : (cb: (x: string, ...rest: T) => void) => void +>cb : (x: string, ...rest: T) => void +>x : string +>rest : T +>(cb) => {} : (cb: (x: string, ...rest: T) => void) => void +>cb : (x: string, ...rest: T) => void + + const fn2: (cb: (...args: never) => void) => void = fn1; +>fn2 : (cb: (...args: never) => void) => void +>cb : (...args: never) => void +>args : never +>fn1 : (cb: (x: string, ...rest: T) => void) => void +} + diff --git a/tests/cases/compiler/genericRestTypes.ts b/tests/cases/compiler/genericRestTypes.ts index f0e053187537a..7312394459e7c 100644 --- a/tests/cases/compiler/genericRestTypes.ts +++ b/tests/cases/compiler/genericRestTypes.ts @@ -17,3 +17,8 @@ function assignmentWithComplexRest() { const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; const fn2: (...args: never) => void = fn1; } + +function assignmentWithComplexRest2() { + const fn1: (cb: (x: string, ...rest: T) => void) => void = (cb) => {}; + const fn2: (cb: (...args: never) => void) => void = fn1; +} From 2a1f7eb926902c825ce0b53a5140a1d6ab70a24c Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 30 Mar 2020 13:39:12 -0700 Subject: [PATCH 3/3] properly support types which reduce to never --- src/compiler/checker.ts | 4 ++-- .../reference/genericRestTypes.errors.txt | 6 +++++- tests/baselines/reference/genericRestTypes.js | 16 ++++++++++++++- .../reference/genericRestTypes.symbols | 20 +++++++++++++++++++ .../reference/genericRestTypes.types | 19 ++++++++++++++++++ tests/cases/compiler/genericRestTypes.ts | 5 +++++ 6 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b23c956eb96fd..2a721c69ce93f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -26639,7 +26639,7 @@ namespace ts { function getNonArrayRestType(signature: Signature) { const restType = getEffectiveRestType(signature); - return restType && !isArrayType(restType) && !isTypeAny(restType) && (restType.flags & TypeFlags.Never) === 0 ? restType : undefined; + return restType && !isArrayType(restType) && !isTypeAny(restType) && (getReducedType(restType).flags & TypeFlags.Never) === 0 ? restType : undefined; } function getTypeOfFirstParameterOfSignature(signature: Signature) { @@ -29029,7 +29029,7 @@ namespace ts { // Only check rest parameter type if it's not a binding pattern. Since binding patterns are // not allowed in a rest parameter, we already have an error from checkGrammarParameterList. - if (node.dotDotDotToken && !isBindingPattern(node.name) && !isTypeAssignableTo(getTypeOfSymbol(node.symbol), anyReadonlyArrayType)) { + if (node.dotDotDotToken && !isBindingPattern(node.name) && !isTypeAssignableTo(getReducedType(getTypeOfSymbol(node.symbol)), anyReadonlyArrayType)) { error(node, Diagnostics.A_rest_parameter_must_be_of_an_array_type); } } diff --git a/tests/baselines/reference/genericRestTypes.errors.txt b/tests/baselines/reference/genericRestTypes.errors.txt index f44b77525dfce..c0fcb85e49201 100644 --- a/tests/baselines/reference/genericRestTypes.errors.txt +++ b/tests/baselines/reference/genericRestTypes.errors.txt @@ -32,4 +32,8 @@ tests/cases/compiler/genericRestTypes.ts(21,11): error TS2322: Type '(cb: (x: st !!! error TS2322: Types of parameters 'args' and 'x' are incompatible. !!! error TS2322: Type '[string, ...T[number][]]' is not assignable to type 'never'. } - \ No newline at end of file + + function assignmentWithComplexRest3() { + const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; + const fn2: (...args: {x: "a"} & {x: "b"}) => void = fn1; + } \ No newline at end of file diff --git a/tests/baselines/reference/genericRestTypes.js b/tests/baselines/reference/genericRestTypes.js index 6f4ffcac989b4..286e2aba1b73a 100644 --- a/tests/baselines/reference/genericRestTypes.js +++ b/tests/baselines/reference/genericRestTypes.js @@ -21,7 +21,11 @@ function assignmentWithComplexRest2() { const fn1: (cb: (x: string, ...rest: T) => void) => void = (cb) => {}; const fn2: (cb: (...args: never) => void) => void = fn1; } - + +function assignmentWithComplexRest3() { + const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; + const fn2: (...args: {x: "a"} & {x: "b"}) => void = fn1; +} //// [genericRestTypes.js] "use strict"; @@ -40,3 +44,13 @@ function assignmentWithComplexRest2() { var fn1 = function (cb) { }; var fn2 = fn1; } +function assignmentWithComplexRest3() { + var fn1 = function (x) { + var _ = []; + for (var _i = 1; _i < arguments.length; _i++) { + _[_i - 1] = arguments[_i]; + } + return x; + }; + var fn2 = fn1; +} diff --git a/tests/baselines/reference/genericRestTypes.symbols b/tests/baselines/reference/genericRestTypes.symbols index c30f2317c8ccf..bd2545d9b9c2e 100644 --- a/tests/baselines/reference/genericRestTypes.symbols +++ b/tests/baselines/reference/genericRestTypes.symbols @@ -82,3 +82,23 @@ function assignmentWithComplexRest2() { >fn1 : Symbol(fn1, Decl(genericRestTypes.ts, 19, 9)) } +function assignmentWithComplexRest3() { +>assignmentWithComplexRest3 : Symbol(assignmentWithComplexRest3, Decl(genericRestTypes.ts, 21, 1)) +>T : Symbol(T, Decl(genericRestTypes.ts, 23, 36)) + + const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; +>fn1 : Symbol(fn1, Decl(genericRestTypes.ts, 24, 9)) +>x : Symbol(x, Decl(genericRestTypes.ts, 24, 16)) +>rest : Symbol(rest, Decl(genericRestTypes.ts, 24, 26)) +>T : Symbol(T, Decl(genericRestTypes.ts, 23, 36)) +>x : Symbol(x, Decl(genericRestTypes.ts, 24, 50)) +>_ : Symbol(_, Decl(genericRestTypes.ts, 24, 52)) +>x : Symbol(x, Decl(genericRestTypes.ts, 24, 50)) + + const fn2: (...args: {x: "a"} & {x: "b"}) => void = fn1; +>fn2 : Symbol(fn2, Decl(genericRestTypes.ts, 25, 9)) +>args : Symbol(args, Decl(genericRestTypes.ts, 25, 16)) +>x : Symbol(x, Decl(genericRestTypes.ts, 25, 26)) +>x : Symbol(x, Decl(genericRestTypes.ts, 25, 37)) +>fn1 : Symbol(fn1, Decl(genericRestTypes.ts, 24, 9)) +} diff --git a/tests/baselines/reference/genericRestTypes.types b/tests/baselines/reference/genericRestTypes.types index 04b6499cffef6..78da48e79baf9 100644 --- a/tests/baselines/reference/genericRestTypes.types +++ b/tests/baselines/reference/genericRestTypes.types @@ -63,3 +63,22 @@ function assignmentWithComplexRest2() { >fn1 : (cb: (x: string, ...rest: T) => void) => void } +function assignmentWithComplexRest3() { +>assignmentWithComplexRest3 : () => void + + const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; +>fn1 : (x: string, ...rest: T) => void +>x : string +>rest : T +>(x, ..._) => x : (x: string, ..._: T) => string +>x : string +>_ : T +>x : string + + const fn2: (...args: {x: "a"} & {x: "b"}) => void = fn1; +>fn2 : (...args: never) => void +>args : never +>x : "a" +>x : "b" +>fn1 : (x: string, ...rest: T) => void +} diff --git a/tests/cases/compiler/genericRestTypes.ts b/tests/cases/compiler/genericRestTypes.ts index 7312394459e7c..a8ecedeb070e9 100644 --- a/tests/cases/compiler/genericRestTypes.ts +++ b/tests/cases/compiler/genericRestTypes.ts @@ -22,3 +22,8 @@ function assignmentWithComplexRest2() { const fn1: (cb: (x: string, ...rest: T) => void) => void = (cb) => {}; const fn2: (cb: (...args: never) => void) => void = fn1; } + +function assignmentWithComplexRest3() { + const fn1: (x: string, ...rest: T) => void = (x, ..._) => x; + const fn2: (...args: {x: "a"} & {x: "b"}) => void = fn1; +} \ No newline at end of file