From 7d6f983185b8e2c1d7fca524ec2be69420447fc5 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 6 Dec 2021 16:33:15 -0800 Subject: [PATCH 1/5] Add test for initial behavior --- ...rolFlowCommaExpressionAssertionMultiple.js | 17 ++++++++++++ ...owCommaExpressionAssertionMultiple.symbols | 26 +++++++++++++++++++ ...FlowCommaExpressionAssertionMultiple.types | 26 +++++++++++++++++++ ...rolFlowCommaExpressionAssertionMultiple.ts | 7 +++++ 4 files changed, 76 insertions(+) create mode 100644 tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.js create mode 100644 tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.symbols create mode 100644 tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.types create mode 100644 tests/cases/compiler/controlFlowCommaExpressionAssertionMultiple.ts diff --git a/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.js b/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.js new file mode 100644 index 0000000000000..02ca48f98a562 --- /dev/null +++ b/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.js @@ -0,0 +1,17 @@ +//// [controlFlowCommaExpressionAssertionMultiple.ts] +function Narrow(value: any): asserts value is T {} + +function func(foo: any, bar: any) { + Narrow(foo), Narrow(bar); + foo; + bar; +} + + +//// [controlFlowCommaExpressionAssertionMultiple.js] +function Narrow(value) { } +function func(foo, bar) { + Narrow(foo), Narrow(bar); + foo; + bar; +} diff --git a/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.symbols b/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.symbols new file mode 100644 index 0000000000000..a5bd0ce88c205 --- /dev/null +++ b/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.symbols @@ -0,0 +1,26 @@ +=== 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)) +} + diff --git a/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.types b/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.types new file mode 100644 index 0000000000000..b142c72576b65 --- /dev/null +++ b/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.types @@ -0,0 +1,26 @@ +=== 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 : any +} + diff --git a/tests/cases/compiler/controlFlowCommaExpressionAssertionMultiple.ts b/tests/cases/compiler/controlFlowCommaExpressionAssertionMultiple.ts new file mode 100644 index 0000000000000..3892d8f89b9d6 --- /dev/null +++ b/tests/cases/compiler/controlFlowCommaExpressionAssertionMultiple.ts @@ -0,0 +1,7 @@ +function Narrow(value: any): asserts value is T {} + +function func(foo: any, bar: any) { + Narrow(foo), Narrow(bar); + foo; + bar; +} From 6c9ec85f9bc0cee062a420a93cae2bebd5639c87 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 6 Dec 2021 16:52:37 -0800 Subject: [PATCH 2/5] Apply previous comma fix to right side of comma expression --- src/compiler/binder.ts | 5 +++++ .../controlFlowCommaExpressionAssertionMultiple.types | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index eefc41fdaf8b5..f744e85cc7373 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1574,6 +1574,11 @@ namespace ts { function onExit(node: BinaryExpression, state: WorkArea) { if (!state.skip) { const operator = node.operatorToken.kind; + + if (operator === SyntaxKind.CommaToken) { + maybeBindExpressionFlowIfCall(node.right); + } + if (isAssignmentOperator(operator) && !isAssignmentTarget(node)) { bindAssignmentTargetFlow(node.left); if (operator === SyntaxKind.EqualsToken && node.left.kind === SyntaxKind.ElementAccessExpression) { diff --git a/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.types b/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.types index b142c72576b65..3a34a21bfa849 100644 --- a/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.types +++ b/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.types @@ -21,6 +21,6 @@ function func(foo: any, bar: any) { >foo : number bar; ->bar : any +>bar : string } From 0fe65fd0939bdedc5063d8872b508ed7f78b15c6 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 6 Dec 2021 16:53:35 -0800 Subject: [PATCH 3/5] Test multiple commas --- ...rolFlowCommaExpressionAssertionMultiple.js | 13 +++++++++ ...owCommaExpressionAssertionMultiple.symbols | 24 +++++++++++++++ ...FlowCommaExpressionAssertionMultiple.types | 29 +++++++++++++++++++ ...rolFlowCommaExpressionAssertionMultiple.ts | 7 +++++ 4 files changed, 73 insertions(+) diff --git a/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.js b/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.js index 02ca48f98a562..0a60d98a46b2c 100644 --- a/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.js +++ b/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.js @@ -6,6 +6,13 @@ function func(foo: any, bar: any) { foo; bar; } + +function func2(foo: any, bar: any, baz: any) { + Narrow(foo), Narrow(bar), Narrow(baz); + foo; + bar; + baz; +} //// [controlFlowCommaExpressionAssertionMultiple.js] @@ -15,3 +22,9 @@ function func(foo, 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 index a5bd0ce88c205..d95ac53dd5e8e 100644 --- a/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.symbols +++ b/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.symbols @@ -24,3 +24,27 @@ function func(foo: any, bar: any) { >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 index 3a34a21bfa849..8010e69acd79d 100644 --- a/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.types +++ b/tests/baselines/reference/controlFlowCommaExpressionAssertionMultiple.types @@ -24,3 +24,32 @@ function func(foo: any, bar: any) { >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 index 3892d8f89b9d6..8e4d1459bcfd6 100644 --- a/tests/cases/compiler/controlFlowCommaExpressionAssertionMultiple.ts +++ b/tests/cases/compiler/controlFlowCommaExpressionAssertionMultiple.ts @@ -5,3 +5,10 @@ function func(foo: any, bar: any) { foo; bar; } + +function func2(foo: any, bar: any, baz: any) { + Narrow(foo), Narrow(bar), Narrow(baz); + foo; + bar; + baz; +} From 5be259448bd9ad4e915cb8d8b628806cac229fc6 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Mon, 6 Dec 2021 17:09:41 -0800 Subject: [PATCH 4/5] Remove LHS wording from comment --- src/compiler/binder.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index f744e85cc7373..197078b1c5065 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; From 6a1fa03d40288a2a82f7bcb05008099861d3d1f5 Mon Sep 17 00:00:00 2001 From: Jake Bailey <5341706+jakebailey@users.noreply.github.com> Date: Tue, 7 Dec 2021 13:49:41 -0800 Subject: [PATCH 5/5] Move maybeBindExpressionFlowIfCall into onLeft and onRight --- src/compiler/binder.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 197078b1c5065..24e8b96d6302c 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1550,35 +1550,35 @@ 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; } } function onExit(node: BinaryExpression, state: WorkArea) { if (!state.skip) { const operator = node.operatorToken.kind; - - if (operator === SyntaxKind.CommaToken) { - maybeBindExpressionFlowIfCall(node.right); - } - if (isAssignmentOperator(operator) && !isAssignmentTarget(node)) { bindAssignmentTargetFlow(node.left); if (operator === SyntaxKind.EqualsToken && node.left.kind === SyntaxKind.ElementAccessExpression) {