Skip to content

Commit cd09cbb

Browse files
authored
Cache widened types (#31586)
* Cache widened types * Fix lint
1 parent 63b8c64 commit cd09cbb

File tree

6 files changed

+386
-9
lines changed

6 files changed

+386
-9
lines changed

src/compiler/checker.ts

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14740,26 +14740,34 @@ namespace ts {
1474014740

1474114741
function getWidenedTypeWithContext(type: Type, context: WideningContext | undefined): Type {
1474214742
if (getObjectFlags(type) & ObjectFlags.RequiresWidening) {
14743+
if (context === undefined && type.widened) {
14744+
return type.widened;
14745+
}
14746+
let result: Type | undefined;
1474314747
if (type.flags & TypeFlags.Nullable) {
14744-
return anyType;
14748+
result = anyType;
1474514749
}
14746-
if (isObjectLiteralType(type)) {
14747-
return getWidenedTypeOfObjectLiteral(type, context);
14750+
else if (isObjectLiteralType(type)) {
14751+
result = getWidenedTypeOfObjectLiteral(type, context);
1474814752
}
14749-
if (type.flags & TypeFlags.Union) {
14753+
else if (type.flags & TypeFlags.Union) {
1475014754
const unionContext = context || createWideningContext(/*parent*/ undefined, /*propertyName*/ undefined, (<UnionType>type).types);
1475114755
const widenedTypes = sameMap((<UnionType>type).types, t => t.flags & TypeFlags.Nullable ? t : getWidenedTypeWithContext(t, unionContext));
1475214756
// Widening an empty object literal transitions from a highly restrictive type to
1475314757
// a highly inclusive one. For that reason we perform subtype reduction here if the
1475414758
// union includes empty object types (e.g. reducing {} | string to just {}).
14755-
return getUnionType(widenedTypes, some(widenedTypes, isEmptyObjectType) ? UnionReduction.Subtype : UnionReduction.Literal);
14759+
result = getUnionType(widenedTypes, some(widenedTypes, isEmptyObjectType) ? UnionReduction.Subtype : UnionReduction.Literal);
14760+
}
14761+
else if (type.flags & TypeFlags.Intersection) {
14762+
result = getIntersectionType(sameMap((<IntersectionType>type).types, getWidenedType));
1475614763
}
14757-
if (type.flags & TypeFlags.Intersection) {
14758-
return getIntersectionType(sameMap((<IntersectionType>type).types, getWidenedType));
14764+
else if (isArrayType(type) || isTupleType(type)) {
14765+
result = createTypeReference((<TypeReference>type).target, sameMap((<TypeReference>type).typeArguments, getWidenedType));
1475914766
}
14760-
if (isArrayType(type) || isTupleType(type)) {
14761-
return createTypeReference((<TypeReference>type).target, sameMap((<TypeReference>type).typeArguments, getWidenedType));
14767+
if (result && context === undefined) {
14768+
type.widened = result;
1476214769
}
14770+
return result || type;
1476314771
}
1476414772
return type;
1476514773
}

src/compiler/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4013,6 +4013,8 @@ namespace ts {
40134013
restrictiveInstantiation?: Type; // Instantiation with type parameters mapped to unconstrained form
40144014
/* @internal */
40154015
immediateBaseConstraint?: Type; // Immediate base constraint cache
4016+
/* @internal */
4017+
widened?: Type; // Cached widened form of the type
40164018
}
40174019

40184020
/* @internal */
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
//// [noImplicitThisBigThis.ts]
2+
// https://github.com/microsoft/TypeScript/issues/29902
3+
4+
function createObj() {
5+
return {
6+
func1() {
7+
return this;
8+
},
9+
func2() {
10+
return this;
11+
},
12+
func3() {
13+
return this;
14+
}
15+
};
16+
}
17+
18+
function createObjNoCrash() {
19+
return {
20+
func1() {
21+
return this;
22+
},
23+
func2() {
24+
return this;
25+
},
26+
func3() {
27+
return this;
28+
},
29+
func4() {
30+
return this;
31+
},
32+
func5() {
33+
return this;
34+
},
35+
func6() {
36+
return this;
37+
},
38+
func7() {
39+
return this;
40+
},
41+
func8() {
42+
return this;
43+
},
44+
func9() {
45+
return this;
46+
}
47+
};
48+
}
49+
50+
51+
//// [noImplicitThisBigThis.js]
52+
// https://github.com/microsoft/TypeScript/issues/29902
53+
function createObj() {
54+
return {
55+
func1: function () {
56+
return this;
57+
},
58+
func2: function () {
59+
return this;
60+
},
61+
func3: function () {
62+
return this;
63+
}
64+
};
65+
}
66+
function createObjNoCrash() {
67+
return {
68+
func1: function () {
69+
return this;
70+
},
71+
func2: function () {
72+
return this;
73+
},
74+
func3: function () {
75+
return this;
76+
},
77+
func4: function () {
78+
return this;
79+
},
80+
func5: function () {
81+
return this;
82+
},
83+
func6: function () {
84+
return this;
85+
},
86+
func7: function () {
87+
return this;
88+
},
89+
func8: function () {
90+
return this;
91+
},
92+
func9: function () {
93+
return this;
94+
}
95+
};
96+
}
97+
98+
99+
//// [noImplicitThisBigThis.d.ts]
100+
declare function createObj(): {
101+
func1(): any;
102+
func2(): any;
103+
func3(): any;
104+
};
105+
declare function createObjNoCrash(): {
106+
func1(): any;
107+
func2(): any;
108+
func3(): any;
109+
func4(): any;
110+
func5(): any;
111+
func6(): any;
112+
func7(): any;
113+
func8(): any;
114+
func9(): any;
115+
};
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
=== tests/cases/compiler/noImplicitThisBigThis.ts ===
2+
// https://github.com/microsoft/TypeScript/issues/29902
3+
4+
function createObj() {
5+
>createObj : Symbol(createObj, Decl(noImplicitThisBigThis.ts, 0, 0))
6+
7+
return {
8+
func1() {
9+
>func1 : Symbol(func1, Decl(noImplicitThisBigThis.ts, 3, 12))
10+
11+
return this;
12+
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 3, 10))
13+
14+
},
15+
func2() {
16+
>func2 : Symbol(func2, Decl(noImplicitThisBigThis.ts, 6, 10))
17+
18+
return this;
19+
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 3, 10))
20+
21+
},
22+
func3() {
23+
>func3 : Symbol(func3, Decl(noImplicitThisBigThis.ts, 9, 10))
24+
25+
return this;
26+
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 3, 10))
27+
}
28+
};
29+
}
30+
31+
function createObjNoCrash() {
32+
>createObjNoCrash : Symbol(createObjNoCrash, Decl(noImplicitThisBigThis.ts, 14, 1))
33+
34+
return {
35+
func1() {
36+
>func1 : Symbol(func1, Decl(noImplicitThisBigThis.ts, 17, 12))
37+
38+
return this;
39+
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10))
40+
41+
},
42+
func2() {
43+
>func2 : Symbol(func2, Decl(noImplicitThisBigThis.ts, 20, 10))
44+
45+
return this;
46+
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10))
47+
48+
},
49+
func3() {
50+
>func3 : Symbol(func3, Decl(noImplicitThisBigThis.ts, 23, 10))
51+
52+
return this;
53+
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10))
54+
55+
},
56+
func4() {
57+
>func4 : Symbol(func4, Decl(noImplicitThisBigThis.ts, 26, 10))
58+
59+
return this;
60+
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10))
61+
62+
},
63+
func5() {
64+
>func5 : Symbol(func5, Decl(noImplicitThisBigThis.ts, 29, 10))
65+
66+
return this;
67+
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10))
68+
69+
},
70+
func6() {
71+
>func6 : Symbol(func6, Decl(noImplicitThisBigThis.ts, 32, 10))
72+
73+
return this;
74+
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10))
75+
76+
},
77+
func7() {
78+
>func7 : Symbol(func7, Decl(noImplicitThisBigThis.ts, 35, 10))
79+
80+
return this;
81+
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10))
82+
83+
},
84+
func8() {
85+
>func8 : Symbol(func8, Decl(noImplicitThisBigThis.ts, 38, 10))
86+
87+
return this;
88+
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10))
89+
90+
},
91+
func9() {
92+
>func9 : Symbol(func9, Decl(noImplicitThisBigThis.ts, 41, 10))
93+
94+
return this;
95+
>this : Symbol(__object, Decl(noImplicitThisBigThis.ts, 17, 10))
96+
}
97+
};
98+
}
99+

0 commit comments

Comments
 (0)