From 18193973fec66716b1489d3edeeb4a3c837bd39f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 23 May 2022 17:22:17 +0200 Subject: [PATCH 01/13] Fixed an issue with shorter param list not being assignable to rest param with tuple union --- src/compiler/checker.ts | 5 ++- .../genericRestParameters3.errors.txt | 12 +++---- ...tTupleUnionShorterContextualParams.symbols | 31 +++++++++++++++++ ...estTupleUnionShorterContextualParams.types | 34 +++++++++++++++++++ .../restTupleUnionShorterContextualParams.ts | 12 +++++++ 5 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 tests/baselines/reference/restTupleUnionShorterContextualParams.symbols create mode 100644 tests/baselines/reference/restTupleUnionShorterContextualParams.types create mode 100644 tests/cases/compiler/restTupleUnionShorterContextualParams.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ec43221b1f7a4..bc9529aa30995 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17967,7 +17967,10 @@ namespace ts { for (let i = 0; i < paramCount; i++) { const sourceType = i === restIndex ? getRestTypeAtPosition(source, i) : tryGetTypeAtPosition(source, i); - const targetType = i === restIndex ? getRestTypeAtPosition(target, i) : tryGetTypeAtPosition(target, i); + let targetType = i === restIndex ? getRestTypeAtPosition(target, i) : tryGetTypeAtPosition(target, i); + if (i === restIndex && targetType && sourceType && isTupleType(sourceType) && !sourceType.target.hasRestElement) { + targetType = mapType(targetType, t => isTupleType(t) && !t.target.hasRestElement ? sliceTupleType(t, 0, t.target.fixedLength - sourceType.target.fixedLength) : t); + } if (sourceType && targetType) { // In order to ensure that any generic type Foo is at least co-variant with respect to T no matter // how Foo uses T, we need to relate parameters bi-variantly (given that parameters are input positions, diff --git a/tests/baselines/reference/genericRestParameters3.errors.txt b/tests/baselines/reference/genericRestParameters3.errors.txt index d306bbf3a6748..d2a8772fd0a7d 100644 --- a/tests/baselines/reference/genericRestParameters3.errors.txt +++ b/tests/baselines/reference/genericRestParameters3.errors.txt @@ -6,9 +6,9 @@ tests/cases/conformance/types/rest/genericRestParameters3.ts(18,1): error TS2345 Source has 0 element(s) but target requires 2. tests/cases/conformance/types/rest/genericRestParameters3.ts(23,1): error TS2322: Type '(x: string, y: string) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'. Types of parameters 'y' and 'args' are incompatible. - Type '[string] | [number, boolean]' is not assignable to type '[y: string]'. - Type '[number, boolean]' is not assignable to type '[y: string]'. - Source has 2 element(s) but target allows only 1. + Type '[string] | [number]' is not assignable to type '[y: string]'. + Type '[number]' is not assignable to type '[y: string]'. + Type 'number' is not assignable to type 'string'. tests/cases/conformance/types/rest/genericRestParameters3.ts(24,1): error TS2322: Type '(x: string, y: number, z: boolean) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'. Types of parameters 'y' and 'args' are incompatible. Type '[string] | [number, boolean]' is not assignable to type '[y: number, z: boolean]'. @@ -69,9 +69,9 @@ tests/cases/conformance/types/rest/genericRestParameters3.ts(59,5): error TS2345 ~~ !!! error TS2322: Type '(x: string, y: string) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'. !!! error TS2322: Types of parameters 'y' and 'args' are incompatible. -!!! error TS2322: Type '[string] | [number, boolean]' is not assignable to type '[y: string]'. -!!! error TS2322: Type '[number, boolean]' is not assignable to type '[y: string]'. -!!! error TS2322: Source has 2 element(s) but target allows only 1. +!!! error TS2322: Type '[string] | [number]' is not assignable to type '[y: string]'. +!!! error TS2322: Type '[number]' is not assignable to type '[y: string]'. +!!! error TS2322: Type 'number' is not assignable to type 'string'. f1 = f3; // Error ~~ !!! error TS2322: Type '(x: string, y: number, z: boolean) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'. diff --git a/tests/baselines/reference/restTupleUnionShorterContextualParams.symbols b/tests/baselines/reference/restTupleUnionShorterContextualParams.symbols new file mode 100644 index 0000000000000..ff31b639f15b3 --- /dev/null +++ b/tests/baselines/reference/restTupleUnionShorterContextualParams.symbols @@ -0,0 +1,31 @@ +=== tests/cases/compiler/restTupleUnionShorterContextualParams.ts === +// repro #48663 + +// showcase how those transitive assignments are OK +const f1: (x: string | number) => void = x => {}; +>f1 : Symbol(f1, Decl(restTupleUnionShorterContextualParams.ts, 3, 5)) +>x : Symbol(x, Decl(restTupleUnionShorterContextualParams.ts, 3, 11)) +>x : Symbol(x, Decl(restTupleUnionShorterContextualParams.ts, 3, 40)) + +const f2: (x: string | number, y: string | number) => void = f1; +>f2 : Symbol(f2, Decl(restTupleUnionShorterContextualParams.ts, 4, 5)) +>x : Symbol(x, Decl(restTupleUnionShorterContextualParams.ts, 4, 11)) +>y : Symbol(y, Decl(restTupleUnionShorterContextualParams.ts, 4, 30)) +>f1 : Symbol(f1, Decl(restTupleUnionShorterContextualParams.ts, 3, 5)) + +const f3: (...args: [number, string] | [string, number]) => void = f2; +>f3 : Symbol(f3, Decl(restTupleUnionShorterContextualParams.ts, 5, 5)) +>args : Symbol(args, Decl(restTupleUnionShorterContextualParams.ts, 5, 11)) +>f2 : Symbol(f2, Decl(restTupleUnionShorterContextualParams.ts, 4, 5)) + +// by extension those should be OK too +const f4: (...args: [number, string] | [string, number]) => void = (item) => {} +>f4 : Symbol(f4, Decl(restTupleUnionShorterContextualParams.ts, 8, 5)) +>args : Symbol(args, Decl(restTupleUnionShorterContextualParams.ts, 8, 11)) +>item : Symbol(item, Decl(restTupleUnionShorterContextualParams.ts, 8, 68)) + +const f5: (...args: [number, string] | [string, number]) => void = (item: number | string) => {} +>f5 : Symbol(f5, Decl(restTupleUnionShorterContextualParams.ts, 9, 5)) +>args : Symbol(args, Decl(restTupleUnionShorterContextualParams.ts, 9, 11)) +>item : Symbol(item, Decl(restTupleUnionShorterContextualParams.ts, 9, 68)) + diff --git a/tests/baselines/reference/restTupleUnionShorterContextualParams.types b/tests/baselines/reference/restTupleUnionShorterContextualParams.types new file mode 100644 index 0000000000000..3bc38acd97779 --- /dev/null +++ b/tests/baselines/reference/restTupleUnionShorterContextualParams.types @@ -0,0 +1,34 @@ +=== tests/cases/compiler/restTupleUnionShorterContextualParams.ts === +// repro #48663 + +// showcase how those transitive assignments are OK +const f1: (x: string | number) => void = x => {}; +>f1 : (x: string | number) => void +>x : string | number +>x => {} : (x: string | number) => void +>x : string | number + +const f2: (x: string | number, y: string | number) => void = f1; +>f2 : (x: string | number, y: string | number) => void +>x : string | number +>y : string | number +>f1 : (x: string | number) => void + +const f3: (...args: [number, string] | [string, number]) => void = f2; +>f3 : (...args: [number, string] | [string, number]) => void +>args : [number, string] | [string, number] +>f2 : (x: string | number, y: string | number) => void + +// by extension those should be OK too +const f4: (...args: [number, string] | [string, number]) => void = (item) => {} +>f4 : (...args: [number, string] | [string, number]) => void +>args : [number, string] | [string, number] +>(item) => {} : (item: string | number) => void +>item : string | number + +const f5: (...args: [number, string] | [string, number]) => void = (item: number | string) => {} +>f5 : (...args: [number, string] | [string, number]) => void +>args : [number, string] | [string, number] +>(item: number | string) => {} : (item: number | string) => void +>item : string | number + diff --git a/tests/cases/compiler/restTupleUnionShorterContextualParams.ts b/tests/cases/compiler/restTupleUnionShorterContextualParams.ts new file mode 100644 index 0000000000000..c933a44338478 --- /dev/null +++ b/tests/cases/compiler/restTupleUnionShorterContextualParams.ts @@ -0,0 +1,12 @@ +// @noEmit: true + +// repro #48663 + +// showcase how those transitive assignments are OK +const f1: (x: string | number) => void = x => {}; +const f2: (x: string | number, y: string | number) => void = f1; +const f3: (...args: [number, string] | [string, number]) => void = f2; + +// by extension those should be OK too +const f4: (...args: [number, string] | [string, number]) => void = (item) => {} +const f5: (...args: [number, string] | [string, number]) => void = (item: number | string) => {} From 88027d561f4a456c118dc9d846a6e65d4b067d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 28 Dec 2022 17:04:53 +0100 Subject: [PATCH 02/13] Fixed the contextual params assignability with target params declared using union of tuples as its rest --- src/compiler/checker.ts | 19 ++++++++++++++++++- ...TupleUnionWithRestContextualParams.symbols | 8 ++++++++ ...stTupleUnionWithRestContextualParams.types | 9 +++++++++ .../restTupleUnionShorterContextualParams.ts | 1 + .../restTupleUnionWithRestContextualParams.ts | 4 ++++ 5 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols create mode 100644 tests/baselines/reference/restTupleUnionWithRestContextualParams.types create mode 100644 tests/cases/compiler/restTupleUnionWithRestContextualParams.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f0b025a821720..8feaec924350f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -19383,7 +19383,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const sourceType = i === restIndex ? getRestTypeAtPosition(source, i) : tryGetTypeAtPosition(source, i); let targetType = i === restIndex ? getRestTypeAtPosition(target, i) : tryGetTypeAtPosition(target, i); if (i === restIndex && targetType && sourceType && isTupleType(sourceType) && !sourceType.target.hasRestElement) { - targetType = mapType(targetType, t => isTupleType(t) && !t.target.hasRestElement ? sliceTupleType(t, 0, t.target.fixedLength - sourceType.target.fixedLength) : t); + targetType = mapType(targetType, t => { + if (!isTupleType(t)) { + return t; + } + + const typeArguments = getTypeArguments(t); + const elementTypes: Type[] = []; + + for (let i = 0; i < getTypeReferenceArity(sourceType); i++) { + elementTypes.push( + t.target.elementFlags[i] & ElementFlags.Required + ? typeArguments[i] + : getElementTypeOfSliceOfTupleType(t, i)! + ); + } + + return createTupleType(elementTypes, elementTypes.map(() => ElementFlags.Required)); + }); } if (sourceType && targetType) { // In order to ensure that any generic type Foo is at least co-variant with respect to T no matter diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols b/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols new file mode 100644 index 0000000000000..d59a8755875fd --- /dev/null +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols @@ -0,0 +1,8 @@ +=== tests/cases/compiler/restTupleUnionWithRestContextualParams.ts === +const f1: (...args: [number, string, ...boolean[]] | [string, number, ...boolean[]]) => void = (a, b, c) => {}; +>f1 : Symbol(f1, Decl(restTupleUnionWithRestContextualParams.ts, 0, 5)) +>args : Symbol(args, Decl(restTupleUnionWithRestContextualParams.ts, 0, 11)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 0, 96)) +>b : Symbol(b, Decl(restTupleUnionWithRestContextualParams.ts, 0, 98)) +>c : Symbol(c, Decl(restTupleUnionWithRestContextualParams.ts, 0, 101)) + diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.types b/tests/baselines/reference/restTupleUnionWithRestContextualParams.types new file mode 100644 index 0000000000000..2237dc1c67fd4 --- /dev/null +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.types @@ -0,0 +1,9 @@ +=== tests/cases/compiler/restTupleUnionWithRestContextualParams.ts === +const f1: (...args: [number, string, ...boolean[]] | [string, number, ...boolean[]]) => void = (a, b, c) => {}; +>f1 : (...args: [number, string, ...boolean[]] | [string, number, ...boolean[]]) => void +>args : [number, string, ...boolean[]] | [string, number, ...boolean[]] +>(a, b, c) => {} : (a: string | number, b: string | number, c: boolean) => void +>a : string | number +>b : string | number +>c : boolean + diff --git a/tests/cases/compiler/restTupleUnionShorterContextualParams.ts b/tests/cases/compiler/restTupleUnionShorterContextualParams.ts index c933a44338478..5b1ac908e79a9 100644 --- a/tests/cases/compiler/restTupleUnionShorterContextualParams.ts +++ b/tests/cases/compiler/restTupleUnionShorterContextualParams.ts @@ -1,3 +1,4 @@ +// @strict: true // @noEmit: true // repro #48663 diff --git a/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts b/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts new file mode 100644 index 0000000000000..e1c5e98e5032a --- /dev/null +++ b/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts @@ -0,0 +1,4 @@ +// @strict: true +// @noEmit: true + +const f1: (...args: [number, string, ...boolean[]] | [string, number, ...boolean[]]) => void = (a, b, c) => {}; From 6c5383d701417e8a98398b4171af0f201ee593c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 28 Dec 2022 19:32:36 +0100 Subject: [PATCH 03/13] Fill the shorter target tuple with undefined when comparing signatures --- src/compiler/checker.ts | 8 +++++--- .../reference/genericRestParameters3.errors.txt | 14 ++++++++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8feaec924350f..2240466e70f1f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -19393,9 +19393,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (let i = 0; i < getTypeReferenceArity(sourceType); i++) { elementTypes.push( - t.target.elementFlags[i] & ElementFlags.Required - ? typeArguments[i] - : getElementTypeOfSliceOfTupleType(t, i)! + i < typeArguments.length + ? t.target.elementFlags[i] & ElementFlags.Required + ? typeArguments[i] + : getElementTypeOfSliceOfTupleType(t, i)! + : undefinedType ); } diff --git a/tests/baselines/reference/genericRestParameters3.errors.txt b/tests/baselines/reference/genericRestParameters3.errors.txt index d2a8772fd0a7d..67ab2bf6d176f 100644 --- a/tests/baselines/reference/genericRestParameters3.errors.txt +++ b/tests/baselines/reference/genericRestParameters3.errors.txt @@ -11,9 +11,10 @@ tests/cases/conformance/types/rest/genericRestParameters3.ts(23,1): error TS2322 Type 'number' is not assignable to type 'string'. tests/cases/conformance/types/rest/genericRestParameters3.ts(24,1): error TS2322: Type '(x: string, y: number, z: boolean) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'. Types of parameters 'y' and 'args' are incompatible. - Type '[string] | [number, boolean]' is not assignable to type '[y: number, z: boolean]'. - Type '[string]' is not assignable to type '[y: number, z: boolean]'. - Source has 1 element(s) but target requires 2. + Type '[number, boolean] | [string, undefined]' is not assignable to type '[y: number, z: boolean]'. + Type '[string, undefined]' is not assignable to type '[y: number, z: boolean]'. + Type at position 0 in source is not compatible with type at position 0 in target. + Type 'string' is not assignable to type 'number'. tests/cases/conformance/types/rest/genericRestParameters3.ts(35,1): error TS2554: Expected 1 arguments, but got 0. tests/cases/conformance/types/rest/genericRestParameters3.ts(36,21): error TS2345: Argument of type 'number' is not assignable to parameter of type '(...args: CoolArray) => void'. tests/cases/conformance/types/rest/genericRestParameters3.ts(37,21): error TS2345: Argument of type '(cb: (...args: T) => void) => void' is not assignable to parameter of type '(...args: CoolArray) => void'. @@ -76,9 +77,10 @@ tests/cases/conformance/types/rest/genericRestParameters3.ts(59,5): error TS2345 ~~ !!! error TS2322: Type '(x: string, y: number, z: boolean) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'. !!! error TS2322: Types of parameters 'y' and 'args' are incompatible. -!!! error TS2322: Type '[string] | [number, boolean]' is not assignable to type '[y: number, z: boolean]'. -!!! error TS2322: Type '[string]' is not assignable to type '[y: number, z: boolean]'. -!!! error TS2322: Source has 1 element(s) but target requires 2. +!!! error TS2322: Type '[number, boolean] | [string, undefined]' is not assignable to type '[y: number, z: boolean]'. +!!! error TS2322: Type '[string, undefined]' is not assignable to type '[y: number, z: boolean]'. +!!! error TS2322: Type at position 0 in source is not compatible with type at position 0 in target. +!!! error TS2322: Type 'string' is not assignable to type 'number'. f1 = f4; // Repro from #26110 From 46f2e57d76f26b74f596f2acb5d04a30572f13a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 28 Dec 2022 20:00:45 +0100 Subject: [PATCH 04/13] Add an additional test case for mixed length tuples in the target's rest --- .../restTupleUnionWithRestContextualParams.symbols | 8 ++++++++ .../restTupleUnionWithRestContextualParams.types | 9 +++++++++ .../compiler/restTupleUnionWithRestContextualParams.ts | 2 ++ 3 files changed, 19 insertions(+) diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols b/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols index d59a8755875fd..ba02848adb5a5 100644 --- a/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols @@ -6,3 +6,11 @@ const f1: (...args: [number, string, ...boolean[]] | [string, number, ...boolean >b : Symbol(b, Decl(restTupleUnionWithRestContextualParams.ts, 0, 98)) >c : Symbol(c, Decl(restTupleUnionWithRestContextualParams.ts, 0, 101)) +const f2: (x: string, ...args: [string] | [number, boolean]) => void = (a, b, c) => {}; +>f2 : Symbol(f2, Decl(restTupleUnionWithRestContextualParams.ts, 2, 5)) +>x : Symbol(x, Decl(restTupleUnionWithRestContextualParams.ts, 2, 11)) +>args : Symbol(args, Decl(restTupleUnionWithRestContextualParams.ts, 2, 21)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 2, 72)) +>b : Symbol(b, Decl(restTupleUnionWithRestContextualParams.ts, 2, 74)) +>c : Symbol(c, Decl(restTupleUnionWithRestContextualParams.ts, 2, 77)) + diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.types b/tests/baselines/reference/restTupleUnionWithRestContextualParams.types index 2237dc1c67fd4..937595e4f0a01 100644 --- a/tests/baselines/reference/restTupleUnionWithRestContextualParams.types +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.types @@ -7,3 +7,12 @@ const f1: (...args: [number, string, ...boolean[]] | [string, number, ...boolean >b : string | number >c : boolean +const f2: (x: string, ...args: [string] | [number, boolean]) => void = (a, b, c) => {}; +>f2 : (x: string, ...args: [string] | [number, boolean]) => void +>x : string +>args : [string] | [number, boolean] +>(a, b, c) => {} : (a: string, b: string | number, c: boolean | undefined) => void +>a : string +>b : string | number +>c : boolean | undefined + diff --git a/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts b/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts index e1c5e98e5032a..aed8132cb741c 100644 --- a/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts +++ b/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts @@ -2,3 +2,5 @@ // @noEmit: true const f1: (...args: [number, string, ...boolean[]] | [string, number, ...boolean[]]) => void = (a, b, c) => {}; + +const f2: (x: string, ...args: [string] | [number, boolean]) => void = (a, b, c) => {}; From 0de8923abaa3424e113cc58f33c5b9480a2d9f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 28 Dec 2022 20:53:27 +0100 Subject: [PATCH 05/13] Add tests for mixed-length tuples used as rest --- .../dependentDestructuredVariables.errors.txt | 8 +++++ .../dependentDestructuredVariables.js | 19 +++++++++++ .../dependentDestructuredVariables.symbols | 26 ++++++++++++++ .../dependentDestructuredVariables.types | 34 +++++++++++++++++++ ...TupleUnionWithRestContextualParams.symbols | 12 +++++++ ...stTupleUnionWithRestContextualParams.types | 14 ++++++++ .../restTupleUnionWithRestContextualParams.ts | 4 +++ .../dependentDestructuredVariables.ts | 8 +++++ 8 files changed, 125 insertions(+) diff --git a/tests/baselines/reference/dependentDestructuredVariables.errors.txt b/tests/baselines/reference/dependentDestructuredVariables.errors.txt index 20f9dce5790ed..eb268d806942d 100644 --- a/tests/baselines/reference/dependentDestructuredVariables.errors.txt +++ b/tests/baselines/reference/dependentDestructuredVariables.errors.txt @@ -394,4 +394,12 @@ tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(334,5): er } } } + + // repros from #47190#issuecomment-1339753554 + const f70: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => { + if (type !== "one") x.toUpperCase(); + } + const f71: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => { + if (type !== "one") x.toUpperCase(); + } \ No newline at end of file diff --git a/tests/baselines/reference/dependentDestructuredVariables.js b/tests/baselines/reference/dependentDestructuredVariables.js index 1b3316a8471b0..42041da39a30e 100644 --- a/tests/baselines/reference/dependentDestructuredVariables.js +++ b/tests/baselines/reference/dependentDestructuredVariables.js @@ -386,6 +386,14 @@ const fa3: (...args: [true, number] | [false, string]) => void = (guard, value) } } } + +// repros from #47190#issuecomment-1339753554 +const f70: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => { + if (type !== "one") x.toUpperCase(); +} +const f71: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => { + if (type !== "one") x.toUpperCase(); +} //// [dependentDestructuredVariables.js] @@ -687,6 +695,15 @@ const fa3 = (guard, value) => { } } }; +// repros from #47190#issuecomment-1339753554 +const f70 = (type, x) => { + if (type !== "one") + x.toUpperCase(); +}; +const f71 = (type, x) => { + if (type !== "one") + x.toUpperCase(); +}; //// [dependentDestructuredVariables.d.ts] @@ -827,3 +844,5 @@ declare function fa2(x: { value: string; }): void; declare const fa3: (...args: [true, number] | [false, string]) => void; +declare const f70: (...args: [type: "one"] | [type: "two", x: string]) => void; +declare const f71: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void; diff --git a/tests/baselines/reference/dependentDestructuredVariables.symbols b/tests/baselines/reference/dependentDestructuredVariables.symbols index 438466e06bd33..d284cb2dec054 100644 --- a/tests/baselines/reference/dependentDestructuredVariables.symbols +++ b/tests/baselines/reference/dependentDestructuredVariables.symbols @@ -965,3 +965,29 @@ const fa3: (...args: [true, number] | [false, string]) => void = (guard, value) } } +// repros from #47190#issuecomment-1339753554 +const f70: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => { +>f70 : Symbol(f70, Decl(dependentDestructuredVariables.ts, 389, 5)) +>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 389, 12)) +>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 389, 74)) +>x : Symbol(x, Decl(dependentDestructuredVariables.ts, 389, 79)) + + if (type !== "one") x.toUpperCase(); +>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 389, 74)) +>x.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(dependentDestructuredVariables.ts, 389, 79)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +} +const f71: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => { +>f71 : Symbol(f71, Decl(dependentDestructuredVariables.ts, 392, 5)) +>args : Symbol(args, Decl(dependentDestructuredVariables.ts, 392, 12)) +>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 392, 86)) +>x : Symbol(x, Decl(dependentDestructuredVariables.ts, 392, 91)) + + if (type !== "one") x.toUpperCase(); +>type : Symbol(type, Decl(dependentDestructuredVariables.ts, 392, 86)) +>x.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(dependentDestructuredVariables.ts, 392, 91)) +>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --)) +} + diff --git a/tests/baselines/reference/dependentDestructuredVariables.types b/tests/baselines/reference/dependentDestructuredVariables.types index 365c8428a3622..4cf33d054e482 100644 --- a/tests/baselines/reference/dependentDestructuredVariables.types +++ b/tests/baselines/reference/dependentDestructuredVariables.types @@ -1115,3 +1115,37 @@ const fa3: (...args: [true, number] | [false, string]) => void = (guard, value) } } +// repros from #47190#issuecomment-1339753554 +const f70: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => { +>f70 : (...args: [type: "one"] | [type: "two", x: string]) => void +>args : [type: "one"] | [type: "two", x: string] +>(type, x) => { if (type !== "one") x.toUpperCase();} : (type: "one" | "two", x: string | undefined) => void +>type : "one" | "two" +>x : string | undefined + + if (type !== "one") x.toUpperCase(); +>type !== "one" : boolean +>type : "one" | "two" +>"one" : "one" +>x.toUpperCase() : string +>x.toUpperCase : () => string +>x : string +>toUpperCase : () => string +} +const f71: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => { +>f71 : (...args: [type: "one", x?: number] | [type: "two", x: string]) => void +>args : [type: "one", x?: number | undefined] | [type: "two", x: string] +>(type, x) => { if (type !== "one") x.toUpperCase();} : (type: "one" | "two", x: string | number | undefined) => void +>type : "one" | "two" +>x : string | number | undefined + + if (type !== "one") x.toUpperCase(); +>type !== "one" : boolean +>type : "one" | "two" +>"one" : "one" +>x.toUpperCase() : string +>x.toUpperCase : () => string +>x : string +>toUpperCase : () => string +} + diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols b/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols index ba02848adb5a5..7cd316425e3f9 100644 --- a/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols @@ -14,3 +14,15 @@ const f2: (x: string, ...args: [string] | [number, boolean]) => void = (a, b, c) >b : Symbol(b, Decl(restTupleUnionWithRestContextualParams.ts, 2, 74)) >c : Symbol(c, Decl(restTupleUnionWithRestContextualParams.ts, 2, 77)) +const f3: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => {} +>f3 : Symbol(f3, Decl(restTupleUnionWithRestContextualParams.ts, 4, 5)) +>args : Symbol(args, Decl(restTupleUnionWithRestContextualParams.ts, 4, 11)) +>type : Symbol(type, Decl(restTupleUnionWithRestContextualParams.ts, 4, 73)) +>x : Symbol(x, Decl(restTupleUnionWithRestContextualParams.ts, 4, 78)) + +const f4: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => {} +>f4 : Symbol(f4, Decl(restTupleUnionWithRestContextualParams.ts, 6, 5)) +>args : Symbol(args, Decl(restTupleUnionWithRestContextualParams.ts, 6, 11)) +>type : Symbol(type, Decl(restTupleUnionWithRestContextualParams.ts, 6, 85)) +>x : Symbol(x, Decl(restTupleUnionWithRestContextualParams.ts, 6, 90)) + diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.types b/tests/baselines/reference/restTupleUnionWithRestContextualParams.types index 937595e4f0a01..89d88abaded36 100644 --- a/tests/baselines/reference/restTupleUnionWithRestContextualParams.types +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.types @@ -16,3 +16,17 @@ const f2: (x: string, ...args: [string] | [number, boolean]) => void = (a, b, c) >b : string | number >c : boolean | undefined +const f3: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => {} +>f3 : (...args: [type: "one"] | [type: "two", x: string]) => void +>args : [type: "one"] | [type: "two", x: string] +>(type, x) => {} : (type: "one" | "two", x: string | undefined) => void +>type : "one" | "two" +>x : string | undefined + +const f4: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => {} +>f4 : (...args: [type: "one", x?: number] | [type: "two", x: string]) => void +>args : [type: "one", x?: number | undefined] | [type: "two", x: string] +>(type, x) => {} : (type: "one" | "two", x: string | number | undefined) => void +>type : "one" | "two" +>x : string | number | undefined + diff --git a/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts b/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts index aed8132cb741c..c43fecf4f58a6 100644 --- a/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts +++ b/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts @@ -4,3 +4,7 @@ const f1: (...args: [number, string, ...boolean[]] | [string, number, ...boolean[]]) => void = (a, b, c) => {}; const f2: (x: string, ...args: [string] | [number, boolean]) => void = (a, b, c) => {}; + +const f3: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => {} + +const f4: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => {} diff --git a/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts b/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts index 2d7dc5ae5af51..5832b9985c8ee 100644 --- a/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts +++ b/tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts @@ -390,3 +390,11 @@ const fa3: (...args: [true, number] | [false, string]) => void = (guard, value) } } } + +// repros from #47190#issuecomment-1339753554 +const f70: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => { + if (type !== "one") x.toUpperCase(); +} +const f71: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => { + if (type !== "one") x.toUpperCase(); +} From beb241d9880a869469111912fcff53ab934a537b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 29 Dec 2022 00:03:43 +0100 Subject: [PATCH 06/13] add tests from #45972 --- ...TupleUnionWithRestContextualParams.symbols | 46 +++++++++++++++++++ ...stTupleUnionWithRestContextualParams.types | 46 +++++++++++++++++++ .../restTupleUnionWithRestContextualParams.ts | 12 +++++ 3 files changed, 104 insertions(+) diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols b/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols index 7cd316425e3f9..2a9cc981eda6d 100644 --- a/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols @@ -26,3 +26,49 @@ const f4: (...args: [type: "one", x?: number] | [type: "two", x: string]) => voi >type : Symbol(type, Decl(restTupleUnionWithRestContextualParams.ts, 6, 85)) >x : Symbol(x, Decl(restTupleUnionWithRestContextualParams.ts, 6, 90)) +// #45972 +type Fn1 = (...args: [...strs: string[], num1: number, num2: number]) => void; +>Fn1 : Symbol(Fn1, Decl(restTupleUnionWithRestContextualParams.ts, 6, 99)) +>args : Symbol(args, Decl(restTupleUnionWithRestContextualParams.ts, 9, 12)) + +const f5: Fn1 = () => {} +>f5 : Symbol(f5, Decl(restTupleUnionWithRestContextualParams.ts, 10, 5)) +>Fn1 : Symbol(Fn1, Decl(restTupleUnionWithRestContextualParams.ts, 6, 99)) + +const f6: Fn1 = (arg1) => {} +>f6 : Symbol(f6, Decl(restTupleUnionWithRestContextualParams.ts, 11, 5)) +>Fn1 : Symbol(Fn1, Decl(restTupleUnionWithRestContextualParams.ts, 6, 99)) +>arg1 : Symbol(arg1, Decl(restTupleUnionWithRestContextualParams.ts, 11, 17)) + +const f7: Fn1 = (arg1, arg2) => {} +>f7 : Symbol(f7, Decl(restTupleUnionWithRestContextualParams.ts, 12, 5)) +>Fn1 : Symbol(Fn1, Decl(restTupleUnionWithRestContextualParams.ts, 6, 99)) +>arg1 : Symbol(arg1, Decl(restTupleUnionWithRestContextualParams.ts, 12, 17)) +>arg2 : Symbol(arg2, Decl(restTupleUnionWithRestContextualParams.ts, 12, 22)) + +const f8: Fn1 = (arg1, arg2, arg3) => {} +>f8 : Symbol(f8, Decl(restTupleUnionWithRestContextualParams.ts, 13, 5)) +>Fn1 : Symbol(Fn1, Decl(restTupleUnionWithRestContextualParams.ts, 6, 99)) +>arg1 : Symbol(arg1, Decl(restTupleUnionWithRestContextualParams.ts, 13, 17)) +>arg2 : Symbol(arg2, Decl(restTupleUnionWithRestContextualParams.ts, 13, 22)) +>arg3 : Symbol(arg3, Decl(restTupleUnionWithRestContextualParams.ts, 13, 28)) + +// #45972#issuecomment-1140417029 +const f9: Fn1 = (...[arg1]: [string | number]) => {} +>f9 : Symbol(f9, Decl(restTupleUnionWithRestContextualParams.ts, 16, 5)) +>Fn1 : Symbol(Fn1, Decl(restTupleUnionWithRestContextualParams.ts, 6, 99)) +>arg1 : Symbol(arg1, Decl(restTupleUnionWithRestContextualParams.ts, 16, 21)) + +const f10: Fn1 = (...[arg1, arg2]: [string | number, string | number]) => {} +>f10 : Symbol(f10, Decl(restTupleUnionWithRestContextualParams.ts, 17, 5)) +>Fn1 : Symbol(Fn1, Decl(restTupleUnionWithRestContextualParams.ts, 6, 99)) +>arg1 : Symbol(arg1, Decl(restTupleUnionWithRestContextualParams.ts, 17, 22)) +>arg2 : Symbol(arg2, Decl(restTupleUnionWithRestContextualParams.ts, 17, 27)) + +const f11: Fn1 = (...[arg1, arg2, arg3]: [string | number, string | number, string | number]) => {} +>f11 : Symbol(f11, Decl(restTupleUnionWithRestContextualParams.ts, 18, 5)) +>Fn1 : Symbol(Fn1, Decl(restTupleUnionWithRestContextualParams.ts, 6, 99)) +>arg1 : Symbol(arg1, Decl(restTupleUnionWithRestContextualParams.ts, 18, 22)) +>arg2 : Symbol(arg2, Decl(restTupleUnionWithRestContextualParams.ts, 18, 27)) +>arg3 : Symbol(arg3, Decl(restTupleUnionWithRestContextualParams.ts, 18, 33)) + diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.types b/tests/baselines/reference/restTupleUnionWithRestContextualParams.types index 89d88abaded36..6ce8a04ed890e 100644 --- a/tests/baselines/reference/restTupleUnionWithRestContextualParams.types +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.types @@ -30,3 +30,49 @@ const f4: (...args: [type: "one", x?: number] | [type: "two", x: string]) => voi >type : "one" | "two" >x : string | number | undefined +// #45972 +type Fn1 = (...args: [...strs: string[], num1: number, num2: number]) => void; +>Fn1 : (...args: [...strs: string[], num1: number, num2: number]) => void +>args : [...strs: string[], num1: number, num2: number] + +const f5: Fn1 = () => {} +>f5 : Fn1 +>() => {} : () => void + +const f6: Fn1 = (arg1) => {} +>f6 : Fn1 +>(arg1) => {} : (arg1: string | number) => void +>arg1 : string | number + +const f7: Fn1 = (arg1, arg2) => {} +>f7 : Fn1 +>(arg1, arg2) => {} : (arg1: string | number, arg2: string | number) => void +>arg1 : string | number +>arg2 : string | number + +const f8: Fn1 = (arg1, arg2, arg3) => {} +>f8 : Fn1 +>(arg1, arg2, arg3) => {} : (arg1: string | number, arg2: string | number, arg3: string | number) => void +>arg1 : string | number +>arg2 : string | number +>arg3 : string | number + +// #45972#issuecomment-1140417029 +const f9: Fn1 = (...[arg1]: [string | number]) => {} +>f9 : Fn1 +>(...[arg1]: [string | number]) => {} : (__0_0: string | number) => void +>arg1 : string | number + +const f10: Fn1 = (...[arg1, arg2]: [string | number, string | number]) => {} +>f10 : Fn1 +>(...[arg1, arg2]: [string | number, string | number]) => {} : (__0_0: string | number, __0_1: string | number) => void +>arg1 : string | number +>arg2 : string | number + +const f11: Fn1 = (...[arg1, arg2, arg3]: [string | number, string | number, string | number]) => {} +>f11 : Fn1 +>(...[arg1, arg2, arg3]: [string | number, string | number, string | number]) => {} : (__0_0: string | number, __0_1: string | number, __0_2: string | number) => void +>arg1 : string | number +>arg2 : string | number +>arg3 : string | number + diff --git a/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts b/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts index c43fecf4f58a6..11f632cbbaa55 100644 --- a/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts +++ b/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts @@ -8,3 +8,15 @@ const f2: (x: string, ...args: [string] | [number, boolean]) => void = (a, b, c) const f3: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => {} const f4: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => {} + +// #45972 +type Fn1 = (...args: [...strs: string[], num1: number, num2: number]) => void; +const f5: Fn1 = () => {} +const f6: Fn1 = (arg1) => {} +const f7: Fn1 = (arg1, arg2) => {} +const f8: Fn1 = (arg1, arg2, arg3) => {} + +// #45972#issuecomment-1140417029 +const f9: Fn1 = (...[arg1]: [string | number]) => {} +const f10: Fn1 = (...[arg1, arg2]: [string | number, string | number]) => {} +const f11: Fn1 = (...[arg1, arg2, arg3]: [string | number, string | number, string | number]) => {} From 388ec89723cccef3f34169549f498857f59b0670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 29 Dec 2022 21:49:24 +0100 Subject: [PATCH 07/13] Allow rest in source --- src/compiler/checker.ts | 17 ++++++----------- ...stTupleUnionWithRestContextualParams.symbols | 6 ++++++ ...restTupleUnionWithRestContextualParams.types | 7 +++++++ .../restTupleUnionWithRestContextualParams.ts | 2 ++ 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2240466e70f1f..e5360ec553a36 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -19382,26 +19382,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (let i = 0; i < paramCount; i++) { const sourceType = i === restIndex ? getRestTypeAtPosition(source, i) : tryGetTypeAtPosition(source, i); let targetType = i === restIndex ? getRestTypeAtPosition(target, i) : tryGetTypeAtPosition(target, i); - if (i === restIndex && targetType && sourceType && isTupleType(sourceType) && !sourceType.target.hasRestElement) { + if (i === restIndex && targetType && sourceType && isTupleType(sourceType)) { targetType = mapType(targetType, t => { - if (!isTupleType(t)) { + if (!isTupleType(t) || isTypeIdenticalTo(sourceType, t)) { return t; } - const typeArguments = getTypeArguments(t); const elementTypes: Type[] = []; + const elementFlags: ElementFlags[] = []; for (let i = 0; i < getTypeReferenceArity(sourceType); i++) { - elementTypes.push( - i < typeArguments.length - ? t.target.elementFlags[i] & ElementFlags.Required - ? typeArguments[i] - : getElementTypeOfSliceOfTupleType(t, i)! - : undefinedType - ); + elementTypes.push(getTupleElementType(t, i)!); + elementFlags.push(sourceType.target.elementFlags[i]); } - return createTupleType(elementTypes, elementTypes.map(() => ElementFlags.Required)); + return createTupleType(elementTypes, elementFlags); }); } if (sourceType && targetType) { diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols b/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols index 2a9cc981eda6d..1657f3328ebec 100644 --- a/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols @@ -72,3 +72,9 @@ const f11: Fn1 = (...[arg1, arg2, arg3]: [string | number, string | number, stri >arg2 : Symbol(arg2, Decl(restTupleUnionWithRestContextualParams.ts, 18, 27)) >arg3 : Symbol(arg3, Decl(restTupleUnionWithRestContextualParams.ts, 18, 33)) +const f12: (...args: [...strs: string[], num: number]) => void = (a, ...rest) => {} +>f12 : Symbol(f12, Decl(restTupleUnionWithRestContextualParams.ts, 20, 5)) +>args : Symbol(args, Decl(restTupleUnionWithRestContextualParams.ts, 20, 12)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 20, 66)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 20, 68)) + diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.types b/tests/baselines/reference/restTupleUnionWithRestContextualParams.types index 6ce8a04ed890e..a08fcf169b768 100644 --- a/tests/baselines/reference/restTupleUnionWithRestContextualParams.types +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.types @@ -76,3 +76,10 @@ const f11: Fn1 = (...[arg1, arg2, arg3]: [string | number, string | number, stri >arg2 : string | number >arg3 : string | number +const f12: (...args: [...strs: string[], num: number]) => void = (a, ...rest) => {} +>f12 : (...args: [...strs: string[], num: number]) => void +>args : [...strs: string[], num: number] +>(a, ...rest) => {} : (a: string | number, ...rest: (string | number)[]) => void +>a : string | number +>rest : (string | number)[] + diff --git a/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts b/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts index 11f632cbbaa55..070a6460ad081 100644 --- a/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts +++ b/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts @@ -20,3 +20,5 @@ const f8: Fn1 = (arg1, arg2, arg3) => {} const f9: Fn1 = (...[arg1]: [string | number]) => {} const f10: Fn1 = (...[arg1, arg2]: [string | number, string | number]) => {} const f11: Fn1 = (...[arg1, arg2, arg3]: [string | number, string | number, string | number]) => {} + +const f12: (...args: [...strs: string[], num: number]) => void = (a, ...rest) => {} From e3574503013a5dc983967a7ea30841ce4be3f7d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 16 Jan 2023 10:30:12 +0100 Subject: [PATCH 08/13] Fixed cases involving generics and add comments --- src/compiler/checker.ts | 39 +++++++++++++++-- .../dependentDestructuredVariables.errors.txt | 13 +++++- ...leUnionWithRestContextualParams.errors.txt | 43 +++++++++++++++++++ ...TupleUnionWithRestContextualParams.symbols | 30 +++++++++++++ ...stTupleUnionWithRestContextualParams.types | 28 ++++++++++++ .../restTupleUnionWithRestContextualParams.ts | 8 ++++ 6 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 tests/baselines/reference/restTupleUnionWithRestContextualParams.errors.txt diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bc557a5c7035d..9fce50509a17d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -19491,10 +19491,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let targetType = i === restIndex ? getRestTypeAtPosition(target, i) : tryGetTypeAtPosition(target, i); if (i === restIndex && targetType && sourceType && isTupleType(sourceType)) { targetType = mapType(targetType, t => { - if (!isTupleType(t) || isTypeIdenticalTo(sourceType, t)) { + if ( + !isTupleType(t) || + // When both sides are tuples of the same structure, we don't want to "propagate" types from elements of variable positions + // to the following positions as that would disallow signatures of the exact same structures when trailing fixed elements are involved: + // + // let fn: (...rest: [...string[], number]) => void = (...rest: [...string[], number]) => {}; // ok + // + // Since we want to allow contextual types to flow into paremeters, we don't need to differentiate between rest and variadic elements + // as that doesn't affect the contextual type of the parameter + isTupleTypeStructureMatching(sourceType, t, /*strictVariableElementsComparison*/ false) + ) { return t; } + // We create a tuple type based on the target elements and the source's length here. + // When the source signature accepts less parameters than the target signature + // we only need to check the *used* elements of the target tuple, the rest is ignored by the source anyway + // and thus it can be safely ignored here. + // + // let fn: (a: number, b: string) => void = (a: number) => {}; // ok + // + // In addition to that we also want to "propagate" element types of variable positions + // to all following positions, as that represents possible argument types. + // + // function fn(...[a, b]: [...number[], string]) { + // a; // number | string + // b; // number | string + // } + // fn('str'); // valid const elementTypes: Type[] = []; const elementFlags: ElementFlags[] = []; @@ -22898,9 +22923,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function isTupleTypeStructureMatching(t1: TupleTypeReference, t2: TupleTypeReference) { + function isTupleTypeStructureMatching(t1: TupleTypeReference, t2: TupleTypeReference, strictVariableElementsComparison: boolean) { return getTypeReferenceArity(t1) === getTypeReferenceArity(t2) && - every(t1.target.elementFlags, (f, i) => (f & ElementFlags.Variable) === (t2.target.elementFlags[i] & ElementFlags.Variable)); + every(t1.target.elementFlags, (f, i) => { + const variableFlag1 = f & ElementFlags.Variable; + const variableFlag2 = t2.target.elementFlags[i] & ElementFlags.Variable; + return strictVariableElementsComparison ? + variableFlag1 === variableFlag2 : + variableFlag1 === variableFlag2 || !!variableFlag1 && !!variableFlag2; + }); } function isZeroBigInt({value}: BigIntLiteralType) { @@ -24424,7 +24455,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const elementFlags = target.target.elementFlags; // When source and target are tuple types with the same structure (fixed, variadic, and rest are matched // to the same kind in each position), simply infer between the element types. - if (isTupleType(source) && isTupleTypeStructureMatching(source, target)) { + if (isTupleType(source) && isTupleTypeStructureMatching(source, target, /*strictVariableElementsComparison*/ true)) { for (let i = 0; i < targetArity; i++) { inferFromTypes(getTypeArguments(source)[i], elementTypes[i]); } diff --git a/tests/baselines/reference/dependentDestructuredVariables.errors.txt b/tests/baselines/reference/dependentDestructuredVariables.errors.txt index 80eefc8a1d353..c9b639e794452 100644 --- a/tests/baselines/reference/dependentDestructuredVariables.errors.txt +++ b/tests/baselines/reference/dependentDestructuredVariables.errors.txt @@ -1,8 +1,13 @@ tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(334,5): error TS7022: 'value1' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer. tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(334,5): error TS7031: Binding element 'value1' implicitly has an 'any' type. +tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(408,7): error TS2322: Type '(type: "one" | "two", x: string | number | undefined) => void' is not assignable to type '(...args: [type: "one", x?: number | undefined] | [type: "two", x: string]) => void'. + Types of parameters 'type' and 'args' are incompatible. + Type '[type: "one", x?: number | undefined] | [type: "two", x: string]' is not assignable to type '[type: "one" | "two", x: string | number | undefined]'. + Type '[type: "one", x?: number | undefined]' is not assignable to type '[type: "one" | "two", x: string | number | undefined]'. + Source provides no match for required element at position 1 in target. -==== tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts (2 errors) ==== +==== tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts (3 errors) ==== type Action = | { kind: 'A', payload: number } | { kind: 'B', payload: string }; @@ -415,6 +420,12 @@ tests/cases/conformance/controlFlow/dependentDestructuredVariables.ts(334,5): er if (type !== "one") x.toUpperCase(); } const f71: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => { + ~~~ +!!! error TS2322: Type '(type: "one" | "two", x: string | number | undefined) => void' is not assignable to type '(...args: [type: "one", x?: number | undefined] | [type: "two", x: string]) => void'. +!!! error TS2322: Types of parameters 'type' and 'args' are incompatible. +!!! error TS2322: Type '[type: "one", x?: number | undefined] | [type: "two", x: string]' is not assignable to type '[type: "one" | "two", x: string | number | undefined]'. +!!! error TS2322: Type '[type: "one", x?: number | undefined]' is not assignable to type '[type: "one" | "two", x: string | number | undefined]'. +!!! error TS2322: Source provides no match for required element at position 1 in target. if (type !== "one") x.toUpperCase(); } \ No newline at end of file diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.errors.txt b/tests/baselines/reference/restTupleUnionWithRestContextualParams.errors.txt new file mode 100644 index 0000000000000..801c4754d8b8d --- /dev/null +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.errors.txt @@ -0,0 +1,43 @@ +tests/cases/compiler/restTupleUnionWithRestContextualParams.ts(7,7): error TS2322: Type '(type: "one" | "two", x: string | number | undefined) => void' is not assignable to type '(...args: [type: "one", x?: number | undefined] | [type: "two", x: string]) => void'. + Types of parameters 'type' and 'args' are incompatible. + Type '[type: "one", x?: number | undefined] | [type: "two", x: string]' is not assignable to type '[type: "one" | "two", x: string | number | undefined]'. + Type '[type: "one", x?: number | undefined]' is not assignable to type '[type: "one" | "two", x: string | number | undefined]'. + Source provides no match for required element at position 1 in target. + + +==== tests/cases/compiler/restTupleUnionWithRestContextualParams.ts (1 errors) ==== + const f1: (...args: [number, string, ...boolean[]] | [string, number, ...boolean[]]) => void = (a, b, c) => {}; + + const f2: (x: string, ...args: [string] | [number, boolean]) => void = (a, b, c) => {}; + + const f3: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => {} + + const f4: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => {} + ~~ +!!! error TS2322: Type '(type: "one" | "two", x: string | number | undefined) => void' is not assignable to type '(...args: [type: "one", x?: number | undefined] | [type: "two", x: string]) => void'. +!!! error TS2322: Types of parameters 'type' and 'args' are incompatible. +!!! error TS2322: Type '[type: "one", x?: number | undefined] | [type: "two", x: string]' is not assignable to type '[type: "one" | "two", x: string | number | undefined]'. +!!! error TS2322: Type '[type: "one", x?: number | undefined]' is not assignable to type '[type: "one" | "two", x: string | number | undefined]'. +!!! error TS2322: Source provides no match for required element at position 1 in target. + + // #45972 + type Fn1 = (...args: [...strs: string[], num1: number, num2: number]) => void; + const f5: Fn1 = () => {} + const f6: Fn1 = (arg1) => {} + const f7: Fn1 = (arg1, arg2) => {} + const f8: Fn1 = (arg1, arg2, arg3) => {} + + // #45972#issuecomment-1140417029 + const f9: Fn1 = (...[arg1]: [string | number]) => {} + const f10: Fn1 = (...[arg1, arg2]: [string | number, string | number]) => {} + const f11: Fn1 = (...[arg1, arg2, arg3]: [string | number, string | number, string | number]) => {} + + const f12: (...args: [...strs: string[], num: number]) => void = (a, ...rest) => {} + + // #49218#pullrequestreview-1241473951 + const f13: (...rest: [number, ...T, boolean] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; + + const f14: (...rest: [number, ...string[], T] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; + const f15: (...rest: [number, ...T[], boolean] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; + + let fn: (...rest: [...string[], number]) => void = (...rest: [...string[], number]) => {}; \ No newline at end of file diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols b/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols index 1657f3328ebec..40de95c9ac621 100644 --- a/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols @@ -78,3 +78,33 @@ const f12: (...args: [...strs: string[], num: number]) => void = (a, ...rest) => >a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 20, 66)) >rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 20, 68)) +// #49218#pullrequestreview-1241473951 +const f13: (...rest: [number, ...T, boolean] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; +>f13 : Symbol(f13, Decl(restTupleUnionWithRestContextualParams.ts, 23, 5)) +>T : Symbol(T, Decl(restTupleUnionWithRestContextualParams.ts, 23, 12)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 23, 32)) +>T : Symbol(T, Decl(restTupleUnionWithRestContextualParams.ts, 23, 12)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 23, 78)) +>arg : Symbol(arg, Decl(restTupleUnionWithRestContextualParams.ts, 23, 88)) + +const f14: (...rest: [number, ...string[], T] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; +>f14 : Symbol(f14, Decl(restTupleUnionWithRestContextualParams.ts, 25, 5)) +>T : Symbol(T, Decl(restTupleUnionWithRestContextualParams.ts, 25, 12)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 25, 31)) +>T : Symbol(T, Decl(restTupleUnionWithRestContextualParams.ts, 25, 12)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 25, 78)) +>arg : Symbol(arg, Decl(restTupleUnionWithRestContextualParams.ts, 25, 88)) + +const f15: (...rest: [number, ...T[], boolean] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; +>f15 : Symbol(f15, Decl(restTupleUnionWithRestContextualParams.ts, 26, 5)) +>T : Symbol(T, Decl(restTupleUnionWithRestContextualParams.ts, 26, 12)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 26, 30)) +>T : Symbol(T, Decl(restTupleUnionWithRestContextualParams.ts, 26, 12)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 26, 78)) +>arg : Symbol(arg, Decl(restTupleUnionWithRestContextualParams.ts, 26, 88)) + +let fn: (...rest: [...string[], number]) => void = (...rest: [...string[], number]) => {}; +>fn : Symbol(fn, Decl(restTupleUnionWithRestContextualParams.ts, 28, 3)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 28, 9)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 28, 52)) + diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.types b/tests/baselines/reference/restTupleUnionWithRestContextualParams.types index a08fcf169b768..9b8fdc8f98d76 100644 --- a/tests/baselines/reference/restTupleUnionWithRestContextualParams.types +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.types @@ -83,3 +83,31 @@ const f12: (...args: [...strs: string[], num: number]) => void = (a, ...rest) => >a : string | number >rest : (string | number)[] +// #49218#pullrequestreview-1241473951 +const f13: (...rest: [number, ...T, boolean] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; +>f13 : (...rest: [number, ...T, boolean]) => void +>rest : [number, ...T, boolean] +>(a: number, ...arg: [...string[], boolean]) => {} : (a: number, ...arg: [...string[], boolean]) => void +>a : number +>arg : [...string[], boolean] + +const f14: (...rest: [number, ...string[], T] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; +>f14 : (...rest: [number, ...string[], T]) => void +>rest : [number, ...string[], T] +>(a: number, ...arg: [...string[], boolean]) => {} : (a: number, ...arg: [...string[], boolean]) => void +>a : number +>arg : [...string[], boolean] + +const f15: (...rest: [number, ...T[], boolean] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; +>f15 : (...rest: [number, ...T[], boolean]) => void +>rest : [number, ...T[], boolean] +>(a: number, ...arg: [...string[], boolean]) => {} : (a: number, ...arg: [...string[], boolean]) => void +>a : number +>arg : [...string[], boolean] + +let fn: (...rest: [...string[], number]) => void = (...rest: [...string[], number]) => {}; +>fn : (...rest: [...string[], number]) => void +>rest : [...string[], number] +>(...rest: [...string[], number]) => {} : (...rest: [...string[], number]) => void +>rest : [...string[], number] + diff --git a/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts b/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts index 070a6460ad081..434905486f943 100644 --- a/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts +++ b/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts @@ -22,3 +22,11 @@ const f10: Fn1 = (...[arg1, arg2]: [string | number, string | number]) => {} const f11: Fn1 = (...[arg1, arg2, arg3]: [string | number, string | number, string | number]) => {} const f12: (...args: [...strs: string[], num: number]) => void = (a, ...rest) => {} + +// #49218#pullrequestreview-1241473951 +const f13: (...rest: [number, ...T, boolean] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; + +const f14: (...rest: [number, ...string[], T] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; +const f15: (...rest: [number, ...T[], boolean] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; + +let fn: (...rest: [...string[], number]) => void = (...rest: [...string[], number]) => {}; \ No newline at end of file From 336288a57d8ccba1d6853e54ae8ac053672565a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 10 Jul 2023 18:44:40 +0200 Subject: [PATCH 09/13] fix extra cases --- src/compiler/checker.ts | 10 ++++++- .../genericRestParameters3.errors.txt | 8 +++--- ...leUnionWithRestContextualParams.errors.txt | 7 ++++- ...TupleUnionWithRestContextualParams.symbols | 28 ++++++++++++++++--- ...stTupleUnionWithRestContextualParams.types | 27 ++++++++++++++++-- .../restTupleUnionWithRestContextualParams.ts | 7 ++++- 6 files changed, 74 insertions(+), 13 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index da997c86e0f72..912366b11a991 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -20024,7 +20024,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const elementTypes: Type[] = []; const elementFlags: ElementFlags[] = []; - for (let i = 0; i < getTypeReferenceArity(sourceType); i++) { + const sourceArity = getTypeReferenceArity(sourceType); + const targetArity = getTypeReferenceArity(t); + + for (let i = 0; i < sourceArity; i++) { + if (i >= targetArity) { + elementTypes.push(anyType); + elementFlags.push(sourceType.target.elementFlags[i]); + continue; + } elementTypes.push(getTupleElementType(t, i)!); elementFlags.push(sourceType.target.elementFlags[i]); } diff --git a/tests/baselines/reference/genericRestParameters3.errors.txt b/tests/baselines/reference/genericRestParameters3.errors.txt index e1201b2ba3e9a..688a9ce44c376 100644 --- a/tests/baselines/reference/genericRestParameters3.errors.txt +++ b/tests/baselines/reference/genericRestParameters3.errors.txt @@ -11,8 +11,8 @@ genericRestParameters3.ts(23,1): error TS2322: Type '(x: string, y: string) => v Type 'number' is not assignable to type 'string'. genericRestParameters3.ts(24,1): error TS2322: Type '(x: string, y: number, z: boolean) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'. Types of parameters 'y' and 'args' are incompatible. - Type '[number, boolean] | [string, undefined]' is not assignable to type '[y: number, z: boolean]'. - Type '[string, undefined]' is not assignable to type '[y: number, z: boolean]'. + Type '[number, boolean] | [string, any]' is not assignable to type '[y: number, z: boolean]'. + Type '[string, any]' is not assignable to type '[y: number, z: boolean]'. Type at position 0 in source is not compatible with type at position 0 in target. Type 'string' is not assignable to type 'number'. genericRestParameters3.ts(35,1): error TS2554: Expected 1 arguments, but got 0. @@ -77,8 +77,8 @@ genericRestParameters3.ts(59,5): error TS2345: Argument of type '["what"]' is no ~~ !!! error TS2322: Type '(x: string, y: number, z: boolean) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'. !!! error TS2322: Types of parameters 'y' and 'args' are incompatible. -!!! error TS2322: Type '[number, boolean] | [string, undefined]' is not assignable to type '[y: number, z: boolean]'. -!!! error TS2322: Type '[string, undefined]' is not assignable to type '[y: number, z: boolean]'. +!!! error TS2322: Type '[number, boolean] | [string, any]' is not assignable to type '[y: number, z: boolean]'. +!!! error TS2322: Type '[string, any]' is not assignable to type '[y: number, z: boolean]'. !!! error TS2322: Type at position 0 in source is not compatible with type at position 0 in target. !!! error TS2322: Type 'string' is not assignable to type 'number'. f1 = f4; diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.errors.txt b/tests/baselines/reference/restTupleUnionWithRestContextualParams.errors.txt index 99ba971afac56..759f8172a0726 100644 --- a/tests/baselines/reference/restTupleUnionWithRestContextualParams.errors.txt +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.errors.txt @@ -40,4 +40,9 @@ restTupleUnionWithRestContextualParams.ts(7,7): error TS2322: Type '(type: "one" const f14: (...rest: [number, ...string[], T] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; const f15: (...rest: [number, ...T[], boolean] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; - let fn: (...rest: [...string[], number]) => void = (...rest: [...string[], number]) => {}; \ No newline at end of file + const f16: (...rest: [...string[], number]) => void = (...rest: [...string[], number]) => {}; + + const f17: (...rest: [...string[], number]) => void = (a, b, c?) => {}; + const f18: (...rest: [...string[], number]) => void = (a, b, c?: string | number) => {}; + + const f19: (...rest: [string, ...boolean[], string] | [number]) => void = (a, ...rest) => {}; \ No newline at end of file diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols b/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols index 2df2aff8e2dd9..48ce87c8cae72 100644 --- a/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols @@ -105,8 +105,28 @@ const f15: (...rest: [number, ...T[], boolean] ) => void = (a: >a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 26, 78)) >arg : Symbol(arg, Decl(restTupleUnionWithRestContextualParams.ts, 26, 88)) -let fn: (...rest: [...string[], number]) => void = (...rest: [...string[], number]) => {}; ->fn : Symbol(fn, Decl(restTupleUnionWithRestContextualParams.ts, 28, 3)) ->rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 28, 9)) ->rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 28, 52)) +const f16: (...rest: [...string[], number]) => void = (...rest: [...string[], number]) => {}; +>f16 : Symbol(f16, Decl(restTupleUnionWithRestContextualParams.ts, 28, 5)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 28, 12)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 28, 55)) + +const f17: (...rest: [...string[], number]) => void = (a, b, c?) => {}; +>f17 : Symbol(f17, Decl(restTupleUnionWithRestContextualParams.ts, 30, 5)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 30, 12)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 30, 55)) +>b : Symbol(b, Decl(restTupleUnionWithRestContextualParams.ts, 30, 57)) +>c : Symbol(c, Decl(restTupleUnionWithRestContextualParams.ts, 30, 60)) + +const f18: (...rest: [...string[], number]) => void = (a, b, c?: string | number) => {}; +>f18 : Symbol(f18, Decl(restTupleUnionWithRestContextualParams.ts, 31, 5)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 31, 12)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 31, 55)) +>b : Symbol(b, Decl(restTupleUnionWithRestContextualParams.ts, 31, 57)) +>c : Symbol(c, Decl(restTupleUnionWithRestContextualParams.ts, 31, 60)) + +const f19: (...rest: [string, ...boolean[], string] | [number]) => void = (a, ...rest) => {}; +>f19 : Symbol(f19, Decl(restTupleUnionWithRestContextualParams.ts, 33, 5)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 33, 12)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 33, 75)) +>rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 33, 77)) diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.types b/tests/baselines/reference/restTupleUnionWithRestContextualParams.types index 208d1a7692df7..9281410751eb3 100644 --- a/tests/baselines/reference/restTupleUnionWithRestContextualParams.types +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.types @@ -107,9 +107,32 @@ const f15: (...rest: [number, ...T[], boolean] ) => void = (a: >a : number >arg : [...string[], boolean] -let fn: (...rest: [...string[], number]) => void = (...rest: [...string[], number]) => {}; ->fn : (...rest: [...string[], number]) => void +const f16: (...rest: [...string[], number]) => void = (...rest: [...string[], number]) => {}; +>f16 : (...rest: [...string[], number]) => void >rest : [...string[], number] >(...rest: [...string[], number]) => {} : (...rest: [...string[], number]) => void >rest : [...string[], number] +const f17: (...rest: [...string[], number]) => void = (a, b, c?) => {}; +>f17 : (...rest: [...string[], number]) => void +>rest : [...string[], number] +>(a, b, c?) => {} : (a: string | number, b: string | number, c?: string | number) => void +>a : string | number +>b : string | number +>c : string | number + +const f18: (...rest: [...string[], number]) => void = (a, b, c?: string | number) => {}; +>f18 : (...rest: [...string[], number]) => void +>rest : [...string[], number] +>(a, b, c?: string | number) => {} : (a: string | number, b: string | number, c?: string | number) => void +>a : string | number +>b : string | number +>c : string | number | undefined + +const f19: (...rest: [string, ...boolean[], string] | [number]) => void = (a, ...rest) => {}; +>f19 : (...rest: [string, ...boolean[], string] | [number]) => void +>rest : [string, ...boolean[], string] | [number] +>(a, ...rest) => {} : (a: string | number, ...rest: (string | number | boolean)[]) => void +>a : string | number +>rest : (string | number | boolean)[] + diff --git a/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts b/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts index 434905486f943..bd5d3c66245ba 100644 --- a/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts +++ b/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts @@ -29,4 +29,9 @@ const f13: (...rest: [number, ...T, boolean] ) => void = (a: const f14: (...rest: [number, ...string[], T] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; const f15: (...rest: [number, ...T[], boolean] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; -let fn: (...rest: [...string[], number]) => void = (...rest: [...string[], number]) => {}; \ No newline at end of file +const f16: (...rest: [...string[], number]) => void = (...rest: [...string[], number]) => {}; + +const f17: (...rest: [...string[], number]) => void = (a, b, c?) => {}; +const f18: (...rest: [...string[], number]) => void = (a, b, c?: string | number) => {}; + +const f19: (...rest: [string, ...boolean[], string] | [number]) => void = (a, ...rest) => {}; \ No newline at end of file From 92d0267a28fb0a3955a5be0b0a52dfca3ebc332e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 10 Jul 2023 19:06:41 +0200 Subject: [PATCH 10/13] Fixed tupel structure matching in the signature-related codepath --- src/compiler/checker.ts | 23 +++++---- .../dependentDestructuredVariables.errors.txt | 13 +---- ...leUnionWithRestContextualParams.errors.txt | 48 ------------------- 3 files changed, 15 insertions(+), 69 deletions(-) delete mode 100644 tests/baselines/reference/restTupleUnionWithRestContextualParams.errors.txt diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 912366b11a991..860b3a195084d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1273,6 +1273,12 @@ export const enum SignatureCheckMode { Callback = BivariantCallback | StrictCallback, } +const enum TupleStructureComparisonKind { + None = 0, + MatchFixed = 1 << 0, + MatchVariable = 1 << 1, +} + const enum IntersectionState { None = 0, Source = 1 << 0, // Source type is a constituent of an outer intersection @@ -20001,7 +20007,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // // Since we want to allow contextual types to flow into paremeters, we don't need to differentiate between rest and variadic elements // as that doesn't affect the contextual type of the parameter - isTupleTypeStructureMatching(sourceType, t, /*strictVariableElementsComparison*/ false) + isTupleTypeStructureMatching(sourceType, t, TupleStructureComparisonKind.MatchVariable) ) { return t; } @@ -23521,14 +23527,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - function isTupleTypeStructureMatching(t1: TupleTypeReference, t2: TupleTypeReference, strictVariableElementsComparison: boolean) { + function isTupleTypeStructureMatching(t1: TupleTypeReference, t2: TupleTypeReference, tupleStructureComparisonKind: TupleStructureComparisonKind) { return getTypeReferenceArity(t1) === getTypeReferenceArity(t2) && - every(t1.target.elementFlags, (f, i) => { - const variableFlag1 = f & ElementFlags.Variable; - const variableFlag2 = t2.target.elementFlags[i] & ElementFlags.Variable; - return strictVariableElementsComparison ? - variableFlag1 === variableFlag2 : - variableFlag1 === variableFlag2 || !!variableFlag1 && !!variableFlag2; + every(t1.target.elementFlags, (f1, i) => { + const f2 = t2.target.elementFlags[i]; + return f1 === f2 || + !!(tupleStructureComparisonKind & TupleStructureComparisonKind.MatchFixed && f1 & ElementFlags.Fixed && f2 & ElementFlags.Fixed) || + !!(tupleStructureComparisonKind & TupleStructureComparisonKind.MatchVariable && f1 & ElementFlags.Variable && f2 & ElementFlags.Variable); }); } @@ -25059,7 +25064,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const elementFlags = target.target.elementFlags; // When source and target are tuple types with the same structure (fixed, variadic, and rest are matched // to the same kind in each position), simply infer between the element types. - if (isTupleType(source) && isTupleTypeStructureMatching(source, target, /*strictVariableElementsComparison*/ true)) { + if (isTupleType(source) && isTupleTypeStructureMatching(source, target, TupleStructureComparisonKind.MatchFixed)) { for (let i = 0; i < targetArity; i++) { inferFromTypes(getTypeArguments(source)[i], elementTypes[i]); } diff --git a/tests/baselines/reference/dependentDestructuredVariables.errors.txt b/tests/baselines/reference/dependentDestructuredVariables.errors.txt index ac2dc64f0651f..a9c1e0ec9893d 100644 --- a/tests/baselines/reference/dependentDestructuredVariables.errors.txt +++ b/tests/baselines/reference/dependentDestructuredVariables.errors.txt @@ -1,13 +1,8 @@ dependentDestructuredVariables.ts(334,5): error TS7022: 'value1' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer. dependentDestructuredVariables.ts(334,5): error TS7031: Binding element 'value1' implicitly has an 'any' type. -dependentDestructuredVariables.ts(408,7): error TS2322: Type '(type: "one" | "two", x: string | number | undefined) => void' is not assignable to type '(...args: [type: "one", x?: number | undefined] | [type: "two", x: string]) => void'. - Types of parameters 'type' and 'args' are incompatible. - Type '[type: "one", x?: number | undefined] | [type: "two", x: string]' is not assignable to type '[type: "one" | "two", x: string | number | undefined]'. - Type '[type: "one", x?: number | undefined]' is not assignable to type '[type: "one" | "two", x: string | number | undefined]'. - Source provides no match for required element at position 1 in target. -==== dependentDestructuredVariables.ts (3 errors) ==== +==== dependentDestructuredVariables.ts (2 errors) ==== type Action = | { kind: 'A', payload: number } | { kind: 'B', payload: string }; @@ -420,12 +415,6 @@ dependentDestructuredVariables.ts(408,7): error TS2322: Type '(type: "one" | "tw if (type !== "one") x.toUpperCase(); } const f71: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => { - ~~~ -!!! error TS2322: Type '(type: "one" | "two", x: string | number | undefined) => void' is not assignable to type '(...args: [type: "one", x?: number | undefined] | [type: "two", x: string]) => void'. -!!! error TS2322: Types of parameters 'type' and 'args' are incompatible. -!!! error TS2322: Type '[type: "one", x?: number | undefined] | [type: "two", x: string]' is not assignable to type '[type: "one" | "two", x: string | number | undefined]'. -!!! error TS2322: Type '[type: "one", x?: number | undefined]' is not assignable to type '[type: "one" | "two", x: string | number | undefined]'. -!!! error TS2322: Source provides no match for required element at position 1 in target. if (type !== "one") x.toUpperCase(); } \ No newline at end of file diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.errors.txt b/tests/baselines/reference/restTupleUnionWithRestContextualParams.errors.txt deleted file mode 100644 index 759f8172a0726..0000000000000 --- a/tests/baselines/reference/restTupleUnionWithRestContextualParams.errors.txt +++ /dev/null @@ -1,48 +0,0 @@ -restTupleUnionWithRestContextualParams.ts(7,7): error TS2322: Type '(type: "one" | "two", x: string | number | undefined) => void' is not assignable to type '(...args: [type: "one", x?: number | undefined] | [type: "two", x: string]) => void'. - Types of parameters 'type' and 'args' are incompatible. - Type '[type: "one", x?: number | undefined] | [type: "two", x: string]' is not assignable to type '[type: "one" | "two", x: string | number | undefined]'. - Type '[type: "one", x?: number | undefined]' is not assignable to type '[type: "one" | "two", x: string | number | undefined]'. - Source provides no match for required element at position 1 in target. - - -==== restTupleUnionWithRestContextualParams.ts (1 errors) ==== - const f1: (...args: [number, string, ...boolean[]] | [string, number, ...boolean[]]) => void = (a, b, c) => {}; - - const f2: (x: string, ...args: [string] | [number, boolean]) => void = (a, b, c) => {}; - - const f3: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => {} - - const f4: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => {} - ~~ -!!! error TS2322: Type '(type: "one" | "two", x: string | number | undefined) => void' is not assignable to type '(...args: [type: "one", x?: number | undefined] | [type: "two", x: string]) => void'. -!!! error TS2322: Types of parameters 'type' and 'args' are incompatible. -!!! error TS2322: Type '[type: "one", x?: number | undefined] | [type: "two", x: string]' is not assignable to type '[type: "one" | "two", x: string | number | undefined]'. -!!! error TS2322: Type '[type: "one", x?: number | undefined]' is not assignable to type '[type: "one" | "two", x: string | number | undefined]'. -!!! error TS2322: Source provides no match for required element at position 1 in target. - - // #45972 - type Fn1 = (...args: [...strs: string[], num1: number, num2: number]) => void; - const f5: Fn1 = () => {} - const f6: Fn1 = (arg1) => {} - const f7: Fn1 = (arg1, arg2) => {} - const f8: Fn1 = (arg1, arg2, arg3) => {} - - // #45972#issuecomment-1140417029 - const f9: Fn1 = (...[arg1]: [string | number]) => {} - const f10: Fn1 = (...[arg1, arg2]: [string | number, string | number]) => {} - const f11: Fn1 = (...[arg1, arg2, arg3]: [string | number, string | number, string | number]) => {} - - const f12: (...args: [...strs: string[], num: number]) => void = (a, ...rest) => {} - - // #49218#pullrequestreview-1241473951 - const f13: (...rest: [number, ...T, boolean] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; - - const f14: (...rest: [number, ...string[], T] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; - const f15: (...rest: [number, ...T[], boolean] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; - - const f16: (...rest: [...string[], number]) => void = (...rest: [...string[], number]) => {}; - - const f17: (...rest: [...string[], number]) => void = (a, b, c?) => {}; - const f18: (...rest: [...string[], number]) => void = (a, b, c?: string | number) => {}; - - const f19: (...rest: [string, ...boolean[], string] | [number]) => void = (a, ...rest) => {}; \ No newline at end of file From 1c240358a4c83eac419626bb66868071af099a33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 10 Jul 2023 19:15:05 +0200 Subject: [PATCH 11/13] use conditional undefined instead of any --- src/compiler/checker.ts | 6 ++++-- .../baselines/reference/genericRestParameters3.errors.txt | 8 ++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 860b3a195084d..0d901579f91b7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -20035,8 +20035,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (let i = 0; i < sourceArity; i++) { if (i >= targetArity) { - elementTypes.push(anyType); - elementFlags.push(sourceType.target.elementFlags[i]); + if (sourceType.target.elementFlags[i] & ElementFlags.Fixed) { + elementTypes.push(undefinedType); + elementFlags.push(sourceType.target.elementFlags[i]); + } continue; } elementTypes.push(getTupleElementType(t, i)!); diff --git a/tests/baselines/reference/genericRestParameters3.errors.txt b/tests/baselines/reference/genericRestParameters3.errors.txt index 688a9ce44c376..e1201b2ba3e9a 100644 --- a/tests/baselines/reference/genericRestParameters3.errors.txt +++ b/tests/baselines/reference/genericRestParameters3.errors.txt @@ -11,8 +11,8 @@ genericRestParameters3.ts(23,1): error TS2322: Type '(x: string, y: string) => v Type 'number' is not assignable to type 'string'. genericRestParameters3.ts(24,1): error TS2322: Type '(x: string, y: number, z: boolean) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'. Types of parameters 'y' and 'args' are incompatible. - Type '[number, boolean] | [string, any]' is not assignable to type '[y: number, z: boolean]'. - Type '[string, any]' is not assignable to type '[y: number, z: boolean]'. + Type '[number, boolean] | [string, undefined]' is not assignable to type '[y: number, z: boolean]'. + Type '[string, undefined]' is not assignable to type '[y: number, z: boolean]'. Type at position 0 in source is not compatible with type at position 0 in target. Type 'string' is not assignable to type 'number'. genericRestParameters3.ts(35,1): error TS2554: Expected 1 arguments, but got 0. @@ -77,8 +77,8 @@ genericRestParameters3.ts(59,5): error TS2345: Argument of type '["what"]' is no ~~ !!! error TS2322: Type '(x: string, y: number, z: boolean) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'. !!! error TS2322: Types of parameters 'y' and 'args' are incompatible. -!!! error TS2322: Type '[number, boolean] | [string, any]' is not assignable to type '[y: number, z: boolean]'. -!!! error TS2322: Type '[string, any]' is not assignable to type '[y: number, z: boolean]'. +!!! error TS2322: Type '[number, boolean] | [string, undefined]' is not assignable to type '[y: number, z: boolean]'. +!!! error TS2322: Type '[string, undefined]' is not assignable to type '[y: number, z: boolean]'. !!! error TS2322: Type at position 0 in source is not compatible with type at position 0 in target. !!! error TS2322: Type 'string' is not assignable to type 'number'. f1 = f4; From 919fc0e81566a9570fda47118d49b1dbce3b183d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 19 Feb 2024 18:42:05 +0100 Subject: [PATCH 12/13] add extra test case --- ...TupleUnionWithRestContextualParams.symbols | 80 ++++++++++++++++++ ...stTupleUnionWithRestContextualParams.types | 82 +++++++++++++++++++ .../restTupleUnionWithRestContextualParams.ts | 23 +++++- 3 files changed, 184 insertions(+), 1 deletion(-) diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols b/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols index 48ce87c8cae72..76009ec9c8e8c 100644 --- a/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.symbols @@ -130,3 +130,83 @@ const f19: (...rest: [string, ...boolean[], string] | [number]) => void = (a, .. >a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 33, 75)) >rest : Symbol(rest, Decl(restTupleUnionWithRestContextualParams.ts, 33, 77)) +type entryArgsWithIndex = { +>entryArgsWithIndex : Symbol(entryArgsWithIndex, Decl(restTupleUnionWithRestContextualParams.ts, 33, 93)) +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 35, 24)) + + [k in keyof o]: [k: k, v: o[k], i: number]; +>k : Symbol(k, Decl(restTupleUnionWithRestContextualParams.ts, 36, 3)) +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 35, 24)) +>k : Symbol(k, Decl(restTupleUnionWithRestContextualParams.ts, 36, 3)) +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 35, 24)) +>k : Symbol(k, Decl(restTupleUnionWithRestContextualParams.ts, 36, 3)) + +}[keyof o]; +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 35, 24)) + +declare const iterateEntries1: ( +>iterateEntries1 : Symbol(iterateEntries1, Decl(restTupleUnionWithRestContextualParams.ts, 39, 13)) +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 39, 32), Decl(restTupleUnionWithRestContextualParams.ts, 39, 56)) + + o: o, +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 39, 32), Decl(restTupleUnionWithRestContextualParams.ts, 39, 56)) +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 39, 32), Decl(restTupleUnionWithRestContextualParams.ts, 39, 56)) + + flatMapEntry: (...args: entryArgsWithIndex) => void, +>flatMapEntry : Symbol(flatMapEntry, Decl(restTupleUnionWithRestContextualParams.ts, 40, 7)) +>args : Symbol(args, Decl(restTupleUnionWithRestContextualParams.ts, 41, 17)) +>entryArgsWithIndex : Symbol(entryArgsWithIndex, Decl(restTupleUnionWithRestContextualParams.ts, 33, 93)) +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 39, 32), Decl(restTupleUnionWithRestContextualParams.ts, 39, 56)) + +) => void; + +const ie1 = iterateEntries1({ a: true, b: false }, (k, v) => [k, v]); +>ie1 : Symbol(ie1, Decl(restTupleUnionWithRestContextualParams.ts, 44, 5)) +>iterateEntries1 : Symbol(iterateEntries1, Decl(restTupleUnionWithRestContextualParams.ts, 39, 13)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 44, 29)) +>b : Symbol(b, Decl(restTupleUnionWithRestContextualParams.ts, 44, 38)) +>k : Symbol(k, Decl(restTupleUnionWithRestContextualParams.ts, 44, 52)) +>v : Symbol(v, Decl(restTupleUnionWithRestContextualParams.ts, 44, 54)) +>k : Symbol(k, Decl(restTupleUnionWithRestContextualParams.ts, 44, 52)) +>v : Symbol(v, Decl(restTupleUnionWithRestContextualParams.ts, 44, 54)) + +const ie2 = iterateEntries1({ a: true, b: false }, (k, v) => { +>ie2 : Symbol(ie2, Decl(restTupleUnionWithRestContextualParams.ts, 45, 5)) +>iterateEntries1 : Symbol(iterateEntries1, Decl(restTupleUnionWithRestContextualParams.ts, 39, 13)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 45, 29)) +>b : Symbol(b, Decl(restTupleUnionWithRestContextualParams.ts, 45, 38)) +>k : Symbol(k, Decl(restTupleUnionWithRestContextualParams.ts, 45, 52)) +>v : Symbol(v, Decl(restTupleUnionWithRestContextualParams.ts, 45, 54)) + + return [k, v]; +>k : Symbol(k, Decl(restTupleUnionWithRestContextualParams.ts, 45, 52)) +>v : Symbol(v, Decl(restTupleUnionWithRestContextualParams.ts, 45, 54)) + +}); + +declare const iterateEntries2: ( +>iterateEntries2 : Symbol(iterateEntries2, Decl(restTupleUnionWithRestContextualParams.ts, 49, 13)) +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 49, 32), Decl(restTupleUnionWithRestContextualParams.ts, 49, 56)) + + o: o, +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 49, 32), Decl(restTupleUnionWithRestContextualParams.ts, 49, 56)) +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 49, 32), Decl(restTupleUnionWithRestContextualParams.ts, 49, 56)) + + flatMapEntry: (...args: entryArgsWithIndex) => unknown, +>flatMapEntry : Symbol(flatMapEntry, Decl(restTupleUnionWithRestContextualParams.ts, 50, 7)) +>args : Symbol(args, Decl(restTupleUnionWithRestContextualParams.ts, 51, 17)) +>entryArgsWithIndex : Symbol(entryArgsWithIndex, Decl(restTupleUnionWithRestContextualParams.ts, 33, 93)) +>o : Symbol(o, Decl(restTupleUnionWithRestContextualParams.ts, 49, 32), Decl(restTupleUnionWithRestContextualParams.ts, 49, 56)) + +) => void; + +const ie3 = iterateEntries2({ a: true, b: false }, (k, v) => [k, v]); +>ie3 : Symbol(ie3, Decl(restTupleUnionWithRestContextualParams.ts, 54, 5)) +>iterateEntries2 : Symbol(iterateEntries2, Decl(restTupleUnionWithRestContextualParams.ts, 49, 13)) +>a : Symbol(a, Decl(restTupleUnionWithRestContextualParams.ts, 54, 29)) +>b : Symbol(b, Decl(restTupleUnionWithRestContextualParams.ts, 54, 38)) +>k : Symbol(k, Decl(restTupleUnionWithRestContextualParams.ts, 54, 52)) +>v : Symbol(v, Decl(restTupleUnionWithRestContextualParams.ts, 54, 54)) +>k : Symbol(k, Decl(restTupleUnionWithRestContextualParams.ts, 54, 52)) +>v : Symbol(v, Decl(restTupleUnionWithRestContextualParams.ts, 54, 54)) + diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.types b/tests/baselines/reference/restTupleUnionWithRestContextualParams.types index 848e76bcda32c..de03ada6c8ec1 100644 --- a/tests/baselines/reference/restTupleUnionWithRestContextualParams.types +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.types @@ -136,3 +136,85 @@ const f19: (...rest: [string, ...boolean[], string] | [number]) => void = (a, .. >a : string | number >rest : (string | number | boolean)[] +type entryArgsWithIndex = { +>entryArgsWithIndex : entryArgsWithIndex + + [k in keyof o]: [k: k, v: o[k], i: number]; +}[keyof o]; + +declare const iterateEntries1: ( +>iterateEntries1 : (o: o, flatMapEntry: (...args: entryArgsWithIndex) => void) => void + + o: o, +>o : o + + flatMapEntry: (...args: entryArgsWithIndex) => void, +>flatMapEntry : (...args: entryArgsWithIndex) => void +>args : entryArgsWithIndex + +) => void; + +const ie1 = iterateEntries1({ a: true, b: false }, (k, v) => [k, v]); +>ie1 : void +>iterateEntries1({ a: true, b: false }, (k, v) => [k, v]) : void +>iterateEntries1 : (o: o, flatMapEntry: (...args: entryArgsWithIndex) => void) => void +>{ a: true, b: false } : { a: true; b: false; } +>a : true +>true : true +>b : false +>false : false +>(k, v) => [k, v] : (k: "a" | "b", v: boolean) => (boolean | "a" | "b")[] +>k : "a" | "b" +>v : boolean +>[k, v] : (boolean | "a" | "b")[] +>k : "a" | "b" +>v : boolean + +const ie2 = iterateEntries1({ a: true, b: false }, (k, v) => { +>ie2 : void +>iterateEntries1({ a: true, b: false }, (k, v) => { return [k, v];}) : void +>iterateEntries1 : (o: o, flatMapEntry: (...args: entryArgsWithIndex) => void) => void +>{ a: true, b: false } : { a: true; b: false; } +>a : true +>true : true +>b : false +>false : false +>(k, v) => { return [k, v];} : (k: "a" | "b", v: boolean) => (boolean | "a" | "b")[] +>k : "a" | "b" +>v : boolean + + return [k, v]; +>[k, v] : (boolean | "a" | "b")[] +>k : "a" | "b" +>v : boolean + +}); + +declare const iterateEntries2: ( +>iterateEntries2 : (o: o, flatMapEntry: (...args: entryArgsWithIndex) => unknown) => void + + o: o, +>o : o + + flatMapEntry: (...args: entryArgsWithIndex) => unknown, +>flatMapEntry : (...args: entryArgsWithIndex) => unknown +>args : entryArgsWithIndex + +) => void; + +const ie3 = iterateEntries2({ a: true, b: false }, (k, v) => [k, v]); +>ie3 : void +>iterateEntries2({ a: true, b: false }, (k, v) => [k, v]) : void +>iterateEntries2 : (o: o, flatMapEntry: (...args: entryArgsWithIndex) => unknown) => void +>{ a: true, b: false } : { a: true; b: false; } +>a : true +>true : true +>b : false +>false : false +>(k, v) => [k, v] : (k: "a" | "b", v: boolean) => (boolean | "a" | "b")[] +>k : "a" | "b" +>v : boolean +>[k, v] : (boolean | "a" | "b")[] +>k : "a" | "b" +>v : boolean + diff --git a/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts b/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts index bd5d3c66245ba..4c59964c19898 100644 --- a/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts +++ b/tests/cases/compiler/restTupleUnionWithRestContextualParams.ts @@ -34,4 +34,25 @@ const f16: (...rest: [...string[], number]) => void = (...rest: [...string[], nu const f17: (...rest: [...string[], number]) => void = (a, b, c?) => {}; const f18: (...rest: [...string[], number]) => void = (a, b, c?: string | number) => {}; -const f19: (...rest: [string, ...boolean[], string] | [number]) => void = (a, ...rest) => {}; \ No newline at end of file +const f19: (...rest: [string, ...boolean[], string] | [number]) => void = (a, ...rest) => {}; + +type entryArgsWithIndex = { + [k in keyof o]: [k: k, v: o[k], i: number]; +}[keyof o]; + +declare const iterateEntries1: ( + o: o, + flatMapEntry: (...args: entryArgsWithIndex) => void, +) => void; + +const ie1 = iterateEntries1({ a: true, b: false }, (k, v) => [k, v]); +const ie2 = iterateEntries1({ a: true, b: false }, (k, v) => { + return [k, v]; +}); + +declare const iterateEntries2: ( + o: o, + flatMapEntry: (...args: entryArgsWithIndex) => unknown, +) => void; + +const ie3 = iterateEntries2({ a: true, b: false }, (k, v) => [k, v]); From a8ddfc3967b546fb0c6098430bff0025f6f81f69 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Fri, 19 Apr 2024 11:57:44 -0700 Subject: [PATCH 13/13] Update baselines --- .../dependentDestructuredVariables.types | 26 +++- ...estTupleUnionShorterContextualParams.types | 19 +++ ...stTupleUnionWithRestContextualParams.types | 145 +++++++++++++++++- 3 files changed, 188 insertions(+), 2 deletions(-) diff --git a/tests/baselines/reference/dependentDestructuredVariables.types b/tests/baselines/reference/dependentDestructuredVariables.types index b283d8c9f5f4b..796c440028075 100644 --- a/tests/baselines/reference/dependentDestructuredVariables.types +++ b/tests/baselines/reference/dependentDestructuredVariables.types @@ -2,7 +2,7 @@ === Performance Stats === Type Count: 2,500 -Instantiation count: 1,000 +Instantiation count: 1,000 -> 2,500 === dependentDestructuredVariables.ts === type Action = @@ -2070,34 +2070,58 @@ const parameterReassignedContextualRest1: (...args: [1, 2] | [3, 4]) => void = ( // repros from #47190#issuecomment-1339753554 const f70: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => { >f70 : (...args: [type: "one"] | [type: "two", x: string]) => void +> : ^^^^ ^^ ^^^^^ >args : [type: "one"] | [type: "two", x: string] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >(type, x) => { if (type !== "one") x.toUpperCase();} : (type: "one" | "two", x: string | undefined) => void +> : ^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >type : "one" | "two" +> : ^^^^^^^^^^^^^ >x : string | undefined +> : ^^^^^^^^^^^^^^^^^^ if (type !== "one") x.toUpperCase(); >type !== "one" : boolean +> : ^^^^^^^ >type : "one" | "two" +> : ^^^^^^^^^^^^^ >"one" : "one" +> : ^^^^^ >x.toUpperCase() : string +> : ^^^^^^ >x.toUpperCase : () => string +> : ^^^^^^^^^^^^ >x : string +> : ^^^^^^ >toUpperCase : () => string +> : ^^^^^^^^^^^^ } const f71: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => { >f71 : (...args: [type: "one", x?: number] | [type: "two", x: string]) => void +> : ^^^^ ^^ ^^^^^ >args : [type: "one", x?: number | undefined] | [type: "two", x: string] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >(type, x) => { if (type !== "one") x.toUpperCase();} : (type: "one" | "two", x: string | number | undefined) => void +> : ^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >type : "one" | "two" +> : ^^^^^^^^^^^^^ >x : string | number | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ if (type !== "one") x.toUpperCase(); >type !== "one" : boolean +> : ^^^^^^^ >type : "one" | "two" +> : ^^^^^^^^^^^^^ >"one" : "one" +> : ^^^^^ >x.toUpperCase() : string +> : ^^^^^^ >x.toUpperCase : () => string +> : ^^^^^^^^^^^^ >x : string +> : ^^^^^^ >toUpperCase : () => string +> : ^^^^^^^^^^^^ } diff --git a/tests/baselines/reference/restTupleUnionShorterContextualParams.types b/tests/baselines/reference/restTupleUnionShorterContextualParams.types index 9d528a450ac21..617c52a604e46 100644 --- a/tests/baselines/reference/restTupleUnionShorterContextualParams.types +++ b/tests/baselines/reference/restTupleUnionShorterContextualParams.types @@ -6,31 +6,50 @@ // showcase how those transitive assignments are OK const f1: (x: string | number) => void = x => {}; >f1 : (x: string | number) => void +> : ^ ^^ ^^^^^ >x : string | number +> : ^^^^^^^^^^^^^^^ >x => {} : (x: string | number) => void +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ >x : string | number +> : ^^^^^^^^^^^^^^^ const f2: (x: string | number, y: string | number) => void = f1; >f2 : (x: string | number, y: string | number) => void +> : ^ ^^ ^^ ^^ ^^^^^ >x : string | number +> : ^^^^^^^^^^^^^^^ >y : string | number +> : ^^^^^^^^^^^^^^^ >f1 : (x: string | number) => void +> : ^ ^^ ^^^^^^^^^ const f3: (...args: [number, string] | [string, number]) => void = f2; >f3 : (...args: [number, string] | [string, number]) => void +> : ^^^^ ^^ ^^^^^ >args : [number, string] | [string, number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >f2 : (x: string | number, y: string | number) => void +> : ^ ^^ ^^ ^^ ^^^^^^^^^ // by extension those should be OK too const f4: (...args: [number, string] | [string, number]) => void = (item) => {} >f4 : (...args: [number, string] | [string, number]) => void +> : ^^^^ ^^ ^^^^^ >args : [number, string] | [string, number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >(item) => {} : (item: string | number) => void +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ >item : string | number +> : ^^^^^^^^^^^^^^^ const f5: (...args: [number, string] | [string, number]) => void = (item: number | string) => {} >f5 : (...args: [number, string] | [string, number]) => void +> : ^^^^ ^^ ^^^^^ >args : [number, string] | [string, number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >(item: number | string) => {} : (item: number | string) => void +> : ^ ^^ ^^^^^^^^^ >item : string | number +> : ^^^^^^^^^^^^^^^ diff --git a/tests/baselines/reference/restTupleUnionWithRestContextualParams.types b/tests/baselines/reference/restTupleUnionWithRestContextualParams.types index de03ada6c8ec1..450b35d896371 100644 --- a/tests/baselines/reference/restTupleUnionWithRestContextualParams.types +++ b/tests/baselines/reference/restTupleUnionWithRestContextualParams.types @@ -3,218 +3,361 @@ === restTupleUnionWithRestContextualParams.ts === const f1: (...args: [number, string, ...boolean[]] | [string, number, ...boolean[]]) => void = (a, b, c) => {}; >f1 : (...args: [number, string, ...boolean[]] | [string, number, ...boolean[]]) => void +> : ^^^^ ^^ ^^^^^ >args : [number, string, ...boolean[]] | [string, number, ...boolean[]] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >(a, b, c) => {} : (a: string | number, b: string | number, c: boolean) => void +> : ^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ >a : string | number +> : ^^^^^^^^^^^^^^^ >b : string | number +> : ^^^^^^^^^^^^^^^ >c : boolean +> : ^^^^^^^ const f2: (x: string, ...args: [string] | [number, boolean]) => void = (a, b, c) => {}; >f2 : (x: string, ...args: [string] | [number, boolean]) => void +> : ^ ^^ ^^^^^ ^^ ^^^^^ >x : string +> : ^^^^^^ >args : [string] | [number, boolean] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >(a, b, c) => {} : (a: string, b: string | number, c: boolean | undefined) => void +> : ^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >a : string +> : ^^^^^^ >b : string | number +> : ^^^^^^^^^^^^^^^ >c : boolean | undefined +> : ^^^^^^^^^^^^^^^^^^^ const f3: (...args: [type: "one"] | [type: "two", x: string]) => void = (type, x) => {} >f3 : (...args: [type: "one"] | [type: "two", x: string]) => void +> : ^^^^ ^^ ^^^^^ >args : [type: "one"] | [type: "two", x: string] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >(type, x) => {} : (type: "one" | "two", x: string | undefined) => void +> : ^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >type : "one" | "two" +> : ^^^^^^^^^^^^^ >x : string | undefined +> : ^^^^^^^^^^^^^^^^^^ const f4: (...args: [type: "one", x?: number] | [type: "two", x: string]) => void = (type, x) => {} >f4 : (...args: [type: "one", x?: number] | [type: "two", x: string]) => void +> : ^^^^ ^^ ^^^^^ >args : [type: "one", x?: number | undefined] | [type: "two", x: string] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >(type, x) => {} : (type: "one" | "two", x: string | number | undefined) => void +> : ^ ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >type : "one" | "two" +> : ^^^^^^^^^^^^^ >x : string | number | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ // #45972 type Fn1 = (...args: [...strs: string[], num1: number, num2: number]) => void; ->Fn1 : (...args: [...strs: string[], num1: number, num2: number]) => void +>Fn1 : Fn1 +> : ^^^ >args : [...strs: string[], num1: number, num2: number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ const f5: Fn1 = () => {} >f5 : Fn1 +> : ^^^ >() => {} : () => void +> : ^^^^^^^^^^ const f6: Fn1 = (arg1) => {} >f6 : Fn1 +> : ^^^ >(arg1) => {} : (arg1: string | number) => void +> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ >arg1 : string | number +> : ^^^^^^^^^^^^^^^ const f7: Fn1 = (arg1, arg2) => {} >f7 : Fn1 +> : ^^^ >(arg1, arg2) => {} : (arg1: string | number, arg2: string | number) => void +> : ^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ >arg1 : string | number +> : ^^^^^^^^^^^^^^^ >arg2 : string | number +> : ^^^^^^^^^^^^^^^ const f8: Fn1 = (arg1, arg2, arg3) => {} >f8 : Fn1 +> : ^^^ >(arg1, arg2, arg3) => {} : (arg1: string | number, arg2: string | number, arg3: string | number) => void +> : ^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^ >arg1 : string | number +> : ^^^^^^^^^^^^^^^ >arg2 : string | number +> : ^^^^^^^^^^^^^^^ >arg3 : string | number +> : ^^^^^^^^^^^^^^^ // #45972#issuecomment-1140417029 const f9: Fn1 = (...[arg1]: [string | number]) => {} >f9 : Fn1 +> : ^^^ >(...[arg1]: [string | number]) => {} : (__0_0: string | number) => void +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >arg1 : string | number +> : ^^^^^^^^^^^^^^^ const f10: Fn1 = (...[arg1, arg2]: [string | number, string | number]) => {} >f10 : Fn1 +> : ^^^ >(...[arg1, arg2]: [string | number, string | number]) => {} : (__0_0: string | number, __0_1: string | number) => void +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >arg1 : string | number +> : ^^^^^^^^^^^^^^^ >arg2 : string | number +> : ^^^^^^^^^^^^^^^ const f11: Fn1 = (...[arg1, arg2, arg3]: [string | number, string | number, string | number]) => {} >f11 : Fn1 +> : ^^^ >(...[arg1, arg2, arg3]: [string | number, string | number, string | number]) => {} : (__0_0: string | number, __0_1: string | number, __0_2: string | number) => void +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >arg1 : string | number +> : ^^^^^^^^^^^^^^^ >arg2 : string | number +> : ^^^^^^^^^^^^^^^ >arg3 : string | number +> : ^^^^^^^^^^^^^^^ const f12: (...args: [...strs: string[], num: number]) => void = (a, ...rest) => {} >f12 : (...args: [...strs: string[], num: number]) => void +> : ^^^^ ^^ ^^^^^ >args : [...strs: string[], num: number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >(a, ...rest) => {} : (a: string | number, ...rest: (string | number)[]) => void +> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >a : string | number +> : ^^^^^^^^^^^^^^^ >rest : (string | number)[] +> : ^^^^^^^^^^^^^^^^^^^ // #49218#pullrequestreview-1241473951 const f13: (...rest: [number, ...T, boolean] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; >f13 : (...rest: [number, ...T, boolean]) => void +> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^ ^^^^^ >rest : [number, ...T, boolean] +> : ^^^^^^^^^^^^^^^^^^^^^^^ >(a: number, ...arg: [...string[], boolean]) => {} : (a: number, ...arg: [...string[], boolean]) => void +> : ^ ^^ ^^^^^ ^^ ^^^^^^^^^ >a : number +> : ^^^^^^ >arg : [...string[], boolean] +> : ^^^^^^^^^^^^^^^^^^^^^^ const f14: (...rest: [number, ...string[], T] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; >f14 : (...rest: [number, ...string[], T]) => void +> : ^ ^^^^^^^^^^^^^^^^^^^^^ ^^ ^^^^^ >rest : [number, ...string[], T] +> : ^^^^^^^^^^^^^^^^^^^^^^^^ >(a: number, ...arg: [...string[], boolean]) => {} : (a: number, ...arg: [...string[], boolean]) => void +> : ^ ^^ ^^^^^ ^^ ^^^^^^^^^ >a : number +> : ^^^^^^ >arg : [...string[], boolean] +> : ^^^^^^^^^^^^^^^^^^^^^^ const f15: (...rest: [number, ...T[], boolean] ) => void = (a: number, ...arg: [...string[], boolean]) => {}; >f15 : (...rest: [number, ...T[], boolean]) => void +> : ^ ^^^^^^^^^^^^^^^^^^^^ ^^ ^^^^^ >rest : [number, ...T[], boolean] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^ >(a: number, ...arg: [...string[], boolean]) => {} : (a: number, ...arg: [...string[], boolean]) => void +> : ^ ^^ ^^^^^ ^^ ^^^^^^^^^ >a : number +> : ^^^^^^ >arg : [...string[], boolean] +> : ^^^^^^^^^^^^^^^^^^^^^^ const f16: (...rest: [...string[], number]) => void = (...rest: [...string[], number]) => {}; >f16 : (...rest: [...string[], number]) => void +> : ^^^^ ^^ ^^^^^ >rest : [...string[], number] +> : ^^^^^^^^^^^^^^^^^^^^^ >(...rest: [...string[], number]) => {} : (...rest: [...string[], number]) => void +> : ^^^^ ^^ ^^^^^^^^^ >rest : [...string[], number] +> : ^^^^^^^^^^^^^^^^^^^^^ const f17: (...rest: [...string[], number]) => void = (a, b, c?) => {}; >f17 : (...rest: [...string[], number]) => void +> : ^^^^ ^^ ^^^^^ >rest : [...string[], number] +> : ^^^^^^^^^^^^^^^^^^^^^ >(a, b, c?) => {} : (a: string | number, b: string | number, c?: string | number | undefined) => void +> : ^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >a : string | number +> : ^^^^^^^^^^^^^^^ >b : string | number +> : ^^^^^^^^^^^^^^^ >c : string | number | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ const f18: (...rest: [...string[], number]) => void = (a, b, c?: string | number) => {}; >f18 : (...rest: [...string[], number]) => void +> : ^^^^ ^^ ^^^^^ >rest : [...string[], number] +> : ^^^^^^^^^^^^^^^^^^^^^ >(a, b, c?: string | number) => {} : (a: string | number, b: string | number, c?: string | number) => void +> : ^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^^ >a : string | number +> : ^^^^^^^^^^^^^^^ >b : string | number +> : ^^^^^^^^^^^^^^^ >c : string | number | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^ const f19: (...rest: [string, ...boolean[], string] | [number]) => void = (a, ...rest) => {}; >f19 : (...rest: [string, ...boolean[], string] | [number]) => void +> : ^^^^ ^^ ^^^^^ >rest : [string, ...boolean[], string] | [number] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >(a, ...rest) => {} : (a: string | number, ...rest: (string | number | boolean)[]) => void +> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >a : string | number +> : ^^^^^^^^^^^^^^^ >rest : (string | number | boolean)[] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type entryArgsWithIndex = { >entryArgsWithIndex : entryArgsWithIndex +> : ^^^^^^^^^^^^^^^^^^^^^ [k in keyof o]: [k: k, v: o[k], i: number]; }[keyof o]; declare const iterateEntries1: ( >iterateEntries1 : (o: o, flatMapEntry: (...args: entryArgsWithIndex) => void) => void +> : ^^^^^^^ ^^^^^^^^^^^^^^^^^ ^^ ^^ ^^ ^^^^^ o: o, >o : o +> : ^ flatMapEntry: (...args: entryArgsWithIndex) => void, >flatMapEntry : (...args: entryArgsWithIndex) => void +> : ^^^^ ^^ ^^^^^ >args : entryArgsWithIndex +> : ^^^^^^^^^^^^^^^^^^^^^ ) => void; const ie1 = iterateEntries1({ a: true, b: false }, (k, v) => [k, v]); >ie1 : void +> : ^^^^ >iterateEntries1({ a: true, b: false }, (k, v) => [k, v]) : void +> : ^^^^ >iterateEntries1 : (o: o, flatMapEntry: (...args: entryArgsWithIndex) => void) => void +> : ^^^^^^^ ^^^^^^^^^^^^^^^^^ ^^ ^^ ^^ ^^^^^^^^^ >{ a: true, b: false } : { a: true; b: false; } +> : ^^^^^^^^^^^^^^^^^^^^^^ >a : true +> : ^^^^ >true : true +> : ^^^^ >b : false +> : ^^^^^ >false : false +> : ^^^^^ >(k, v) => [k, v] : (k: "a" | "b", v: boolean) => (boolean | "a" | "b")[] +> : ^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >k : "a" | "b" +> : ^^^^^^^^^ >v : boolean +> : ^^^^^^^ >[k, v] : (boolean | "a" | "b")[] +> : ^^^^^^^^^^^^^^^^^^^^^^^ >k : "a" | "b" +> : ^^^^^^^^^ >v : boolean +> : ^^^^^^^ const ie2 = iterateEntries1({ a: true, b: false }, (k, v) => { >ie2 : void +> : ^^^^ >iterateEntries1({ a: true, b: false }, (k, v) => { return [k, v];}) : void +> : ^^^^ >iterateEntries1 : (o: o, flatMapEntry: (...args: entryArgsWithIndex) => void) => void +> : ^^^^^^^ ^^^^^^^^^^^^^^^^^ ^^ ^^ ^^ ^^^^^^^^^ >{ a: true, b: false } : { a: true; b: false; } +> : ^^^^^^^^^^^^^^^^^^^^^^ >a : true +> : ^^^^ >true : true +> : ^^^^ >b : false +> : ^^^^^ >false : false +> : ^^^^^ >(k, v) => { return [k, v];} : (k: "a" | "b", v: boolean) => (boolean | "a" | "b")[] +> : ^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >k : "a" | "b" +> : ^^^^^^^^^ >v : boolean +> : ^^^^^^^ return [k, v]; >[k, v] : (boolean | "a" | "b")[] +> : ^^^^^^^^^^^^^^^^^^^^^^^ >k : "a" | "b" +> : ^^^^^^^^^ >v : boolean +> : ^^^^^^^ }); declare const iterateEntries2: ( >iterateEntries2 : (o: o, flatMapEntry: (...args: entryArgsWithIndex) => unknown) => void +> : ^^^^^^^ ^^^^^^^^^^^^^^^^^ ^^ ^^ ^^ ^^^^^ o: o, >o : o +> : ^ flatMapEntry: (...args: entryArgsWithIndex) => unknown, >flatMapEntry : (...args: entryArgsWithIndex) => unknown +> : ^^^^ ^^ ^^^^^ >args : entryArgsWithIndex +> : ^^^^^^^^^^^^^^^^^^^^^ ) => void; const ie3 = iterateEntries2({ a: true, b: false }, (k, v) => [k, v]); >ie3 : void +> : ^^^^ >iterateEntries2({ a: true, b: false }, (k, v) => [k, v]) : void +> : ^^^^ >iterateEntries2 : (o: o, flatMapEntry: (...args: entryArgsWithIndex) => unknown) => void +> : ^^^^^^^ ^^^^^^^^^^^^^^^^^ ^^ ^^ ^^ ^^^^^^^^^ >{ a: true, b: false } : { a: true; b: false; } +> : ^^^^^^^^^^^^^^^^^^^^^^ >a : true +> : ^^^^ >true : true +> : ^^^^ >b : false +> : ^^^^^ >false : false +> : ^^^^^ >(k, v) => [k, v] : (k: "a" | "b", v: boolean) => (boolean | "a" | "b")[] +> : ^ ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ >k : "a" | "b" +> : ^^^^^^^^^ >v : boolean +> : ^^^^^^^ >[k, v] : (boolean | "a" | "b")[] +> : ^^^^^^^^^^^^^^^^^^^^^^^ >k : "a" | "b" +> : ^^^^^^^^^ >v : boolean +> : ^^^^^^^