Skip to content

Commit b92ec99

Browse files
authored
Fixed a crash caused by circularly-reentrant getEffectsSignature (#63026)
1 parent 8a55156 commit b92ec99

9 files changed

+1387
-4
lines changed

src/compiler/binder.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,7 @@ export const enum ContainerFlags {
488488
HasLocals = 1 << 5,
489489
IsInterface = 1 << 6,
490490
IsObjectLiteralOrClassExpressionMethodOrAccessor = 1 << 7,
491+
PropagatesThisKeyword = 1 << 8,
491492
}
492493

493494
/** @internal */
@@ -1055,7 +1056,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void {
10551056
currentExceptionTarget = saveExceptionTarget;
10561057
activeLabelList = saveActiveLabelList;
10571058
hasExplicitReturn = saveHasExplicitReturn;
1058-
seenThisKeyword = node.kind === SyntaxKind.ArrowFunction ? saveSeenThisKeyword || seenThisKeyword : saveSeenThisKeyword;
1059+
seenThisKeyword = containerFlags & ContainerFlags.PropagatesThisKeyword ? saveSeenThisKeyword || seenThisKeyword : saveSeenThisKeyword;
10591060
}
10601061
else if (containerFlags & ContainerFlags.IsInterface) {
10611062
const saveSeenThisKeyword = seenThisKeyword;
@@ -3845,23 +3846,26 @@ export function getContainerFlags(node: Node): ContainerFlags {
38453846
case SyntaxKind.FunctionDeclaration:
38463847
case SyntaxKind.ClassStaticBlockDeclaration:
38473848
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike;
3849+
38483850
case SyntaxKind.MethodSignature:
38493851
case SyntaxKind.CallSignature:
38503852
case SyntaxKind.JSDocSignature:
38513853
case SyntaxKind.JSDocFunctionType:
38523854
case SyntaxKind.FunctionType:
38533855
case SyntaxKind.ConstructSignature:
38543856
case SyntaxKind.ConstructorType:
3855-
return ContainerFlags.IsContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike;
3857+
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike | ContainerFlags.PropagatesThisKeyword;
38563858

38573859
case SyntaxKind.JSDocImportTag:
38583860
// treat as a container to prevent using an enclosing effective host, ensuring import bindings are scoped correctly
3859-
return ContainerFlags.IsContainer | ContainerFlags.HasLocals;
3861+
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.PropagatesThisKeyword;
38603862

38613863
case SyntaxKind.FunctionExpression:
3862-
case SyntaxKind.ArrowFunction:
38633864
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike | ContainerFlags.IsFunctionExpression;
38643865

3866+
case SyntaxKind.ArrowFunction:
3867+
return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike | ContainerFlags.IsFunctionExpression | ContainerFlags.PropagatesThisKeyword;
3868+
38653869
case SyntaxKind.ModuleBlock:
38663870
return ContainerFlags.IsControlFlowContainer;
38673871

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
controlFlowForFunctionLike1.ts(10,12): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
2+
controlFlowForFunctionLike1.ts(31,10): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
3+
4+
5+
==== controlFlowForFunctionLike1.ts (2 errors) ====
6+
function test1(a: number | string) {
7+
if (typeof a === "number") {
8+
const fn = (arg: typeof a) => true;
9+
return fn;
10+
}
11+
return;
12+
}
13+
14+
test1(0)?.(100);
15+
test1(0)?.("");
16+
~~
17+
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
18+
19+
function test2(a: number | string) {
20+
if (typeof a === "number") {
21+
const fn: { (arg: typeof a): boolean; } = () => true;
22+
return fn;
23+
}
24+
return;
25+
}
26+
27+
test2(0)?.(100);
28+
test2(0)?.("");
29+
30+
function test3(a: number | string) {
31+
if (typeof a === "number") {
32+
return (arg: typeof a) => {};
33+
}
34+
throw new Error("");
35+
}
36+
37+
test3(1)(100);
38+
test3(1)("");
39+
~~
40+
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
41+
42+
function test4(a: number | string) {
43+
let fn = (arg: typeof a) => {};
44+
if (Math.random() && typeof a === "number") {
45+
return fn;
46+
}
47+
throw new Error("");
48+
}
49+
50+
test4(1)?.(100);
51+
test4(1)?.("");
52+
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
//// [tests/cases/compiler/controlFlowForFunctionLike1.ts] ////
2+
3+
=== controlFlowForFunctionLike1.ts ===
4+
function test1(a: number | string) {
5+
>test1 : Symbol(test1, Decl(controlFlowForFunctionLike1.ts, 0, 0))
6+
>a : Symbol(a, Decl(controlFlowForFunctionLike1.ts, 0, 15))
7+
8+
if (typeof a === "number") {
9+
>a : Symbol(a, Decl(controlFlowForFunctionLike1.ts, 0, 15))
10+
11+
const fn = (arg: typeof a) => true;
12+
>fn : Symbol(fn, Decl(controlFlowForFunctionLike1.ts, 2, 9))
13+
>arg : Symbol(arg, Decl(controlFlowForFunctionLike1.ts, 2, 16))
14+
>a : Symbol(a, Decl(controlFlowForFunctionLike1.ts, 0, 15))
15+
16+
return fn;
17+
>fn : Symbol(fn, Decl(controlFlowForFunctionLike1.ts, 2, 9))
18+
}
19+
return;
20+
}
21+
22+
test1(0)?.(100);
23+
>test1 : Symbol(test1, Decl(controlFlowForFunctionLike1.ts, 0, 0))
24+
25+
test1(0)?.("");
26+
>test1 : Symbol(test1, Decl(controlFlowForFunctionLike1.ts, 0, 0))
27+
28+
function test2(a: number | string) {
29+
>test2 : Symbol(test2, Decl(controlFlowForFunctionLike1.ts, 9, 15))
30+
>a : Symbol(a, Decl(controlFlowForFunctionLike1.ts, 11, 15))
31+
32+
if (typeof a === "number") {
33+
>a : Symbol(a, Decl(controlFlowForFunctionLike1.ts, 11, 15))
34+
35+
const fn: { (arg: typeof a): boolean; } = () => true;
36+
>fn : Symbol(fn, Decl(controlFlowForFunctionLike1.ts, 13, 9))
37+
>arg : Symbol(arg, Decl(controlFlowForFunctionLike1.ts, 13, 17))
38+
>a : Symbol(a, Decl(controlFlowForFunctionLike1.ts, 11, 15))
39+
40+
return fn;
41+
>fn : Symbol(fn, Decl(controlFlowForFunctionLike1.ts, 13, 9))
42+
}
43+
return;
44+
}
45+
46+
test2(0)?.(100);
47+
>test2 : Symbol(test2, Decl(controlFlowForFunctionLike1.ts, 9, 15))
48+
49+
test2(0)?.("");
50+
>test2 : Symbol(test2, Decl(controlFlowForFunctionLike1.ts, 9, 15))
51+
52+
function test3(a: number | string) {
53+
>test3 : Symbol(test3, Decl(controlFlowForFunctionLike1.ts, 20, 15))
54+
>a : Symbol(a, Decl(controlFlowForFunctionLike1.ts, 22, 15))
55+
56+
if (typeof a === "number") {
57+
>a : Symbol(a, Decl(controlFlowForFunctionLike1.ts, 22, 15))
58+
59+
return (arg: typeof a) => {};
60+
>arg : Symbol(arg, Decl(controlFlowForFunctionLike1.ts, 24, 12))
61+
>a : Symbol(a, Decl(controlFlowForFunctionLike1.ts, 22, 15))
62+
}
63+
throw new Error("");
64+
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2022.error.d.ts, --, --))
65+
}
66+
67+
test3(1)(100);
68+
>test3 : Symbol(test3, Decl(controlFlowForFunctionLike1.ts, 20, 15))
69+
70+
test3(1)("");
71+
>test3 : Symbol(test3, Decl(controlFlowForFunctionLike1.ts, 20, 15))
72+
73+
function test4(a: number | string) {
74+
>test4 : Symbol(test4, Decl(controlFlowForFunctionLike1.ts, 30, 13))
75+
>a : Symbol(a, Decl(controlFlowForFunctionLike1.ts, 32, 15))
76+
77+
let fn = (arg: typeof a) => {};
78+
>fn : Symbol(fn, Decl(controlFlowForFunctionLike1.ts, 33, 5))
79+
>arg : Symbol(arg, Decl(controlFlowForFunctionLike1.ts, 33, 12))
80+
>a : Symbol(a, Decl(controlFlowForFunctionLike1.ts, 32, 15))
81+
82+
if (Math.random() && typeof a === "number") {
83+
>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
84+
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
85+
>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
86+
>a : Symbol(a, Decl(controlFlowForFunctionLike1.ts, 32, 15))
87+
88+
return fn;
89+
>fn : Symbol(fn, Decl(controlFlowForFunctionLike1.ts, 33, 5))
90+
}
91+
throw new Error("");
92+
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2022.error.d.ts, --, --))
93+
}
94+
95+
test4(1)?.(100);
96+
>test4 : Symbol(test4, Decl(controlFlowForFunctionLike1.ts, 30, 13))
97+
98+
test4(1)?.("");
99+
>test4 : Symbol(test4, Decl(controlFlowForFunctionLike1.ts, 30, 13))
100+

0 commit comments

Comments
 (0)