Skip to content

Commit 8202200

Browse files
authored
Port evolving array type stack/oom fix to release-3.0 (#26620)
* Use context free expression types in evolving array checking and cache context free type (#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 * Add missing declaration
1 parent 9cb03bd commit 8202200

8 files changed

+6278
-4
lines changed

src/compiler/checker.ts

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

1414714147
function getTypeAtFlowNode(flow: FlowNode): FlowType {
14148-
if (flowDepth === 2500) {
14149-
// We have made 2500 recursive invocations. To avoid overflowing the call stack we report an error
14148+
if (flowDepth === 2000) {
14149+
// We have made 2000 recursive invocations. To avoid overflowing the call stack we report an error
1415014150
// and disable further control flow analysis in the containing function or module body.
1415114151
flowAnalysisDisabled = true;
1415214152
reportFlowControlError(reference);
@@ -14283,7 +14283,8 @@ namespace ts {
1428314283
}
1428414284
}
1428514285
else {
14286-
const indexType = getTypeOfExpression((<ElementAccessExpression>node.left).argumentExpression);
14286+
// 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)
14287+
const indexType = getContextFreeTypeOfExpression((<ElementAccessExpression>node.left).argumentExpression);
1428714288
if (isTypeAssignableToKind(indexType, TypeFlags.NumberLike)) {
1428814289
evolvedType = addEvolvingArrayElementType(evolvedType, node.right);
1428914290
}
@@ -21619,9 +21620,13 @@ namespace ts {
2161921620
* It sets the contextual type of the node to any before calling getTypeOfExpression.
2162021621
*/
2162121622
function getContextFreeTypeOfExpression(node: Expression) {
21623+
const links = getNodeLinks(node);
21624+
if (links.contextFreeType) {
21625+
return links.contextFreeType;
21626+
}
2162221627
const saveContextualType = node.contextualType;
2162321628
node.contextualType = anyType;
21624-
const type = getTypeOfExpression(node);
21629+
const type = links.contextFreeType = checkExpression(node, CheckMode.SkipContextSensitive);
2162521630
node.contextualType = saveContextualType;
2162621631
return type;
2162721632
}

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3642,6 +3642,7 @@ namespace ts {
36423642
superCall?: SuperCall; // Cached first super-call found in the constructor. Used in checking whether super is called before this-accessing
36433643
switchTypes?: Type[]; // Cached array of switch case expression types
36443644
jsxNamespace?: Symbol | false; // Resolved jsx namespace symbol for this node
3645+
contextFreeType?: Type; // Cached context-free type used by the first pass of inference; used when a function's return is partially contextually sensitive
36453646
}
36463647

36473648
export const enum TypeFlags {
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)