diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index eefc41fdaf8b5..24e8b96d6302c 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1365,7 +1365,7 @@ namespace ts { } function maybeBindExpressionFlowIfCall(node: Expression) { - // A top level or LHS of comma expression call expression with a dotted function name and at least one argument + // A top level or comma expression call expression with a dotted function name and at least one argument // is potentially an assertion and is therefore included in the control flow. if (node.kind === SyntaxKind.CallExpression) { const call = node as CallExpression; @@ -1550,24 +1550,29 @@ namespace ts { return state; } - function onLeft(left: Expression, state: WorkArea, _node: BinaryExpression) { + function onLeft(left: Expression, state: WorkArea, node: BinaryExpression) { if (!state.skip) { - return maybeBind(left); + const maybeBound = maybeBind(left); + if (node.operatorToken.kind === SyntaxKind.CommaToken) { + maybeBindExpressionFlowIfCall(left); + } + return maybeBound; } } - function onOperator(operatorToken: BinaryOperatorToken, state: WorkArea, node: BinaryExpression) { + function onOperator(operatorToken: BinaryOperatorToken, state: WorkArea, _node: BinaryExpression) { if (!state.skip) { - if (operatorToken.kind === SyntaxKind.CommaToken) { - maybeBindExpressionFlowIfCall(node.left); - } bind(operatorToken); } } - function onRight(right: Expression, state: WorkArea, _node: BinaryExpression) { + function onRight(right: Expression, state: WorkArea, node: BinaryExpression) { if (!state.skip) { - return maybeBind(right); + const maybeBound = maybeBind(right); + if (node.operatorToken.kind === SyntaxKind.CommaToken) { + maybeBindExpressionFlowIfCall(right); + } + return maybeBound; } } diff --git a/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.js b/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.js new file mode 100644 index 0000000000000..0a60d98a46b2c --- /dev/null +++ b/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.js @@ -0,0 +1,30 @@ +//// [controlFlowCommaExpressionAssertionMultiple.ts] +function Narrow(value: any): asserts value is T {} + +function func(foo: any, bar: any) { + Narrow(foo), Narrow(bar); + foo; + bar; +} + +function func2(foo: any, bar: any, baz: any) { + Narrow(foo), Narrow(bar), Narrow(baz); + foo; + bar; + baz; +} + + +//// [controlFlowCommaExpressionAssertionMultiple.js] +function Narrow(value) { } +function func(foo, bar) { + Narrow(foo), Narrow(bar); + foo; + bar; +} +function func2(foo, bar, baz) { + Narrow(foo), Narrow(bar), Narrow(baz); + foo; + bar; + baz; +} diff --git a/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.symbols b/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.symbols new file mode 100644 index 0000000000000..d95ac53dd5e8e --- /dev/null +++ b/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.symbols @@ -0,0 +1,50 @@ +=== tests/cases/compiler/controlFlowCommaExpressionAssertionMultiple.ts === +function Narrow(value: any): asserts value is T {} +>Narrow : Symbol(Narrow, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 0)) +>T : Symbol(T, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 16)) +>value : Symbol(value, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 19)) +>value : Symbol(value, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 19)) +>T : Symbol(T, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 16)) + +function func(foo: any, bar: any) { +>func : Symbol(func, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 53)) +>foo : Symbol(foo, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 2, 14)) +>bar : Symbol(bar, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 2, 23)) + + Narrow(foo), Narrow(bar); +>Narrow : Symbol(Narrow, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 0)) +>foo : Symbol(foo, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 2, 14)) +>Narrow : Symbol(Narrow, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 0)) +>bar : Symbol(bar, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 2, 23)) + + foo; +>foo : Symbol(foo, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 2, 14)) + + bar; +>bar : Symbol(bar, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 2, 23)) +} + +function func2(foo: any, bar: any, baz: any) { +>func2 : Symbol(func2, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 6, 1)) +>foo : Symbol(foo, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 8, 15)) +>bar : Symbol(bar, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 8, 24)) +>baz : Symbol(baz, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 8, 34)) + + Narrow(foo), Narrow(bar), Narrow(baz); +>Narrow : Symbol(Narrow, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 0)) +>foo : Symbol(foo, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 8, 15)) +>Narrow : Symbol(Narrow, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 0)) +>bar : Symbol(bar, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 8, 24)) +>Narrow : Symbol(Narrow, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 0, 0)) +>baz : Symbol(baz, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 8, 34)) + + foo; +>foo : Symbol(foo, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 8, 15)) + + bar; +>bar : Symbol(bar, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 8, 24)) + + baz; +>baz : Symbol(baz, Decl(controlFlowCommaExpressionAssertionMultiple.ts, 8, 34)) +} + diff --git a/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.types b/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.types new file mode 100644 index 0000000000000..8010e69acd79d --- /dev/null +++ b/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.types @@ -0,0 +1,55 @@ +=== tests/cases/compiler/controlFlowCommaExpressionAssertionMultiple.ts === +function Narrow(value: any): asserts value is T {} +>Narrow : (value: any) => asserts value is T +>value : any + +function func(foo: any, bar: any) { +>func : (foo: any, bar: any) => void +>foo : any +>bar : any + + Narrow(foo), Narrow(bar); +>Narrow(foo), Narrow(bar) : void +>Narrow(foo) : void +>Narrow : (value: any) => asserts value is T +>foo : any +>Narrow(bar) : void +>Narrow : (value: any) => asserts value is T +>bar : any + + foo; +>foo : number + + bar; +>bar : string +} + +function func2(foo: any, bar: any, baz: any) { +>func2 : (foo: any, bar: any, baz: any) => void +>foo : any +>bar : any +>baz : any + + Narrow(foo), Narrow(bar), Narrow(baz); +>Narrow(foo), Narrow(bar), Narrow(baz) : void +>Narrow(foo), Narrow(bar) : void +>Narrow(foo) : void +>Narrow : (value: any) => asserts value is T +>foo : any +>Narrow(bar) : void +>Narrow : (value: any) => asserts value is T +>bar : any +>Narrow(baz) : void +>Narrow : (value: any) => asserts value is T +>baz : any + + foo; +>foo : number + + bar; +>bar : string + + baz; +>baz : boolean +} + diff --git a/tests/cases/compiler/controlFlowCommaExpressionAssertionMultiple.ts b/tests/cases/compiler/controlFlowCommaExpressionAssertionMultiple.ts new file mode 100644 index 0000000000000..8e4d1459bcfd6 --- /dev/null +++ b/tests/cases/compiler/controlFlowCommaExpressionAssertionMultiple.ts @@ -0,0 +1,14 @@ +function Narrow(value: any): asserts value is T {} + +function func(foo: any, bar: any) { + Narrow(foo), Narrow(bar); + foo; + bar; +} + +function func2(foo: any, bar: any, baz: any) { + Narrow(foo), Narrow(bar), Narrow(baz); + foo; + bar; + baz; +}