Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit fce728e

Browse filesBrowse files
ajafffrbuckton
andcommitted
fix emit for delete on optional chain (microsoft#35090)
* fix emit for delete on optional chain * Apply suggestions from code review Co-Authored-By: Ron Buckton <ron.buckton@microsoft.com>
1 parent 8b83703 commit fce728e
Copy full SHA for fce728e

5 files changed

+406-16Lines changed: 406 additions & 16 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/compiler/transformers/esnext.ts‎

Copy file name to clipboardExpand all lines: src/compiler/transformers/esnext.ts
+22-16Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ namespace ts {
2424
case SyntaxKind.ElementAccessExpression:
2525
case SyntaxKind.CallExpression:
2626
if (node.flags & NodeFlags.OptionalChain) {
27-
const updated = visitOptionalExpression(node as OptionalChain, /*captureThisArg*/ false);
27+
const updated = visitOptionalExpression(node as OptionalChain, /*captureThisArg*/ false, /*isDelete*/ false);
2828
Debug.assertNotNode(updated, isSyntheticReference);
2929
return updated;
3030
}
@@ -34,6 +34,8 @@ namespace ts {
3434
return transformNullishCoalescingExpression(<BinaryExpression>node);
3535
}
3636
return visitEachChild(node, visitor, context);
37+
case SyntaxKind.DeleteExpression:
38+
return visitDeleteExpression(node as DeleteExpression);
3739
default:
3840
return visitEachChild(node, visitor, context);
3941
}
@@ -48,8 +50,8 @@ namespace ts {
4850
return { expression: chain.expression, chain: links };
4951
}
5052

51-
function visitNonOptionalParenthesizedExpression(node: ParenthesizedExpression, captureThisArg: boolean): Expression {
52-
const expression = visitNonOptionalExpression(node.expression, captureThisArg);
53+
function visitNonOptionalParenthesizedExpression(node: ParenthesizedExpression, captureThisArg: boolean, isDelete: boolean): Expression {
54+
const expression = visitNonOptionalExpression(node.expression, captureThisArg, isDelete);
5355
if (isSyntheticReference(expression)) {
5456
// `(a.b)` -> { expression `((_a = a).b)`, thisArg: `_a` }
5557
// `(a[b])` -> { expression `((_a = a)[b])`, thisArg: `_a` }
@@ -58,10 +60,10 @@ namespace ts {
5860
return updateParen(node, expression);
5961
}
6062

61-
function visitNonOptionalPropertyOrElementAccessExpression(node: AccessExpression, captureThisArg: boolean): Expression {
63+
function visitNonOptionalPropertyOrElementAccessExpression(node: AccessExpression, captureThisArg: boolean, isDelete: boolean): Expression {
6264
if (isOptionalChain(node)) {
6365
// If `node` is an optional chain, then it is the outermost chain of an optional expression.
64-
return visitOptionalExpression(node, captureThisArg);
66+
return visitOptionalExpression(node, captureThisArg, isDelete);
6567
}
6668

6769
let expression: Expression = visitNode(node.expression, visitor, isExpression);
@@ -87,24 +89,24 @@ namespace ts {
8789
function visitNonOptionalCallExpression(node: CallExpression, captureThisArg: boolean): Expression {
8890
if (isOptionalChain(node)) {
8991
// If `node` is an optional chain, then it is the outermost chain of an optional expression.
90-
return visitOptionalExpression(node, captureThisArg);
92+
return visitOptionalExpression(node, captureThisArg, /*isDelete*/ false);
9193
}
9294
return visitEachChild(node, visitor, context);
9395
}
9496

95-
function visitNonOptionalExpression(node: Expression, captureThisArg: boolean): Expression {
97+
function visitNonOptionalExpression(node: Expression, captureThisArg: boolean, isDelete: boolean): Expression {
9698
switch (node.kind) {
97-
case SyntaxKind.ParenthesizedExpression: return visitNonOptionalParenthesizedExpression(node as ParenthesizedExpression, captureThisArg);
99+
case SyntaxKind.ParenthesizedExpression: return visitNonOptionalParenthesizedExpression(node as ParenthesizedExpression, captureThisArg, isDelete);
98100
case SyntaxKind.PropertyAccessExpression:
99-
case SyntaxKind.ElementAccessExpression: return visitNonOptionalPropertyOrElementAccessExpression(node as AccessExpression, captureThisArg);
101+
case SyntaxKind.ElementAccessExpression: return visitNonOptionalPropertyOrElementAccessExpression(node as AccessExpression, captureThisArg, isDelete);
100102
case SyntaxKind.CallExpression: return visitNonOptionalCallExpression(node as CallExpression, captureThisArg);
101103
default: return visitNode(node, visitor, isExpression);
102104
}
103105
}
104106

105-
function visitOptionalExpression(node: OptionalChain, captureThisArg: boolean): Expression {
107+
function visitOptionalExpression(node: OptionalChain, captureThisArg: boolean, isDelete: boolean): Expression {
106108
const { expression, chain } = flattenChain(node);
107-
const left = visitNonOptionalExpression(expression, isCallChain(chain[0]));
109+
const left = visitNonOptionalExpression(expression, isCallChain(chain[0]), /*isDelete*/ false);
108110
const leftThisArg = isSyntheticReference(left) ? left.thisArg : undefined;
109111
let leftExpression = isSyntheticReference(left) ? left.expression : left;
110112
let capturedLeft: Expression = leftExpression;
@@ -152,11 +154,9 @@ namespace ts {
152154
setOriginalNode(rightExpression, segment);
153155
}
154156

155-
const target = createConditional(
156-
createNotNullCondition(leftExpression, capturedLeft, /*invert*/ true),
157-
createVoidZero(),
158-
rightExpression,
159-
);
157+
const target = isDelete
158+
? createConditional(createNotNullCondition(leftExpression, capturedLeft, /*invert*/ true), createTrue(), createDelete(rightExpression))
159+
: createConditional(createNotNullCondition(leftExpression, capturedLeft, /*invert*/ true), createVoidZero(), rightExpression);
160160
return thisArg ? createSyntheticReferenceExpression(target, thisArg) : target;
161161
}
162162

@@ -197,5 +197,11 @@ namespace ts {
197197
expression.kind !== SyntaxKind.ThisKeyword &&
198198
expression.kind !== SyntaxKind.SuperKeyword;
199199
}
200+
201+
function visitDeleteExpression(node: DeleteExpression) {
202+
return isOptionalChain(skipParentheses(node.expression))
203+
? setOriginalNode(visitNonOptionalExpression(node.expression, /*captureThisArg*/ false, /*isDelete*/ true), node)
204+
: updateDelete(node, visitNode(node.expression, visitor, isExpression));
205+
}
200206
}
201207
}
Collapse file
+42Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//// [deleteChain.ts]
2+
declare const o1: undefined | { b: string };
3+
delete o1?.b;
4+
delete (o1?.b);
5+
6+
declare const o2: undefined | { b: { c: string } };
7+
delete o2?.b.c;
8+
delete (o2?.b.c);
9+
10+
declare const o3: { b: undefined | { c: string } };
11+
delete o3.b?.c;
12+
delete (o3.b?.c);
13+
14+
declare const o4: { b?: { c: { d?: { e: string } } } };
15+
delete o4.b?.c.d?.e;
16+
delete (o4.b?.c.d)?.e;
17+
delete (o4.b?.c.d?.e);
18+
19+
declare const o5: { b?(): { c: { d?: { e: string } } } };
20+
delete o5.b?.().c.d?.e;
21+
delete (o5.b?.().c.d?.e);
22+
23+
declare const o6: { b?: { c: { d?: { e: string } } } };
24+
delete o6.b?.['c'].d?.['e'];
25+
delete (o6.b?.['c'].d?.['e']);
26+
27+
//// [deleteChain.js]
28+
"use strict";
29+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
30+
o1 === null || o1 === void 0 ? true : delete o1.b;
31+
(o1 === null || o1 === void 0 ? true : delete o1.b);
32+
o2 === null || o2 === void 0 ? true : delete o2.b.c;
33+
(o2 === null || o2 === void 0 ? true : delete o2.b.c);
34+
(_a = o3.b) === null || _a === void 0 ? true : delete _a.c;
35+
((_b = o3.b) === null || _b === void 0 ? true : delete _b.c);
36+
(_d = (_c = o4.b) === null || _c === void 0 ? void 0 : _c.c.d) === null || _d === void 0 ? true : delete _d.e;
37+
(_f = ((_e = o4.b) === null || _e === void 0 ? void 0 : _e.c.d)) === null || _f === void 0 ? true : delete _f.e;
38+
((_h = (_g = o4.b) === null || _g === void 0 ? void 0 : _g.c.d) === null || _h === void 0 ? true : delete _h.e);
39+
(_k = (_j = o5.b) === null || _j === void 0 ? void 0 : _j.call(o5).c.d) === null || _k === void 0 ? true : delete _k.e;
40+
((_m = (_l = o5.b) === null || _l === void 0 ? void 0 : _l.call(o5).c.d) === null || _m === void 0 ? true : delete _m.e);
41+
(_p = (_o = o6.b) === null || _o === void 0 ? void 0 : _o['c'].d) === null || _p === void 0 ? true : delete _p['e'];
42+
((_r = (_q = o6.b) === null || _q === void 0 ? void 0 : _q['c'].d) === null || _r === void 0 ? true : delete _r['e']);
Collapse file
+143Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
=== tests/cases/conformance/expressions/optionalChaining/delete/deleteChain.ts ===
2+
declare const o1: undefined | { b: string };
3+
>o1 : Symbol(o1, Decl(deleteChain.ts, 0, 13))
4+
>b : Symbol(b, Decl(deleteChain.ts, 0, 31))
5+
6+
delete o1?.b;
7+
>o1?.b : Symbol(b, Decl(deleteChain.ts, 0, 31))
8+
>o1 : Symbol(o1, Decl(deleteChain.ts, 0, 13))
9+
>b : Symbol(b, Decl(deleteChain.ts, 0, 31))
10+
11+
delete (o1?.b);
12+
>o1?.b : Symbol(b, Decl(deleteChain.ts, 0, 31))
13+
>o1 : Symbol(o1, Decl(deleteChain.ts, 0, 13))
14+
>b : Symbol(b, Decl(deleteChain.ts, 0, 31))
15+
16+
declare const o2: undefined | { b: { c: string } };
17+
>o2 : Symbol(o2, Decl(deleteChain.ts, 4, 13))
18+
>b : Symbol(b, Decl(deleteChain.ts, 4, 31))
19+
>c : Symbol(c, Decl(deleteChain.ts, 4, 36))
20+
21+
delete o2?.b.c;
22+
>o2?.b.c : Symbol(c, Decl(deleteChain.ts, 4, 36))
23+
>o2?.b : Symbol(b, Decl(deleteChain.ts, 4, 31))
24+
>o2 : Symbol(o2, Decl(deleteChain.ts, 4, 13))
25+
>b : Symbol(b, Decl(deleteChain.ts, 4, 31))
26+
>c : Symbol(c, Decl(deleteChain.ts, 4, 36))
27+
28+
delete (o2?.b.c);
29+
>o2?.b.c : Symbol(c, Decl(deleteChain.ts, 4, 36))
30+
>o2?.b : Symbol(b, Decl(deleteChain.ts, 4, 31))
31+
>o2 : Symbol(o2, Decl(deleteChain.ts, 4, 13))
32+
>b : Symbol(b, Decl(deleteChain.ts, 4, 31))
33+
>c : Symbol(c, Decl(deleteChain.ts, 4, 36))
34+
35+
declare const o3: { b: undefined | { c: string } };
36+
>o3 : Symbol(o3, Decl(deleteChain.ts, 8, 13))
37+
>b : Symbol(b, Decl(deleteChain.ts, 8, 19))
38+
>c : Symbol(c, Decl(deleteChain.ts, 8, 36))
39+
40+
delete o3.b?.c;
41+
>o3.b?.c : Symbol(c, Decl(deleteChain.ts, 8, 36))
42+
>o3.b : Symbol(b, Decl(deleteChain.ts, 8, 19))
43+
>o3 : Symbol(o3, Decl(deleteChain.ts, 8, 13))
44+
>b : Symbol(b, Decl(deleteChain.ts, 8, 19))
45+
>c : Symbol(c, Decl(deleteChain.ts, 8, 36))
46+
47+
delete (o3.b?.c);
48+
>o3.b?.c : Symbol(c, Decl(deleteChain.ts, 8, 36))
49+
>o3.b : Symbol(b, Decl(deleteChain.ts, 8, 19))
50+
>o3 : Symbol(o3, Decl(deleteChain.ts, 8, 13))
51+
>b : Symbol(b, Decl(deleteChain.ts, 8, 19))
52+
>c : Symbol(c, Decl(deleteChain.ts, 8, 36))
53+
54+
declare const o4: { b?: { c: { d?: { e: string } } } };
55+
>o4 : Symbol(o4, Decl(deleteChain.ts, 12, 13))
56+
>b : Symbol(b, Decl(deleteChain.ts, 12, 19))
57+
>c : Symbol(c, Decl(deleteChain.ts, 12, 25))
58+
>d : Symbol(d, Decl(deleteChain.ts, 12, 30))
59+
>e : Symbol(e, Decl(deleteChain.ts, 12, 36))
60+
61+
delete o4.b?.c.d?.e;
62+
>o4.b?.c.d?.e : Symbol(e, Decl(deleteChain.ts, 12, 36))
63+
>o4.b?.c.d : Symbol(d, Decl(deleteChain.ts, 12, 30))
64+
>o4.b?.c : Symbol(c, Decl(deleteChain.ts, 12, 25))
65+
>o4.b : Symbol(b, Decl(deleteChain.ts, 12, 19))
66+
>o4 : Symbol(o4, Decl(deleteChain.ts, 12, 13))
67+
>b : Symbol(b, Decl(deleteChain.ts, 12, 19))
68+
>c : Symbol(c, Decl(deleteChain.ts, 12, 25))
69+
>d : Symbol(d, Decl(deleteChain.ts, 12, 30))
70+
>e : Symbol(e, Decl(deleteChain.ts, 12, 36))
71+
72+
delete (o4.b?.c.d)?.e;
73+
>(o4.b?.c.d)?.e : Symbol(e, Decl(deleteChain.ts, 12, 36))
74+
>o4.b?.c.d : Symbol(d, Decl(deleteChain.ts, 12, 30))
75+
>o4.b?.c : Symbol(c, Decl(deleteChain.ts, 12, 25))
76+
>o4.b : Symbol(b, Decl(deleteChain.ts, 12, 19))
77+
>o4 : Symbol(o4, Decl(deleteChain.ts, 12, 13))
78+
>b : Symbol(b, Decl(deleteChain.ts, 12, 19))
79+
>c : Symbol(c, Decl(deleteChain.ts, 12, 25))
80+
>d : Symbol(d, Decl(deleteChain.ts, 12, 30))
81+
>e : Symbol(e, Decl(deleteChain.ts, 12, 36))
82+
83+
delete (o4.b?.c.d?.e);
84+
>o4.b?.c.d?.e : Symbol(e, Decl(deleteChain.ts, 12, 36))
85+
>o4.b?.c.d : Symbol(d, Decl(deleteChain.ts, 12, 30))
86+
>o4.b?.c : Symbol(c, Decl(deleteChain.ts, 12, 25))
87+
>o4.b : Symbol(b, Decl(deleteChain.ts, 12, 19))
88+
>o4 : Symbol(o4, Decl(deleteChain.ts, 12, 13))
89+
>b : Symbol(b, Decl(deleteChain.ts, 12, 19))
90+
>c : Symbol(c, Decl(deleteChain.ts, 12, 25))
91+
>d : Symbol(d, Decl(deleteChain.ts, 12, 30))
92+
>e : Symbol(e, Decl(deleteChain.ts, 12, 36))
93+
94+
declare const o5: { b?(): { c: { d?: { e: string } } } };
95+
>o5 : Symbol(o5, Decl(deleteChain.ts, 17, 13))
96+
>b : Symbol(b, Decl(deleteChain.ts, 17, 19))
97+
>c : Symbol(c, Decl(deleteChain.ts, 17, 27))
98+
>d : Symbol(d, Decl(deleteChain.ts, 17, 32))
99+
>e : Symbol(e, Decl(deleteChain.ts, 17, 38))
100+
101+
delete o5.b?.().c.d?.e;
102+
>o5.b?.().c.d?.e : Symbol(e, Decl(deleteChain.ts, 17, 38))
103+
>o5.b?.().c.d : Symbol(d, Decl(deleteChain.ts, 17, 32))
104+
>o5.b?.().c : Symbol(c, Decl(deleteChain.ts, 17, 27))
105+
>o5.b : Symbol(b, Decl(deleteChain.ts, 17, 19))
106+
>o5 : Symbol(o5, Decl(deleteChain.ts, 17, 13))
107+
>b : Symbol(b, Decl(deleteChain.ts, 17, 19))
108+
>c : Symbol(c, Decl(deleteChain.ts, 17, 27))
109+
>d : Symbol(d, Decl(deleteChain.ts, 17, 32))
110+
>e : Symbol(e, Decl(deleteChain.ts, 17, 38))
111+
112+
delete (o5.b?.().c.d?.e);
113+
>o5.b?.().c.d?.e : Symbol(e, Decl(deleteChain.ts, 17, 38))
114+
>o5.b?.().c.d : Symbol(d, Decl(deleteChain.ts, 17, 32))
115+
>o5.b?.().c : Symbol(c, Decl(deleteChain.ts, 17, 27))
116+
>o5.b : Symbol(b, Decl(deleteChain.ts, 17, 19))
117+
>o5 : Symbol(o5, Decl(deleteChain.ts, 17, 13))
118+
>b : Symbol(b, Decl(deleteChain.ts, 17, 19))
119+
>c : Symbol(c, Decl(deleteChain.ts, 17, 27))
120+
>d : Symbol(d, Decl(deleteChain.ts, 17, 32))
121+
>e : Symbol(e, Decl(deleteChain.ts, 17, 38))
122+
123+
declare const o6: { b?: { c: { d?: { e: string } } } };
124+
>o6 : Symbol(o6, Decl(deleteChain.ts, 21, 13))
125+
>b : Symbol(b, Decl(deleteChain.ts, 21, 19))
126+
>c : Symbol(c, Decl(deleteChain.ts, 21, 25))
127+
>d : Symbol(d, Decl(deleteChain.ts, 21, 30))
128+
>e : Symbol(e, Decl(deleteChain.ts, 21, 36))
129+
130+
delete o6.b?.['c'].d?.['e'];
131+
>o6.b?.['c'].d : Symbol(d, Decl(deleteChain.ts, 21, 30))
132+
>o6.b : Symbol(b, Decl(deleteChain.ts, 21, 19))
133+
>o6 : Symbol(o6, Decl(deleteChain.ts, 21, 13))
134+
>b : Symbol(b, Decl(deleteChain.ts, 21, 19))
135+
>d : Symbol(d, Decl(deleteChain.ts, 21, 30))
136+
137+
delete (o6.b?.['c'].d?.['e']);
138+
>o6.b?.['c'].d : Symbol(d, Decl(deleteChain.ts, 21, 30))
139+
>o6.b : Symbol(b, Decl(deleteChain.ts, 21, 19))
140+
>o6 : Symbol(o6, Decl(deleteChain.ts, 21, 13))
141+
>b : Symbol(b, Decl(deleteChain.ts, 21, 19))
142+
>d : Symbol(d, Decl(deleteChain.ts, 21, 30))
143+

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.