Skip to content

Commit f8812c9

Browse files
committed
Add cfa
1 parent 5bcfafa commit f8812c9

File tree

53 files changed

+2510
-4
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+2510
-4
lines changed

src/compiler/binder.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1051,6 +1051,17 @@ namespace ts {
10511051
}
10521052
}
10531053

1054+
function isLogicalAssignmentExpressioin(node: Node) {
1055+
while (true) {
1056+
if (isParenthesizedExpression(node)) {
1057+
node = node.expression
1058+
}
1059+
else {
1060+
return isBinaryExpression(node) && isLogicalAssignmentOperator(node.operatorToken.kind);
1061+
}
1062+
}
1063+
}
1064+
10541065
function isTopLevelLogicalExpression(node: Node): boolean {
10551066
while (isParenthesizedExpression(node.parent) ||
10561067
isPrefixUnaryExpression(node.parent) && node.parent.operator === SyntaxKind.ExclamationToken) {
@@ -1073,7 +1084,7 @@ namespace ts {
10731084

10741085
function bindCondition(node: Expression | undefined, trueTarget: FlowLabel, falseTarget: FlowLabel) {
10751086
doWithConditionalBranches(bind, node, trueTarget, falseTarget);
1076-
if (!node || !isLogicalExpression(node) && !(isOptionalChain(node) && isOutermostOptionalChain(node))) {
1087+
if (!node || !isLogicalAssignmentExpressioin(node) && !isLogicalExpression(node) && !(isOptionalChain(node) && isOutermostOptionalChain(node))) {
10771088
addAntecedent(trueTarget, createFlowCondition(FlowFlags.TrueCondition, currentFlow, node));
10781089
addAntecedent(falseTarget, createFlowCondition(FlowFlags.FalseCondition, currentFlow, node));
10791090
}
@@ -1173,6 +1184,25 @@ namespace ts {
11731184
currentFlow = finishFlowLabel(postIfLabel);
11741185
}
11751186

1187+
function bindLogicalAssignmentExpression(node: BinaryExpression) {
1188+
const preRightLabel = createBranchLabel();
1189+
const postExpressionLabel = createBranchLabel();
1190+
1191+
if (node.operatorToken.kind === SyntaxKind.AmpersandAmpersandEqualsToken) {
1192+
bindCondition(node.left, preRightLabel, postExpressionLabel);
1193+
}
1194+
else {
1195+
bindCondition(node.left, postExpressionLabel, preRightLabel);
1196+
}
1197+
1198+
currentFlow = finishFlowLabel(preRightLabel);
1199+
bind(node.operatorToken);
1200+
bind(node.right);
1201+
bindAssignmentTargetFlow(node.left);
1202+
1203+
currentFlow = finishFlowLabel(postExpressionLabel);
1204+
}
1205+
11761206
function bindReturnOrThrow(node: ReturnStatement | ThrowStatement): void {
11771207
bind(node.expression);
11781208
if (node.kind === SyntaxKind.ReturnStatement) {
@@ -1460,6 +1490,10 @@ namespace ts {
14601490
}
14611491

14621492
function bindBinaryExpressionFlow(node: BinaryExpression) {
1493+
const flow = currentFlow
1494+
if (flow) {
1495+
1496+
}
14631497
const workStacks: {
14641498
expr: BinaryExpression[],
14651499
state: BindBinaryExpressionFlowState[],
@@ -1521,6 +1555,10 @@ namespace ts {
15211555
}
15221556
completeNode();
15231557
}
1558+
else if(isLogicalAssignmentOperator(operator)) {
1559+
bindLogicalAssignmentExpression(node);
1560+
completeNode();
1561+
}
15241562
else {
15251563
advanceState(BindBinaryExpressionFlowState.BindToken);
15261564
maybeBind(node.left);
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts(25,21): error TS2532: Object is possibly 'undefined'.
2+
3+
4+
==== tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts (1 errors) ====
5+
function foo1(results: number[] | undefined) {
6+
(results ||= []).push(100);
7+
}
8+
9+
function foo2(results: number[] | undefined) {
10+
(results ??= []).push(100);
11+
}
12+
13+
function foo3(results: number[] | undefined) {
14+
results ||= [];
15+
results.push(100);
16+
}
17+
18+
function foo4(results: number[] | undefined) {
19+
results ||= [];
20+
results.push(100);
21+
}
22+
23+
interface ThingWithOriginal {
24+
name: string;
25+
original?: ThingWithOriginal
26+
}
27+
function doSomethingWithAlias(thing?: ThingWithOriginal | undefined) {
28+
if (thing &&= thing.original) {
29+
console.log(thing.name);
30+
~~~~~
31+
!!! error TS2532: Object is possibly 'undefined'.
32+
}
33+
}

tests/baselines/reference/logicalAssignment4(target=es2015).js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,26 @@ function foo1(results: number[] | undefined) {
55

66
function foo2(results: number[] | undefined) {
77
(results ??= []).push(100);
8+
}
9+
10+
function foo3(results: number[] | undefined) {
11+
results ||= [];
12+
results.push(100);
13+
}
14+
15+
function foo4(results: number[] | undefined) {
16+
results ||= [];
17+
results.push(100);
18+
}
19+
20+
interface ThingWithOriginal {
21+
name: string;
22+
original?: ThingWithOriginal
23+
}
24+
function doSomethingWithAlias(thing?: ThingWithOriginal | undefined) {
25+
if (thing &&= thing.original) {
26+
console.log(thing.name);
27+
}
828
}
929

1030
//// [logicalAssignment4.js]
@@ -15,3 +35,16 @@ function foo1(results) {
1535
function foo2(results) {
1636
(results !== null && results !== void 0 ? results : (results = [])).push(100);
1737
}
38+
function foo3(results) {
39+
results || (results = []);
40+
results.push(100);
41+
}
42+
function foo4(results) {
43+
results || (results = []);
44+
results.push(100);
45+
}
46+
function doSomethingWithAlias(thing) {
47+
if (thing && (thing = thing.original)) {
48+
console.log(thing.name);
49+
}
50+
}

tests/baselines/reference/logicalAssignment4(target=es2015).symbols

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,60 @@ function foo2(results: number[] | undefined) {
1818
>results : Symbol(results, Decl(logicalAssignment4.ts, 4, 14))
1919
>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
2020
}
21+
22+
function foo3(results: number[] | undefined) {
23+
>foo3 : Symbol(foo3, Decl(logicalAssignment4.ts, 6, 1))
24+
>results : Symbol(results, Decl(logicalAssignment4.ts, 8, 14))
25+
26+
results ||= [];
27+
>results : Symbol(results, Decl(logicalAssignment4.ts, 8, 14))
28+
29+
results.push(100);
30+
>results.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
31+
>results : Symbol(results, Decl(logicalAssignment4.ts, 8, 14))
32+
>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
33+
}
34+
35+
function foo4(results: number[] | undefined) {
36+
>foo4 : Symbol(foo4, Decl(logicalAssignment4.ts, 11, 1))
37+
>results : Symbol(results, Decl(logicalAssignment4.ts, 13, 14))
38+
39+
results ||= [];
40+
>results : Symbol(results, Decl(logicalAssignment4.ts, 13, 14))
41+
42+
results.push(100);
43+
>results.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
44+
>results : Symbol(results, Decl(logicalAssignment4.ts, 13, 14))
45+
>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
46+
}
47+
48+
interface ThingWithOriginal {
49+
>ThingWithOriginal : Symbol(ThingWithOriginal, Decl(logicalAssignment4.ts, 16, 1))
50+
51+
name: string;
52+
>name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29))
53+
54+
original?: ThingWithOriginal
55+
>original : Symbol(ThingWithOriginal.original, Decl(logicalAssignment4.ts, 19, 17))
56+
>ThingWithOriginal : Symbol(ThingWithOriginal, Decl(logicalAssignment4.ts, 16, 1))
57+
}
58+
function doSomethingWithAlias(thing?: ThingWithOriginal | undefined) {
59+
>doSomethingWithAlias : Symbol(doSomethingWithAlias, Decl(logicalAssignment4.ts, 21, 1))
60+
>thing : Symbol(thing, Decl(logicalAssignment4.ts, 22, 30))
61+
>ThingWithOriginal : Symbol(ThingWithOriginal, Decl(logicalAssignment4.ts, 16, 1))
62+
63+
if (thing &&= thing.original) {
64+
>thing : Symbol(thing, Decl(logicalAssignment4.ts, 22, 30))
65+
>thing.original : Symbol(ThingWithOriginal.original, Decl(logicalAssignment4.ts, 19, 17))
66+
>thing : Symbol(thing, Decl(logicalAssignment4.ts, 22, 30))
67+
>original : Symbol(ThingWithOriginal.original, Decl(logicalAssignment4.ts, 19, 17))
68+
69+
console.log(thing.name);
70+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
71+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
72+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
73+
>thing.name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29))
74+
>thing : Symbol(thing, Decl(logicalAssignment4.ts, 22, 30))
75+
>name : Symbol(ThingWithOriginal.name, Decl(logicalAssignment4.ts, 18, 29))
76+
}
77+
}

tests/baselines/reference/logicalAssignment4(target=es2015).types

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,66 @@ function foo2(results: number[] | undefined) {
2828
>push : (...items: number[]) => number
2929
>100 : 100
3030
}
31+
32+
function foo3(results: number[] | undefined) {
33+
>foo3 : (results: number[] | undefined) => void
34+
>results : number[] | undefined
35+
36+
results ||= [];
37+
>results ||= [] : number[]
38+
>results : number[] | undefined
39+
>[] : never[]
40+
41+
results.push(100);
42+
>results.push(100) : number
43+
>results.push : (...items: number[]) => number
44+
>results : number[]
45+
>push : (...items: number[]) => number
46+
>100 : 100
47+
}
48+
49+
function foo4(results: number[] | undefined) {
50+
>foo4 : (results: number[] | undefined) => void
51+
>results : number[] | undefined
52+
53+
results ||= [];
54+
>results ||= [] : number[]
55+
>results : number[] | undefined
56+
>[] : never[]
57+
58+
results.push(100);
59+
>results.push(100) : number
60+
>results.push : (...items: number[]) => number
61+
>results : number[]
62+
>push : (...items: number[]) => number
63+
>100 : 100
64+
}
65+
66+
interface ThingWithOriginal {
67+
name: string;
68+
>name : string
69+
70+
original?: ThingWithOriginal
71+
>original : ThingWithOriginal | undefined
72+
}
73+
function doSomethingWithAlias(thing?: ThingWithOriginal | undefined) {
74+
>doSomethingWithAlias : (thing?: ThingWithOriginal | undefined) => void
75+
>thing : ThingWithOriginal | undefined
76+
77+
if (thing &&= thing.original) {
78+
>thing &&= thing.original : ThingWithOriginal | undefined
79+
>thing : ThingWithOriginal | undefined
80+
>thing.original : ThingWithOriginal | undefined
81+
>thing : ThingWithOriginal
82+
>original : ThingWithOriginal | undefined
83+
84+
console.log(thing.name);
85+
>console.log(thing.name) : void
86+
>console.log : (...data: any[]) => void
87+
>console : Console
88+
>log : (...data: any[]) => void
89+
>thing.name : string
90+
>thing : ThingWithOriginal | undefined
91+
>name : string
92+
}
93+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts(25,21): error TS2532: Object is possibly 'undefined'.
2+
3+
4+
==== tests/cases/conformance/esnext/logicalAssignment/logicalAssignment4.ts (1 errors) ====
5+
function foo1(results: number[] | undefined) {
6+
(results ||= []).push(100);
7+
}
8+
9+
function foo2(results: number[] | undefined) {
10+
(results ??= []).push(100);
11+
}
12+
13+
function foo3(results: number[] | undefined) {
14+
results ||= [];
15+
results.push(100);
16+
}
17+
18+
function foo4(results: number[] | undefined) {
19+
results ||= [];
20+
results.push(100);
21+
}
22+
23+
interface ThingWithOriginal {
24+
name: string;
25+
original?: ThingWithOriginal
26+
}
27+
function doSomethingWithAlias(thing?: ThingWithOriginal | undefined) {
28+
if (thing &&= thing.original) {
29+
console.log(thing.name);
30+
~~~~~
31+
!!! error TS2532: Object is possibly 'undefined'.
32+
}
33+
}

tests/baselines/reference/logicalAssignment4(target=es2020).js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,26 @@ function foo1(results: number[] | undefined) {
55

66
function foo2(results: number[] | undefined) {
77
(results ??= []).push(100);
8+
}
9+
10+
function foo3(results: number[] | undefined) {
11+
results ||= [];
12+
results.push(100);
13+
}
14+
15+
function foo4(results: number[] | undefined) {
16+
results ||= [];
17+
results.push(100);
18+
}
19+
20+
interface ThingWithOriginal {
21+
name: string;
22+
original?: ThingWithOriginal
23+
}
24+
function doSomethingWithAlias(thing?: ThingWithOriginal | undefined) {
25+
if (thing &&= thing.original) {
26+
console.log(thing.name);
27+
}
828
}
929

1030
//// [logicalAssignment4.js]
@@ -15,3 +35,16 @@ function foo1(results) {
1535
function foo2(results) {
1636
(results ?? (results = [])).push(100);
1737
}
38+
function foo3(results) {
39+
results || (results = []);
40+
results.push(100);
41+
}
42+
function foo4(results) {
43+
results || (results = []);
44+
results.push(100);
45+
}
46+
function doSomethingWithAlias(thing) {
47+
if (thing && (thing = thing.original)) {
48+
console.log(thing.name);
49+
}
50+
}

0 commit comments

Comments
 (0)