Skip to content

Commit e2c0033

Browse files
authored
Bind RHS of comma expressions too (microsoft#47049)
1 parent 16e96f6 commit e2c0033

5 files changed

+163
-9
lines changed

src/compiler/binder.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,7 +1365,7 @@ namespace ts {
13651365
}
13661366

13671367
function maybeBindExpressionFlowIfCall(node: Expression) {
1368-
// A top level or LHS of comma expression call expression with a dotted function name and at least one argument
1368+
// A top level or comma expression call expression with a dotted function name and at least one argument
13691369
// is potentially an assertion and is therefore included in the control flow.
13701370
if (node.kind === SyntaxKind.CallExpression) {
13711371
const call = node as CallExpression;
@@ -1550,24 +1550,29 @@ namespace ts {
15501550
return state;
15511551
}
15521552

1553-
function onLeft(left: Expression, state: WorkArea, _node: BinaryExpression) {
1553+
function onLeft(left: Expression, state: WorkArea, node: BinaryExpression) {
15541554
if (!state.skip) {
1555-
return maybeBind(left);
1555+
const maybeBound = maybeBind(left);
1556+
if (node.operatorToken.kind === SyntaxKind.CommaToken) {
1557+
maybeBindExpressionFlowIfCall(left);
1558+
}
1559+
return maybeBound;
15561560
}
15571561
}
15581562

1559-
function onOperator(operatorToken: BinaryOperatorToken, state: WorkArea, node: BinaryExpression) {
1563+
function onOperator(operatorToken: BinaryOperatorToken, state: WorkArea, _node: BinaryExpression) {
15601564
if (!state.skip) {
1561-
if (operatorToken.kind === SyntaxKind.CommaToken) {
1562-
maybeBindExpressionFlowIfCall(node.left);
1563-
}
15641565
bind(operatorToken);
15651566
}
15661567
}
15671568

1568-
function onRight(right: Expression, state: WorkArea, _node: BinaryExpression) {
1569+
function onRight(right: Expression, state: WorkArea, node: BinaryExpression) {
15691570
if (!state.skip) {
1570-
return maybeBind(right);
1571+
const maybeBound = maybeBind(right);
1572+
if (node.operatorToken.kind === SyntaxKind.CommaToken) {
1573+
maybeBindExpressionFlowIfCall(right);
1574+
}
1575+
return maybeBound;
15711576
}
15721577
}
15731578

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//// [controlFlowCommaExpressionAssertionMultiple.ts]
2+
function Narrow<T>(value: any): asserts value is T {}
3+
4+
function func(foo: any, bar: any) {
5+
Narrow<number>(foo), Narrow<string>(bar);
6+
foo;
7+
bar;
8+
}
9+
10+
function func2(foo: any, bar: any, baz: any) {
11+
Narrow<number>(foo), Narrow<string>(bar), Narrow<boolean>(baz);
12+
foo;
13+
bar;
14+
baz;
15+
}
16+
17+
18+
//// [controlFlowCommaExpressionAssertionMultiple.js]
19+
function Narrow(value) { }
20+
function func(foo, bar) {
21+
Narrow(foo), Narrow(bar);
22+
foo;
23+
bar;
24+
}
25+
function func2(foo, bar, baz) {
26+
Narrow(foo), Narrow(bar), Narrow(baz);
27+
foo;
28+
bar;
29+
baz;
30+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
=== tests/cases/compiler/controlFlowCommaExpressionAssertionMultiple.ts ===
2+
function Narrow<T>(value: any): asserts value is T {}
3+
>Narrow : Symbol(Narrow, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 0))
4+
>T : Symbol(T, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 16))
5+
>value : Symbol(value, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 19))
6+
>value : Symbol(value, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 19))
7+
>T : Symbol(T, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 16))
8+
9+
function func(foo: any, bar: any) {
10+
>func : Symbol(func, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 53))
11+
>foo : Symbol(foo, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 2, 14))
12+
>bar : Symbol(bar, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 2, 23))
13+
14+
Narrow<number>(foo), Narrow<string>(bar);
15+
>Narrow : Symbol(Narrow, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 0))
16+
>foo : Symbol(foo, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 2, 14))
17+
>Narrow : Symbol(Narrow, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 0))
18+
>bar : Symbol(bar, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 2, 23))
19+
20+
foo;
21+
>foo : Symbol(foo, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 2, 14))
22+
23+
bar;
24+
>bar : Symbol(bar, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 2, 23))
25+
}
26+
27+
function func2(foo: any, bar: any, baz: any) {
28+
>func2 : Symbol(func2, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 6, 1))
29+
>foo : Symbol(foo, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 8, 15))
30+
>bar : Symbol(bar, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 8, 24))
31+
>baz : Symbol(baz, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 8, 34))
32+
33+
Narrow<number>(foo), Narrow<string>(bar), Narrow<boolean>(baz);
34+
>Narrow : Symbol(Narrow, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 0))
35+
>foo : Symbol(foo, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 8, 15))
36+
>Narrow : Symbol(Narrow, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 0))
37+
>bar : Symbol(bar, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 8, 24))
38+
>Narrow : Symbol(Narrow, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 0))
39+
>baz : Symbol(baz, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 8, 34))
40+
41+
foo;
42+
>foo : Symbol(foo, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 8, 15))
43+
44+
bar;
45+
>bar : Symbol(bar, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 8, 24))
46+
47+
baz;
48+
>baz : Symbol(baz, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 8, 34))
49+
}
50+
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
=== tests/cases/compiler/controlFlowCommaExpressionAssertionMultiple.ts ===
2+
function Narrow<T>(value: any): asserts value is T {}
3+
>Narrow : <T>(value: any) => asserts value is T
4+
>value : any
5+
6+
function func(foo: any, bar: any) {
7+
>func : (foo: any, bar: any) => void
8+
>foo : any
9+
>bar : any
10+
11+
Narrow<number>(foo), Narrow<string>(bar);
12+
>Narrow<number>(foo), Narrow<string>(bar) : void
13+
>Narrow<number>(foo) : void
14+
>Narrow : <T>(value: any) => asserts value is T
15+
>foo : any
16+
>Narrow<string>(bar) : void
17+
>Narrow : <T>(value: any) => asserts value is T
18+
>bar : any
19+
20+
foo;
21+
>foo : number
22+
23+
bar;
24+
>bar : string
25+
}
26+
27+
function func2(foo: any, bar: any, baz: any) {
28+
>func2 : (foo: any, bar: any, baz: any) => void
29+
>foo : any
30+
>bar : any
31+
>baz : any
32+
33+
Narrow<number>(foo), Narrow<string>(bar), Narrow<boolean>(baz);
34+
>Narrow<number>(foo), Narrow<string>(bar), Narrow<boolean>(baz) : void
35+
>Narrow<number>(foo), Narrow<string>(bar) : void
36+
>Narrow<number>(foo) : void
37+
>Narrow : <T>(value: any) => asserts value is T
38+
>foo : any
39+
>Narrow<string>(bar) : void
40+
>Narrow : <T>(value: any) => asserts value is T
41+
>bar : any
42+
>Narrow<boolean>(baz) : void
43+
>Narrow : <T>(value: any) => asserts value is T
44+
>baz : any
45+
46+
foo;
47+
>foo : number
48+
49+
bar;
50+
>bar : string
51+
52+
baz;
53+
>baz : boolean
54+
}
55+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
function Narrow<T>(value: any): asserts value is T {}
2+
3+
function func(foo: any, bar: any) {
4+
Narrow<number>(foo), Narrow<string>(bar);
5+
foo;
6+
bar;
7+
}
8+
9+
function func2(foo: any, bar: any, baz: any) {
10+
Narrow<number>(foo), Narrow<string>(bar), Narrow<boolean>(baz);
11+
foo;
12+
bar;
13+
baz;
14+
}

0 commit comments

Comments
 (0)