Skip to content

Commit 5e8b63c

Browse files
authored
Use context free expression types in evolving array checking and cache context free type (microsoft#26585)
* Use context free expression types in evolving array checking and cache context free type * Simplify second test * Low max depth a tad just so node 8 wont stack out * By request make flow control a round number
1 parent 194ffb3 commit 5e8b63c

7 files changed

+6277
-4
lines changed

src/compiler/checker.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14433,8 +14433,8 @@ namespace ts {
1443314433
return resultType;
1443414434

1443514435
function getTypeAtFlowNode(flow: FlowNode): FlowType {
14436-
if (flowDepth === 2500) {
14437-
// We have made 2500 recursive invocations. To avoid overflowing the call stack we report an error
14436+
if (flowDepth === 2000) {
14437+
// We have made 2000 recursive invocations. To avoid overflowing the call stack we report an error
1443814438
// and disable further control flow analysis in the containing function or module body.
1443914439
flowAnalysisDisabled = true;
1444014440
reportFlowControlError(reference);
@@ -14574,7 +14574,8 @@ namespace ts {
1457414574
}
1457514575
}
1457614576
else {
14577-
const indexType = getTypeOfExpression((<ElementAccessExpression>node.left).argumentExpression);
14577+
// We must get the context free expression type so as to not recur in an uncached fashion on the LHS (which causes exponential blowup in compile time)
14578+
const indexType = getContextFreeTypeOfExpression((<ElementAccessExpression>node.left).argumentExpression);
1457814579
if (isTypeAssignableToKind(indexType, TypeFlags.NumberLike)) {
1457914580
evolvedType = addEvolvingArrayElementType(evolvedType, node.right);
1458014581
}
@@ -21720,9 +21721,13 @@ namespace ts {
2172021721
* It sets the contextual type of the node to any before calling getTypeOfExpression.
2172121722
*/
2172221723
function getContextFreeTypeOfExpression(node: Expression) {
21724+
const links = getNodeLinks(node);
21725+
if (links.contextFreeType) {
21726+
return links.contextFreeType;
21727+
}
2172321728
const saveContextualType = node.contextualType;
2172421729
node.contextualType = anyType;
21725-
const type = getTypeOfExpression(node);
21730+
const type = links.contextFreeType = checkExpression(node, CheckMode.SkipContextSensitive);
2172621731
node.contextualType = saveContextualType;
2172721732
return type;
2172821733
}
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
=== tests/cases/compiler/foo.js ===
2+
// repro from #26031
3+
function build() {
4+
>build : Symbol(build, Decl(foo.js, 0, 0))
5+
6+
var arr = [];
7+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
8+
9+
arr[arr.length] = 'value';
10+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
11+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
12+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
13+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
14+
15+
arr[arr.length] = 'value';
16+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
17+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
18+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
19+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
20+
21+
arr[arr.length] = 'value';
22+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
23+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
24+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
25+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
26+
27+
arr[arr.length] = 'value';
28+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
29+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
30+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
31+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
32+
33+
arr[arr.length] = 'value';
34+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
35+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
36+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
37+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
38+
39+
arr[arr.length] = 'value';
40+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
41+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
42+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
43+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
44+
45+
arr[arr.length] = 'value';
46+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
47+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
48+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
49+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
50+
51+
arr[arr.length] = 'value';
52+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
53+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
54+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
55+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
56+
57+
arr[arr.length] = 'value';
58+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
59+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
60+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
61+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
62+
63+
arr[arr.length] = 'value';
64+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
65+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
66+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
67+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
68+
69+
arr[arr.length] = 'value';
70+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
71+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
72+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
73+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
74+
75+
arr[arr.length] = 'value';
76+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
77+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
78+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
79+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
80+
81+
arr[arr.length] = 'value';
82+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
83+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
84+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
85+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
86+
87+
arr[arr.length] = 'value';
88+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
89+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
90+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
91+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
92+
93+
arr[arr.length] = 'value';
94+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
95+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
96+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
97+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
98+
99+
arr[arr.length] = 'value';
100+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
101+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
102+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
103+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
104+
105+
arr[arr.length] = 'value';
106+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
107+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
108+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
109+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
110+
111+
arr[arr.length] = 'value';
112+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
113+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
114+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
115+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
116+
117+
arr[arr.length] = 'value';
118+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
119+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
120+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
121+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
122+
123+
arr[arr.length] = 'value';
124+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
125+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
126+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
127+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
128+
129+
arr[arr.length] = 'value';
130+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
131+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
132+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
133+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
134+
135+
arr[arr.length] = 'value';
136+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
137+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
138+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
139+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
140+
141+
arr[arr.length] = 'value';
142+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
143+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
144+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
145+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
146+
147+
arr[arr.length] = 'value';
148+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
149+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
150+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
151+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
152+
153+
arr[arr.length] = 'value';
154+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
155+
>arr.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
156+
>arr : Symbol(arr, Decl(foo.js, 2, 7))
157+
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
158+
}

0 commit comments

Comments
 (0)