Skip to content

Commit d8d5daf

Browse files
committed
Merge pull request #8566 from Microsoft/controlFlowDeleteOperator
Include delete operator in control flow analysis
2 parents cd11d3d + fb2607c commit d8d5daf

File tree

6 files changed

+215
-0
lines changed

6 files changed

+215
-0
lines changed

src/compiler/binder.ts

+10
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,9 @@ namespace ts {
580580
case SyntaxKind.BinaryExpression:
581581
bindBinaryExpressionFlow(<BinaryExpression>node);
582582
break;
583+
case SyntaxKind.DeleteExpression:
584+
bindDeleteExpressionFlow(<DeleteExpression>node);
585+
break;
583586
case SyntaxKind.ConditionalExpression:
584587
bindConditionalExpressionFlow(<ConditionalExpression>node);
585588
break;
@@ -1055,6 +1058,13 @@ namespace ts {
10551058
}
10561059
}
10571060

1061+
function bindDeleteExpressionFlow(node: DeleteExpression) {
1062+
forEachChild(node, bind);
1063+
if (node.expression.kind === SyntaxKind.PropertyAccessExpression) {
1064+
bindAssignmentTargetFlow(node.expression);
1065+
}
1066+
}
1067+
10581068
function bindConditionalExpressionFlow(node: ConditionalExpression) {
10591069
const trueLabel = createBranchLabel();
10601070
const falseLabel = createBranchLabel();

src/compiler/checker.ts

+2
Original file line numberDiff line numberDiff line change
@@ -7563,6 +7563,8 @@ namespace ts {
75637563
return checkRightHandSideOfForOf((<ForOfStatement>parent).expression) || unknownType;
75647564
case SyntaxKind.BinaryExpression:
75657565
return getAssignedTypeOfBinaryExpression(<BinaryExpression>parent);
7566+
case SyntaxKind.DeleteExpression:
7567+
return undefinedType;
75667568
case SyntaxKind.ArrayLiteralExpression:
75677569
return getAssignedTypeOfArrayLiteralElement(<ArrayLiteralExpression>parent, node);
75687570
case SyntaxKind.SpreadElementExpression:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//// [controlFlowDeleteOperator.ts]
2+
3+
function f() {
4+
let x: { a?: number | string, b: number | string } = { b: 1 };
5+
x.a;
6+
x.b;
7+
x.a = 1;
8+
x.b = 1;
9+
x.a;
10+
x.b;
11+
delete x.a;
12+
delete x.b;
13+
x.a;
14+
x.b;
15+
x;
16+
delete x; // No effect
17+
x;
18+
}
19+
20+
//// [controlFlowDeleteOperator.js]
21+
function f() {
22+
var x = { b: 1 };
23+
x.a;
24+
x.b;
25+
x.a = 1;
26+
x.b = 1;
27+
x.a;
28+
x.b;
29+
delete x.a;
30+
delete x.b;
31+
x.a;
32+
x.b;
33+
x;
34+
delete x; // No effect
35+
x;
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
=== tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts ===
2+
3+
function f() {
4+
>f : Symbol(f, Decl(controlFlowDeleteOperator.ts, 0, 0))
5+
6+
let x: { a?: number | string, b: number | string } = { b: 1 };
7+
>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7))
8+
>a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12))
9+
>b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33))
10+
>b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 58))
11+
12+
x.a;
13+
>x.a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12))
14+
>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7))
15+
>a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12))
16+
17+
x.b;
18+
>x.b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33))
19+
>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7))
20+
>b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33))
21+
22+
x.a = 1;
23+
>x.a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12))
24+
>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7))
25+
>a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12))
26+
27+
x.b = 1;
28+
>x.b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33))
29+
>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7))
30+
>b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33))
31+
32+
x.a;
33+
>x.a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12))
34+
>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7))
35+
>a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12))
36+
37+
x.b;
38+
>x.b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33))
39+
>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7))
40+
>b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33))
41+
42+
delete x.a;
43+
>x.a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12))
44+
>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7))
45+
>a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12))
46+
47+
delete x.b;
48+
>x.b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33))
49+
>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7))
50+
>b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33))
51+
52+
x.a;
53+
>x.a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12))
54+
>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7))
55+
>a : Symbol(a, Decl(controlFlowDeleteOperator.ts, 2, 12))
56+
57+
x.b;
58+
>x.b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33))
59+
>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7))
60+
>b : Symbol(b, Decl(controlFlowDeleteOperator.ts, 2, 33))
61+
62+
x;
63+
>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7))
64+
65+
delete x; // No effect
66+
>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7))
67+
68+
x;
69+
>x : Symbol(x, Decl(controlFlowDeleteOperator.ts, 2, 7))
70+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
=== tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts ===
2+
3+
function f() {
4+
>f : () => void
5+
6+
let x: { a?: number | string, b: number | string } = { b: 1 };
7+
>x : { a?: number | string | undefined; b: number | string; }
8+
>a : number | string | undefined
9+
>b : number | string
10+
>{ b: 1 } : { b: number; }
11+
>b : number
12+
>1 : number
13+
14+
x.a;
15+
>x.a : number | string | undefined
16+
>x : { a?: number | string | undefined; b: number | string; }
17+
>a : number | string | undefined
18+
19+
x.b;
20+
>x.b : number | string
21+
>x : { a?: number | string | undefined; b: number | string; }
22+
>b : number | string
23+
24+
x.a = 1;
25+
>x.a = 1 : number
26+
>x.a : number | string | undefined
27+
>x : { a?: number | string | undefined; b: number | string; }
28+
>a : number | string | undefined
29+
>1 : number
30+
31+
x.b = 1;
32+
>x.b = 1 : number
33+
>x.b : number | string
34+
>x : { a?: number | string | undefined; b: number | string; }
35+
>b : number | string
36+
>1 : number
37+
38+
x.a;
39+
>x.a : number
40+
>x : { a?: number | string | undefined; b: number | string; }
41+
>a : number
42+
43+
x.b;
44+
>x.b : number
45+
>x : { a?: number | string | undefined; b: number | string; }
46+
>b : number
47+
48+
delete x.a;
49+
>delete x.a : boolean
50+
>x.a : number
51+
>x : { a?: number | string | undefined; b: number | string; }
52+
>a : number
53+
54+
delete x.b;
55+
>delete x.b : boolean
56+
>x.b : number
57+
>x : { a?: number | string | undefined; b: number | string; }
58+
>b : number
59+
60+
x.a;
61+
>x.a : undefined
62+
>x : { a?: number | string | undefined; b: number | string; }
63+
>a : undefined
64+
65+
x.b;
66+
>x.b : number | string
67+
>x : { a?: number | string | undefined; b: number | string; }
68+
>b : number | string
69+
70+
x;
71+
>x : { a?: number | string | undefined; b: number | string; }
72+
73+
delete x; // No effect
74+
>delete x : boolean
75+
>x : { a?: number | string | undefined; b: number | string; }
76+
77+
x;
78+
>x : { a?: number | string | undefined; b: number | string; }
79+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// @strictNullChecks: true
2+
3+
function f() {
4+
let x: { a?: number | string, b: number | string } = { b: 1 };
5+
x.a;
6+
x.b;
7+
x.a = 1;
8+
x.b = 1;
9+
x.a;
10+
x.b;
11+
delete x.a;
12+
delete x.b;
13+
x.a;
14+
x.b;
15+
x;
16+
delete x; // No effect
17+
x;
18+
}

0 commit comments

Comments
 (0)