Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f89165d

Browse filesBrowse files
authored
Merge pull request microsoft#32049 from microsoft/noDuplicateIntersectionSignatures
Remove duplicate signatures in intersections
2 parents 410b717 + 10c9fbc commit f89165d
Copy full SHA for f89165d

12 files changed

+230-17Lines changed: 230 additions & 17 deletions
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/compiler/checker.ts‎

Copy file name to clipboardExpand all lines: src/compiler/checker.ts
+29-16Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7234,8 +7234,8 @@ namespace ts {
72347234
function resolveIntersectionTypeMembers(type: IntersectionType) {
72357235
// The members and properties collections are empty for intersection types. To get all properties of an
72367236
// intersection type use getPropertiesOfType (only the language service uses this).
7237-
let callSignatures: ReadonlyArray<Signature> = emptyArray;
7238-
let constructSignatures: ReadonlyArray<Signature> = emptyArray;
7237+
let callSignatures: Signature[] | undefined;
7238+
let constructSignatures: Signature[] | undefined;
72397239
let stringIndexInfo: IndexInfo | undefined;
72407240
let numberIndexInfo: IndexInfo | undefined;
72417241
const types = type.types;
@@ -7257,13 +7257,22 @@ namespace ts {
72577257
return clone;
72587258
});
72597259
}
7260-
constructSignatures = concatenate(constructSignatures, signatures);
7260+
constructSignatures = appendSignatures(constructSignatures, signatures);
72617261
}
7262-
callSignatures = concatenate(callSignatures, getSignaturesOfType(t, SignatureKind.Call));
7262+
callSignatures = appendSignatures(callSignatures, getSignaturesOfType(t, SignatureKind.Call));
72637263
stringIndexInfo = intersectIndexInfos(stringIndexInfo, getIndexInfoOfType(t, IndexKind.String));
72647264
numberIndexInfo = intersectIndexInfos(numberIndexInfo, getIndexInfoOfType(t, IndexKind.Number));
72657265
}
7266-
setStructuredTypeMembers(type, emptySymbols, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo);
7266+
setStructuredTypeMembers(type, emptySymbols, callSignatures || emptyArray, constructSignatures || emptyArray, stringIndexInfo, numberIndexInfo);
7267+
}
7268+
7269+
function appendSignatures(signatures: Signature[] | undefined, newSignatures: readonly Signature[]) {
7270+
for (const sig of newSignatures) {
7271+
if (!signatures || every(signatures, s => !compareSignaturesIdentical(s, sig, /*partialMatch*/ false, /*ignoreThisTypes*/ false, /*ignoreReturnTypes*/ false, compareTypesIdentical))) {
7272+
signatures = append(signatures, sig);
7273+
}
7274+
}
7275+
return signatures;
72677276
}
72687277

72697278
/**
@@ -14325,20 +14334,25 @@ namespace ts {
1432514334
if (!(isMatchingSignature(source, target, partialMatch))) {
1432614335
return Ternary.False;
1432714336
}
14328-
// Check that the two signatures have the same number of type parameters. We might consider
14329-
// also checking that any type parameter constraints match, but that would require instantiating
14330-
// the constraints with a common set of type arguments to get relatable entities in places where
14331-
// type parameters occur in the constraints. The complexity of doing that doesn't seem worthwhile,
14332-
// particularly as we're comparing erased versions of the signatures below.
14337+
// Check that the two signatures have the same number of type parameters.
1433314338
if (length(source.typeParameters) !== length(target.typeParameters)) {
1433414339
return Ternary.False;
1433514340
}
14336-
// Spec 1.0 Section 3.8.3 & 3.8.4:
14337-
// M and N (the signatures) are instantiated using type Any as the type argument for all type parameters declared by M and N
14338-
source = getErasedSignature(source);
14339-
target = getErasedSignature(target);
14341+
// Check that type parameter constraints and defaults match. If they do, instantiate the source
14342+
// signature with the type parameters of the target signature and continue the comparison.
14343+
if (target.typeParameters) {
14344+
const mapper = createTypeMapper(source.typeParameters!, target.typeParameters);
14345+
for (let i = 0; i < target.typeParameters.length; i++) {
14346+
const s = source.typeParameters![i];
14347+
const t = target.typeParameters[i];
14348+
if (!(s === t || compareTypes(instantiateType(getConstraintFromTypeParameter(s), mapper) || unknownType, getConstraintFromTypeParameter(t) || unknownType) &&
14349+
compareTypes(instantiateType(getDefaultFromTypeParameter(s), mapper) || unknownType, getDefaultFromTypeParameter(t) || unknownType))) {
14350+
return Ternary.False;
14351+
}
14352+
}
14353+
source = instantiateSignature(source, mapper, /*eraseTypeParameters*/ true);
14354+
}
1434014355
let result = Ternary.True;
14341-
1434214356
if (!ignoreThisTypes) {
1434314357
const sourceThisType = getThisTypeOfSignature(source);
1434414358
if (sourceThisType) {
@@ -14352,7 +14366,6 @@ namespace ts {
1435214366
}
1435314367
}
1435414368
}
14355-
1435614369
const targetLen = getParameterCount(target);
1435714370
for (let i = 0; i < targetLen; i++) {
1435814371
const s = getTypeAtPosition(source, i);
Collapse file
+36Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
tests/cases/compiler/genericSignatureIdentity.ts(10,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '<T extends Date>(x: T) => T', but here has type '<T extends number>(x: T) => T'.
2+
tests/cases/compiler/genericSignatureIdentity.ts(14,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '<T extends Date>(x: T) => T', but here has type '<T>(x: T) => T'.
3+
tests/cases/compiler/genericSignatureIdentity.ts(18,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '<T extends Date>(x: T) => T', but here has type '<T>(x: any) => any'.
4+
5+
6+
==== tests/cases/compiler/genericSignatureIdentity.ts (3 errors) ====
7+
// This test is here to remind us of our current limits of type identity checking.
8+
// Ideally all of the below declarations would be considered different (and thus errors)
9+
// but they aren't because we erase type parameters to type any and don't check that
10+
// constraints are identical.
11+
12+
var x: {
13+
<T extends Date>(x: T): T;
14+
};
15+
16+
var x: {
17+
~
18+
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '<T extends Date>(x: T) => T', but here has type '<T extends number>(x: T) => T'.
19+
!!! related TS6203 tests/cases/compiler/genericSignatureIdentity.ts:6:5: 'x' was also declared here.
20+
<T extends number>(x: T): T;
21+
};
22+
23+
var x: {
24+
~
25+
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '<T extends Date>(x: T) => T', but here has type '<T>(x: T) => T'.
26+
!!! related TS6203 tests/cases/compiler/genericSignatureIdentity.ts:6:5: 'x' was also declared here.
27+
<T>(x: T): T;
28+
};
29+
30+
var x: {
31+
~
32+
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type '<T extends Date>(x: T) => T', but here has type '<T>(x: any) => any'.
33+
!!! related TS6203 tests/cases/compiler/genericSignatureIdentity.ts:6:5: 'x' was also declared here.
34+
<T>(x: any): any;
35+
};
36+
Collapse file

‎tests/baselines/reference/identityForSignaturesWithTypeParametersAndAny.errors.txt‎

Copy file name to clipboardExpand all lines: tests/baselines/reference/identityForSignaturesWithTypeParametersAndAny.errors.txt
+5-1Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1+
tests/cases/compiler/identityForSignaturesWithTypeParametersAndAny.ts(2,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'f' must be of type '<T, U>(x: T, y: U) => T', but here has type '<T, U>(x: any, y: any) => any'.
12
tests/cases/compiler/identityForSignaturesWithTypeParametersAndAny.ts(5,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'g' must be of type '<T, U>(x: T, y: U) => T', but here has type '<T>(x: any, y: any) => any'.
23
tests/cases/compiler/identityForSignaturesWithTypeParametersAndAny.ts(8,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'h' must be of type '<T, U>(x: T, y: U) => T', but here has type '(x: any, y: any) => any'.
34
tests/cases/compiler/identityForSignaturesWithTypeParametersAndAny.ts(11,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'i' must be of type '<T, U>(x: T, y: U) => T', but here has type '<T, U>(x: any, y: string) => any'.
45
tests/cases/compiler/identityForSignaturesWithTypeParametersAndAny.ts(14,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'j' must be of type '<T, U>(x: T, y: U) => T', but here has type '<T, U>(x: any, y: any) => string'.
56

67

7-
==== tests/cases/compiler/identityForSignaturesWithTypeParametersAndAny.ts (4 errors) ====
8+
==== tests/cases/compiler/identityForSignaturesWithTypeParametersAndAny.ts (5 errors) ====
89
var f: <T, U>(x: T, y: U) => T;
910
var f: <T, U>(x: any, y: any) => any;
11+
~
12+
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'f' must be of type '<T, U>(x: T, y: U) => T', but here has type '<T, U>(x: any, y: any) => any'.
13+
!!! related TS6203 tests/cases/compiler/identityForSignaturesWithTypeParametersAndAny.ts:1:5: 'f' was also declared here.
1014

1115
var g: <T, U>(x: T, y: U) => T;
1216
var g: <T>(x: any, y: any) => any;
Collapse file
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
tests/cases/compiler/identityForSignaturesWithTypeParametersSwitched.ts(2,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'f' must be of type '<T, U>(x: T, y: U) => T', but here has type '<T, U>(x: U, y: T) => U'.
2+
3+
4+
==== tests/cases/compiler/identityForSignaturesWithTypeParametersSwitched.ts (1 errors) ====
5+
var f: <T, U>(x: T, y: U) => T;
6+
var f: <T, U>(x: U, y: T) => U;
7+
~
8+
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'f' must be of type '<T, U>(x: T, y: U) => T', but here has type '<T, U>(x: U, y: T) => U'.
9+
!!! related TS6203 tests/cases/compiler/identityForSignaturesWithTypeParametersSwitched.ts:1:5: 'f' was also declared here.
Collapse file

‎tests/baselines/reference/keyofAndIndexedAccess2.errors.txt‎

Copy file name to clipboardExpand all lines: tests/baselines/reference/keyofAndIndexedAccess2.errors.txt
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,4 +237,13 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(108,5): error TS23
237237
type Baz<T, Q extends Foo<T>> = { [K in keyof Q]: T[Q[K]] };
238238

239239
type Qux<T, Q extends Bar<T>> = { [K in keyof Q]: T[Q[K]["0"]] };
240+
241+
// Repro from #32038
242+
243+
const actions = ['resizeTo', 'resizeBy'] as const;
244+
for (const action of actions) {
245+
window[action] = (x, y) => {
246+
window[action](x, y);
247+
}
248+
}
240249

Collapse file

‎tests/baselines/reference/keyofAndIndexedAccess2.js‎

Copy file name to clipboardExpand all lines: tests/baselines/reference/keyofAndIndexedAccess2.js
+16Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,15 @@ type Bar<T> = { [key: string]: { [K in keyof T]: [K] }[keyof T] };
156156
type Baz<T, Q extends Foo<T>> = { [K in keyof Q]: T[Q[K]] };
157157

158158
type Qux<T, Q extends Bar<T>> = { [K in keyof Q]: T[Q[K]["0"]] };
159+
160+
// Repro from #32038
161+
162+
const actions = ['resizeTo', 'resizeBy'] as const;
163+
for (const action of actions) {
164+
window[action] = (x, y) => {
165+
window[action](x, y);
166+
}
167+
}
159168

160169

161170
//// [keyofAndIndexedAccess2.js]
@@ -253,3 +262,10 @@ export class c {
253262
this["a"] = "b";
254263
}
255264
}
265+
// Repro from #32038
266+
const actions = ['resizeTo', 'resizeBy'];
267+
for (const action of actions) {
268+
window[action] = (x, y) => {
269+
window[action](x, y);
270+
};
271+
}
Collapse file

‎tests/baselines/reference/keyofAndIndexedAccess2.symbols‎

Copy file name to clipboardExpand all lines: tests/baselines/reference/keyofAndIndexedAccess2.symbols
+23Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,3 +564,26 @@ type Qux<T, Q extends Bar<T>> = { [K in keyof Q]: T[Q[K]["0"]] };
564564
>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 156, 11))
565565
>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 156, 35))
566566

567+
// Repro from #32038
568+
569+
const actions = ['resizeTo', 'resizeBy'] as const;
570+
>actions : Symbol(actions, Decl(keyofAndIndexedAccess2.ts, 160, 5))
571+
572+
for (const action of actions) {
573+
>action : Symbol(action, Decl(keyofAndIndexedAccess2.ts, 161, 10))
574+
>actions : Symbol(actions, Decl(keyofAndIndexedAccess2.ts, 160, 5))
575+
576+
window[action] = (x, y) => {
577+
>window : Symbol(window, Decl(lib.dom.d.ts, --, --))
578+
>action : Symbol(action, Decl(keyofAndIndexedAccess2.ts, 161, 10))
579+
>x : Symbol(x, Decl(keyofAndIndexedAccess2.ts, 162, 19))
580+
>y : Symbol(y, Decl(keyofAndIndexedAccess2.ts, 162, 21))
581+
582+
window[action](x, y);
583+
>window : Symbol(window, Decl(lib.dom.d.ts, --, --))
584+
>action : Symbol(action, Decl(keyofAndIndexedAccess2.ts, 161, 10))
585+
>x : Symbol(x, Decl(keyofAndIndexedAccess2.ts, 162, 19))
586+
>y : Symbol(y, Decl(keyofAndIndexedAccess2.ts, 162, 21))
587+
}
588+
}
589+
Collapse file

‎tests/baselines/reference/keyofAndIndexedAccess2.types‎

Copy file name to clipboardExpand all lines: tests/baselines/reference/keyofAndIndexedAccess2.types
+32Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,3 +540,35 @@ type Baz<T, Q extends Foo<T>> = { [K in keyof Q]: T[Q[K]] };
540540
type Qux<T, Q extends Bar<T>> = { [K in keyof Q]: T[Q[K]["0"]] };
541541
>Qux : Qux<T, Q>
542542

543+
// Repro from #32038
544+
545+
const actions = ['resizeTo', 'resizeBy'] as const;
546+
>actions : readonly ["resizeTo", "resizeBy"]
547+
>['resizeTo', 'resizeBy'] as const : readonly ["resizeTo", "resizeBy"]
548+
>['resizeTo', 'resizeBy'] : readonly ["resizeTo", "resizeBy"]
549+
>'resizeTo' : "resizeTo"
550+
>'resizeBy' : "resizeBy"
551+
552+
for (const action of actions) {
553+
>action : "resizeTo" | "resizeBy"
554+
>actions : readonly ["resizeTo", "resizeBy"]
555+
556+
window[action] = (x, y) => {
557+
>window[action] = (x, y) => { window[action](x, y); } : (x: number, y: number) => void
558+
>window[action] : ((x: number, y: number) => void) & ((x: number, y: number) => void)
559+
>window : Window
560+
>action : "resizeTo" | "resizeBy"
561+
>(x, y) => { window[action](x, y); } : (x: number, y: number) => void
562+
>x : number
563+
>y : number
564+
565+
window[action](x, y);
566+
>window[action](x, y) : void
567+
>window[action] : ((x: number, y: number) => void) | ((x: number, y: number) => void)
568+
>window : Window
569+
>action : "resizeTo" | "resizeBy"
570+
>x : number
571+
>y : number
572+
}
573+
}
574+
Collapse file
+28Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
tests/cases/compiler/promiseIdentity.ts(21,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'y' must be of type 'IPromise2<string, number>', but here has type 'Promise2<any, string>'.
2+
3+
4+
==== tests/cases/compiler/promiseIdentity.ts (1 errors) ====
5+
export interface IPromise<T> {
6+
then<U>(callback: (x: T) => IPromise<U>): IPromise<U>;
7+
}
8+
interface Promise<T> {
9+
then<U>(callback: (x: T) => Promise<U>): Promise<U>;
10+
}
11+
var x: IPromise<string>;
12+
var x: Promise<string>;
13+
14+
15+
interface IPromise2<T, V> {
16+
then<U, W>(callback: (x: T) => IPromise2<U, W>): IPromise2<W, U>;
17+
}
18+
interface Promise2<T, V> {
19+
then<U, W>(callback: (x: V) => Promise2<U, T>): Promise2<T, W>; // Uses V instead of T in callback's parameter
20+
}
21+
22+
// Ok because T in this particular Promise2 is any, as are all the U and W references.
23+
// Also, the V of Promise2 happens to coincide with the T of IPromise2 (they are both string).
24+
var y: IPromise2<string, number>;
25+
var y: Promise2<any, string>;
26+
~
27+
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'y' must be of type 'IPromise2<string, number>', but here has type 'Promise2<any, string>'.
28+
!!! related TS6203 tests/cases/compiler/promiseIdentity.ts:20:5: 'y' was also declared here.
Collapse file
+17Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
tests/cases/compiler/promiseIdentityWithAny.ts(10,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type 'IPromise<string, number>', but here has type 'Promise<string, boolean>'.
2+
3+
4+
==== tests/cases/compiler/promiseIdentityWithAny.ts (1 errors) ====
5+
export interface IPromise<T, V> {
6+
then<U, W>(callback: (x: T) => IPromise<U, W>): IPromise<U, W>;
7+
}
8+
export interface Promise<T, V> {
9+
then<U, W>(callback: (x: T) => Promise<any, any>): Promise<any, any>;
10+
}
11+
12+
// Should be ok because signature type parameters get erased to any
13+
var x: IPromise<string, number>;
14+
var x: Promise<string, boolean>;
15+
~
16+
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'x' must be of type 'IPromise<string, number>', but here has type 'Promise<string, boolean>'.
17+
!!! related TS6203 tests/cases/compiler/promiseIdentityWithAny.ts:9:5: 'x' was also declared here.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.