From 29c0024bcfff0044e516462ca7261132acbcb026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Fri, 16 Feb 2024 23:05:33 +0100 Subject: [PATCH] Avoid creating rest elements with `errorType` when `any` is spread (#57116) --- src/compiler/checker.ts | 5 ++- ...mentsSpreadRestIterables(target=es5).types | 14 +++--- ...thBareAnyRestCanBeUsedAsRestParam1.symbols | 38 ++++++++++++++++ ...WithBareAnyRestCanBeUsedAsRestParam1.types | 19 ++++++++ .../mappedTypesGenericTuples2.symbols | 36 +++++++++++++++ .../reference/mappedTypesGenericTuples2.types | 45 +++++++++++++++++++ .../reference/variadicTuples1.errors.txt | 2 + tests/baselines/reference/variadicTuples1.js | 3 ++ .../reference/variadicTuples1.symbols | 3 ++ .../baselines/reference/variadicTuples1.types | 7 ++- ...rayWithBareAnyRestCanBeUsedAsRestParam1.ts | 12 +++++ .../types/mapped/mappedTypesGenericTuples2.ts | 13 ++++++ .../types/tuple/variadicTuples1.ts | 2 + 13 files changed, 189 insertions(+), 10 deletions(-) create mode 100644 tests/baselines/reference/mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.symbols create mode 100644 tests/baselines/reference/mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.types create mode 100644 tests/baselines/reference/mappedTypesGenericTuples2.symbols create mode 100644 tests/baselines/reference/mappedTypesGenericTuples2.types create mode 100644 tests/cases/compiler/mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts create mode 100644 tests/cases/conformance/types/mapped/mappedTypesGenericTuples2.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0d12a7f74fdb4..0e8d2bb486f9f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16883,7 +16883,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const type = elementTypes[i]; const flags = target.elementFlags[i]; if (flags & ElementFlags.Variadic) { - if (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type)) { + if (type.flags & TypeFlags.Any) { + addElement(type, ElementFlags.Rest, target.labeledElementDeclarations?.[i]); + } + else if (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type)) { // Generic variadic elements stay as they are. addElement(type, ElementFlags.Variadic, target.labeledElementDeclarations?.[i]); } diff --git a/tests/baselines/reference/argumentsSpreadRestIterables(target=es5).types b/tests/baselines/reference/argumentsSpreadRestIterables(target=es5).types index 85114134650e5..2e1470c622c3c 100644 --- a/tests/baselines/reference/argumentsSpreadRestIterables(target=es5).types +++ b/tests/baselines/reference/argumentsSpreadRestIterables(target=es5).types @@ -24,10 +24,10 @@ declare const itNum: Iterable ;(function(a, ...rest) {})('', true, ...itNum) >(function(a, ...rest) {})('', true, ...itNum) : void ->(function(a, ...rest) {}) : (a: string, rest_0: boolean, ...rest_1: any[]) => void ->function(a, ...rest) {} : (a: string, rest_0: boolean, ...rest_1: any[]) => void +>(function(a, ...rest) {}) : (a: string, rest_0: boolean, ...rest_1: Iterable[]) => void +>function(a, ...rest) {} : (a: string, rest_0: boolean, ...rest_1: Iterable[]) => void >a : string ->rest : [boolean, ...any[]] +>rest : [boolean, ...Iterable[]] >'' : "" >true : true >...itNum : Iterable @@ -60,8 +60,8 @@ const res3 = fn1(true, ..."hello"); >"hello" : "hello" const res4 = fn1(true, ...itNum); ->res4 : readonly [true, ...any[]] ->fn1(true, ...itNum) : readonly [true, ...any[]] +>res4 : readonly [true, ...Iterable[]] +>fn1(true, ...itNum) : readonly [true, ...Iterable[]] >fn1 : (...args: T) => T >true : true >...itNum : Iterable @@ -95,8 +95,8 @@ const p3 = foo(true, ..."hello"); >"hello" : "hello" const p4 = foo(true, ...itNum); ->p4 : [boolean, ...any[]] ->foo(true, ...itNum) : [boolean, ...any[]] +>p4 : [boolean, ...Iterable[]] +>foo(true, ...itNum) : [boolean, ...Iterable[]] >foo : (...args: T) => T >true : true >...itNum : Iterable diff --git a/tests/baselines/reference/mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.symbols b/tests/baselines/reference/mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.symbols new file mode 100644 index 0000000000000..1a2dbdc34fe86 --- /dev/null +++ b/tests/baselines/reference/mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.symbols @@ -0,0 +1,38 @@ +//// [tests/cases/compiler/mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts] //// + +=== mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts === +// https://github.com/microsoft/TypeScript/issues/55932 + +type Replace = { +>Replace : Symbol(Replace, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 0, 0)) +>T : Symbol(T, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 13)) +>A : Symbol(A, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 32)) +>B : Symbol(B, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 35)) + + [K in keyof T]: T[K] extends A ? B : T[K]; +>K : Symbol(K, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 3, 3)) +>T : Symbol(T, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 13)) +>T : Symbol(T, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 13)) +>K : Symbol(K, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 3, 3)) +>A : Symbol(A, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 32)) +>B : Symbol(B, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 35)) +>T : Symbol(T, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 2, 13)) +>K : Symbol(K, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 3, 3)) + +}; + +type ReplaceParams1 = ( +>ReplaceParams1 : Symbol(ReplaceParams1, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 4, 2)) +>ARRAY : Symbol(ARRAY, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 20)) +>A : Symbol(A, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 43)) +>B : Symbol(B, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 46)) + + ...args: Replace +>args : Symbol(args, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 53)) +>Replace : Symbol(Replace, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 0, 0)) +>ARRAY : Symbol(ARRAY, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 20)) +>A : Symbol(A, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 43)) +>B : Symbol(B, Decl(mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts, 6, 46)) + +) => any; + diff --git a/tests/baselines/reference/mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.types b/tests/baselines/reference/mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.types new file mode 100644 index 0000000000000..097055ad0ab83 --- /dev/null +++ b/tests/baselines/reference/mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.types @@ -0,0 +1,19 @@ +//// [tests/cases/compiler/mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts] //// + +=== mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts === +// https://github.com/microsoft/TypeScript/issues/55932 + +type Replace = { +>Replace : Replace + + [K in keyof T]: T[K] extends A ? B : T[K]; +}; + +type ReplaceParams1 = ( +>ReplaceParams1 : ReplaceParams1 + + ...args: Replace +>args : Replace + +) => any; + diff --git a/tests/baselines/reference/mappedTypesGenericTuples2.symbols b/tests/baselines/reference/mappedTypesGenericTuples2.symbols new file mode 100644 index 0000000000000..d6ee19d65d3f6 --- /dev/null +++ b/tests/baselines/reference/mappedTypesGenericTuples2.symbols @@ -0,0 +1,36 @@ +//// [tests/cases/conformance/types/mapped/mappedTypesGenericTuples2.ts] //// + +=== mappedTypesGenericTuples2.ts === +// https://github.com/microsoft/TypeScript/issues/57389 + +declare function getT(): T; +>getT : Symbol(getT, Decl(mappedTypesGenericTuples2.ts, 0, 0)) +>T : Symbol(T, Decl(mappedTypesGenericTuples2.ts, 2, 22)) +>T : Symbol(T, Decl(mappedTypesGenericTuples2.ts, 2, 22)) + +Promise.all([getT(), ...getT()]).then((result) => { +>Promise.all([getT(), ...getT()]).then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --)) +>Promise.all : Symbol(PromiseConstructor.all, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --)) +>all : Symbol(PromiseConstructor.all, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>getT : Symbol(getT, Decl(mappedTypesGenericTuples2.ts, 0, 0)) +>getT : Symbol(getT, Decl(mappedTypesGenericTuples2.ts, 0, 0)) +>then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --)) +>result : Symbol(result, Decl(mappedTypesGenericTuples2.ts, 4, 52)) + + const head = result[0]; // string +>head : Symbol(head, Decl(mappedTypesGenericTuples2.ts, 5, 7)) +>result : Symbol(result, Decl(mappedTypesGenericTuples2.ts, 4, 52)) +>0 : Symbol(0) + + const tail = result.slice(1); // any[] +>tail : Symbol(tail, Decl(mappedTypesGenericTuples2.ts, 6, 7)) +>result.slice : Symbol(Array.slice, Decl(lib.es5.d.ts, --, --)) +>result : Symbol(result, Decl(mappedTypesGenericTuples2.ts, 4, 52)) +>slice : Symbol(Array.slice, Decl(lib.es5.d.ts, --, --)) + + tail satisfies string[]; // ok +>tail : Symbol(tail, Decl(mappedTypesGenericTuples2.ts, 6, 7)) + +}); + diff --git a/tests/baselines/reference/mappedTypesGenericTuples2.types b/tests/baselines/reference/mappedTypesGenericTuples2.types new file mode 100644 index 0000000000000..140a7b45bf39c --- /dev/null +++ b/tests/baselines/reference/mappedTypesGenericTuples2.types @@ -0,0 +1,45 @@ +//// [tests/cases/conformance/types/mapped/mappedTypesGenericTuples2.ts] //// + +=== mappedTypesGenericTuples2.ts === +// https://github.com/microsoft/TypeScript/issues/57389 + +declare function getT(): T; +>getT : () => T + +Promise.all([getT(), ...getT()]).then((result) => { +>Promise.all([getT(), ...getT()]).then((result) => { const head = result[0]; // string const tail = result.slice(1); // any[] tail satisfies string[]; // ok}) : Promise +>Promise.all([getT(), ...getT()]).then : (onfulfilled?: ((value: [string, ...any[]]) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined) => Promise +>Promise.all([getT(), ...getT()]) : Promise<[string, ...any[]]> +>Promise.all : { (values: Iterable>): Promise[]>; (values: T_1): Promise<{ -readonly [P in keyof T_1]: Awaited; }>; } +>Promise : PromiseConstructor +>all : { (values: Iterable>): Promise[]>; (values: T_1): Promise<{ -readonly [P in keyof T_1]: Awaited; }>; } +>[getT(), ...getT()] : [string, ...any[]] +>getT() : string +>getT : () => T +>...getT() : any +>getT() : any +>getT : () => T +>then : (onfulfilled?: ((value: [string, ...any[]]) => TResult1 | PromiseLike) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike) | null | undefined) => Promise +>(result) => { const head = result[0]; // string const tail = result.slice(1); // any[] tail satisfies string[]; // ok} : (result: [string, ...any[]]) => void +>result : [string, ...any[]] + + const head = result[0]; // string +>head : string +>result[0] : string +>result : [string, ...any[]] +>0 : 0 + + const tail = result.slice(1); // any[] +>tail : any[] +>result.slice(1) : any[] +>result.slice : (start?: number | undefined, end?: number | undefined) => any[] +>result : [string, ...any[]] +>slice : (start?: number | undefined, end?: number | undefined) => any[] +>1 : 1 + + tail satisfies string[]; // ok +>tail satisfies string[] : any[] +>tail : any[] + +}); + diff --git a/tests/baselines/reference/variadicTuples1.errors.txt b/tests/baselines/reference/variadicTuples1.errors.txt index a272e389314f6..fbc7d599c6ff0 100644 --- a/tests/baselines/reference/variadicTuples1.errors.txt +++ b/tests/baselines/reference/variadicTuples1.errors.txt @@ -540,4 +540,6 @@ variadicTuples1.ts(411,7): error TS2322: Type '[boolean, false]' is not assignab type ToStringLength1 = `${T['length']}`; type ToStringLength2 = `${[...T]['length']}`; + + type AnyArr = [...any]; \ No newline at end of file diff --git a/tests/baselines/reference/variadicTuples1.js b/tests/baselines/reference/variadicTuples1.js index 2c966b7dda2a8..ddc781c45d674 100644 --- a/tests/baselines/reference/variadicTuples1.js +++ b/tests/baselines/reference/variadicTuples1.js @@ -421,6 +421,8 @@ type U3 = [...[string, number], boolean]; type ToStringLength1 = `${T['length']}`; type ToStringLength2 = `${[...T]['length']}`; + +type AnyArr = [...any]; //// [variadicTuples1.js] @@ -830,3 +832,4 @@ type U2 = [...[string, ...Numbers], boolean]; type U3 = [...[string, number], boolean]; type ToStringLength1 = `${T['length']}`; type ToStringLength2 = `${[...T]['length']}`; +type AnyArr = [...any]; diff --git a/tests/baselines/reference/variadicTuples1.symbols b/tests/baselines/reference/variadicTuples1.symbols index 2d24c7cffd047..3249c6e53bd44 100644 --- a/tests/baselines/reference/variadicTuples1.symbols +++ b/tests/baselines/reference/variadicTuples1.symbols @@ -1416,3 +1416,6 @@ type ToStringLength2 = `${[...T]['length']}`; >T : Symbol(T, Decl(variadicTuples1.ts, 419, 21)) >T : Symbol(T, Decl(variadicTuples1.ts, 419, 21)) +type AnyArr = [...any]; +>AnyArr : Symbol(AnyArr, Decl(variadicTuples1.ts, 419, 62)) + diff --git a/tests/baselines/reference/variadicTuples1.types b/tests/baselines/reference/variadicTuples1.types index fac1b78db51fc..6df4ef7b1761c 100644 --- a/tests/baselines/reference/variadicTuples1.types +++ b/tests/baselines/reference/variadicTuples1.types @@ -883,7 +883,7 @@ type T17 = DropFirst<[]>; >T17 : unknown[] type T18 = DropFirst; ->T18 : unknown[] | any[] +>T18 : any[] | unknown[] type T19 = DropFirst; >T19 : never @@ -943,7 +943,7 @@ type T37 = DropLast<[]>; // unknown[], maybe should be [] >T37 : [] type T38 = DropLast; ->T38 : unknown[] | any[] +>T38 : any[] | unknown[] type T39 = DropLast; >T39 : never @@ -1455,3 +1455,6 @@ type ToStringLength1 = `${T['length']}`; type ToStringLength2 = `${[...T]['length']}`; >ToStringLength2 : `${[...T]["length"]}` +type AnyArr = [...any]; +>AnyArr : any[] + diff --git a/tests/cases/compiler/mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts b/tests/cases/compiler/mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts new file mode 100644 index 0000000000000..0118bc7c2f770 --- /dev/null +++ b/tests/cases/compiler/mappedTypeOverArrayWithBareAnyRestCanBeUsedAsRestParam1.ts @@ -0,0 +1,12 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/55932 + +type Replace = { + [K in keyof T]: T[K] extends A ? B : T[K]; +}; + +type ReplaceParams1 = ( + ...args: Replace +) => any; diff --git a/tests/cases/conformance/types/mapped/mappedTypesGenericTuples2.ts b/tests/cases/conformance/types/mapped/mappedTypesGenericTuples2.ts new file mode 100644 index 0000000000000..6d411634bc4b6 --- /dev/null +++ b/tests/cases/conformance/types/mapped/mappedTypesGenericTuples2.ts @@ -0,0 +1,13 @@ +// @strict: true +// @lib: esnext +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/57389 + +declare function getT(): T; + +Promise.all([getT(), ...getT()]).then((result) => { + const head = result[0]; // string + const tail = result.slice(1); // any[] + tail satisfies string[]; // ok +}); diff --git a/tests/cases/conformance/types/tuple/variadicTuples1.ts b/tests/cases/conformance/types/tuple/variadicTuples1.ts index 573b95b1da98a..51346c85f0db4 100644 --- a/tests/cases/conformance/types/tuple/variadicTuples1.ts +++ b/tests/cases/conformance/types/tuple/variadicTuples1.ts @@ -421,3 +421,5 @@ type U3 = [...[string, number], boolean]; type ToStringLength1 = `${T['length']}`; type ToStringLength2 = `${[...T]['length']}`; + +type AnyArr = [...any];