Skip to content

Commit 55886a1

Browse files
authored
Fixed incorrect SignatureFlags.HasRestParameter propagation when combining signatures (#58440)
1 parent 413f0fa commit 55886a1

21 files changed

+1689
-3
lines changed

src/compiler/checker.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14032,8 +14032,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1403214032
paramMapper = createTypeMapper(right.typeParameters, left.typeParameters);
1403314033
// We just use the type parameter defaults from the first signature
1403414034
}
14035+
let flags = (left.flags | right.flags) & (SignatureFlags.PropagatingFlags & ~SignatureFlags.HasRestParameter);
1403514036
const declaration = left.declaration;
1403614037
const params = combineUnionParameters(left, right, paramMapper);
14038+
const lastParam = lastOrUndefined(params);
14039+
if (lastParam && getCheckFlags(lastParam) & CheckFlags.RestParameter) {
14040+
flags |= SignatureFlags.HasRestParameter;
14041+
}
1403714042
const thisParam = combineUnionThisParam(left.thisParameter, right.thisParameter, paramMapper);
1403814043
const minArgCount = Math.max(left.minArgumentCount, right.minArgumentCount);
1403914044
const result = createSignature(
@@ -14044,7 +14049,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1404414049
/*resolvedReturnType*/ undefined,
1404514050
/*resolvedTypePredicate*/ undefined,
1404614051
minArgCount,
14047-
(left.flags | right.flags) & SignatureFlags.PropagatingFlags,
14052+
flags,
1404814053
);
1404914054
result.compositeKind = TypeFlags.Union;
1405014055
result.compositeSignatures = concatenate(left.compositeKind !== TypeFlags.Intersection && left.compositeSignatures || [left], [right]);
@@ -32545,12 +32550,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3254532550
const paramSymbol = createSymbol(
3254632551
SymbolFlags.FunctionScopedVariable | (isOptional && !isRestParam ? SymbolFlags.Optional : 0),
3254732552
paramName || `arg${i}` as __String,
32553+
isRestParam ? CheckFlags.RestParameter : isOptional ? CheckFlags.OptionalParameter : 0,
3254832554
);
3254932555
paramSymbol.links.type = isRestParam ? createArrayType(unionParamType) : unionParamType;
3255032556
params[i] = paramSymbol;
3255132557
}
3255232558
if (needsExtraRestElement) {
32553-
const restParamSymbol = createSymbol(SymbolFlags.FunctionScopedVariable, "args" as __String);
32559+
const restParamSymbol = createSymbol(SymbolFlags.FunctionScopedVariable, "args" as __String, CheckFlags.RestParameter);
3255432560
restParamSymbol.links.type = createArrayType(getTypeAtPosition(shorter, longestCount));
3255532561
if (shorter === right) {
3255632562
restParamSymbol.links.type = instantiateType(restParamSymbol.links.type, mapper);
@@ -32567,8 +32573,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3256732573
paramMapper = createTypeMapper(right.typeParameters, left.typeParameters);
3256832574
// We just use the type parameter defaults from the first signature
3256932575
}
32576+
let flags = (left.flags | right.flags) & (SignatureFlags.PropagatingFlags & ~SignatureFlags.HasRestParameter);
3257032577
const declaration = left.declaration;
3257132578
const params = combineIntersectionParameters(left, right, paramMapper);
32579+
const lastParam = lastOrUndefined(params);
32580+
if (lastParam && getCheckFlags(lastParam) & CheckFlags.RestParameter) {
32581+
flags |= SignatureFlags.HasRestParameter;
32582+
}
3257232583
const thisParam = combineIntersectionThisParam(left.thisParameter, right.thisParameter, paramMapper);
3257332584
const minArgCount = Math.max(left.minArgumentCount, right.minArgumentCount);
3257432585
const result = createSignature(
@@ -32579,7 +32590,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3257932590
/*resolvedReturnType*/ undefined,
3258032591
/*resolvedTypePredicate*/ undefined,
3258132592
minArgCount,
32582-
(left.flags | right.flags) & SignatureFlags.PropagatingFlags,
32593+
flags,
3258332594
);
3258432595
result.compositeKind = TypeFlags.Intersection;
3258532596
result.compositeSignatures = concatenate(left.compositeKind === TypeFlags.Intersection && left.compositeSignatures || [left], [right]);
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
signatureCombiningRestParameters1.ts(17,6): error TS2345: Argument of type 'any' is not assignable to parameter of type 'never'.
2+
3+
4+
==== signatureCombiningRestParameters1.ts (1 errors) ====
5+
// https://github.com/microsoft/TypeScript/issues/58371
6+
7+
type T1 = "A" | "B";
8+
9+
type T2 = {
10+
C: [string];
11+
D: [number];
12+
};
13+
14+
declare const map: {
15+
[K in T1 | keyof T2]: (...args: K extends keyof T2 ? T2[K] : []) => unknown;
16+
};
17+
18+
declare const args: any;
19+
20+
for (const [key, fn] of Object.entries(map)) {
21+
fn(...args);
22+
~~~~~~~
23+
!!! error TS2345: Argument of type 'any' is not assignable to parameter of type 'never'.
24+
}
25+
26+
const test2: ((a: number, ...args: []) => void) &
27+
((b: string) => void) &
28+
((c: boolean) => void) = (arg) => {};
29+
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//// [tests/cases/compiler/signatureCombiningRestParameters1.ts] ////
2+
3+
=== signatureCombiningRestParameters1.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/58371
5+
6+
type T1 = "A" | "B";
7+
>T1 : Symbol(T1, Decl(signatureCombiningRestParameters1.ts, 0, 0))
8+
9+
type T2 = {
10+
>T2 : Symbol(T2, Decl(signatureCombiningRestParameters1.ts, 2, 20))
11+
12+
C: [string];
13+
>C : Symbol(C, Decl(signatureCombiningRestParameters1.ts, 4, 11))
14+
15+
D: [number];
16+
>D : Symbol(D, Decl(signatureCombiningRestParameters1.ts, 5, 14))
17+
18+
};
19+
20+
declare const map: {
21+
>map : Symbol(map, Decl(signatureCombiningRestParameters1.ts, 9, 13))
22+
23+
[K in T1 | keyof T2]: (...args: K extends keyof T2 ? T2[K] : []) => unknown;
24+
>K : Symbol(K, Decl(signatureCombiningRestParameters1.ts, 10, 3))
25+
>T1 : Symbol(T1, Decl(signatureCombiningRestParameters1.ts, 0, 0))
26+
>T2 : Symbol(T2, Decl(signatureCombiningRestParameters1.ts, 2, 20))
27+
>args : Symbol(args, Decl(signatureCombiningRestParameters1.ts, 10, 25))
28+
>K : Symbol(K, Decl(signatureCombiningRestParameters1.ts, 10, 3))
29+
>T2 : Symbol(T2, Decl(signatureCombiningRestParameters1.ts, 2, 20))
30+
>T2 : Symbol(T2, Decl(signatureCombiningRestParameters1.ts, 2, 20))
31+
>K : Symbol(K, Decl(signatureCombiningRestParameters1.ts, 10, 3))
32+
33+
};
34+
35+
declare const args: any;
36+
>args : Symbol(args, Decl(signatureCombiningRestParameters1.ts, 13, 13))
37+
38+
for (const [key, fn] of Object.entries(map)) {
39+
>key : Symbol(key, Decl(signatureCombiningRestParameters1.ts, 15, 12))
40+
>fn : Symbol(fn, Decl(signatureCombiningRestParameters1.ts, 15, 16))
41+
>Object.entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --))
42+
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
43+
>entries : Symbol(ObjectConstructor.entries, Decl(lib.es2017.object.d.ts, --, --), Decl(lib.es2017.object.d.ts, --, --))
44+
>map : Symbol(map, Decl(signatureCombiningRestParameters1.ts, 9, 13))
45+
46+
fn(...args);
47+
>fn : Symbol(fn, Decl(signatureCombiningRestParameters1.ts, 15, 16))
48+
>args : Symbol(args, Decl(signatureCombiningRestParameters1.ts, 13, 13))
49+
}
50+
51+
const test2: ((a: number, ...args: []) => void) &
52+
>test2 : Symbol(test2, Decl(signatureCombiningRestParameters1.ts, 19, 5))
53+
>a : Symbol(a, Decl(signatureCombiningRestParameters1.ts, 19, 15))
54+
>args : Symbol(args, Decl(signatureCombiningRestParameters1.ts, 19, 25))
55+
56+
((b: string) => void) &
57+
>b : Symbol(b, Decl(signatureCombiningRestParameters1.ts, 20, 4))
58+
59+
((c: boolean) => void) = (arg) => {};
60+
>c : Symbol(c, Decl(signatureCombiningRestParameters1.ts, 21, 4))
61+
>arg : Symbol(arg, Decl(signatureCombiningRestParameters1.ts, 21, 28))
62+
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//// [tests/cases/compiler/signatureCombiningRestParameters1.ts] ////
2+
3+
=== signatureCombiningRestParameters1.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/58371
5+
6+
type T1 = "A" | "B";
7+
>T1 : T1
8+
> : ^^
9+
10+
type T2 = {
11+
>T2 : T2
12+
> : ^^
13+
14+
C: [string];
15+
>C : [string]
16+
> : ^^^^^^^^
17+
18+
D: [number];
19+
>D : [number]
20+
> : ^^^^^^^^
21+
22+
};
23+
24+
declare const map: {
25+
>map : { A: () => unknown; B: () => unknown; C: (args_0: string) => unknown; D: (args_0: number) => unknown; }
26+
> : ^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^
27+
28+
[K in T1 | keyof T2]: (...args: K extends keyof T2 ? T2[K] : []) => unknown;
29+
>args : K extends keyof T2 ? T2[K] : []
30+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
31+
32+
};
33+
34+
declare const args: any;
35+
>args : any
36+
> : ^^^
37+
38+
for (const [key, fn] of Object.entries(map)) {
39+
>key : string
40+
> : ^^^^^^
41+
>fn : (() => unknown) | (() => unknown) | ((args_0: string) => unknown) | ((args_0: number) => unknown)
42+
> : ^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^
43+
>Object.entries(map) : [string, (() => unknown) | (() => unknown) | ((args_0: string) => unknown) | ((args_0: number) => unknown)][]
44+
> : ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^
45+
>Object.entries : { <T>(o: { [s: string]: T; } | ArrayLike<T>): [string, T][]; (o: {}): [string, any][]; }
46+
> : ^^^ ^^ ^^ ^^^ ^^^ ^^ ^^^ ^^^
47+
>Object : ObjectConstructor
48+
> : ^^^^^^^^^^^^^^^^^
49+
>entries : { <T>(o: { [s: string]: T; } | ArrayLike<T>): [string, T][]; (o: {}): [string, any][]; }
50+
> : ^^^ ^^ ^^ ^^^ ^^^ ^^ ^^^ ^^^
51+
>map : { A: () => unknown; B: () => unknown; C: (args_0: string) => unknown; D: (args_0: number) => unknown; }
52+
> : ^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^
53+
54+
fn(...args);
55+
>fn(...args) : unknown
56+
> : ^^^^^^^
57+
>fn : (() => unknown) | (() => unknown) | ((args_0: string) => unknown) | ((args_0: number) => unknown)
58+
> : ^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^
59+
>...args : any
60+
> : ^^^
61+
>args : any
62+
> : ^^^
63+
}
64+
65+
const test2: ((a: number, ...args: []) => void) &
66+
>test2 : ((a: number) => void) & ((b: string) => void) & ((c: boolean) => void)
67+
> : ^^ ^^ ^^^^^ ^^^^^^ ^^ ^^^^^ ^^^^^^ ^^ ^^^^^ ^
68+
>a : number
69+
> : ^^^^^^
70+
>args : []
71+
> : ^^
72+
73+
((b: string) => void) &
74+
>b : string
75+
> : ^^^^^^
76+
77+
((c: boolean) => void) = (arg) => {};
78+
>c : boolean
79+
> : ^^^^^^^
80+
>(arg) => {} : (arg: string | number | boolean) => void
81+
> : ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
82+
>arg : string | number | boolean
83+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
84+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//// [tests/cases/compiler/signatureCombiningRestParameters2.ts] ////
2+
3+
=== signatureCombiningRestParameters2.ts ===
4+
interface Console {
5+
>Console : Symbol(Console, Decl(lib.dom.d.ts, --, --), Decl(signatureCombiningRestParameters2.ts, 0, 0))
6+
7+
log(message?: any, ...optionalParams: any[]): void;
8+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --), Decl(signatureCombiningRestParameters2.ts, 0, 19))
9+
>message : Symbol(message, Decl(signatureCombiningRestParameters2.ts, 1, 6))
10+
>optionalParams : Symbol(optionalParams, Decl(signatureCombiningRestParameters2.ts, 1, 20))
11+
}
12+
13+
let logs: string[] = [];
14+
>logs : Symbol(logs, Decl(signatureCombiningRestParameters2.ts, 4, 3))
15+
16+
let originalLog: typeof console.log;
17+
>originalLog : Symbol(originalLog, Decl(signatureCombiningRestParameters2.ts, 5, 3))
18+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --), Decl(signatureCombiningRestParameters2.ts, 0, 19))
19+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
20+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --), Decl(signatureCombiningRestParameters2.ts, 0, 19))
21+
22+
console.log = (...args) => {
23+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --), Decl(signatureCombiningRestParameters2.ts, 0, 19))
24+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
25+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --), Decl(signatureCombiningRestParameters2.ts, 0, 19))
26+
>args : Symbol(args, Decl(signatureCombiningRestParameters2.ts, 6, 15))
27+
28+
logs.push(...args);
29+
>logs.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
30+
>logs : Symbol(logs, Decl(signatureCombiningRestParameters2.ts, 4, 3))
31+
>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
32+
>args : Symbol(args, Decl(signatureCombiningRestParameters2.ts, 6, 15))
33+
34+
};
35+
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//// [tests/cases/compiler/signatureCombiningRestParameters2.ts] ////
2+
3+
=== signatureCombiningRestParameters2.ts ===
4+
interface Console {
5+
log(message?: any, ...optionalParams: any[]): void;
6+
>log : { (...data: any[]): void; (message?: any, ...optionalParams: any[]): void; }
7+
> : ^^^^^^ ^^ ^^^ ^^^ ^^^ ^^^^^ ^^ ^^^ ^^^
8+
>message : any
9+
>optionalParams : any[]
10+
> : ^^^^^
11+
}
12+
13+
let logs: string[] = [];
14+
>logs : string[]
15+
> : ^^^^^^^^
16+
>[] : never[]
17+
> : ^^^^^^^
18+
19+
let originalLog: typeof console.log;
20+
>originalLog : { (...data: any[]): void; (message?: any, ...optionalParams: any[]): void; }
21+
> : ^^^^^^ ^^ ^^^ ^^^ ^^^ ^^^^^ ^^ ^^^ ^^^
22+
>console.log : { (...data: any[]): void; (message?: any, ...optionalParams: any[]): void; }
23+
> : ^^^^^^ ^^ ^^^ ^^^ ^^^ ^^^^^ ^^ ^^^ ^^^
24+
>console : Console
25+
> : ^^^^^^^
26+
>log : { (...data: any[]): void; (message?: any, ...optionalParams: any[]): void; }
27+
> : ^^^^^^ ^^ ^^^ ^^^ ^^^ ^^^^^ ^^ ^^^ ^^^
28+
29+
console.log = (...args) => {
30+
>console.log = (...args) => { logs.push(...args);} : (args_0?: any, ...args: any[]) => void
31+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
32+
>console.log : { (...data: any[]): void; (message?: any, ...optionalParams: any[]): void; }
33+
> : ^^^^^^ ^^ ^^^ ^^^ ^^^ ^^^^^ ^^ ^^^ ^^^
34+
>console : Console
35+
> : ^^^^^^^
36+
>log : { (...data: any[]): void; (message?: any, ...optionalParams: any[]): void; }
37+
> : ^^^^^^ ^^ ^^^ ^^^ ^^^ ^^^^^ ^^ ^^^ ^^^
38+
>(...args) => { logs.push(...args);} : (args_0?: any, ...args: any[]) => void
39+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
40+
>args : [any?, ...any[]]
41+
> : ^^^^^^^^^^^^^^^^
42+
43+
logs.push(...args);
44+
>logs.push(...args) : number
45+
> : ^^^^^^
46+
>logs.push : (...items: string[]) => number
47+
> : ^^^^ ^^^^^^^^^^^^^^^
48+
>logs : string[]
49+
> : ^^^^^^^^
50+
>push : (...items: string[]) => number
51+
> : ^^^^ ^^^^^^^^^^^^^^^
52+
>...args : any
53+
>args : [any?, ...any[]]
54+
> : ^^^^^^^^^^^^^^^^
55+
56+
};
57+

0 commit comments

Comments
 (0)