Skip to content

Commit 688e9bc

Browse files
authored
Merge pull request #10234 from Microsoft/correct-this-in-tuple-type-parameter-constraints
Correct this in tuple type parameter constraints
2 parents fa991b5 + 4087808 commit 688e9bc

File tree

6 files changed

+196
-6
lines changed

6 files changed

+196
-6
lines changed

src/compiler/checker.ts

Lines changed: 11 additions & 6 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
@@ -1538,8 +1538,8 @@ namespace ts {
1538

1538

1539
function createType(flags: TypeFlags): Type {
1539
function createType(flags: TypeFlags): Type {
1540
const result = new Type(checker, flags);
1540
const result = new Type(checker, flags);
1541-
result.id = typeCount;
1542
typeCount++;
1541
typeCount++;
1542+
result.id = typeCount;
1543
return result;
1543
return result;
1544
}
1544
}
1545

1545

@@ -4000,6 +4000,9 @@ namespace ts {
4000
return createTypeReference((<TypeReference>type).target,
4000
return createTypeReference((<TypeReference>type).target,
4001
concatenate((<TypeReference>type).typeArguments, [thisArgument || (<TypeReference>type).target.thisType]));
4001
concatenate((<TypeReference>type).typeArguments, [thisArgument || (<TypeReference>type).target.thisType]));
4002
}
4002
}
4003+
if (type.flags & TypeFlags.Tuple) {
4004+
return createTupleType((type as TupleType).elementTypes, thisArgument);
4005+
}
4003
return type;
4006
return type;
4004
}
4007
}
4005

4008

@@ -4103,7 +4106,8 @@ namespace ts {
4103
function resolveTupleTypeMembers(type: TupleType) {
4106
function resolveTupleTypeMembers(type: TupleType) {
4104
const arrayElementType = getUnionType(type.elementTypes);
4107
const arrayElementType = getUnionType(type.elementTypes);
4105
// Make the tuple type itself the 'this' type by including an extra type argument
4108
// Make the tuple type itself the 'this' type by including an extra type argument
4106-
const arrayType = resolveStructuredTypeMembers(createTypeFromGenericGlobalType(globalArrayType, [arrayElementType, type]));
4109+
// (Unless it's provided in the case that the tuple is a type parameter constraint)
4110+
const arrayType = resolveStructuredTypeMembers(createTypeFromGenericGlobalType(globalArrayType, [arrayElementType, type.thisType || type]));
4107
const members = createTupleTypeMemberSymbols(type.elementTypes);
4111
const members = createTupleTypeMemberSymbols(type.elementTypes);
4108
addInheritedMembers(members, arrayType.properties);
4112
addInheritedMembers(members, arrayType.properties);
4109
setObjectTypeMembers(type, members, arrayType.callSignatures, arrayType.constructSignatures, arrayType.stringIndexInfo, arrayType.numberIndexInfo);
4113
setObjectTypeMembers(type, members, arrayType.callSignatures, arrayType.constructSignatures, arrayType.stringIndexInfo, arrayType.numberIndexInfo);
@@ -5230,15 +5234,16 @@ namespace ts {
5230
return links.resolvedType;
5234
return links.resolvedType;
5231
}
5235
}
5232

5236

5233-
function createTupleType(elementTypes: Type[]) {
5237+
function createTupleType(elementTypes: Type[], thisType?: Type) {
5234-
const id = getTypeListId(elementTypes);
5238+
const id = getTypeListId(elementTypes) + "," + (thisType ? thisType.id : 0);
5235-
return tupleTypes[id] || (tupleTypes[id] = createNewTupleType(elementTypes));
5239+
return tupleTypes[id] || (tupleTypes[id] = createNewTupleType(elementTypes, thisType));
5236
}
5240
}
5237

5241

5238-
function createNewTupleType(elementTypes: Type[]) {
5242+
function createNewTupleType(elementTypes: Type[], thisType?: Type) {
5239
const propagatedFlags = getPropagatingFlagsOfTypes(elementTypes, /*excludeKinds*/ 0);
5243
const propagatedFlags = getPropagatingFlagsOfTypes(elementTypes, /*excludeKinds*/ 0);
5240
const type = <TupleType>createObjectType(TypeFlags.Tuple | propagatedFlags);
5244
const type = <TupleType>createObjectType(TypeFlags.Tuple | propagatedFlags);
5241
type.elementTypes = elementTypes;
5245
type.elementTypes = elementTypes;
5246+
type.thisType = thisType;
5242
return type;
5247
return type;
5243
}
5248
}
5244

5249

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
@@ -2371,6 +2371,7 @@ namespace ts {
2371

2371

2372
export interface TupleType extends ObjectType {
2372
export interface TupleType extends ObjectType {
2373
elementTypes: Type[]; // Element types
2373
elementTypes: Type[]; // Element types
2374+
thisType?: Type; // This-type of tuple (only needed for tuples that are constraints of type parameters)
2374
}
2375
}
2375

2376

2376
export interface UnionOrIntersectionType extends Type {
2377
export interface UnionOrIntersectionType extends Type {
Lines changed: 29 additions & 0 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//// [thisInTupleTypeParameterConstraints.ts]
2+
/// <reference no-default-lib="true"/>
3+
4+
interface Boolean {}
5+
interface IArguments {}
6+
interface Function {}
7+
interface Number {}
8+
interface RegExp {}
9+
interface Object {}
10+
interface String {}
11+
12+
interface Array<T> {
13+
// 4 methods will run out of memory if this-types are not instantiated
14+
// correctly for tuple types that are type parameter constraints
15+
map<U>(arg: this): void;
16+
reduceRight<U>(arg: this): void;
17+
reduce<U>(arg: this): void;
18+
reduce2<U>(arg: this): void;
19+
}
20+
21+
declare function f<T extends [(x: number) => number]>(a: T): void;
22+
let x: [(x: number) => number];
23+
f(x);
24+
25+
26+
//// [thisInTupleTypeParameterConstraints.js]
27+
/// <reference no-default-lib="true"/>
28+
var x;
29+
f(x);
Lines changed: 66 additions & 0 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
=== tests/cases/compiler/thisInTupleTypeParameterConstraints.ts ===
2+
/// <reference no-default-lib="true"/>
3+
4+
interface Boolean {}
5+
>Boolean : Symbol(Boolean, Decl(thisInTupleTypeParameterConstraints.ts, 0, 0))
6+
7+
interface IArguments {}
8+
>IArguments : Symbol(IArguments, Decl(thisInTupleTypeParameterConstraints.ts, 2, 20))
9+
10+
interface Function {}
11+
>Function : Symbol(Function, Decl(thisInTupleTypeParameterConstraints.ts, 3, 23))
12+
13+
interface Number {}
14+
>Number : Symbol(Number, Decl(thisInTupleTypeParameterConstraints.ts, 4, 21))
15+
16+
interface RegExp {}
17+
>RegExp : Symbol(RegExp, Decl(thisInTupleTypeParameterConstraints.ts, 5, 19))
18+
19+
interface Object {}
20+
>Object : Symbol(Object, Decl(thisInTupleTypeParameterConstraints.ts, 6, 19))
21+
22+
interface String {}
23+
>String : Symbol(String, Decl(thisInTupleTypeParameterConstraints.ts, 7, 19))
24+
25+
interface Array<T> {
26+
>Array : Symbol(Array, Decl(thisInTupleTypeParameterConstraints.ts, 8, 19))
27+
>T : Symbol(T, Decl(thisInTupleTypeParameterConstraints.ts, 10, 16))
28+
29+
// 4 methods will run out of memory if this-types are not instantiated
30+
// correctly for tuple types that are type parameter constraints
31+
map<U>(arg: this): void;
32+
>map : Symbol(Array.map, Decl(thisInTupleTypeParameterConstraints.ts, 10, 20))
33+
>U : Symbol(U, Decl(thisInTupleTypeParameterConstraints.ts, 13, 8))
34+
>arg : Symbol(arg, Decl(thisInTupleTypeParameterConstraints.ts, 13, 11))
35+
36+
reduceRight<U>(arg: this): void;
37+
>reduceRight : Symbol(Array.reduceRight, Decl(thisInTupleTypeParameterConstraints.ts, 13, 28))
38+
>U : Symbol(U, Decl(thisInTupleTypeParameterConstraints.ts, 14, 16))
39+
>arg : Symbol(arg, Decl(thisInTupleTypeParameterConstraints.ts, 14, 19))
40+
41+
reduce<U>(arg: this): void;
42+
>reduce : Symbol(Array.reduce, Decl(thisInTupleTypeParameterConstraints.ts, 14, 36))
43+
>U : Symbol(U, Decl(thisInTupleTypeParameterConstraints.ts, 15, 11))
44+
>arg : Symbol(arg, Decl(thisInTupleTypeParameterConstraints.ts, 15, 14))
45+
46+
reduce2<U>(arg: this): void;
47+
>reduce2 : Symbol(Array.reduce2, Decl(thisInTupleTypeParameterConstraints.ts, 15, 31))
48+
>U : Symbol(U, Decl(thisInTupleTypeParameterConstraints.ts, 16, 12))
49+
>arg : Symbol(arg, Decl(thisInTupleTypeParameterConstraints.ts, 16, 15))
50+
}
51+
52+
declare function f<T extends [(x: number) => number]>(a: T): void;
53+
>f : Symbol(f, Decl(thisInTupleTypeParameterConstraints.ts, 17, 1))
54+
>T : Symbol(T, Decl(thisInTupleTypeParameterConstraints.ts, 19, 19))
55+
>x : Symbol(x, Decl(thisInTupleTypeParameterConstraints.ts, 19, 31))
56+
>a : Symbol(a, Decl(thisInTupleTypeParameterConstraints.ts, 19, 54))
57+
>T : Symbol(T, Decl(thisInTupleTypeParameterConstraints.ts, 19, 19))
58+
59+
let x: [(x: number) => number];
60+
>x : Symbol(x, Decl(thisInTupleTypeParameterConstraints.ts, 20, 3))
61+
>x : Symbol(x, Decl(thisInTupleTypeParameterConstraints.ts, 20, 9))
62+
63+
f(x);
64+
>f : Symbol(f, Decl(thisInTupleTypeParameterConstraints.ts, 17, 1))
65+
>x : Symbol(x, Decl(thisInTupleTypeParameterConstraints.ts, 20, 3))
66+
Lines changed: 67 additions & 0 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
=== tests/cases/compiler/thisInTupleTypeParameterConstraints.ts ===
2+
/// <reference no-default-lib="true"/>
3+
4+
interface Boolean {}
5+
>Boolean : Boolean
6+
7+
interface IArguments {}
8+
>IArguments : IArguments
9+
10+
interface Function {}
11+
>Function : Function
12+
13+
interface Number {}
14+
>Number : Number
15+
16+
interface RegExp {}
17+
>RegExp : RegExp
18+
19+
interface Object {}
20+
>Object : Object
21+
22+
interface String {}
23+
>String : String
24+
25+
interface Array<T> {
26+
>Array : T[]
27+
>T : T
28+
29+
// 4 methods will run out of memory if this-types are not instantiated
30+
// correctly for tuple types that are type parameter constraints
31+
map<U>(arg: this): void;
32+
>map : <U>(arg: this) => void
33+
>U : U
34+
>arg : this
35+
36+
reduceRight<U>(arg: this): void;
37+
>reduceRight : <U>(arg: this) => void
38+
>U : U
39+
>arg : this
40+
41+
reduce<U>(arg: this): void;
42+
>reduce : <U>(arg: this) => void
43+
>U : U
44+
>arg : this
45+
46+
reduce2<U>(arg: this): void;
47+
>reduce2 : <U>(arg: this) => void
48+
>U : U
49+
>arg : this
50+
}
51+
52+
declare function f<T extends [(x: number) => number]>(a: T): void;
53+
>f : <T extends [(x: number) => number]>(a: T) => void
54+
>T : T
55+
>x : number
56+
>a : T
57+
>T : T
58+
59+
let x: [(x: number) => number];
60+
>x : [(x: number) => number]
61+
>x : number
62+
63+
f(x);
64+
>f(x) : void
65+
>f : <T extends [(x: number) => number]>(a: T) => void
66+
>x : [(x: number) => number]
67+
Lines changed: 22 additions & 0 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/// <reference no-default-lib="true"/>
2+
3+
interface Boolean {}
4+
interface IArguments {}
5+
interface Function {}
6+
interface Number {}
7+
interface RegExp {}
8+
interface Object {}
9+
interface String {}
10+
11+
interface Array<T> {
12+
// 4 methods will run out of memory if this-types are not instantiated
13+
// correctly for tuple types that are type parameter constraints
14+
map<U>(arg: this): void;
15+
reduceRight<U>(arg: this): void;
16+
reduce<U>(arg: this): void;
17+
reduce2<U>(arg: this): void;
18+
}
19+
20+
declare function f<T extends [(x: number) => number]>(a: T): void;
21+
let x: [(x: number) => number];
22+
f(x);

0 commit comments

Comments
 (0)