Skip to content

Commit 0f8c1f7

Browse files
committed
Fix emit for optional chain with non-null assertion
1 parent ad8feb5 commit 0f8c1f7

File tree

14 files changed

+108
-11
lines changed

14 files changed

+108
-11
lines changed

Diff for: src/compiler/parser.ts

+12-4
Original file line numberDiff line numberDiff line change
@@ -4685,12 +4685,20 @@ namespace ts {
46854685
&& lookAhead(nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate);
46864686
}
46874687

4688+
function hasOptionalChain(node: Node) {
4689+
while (true) {
4690+
if (node.flags & NodeFlags.OptionalChain) return true;
4691+
if (!isNonNullExpression(node)) return false;
4692+
node = node.expression;
4693+
}
4694+
}
4695+
46884696
function parsePropertyAccessExpressionRest(expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) {
46894697
const propertyAccess = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
46904698
propertyAccess.expression = expression;
46914699
propertyAccess.questionDotToken = questionDotToken;
46924700
propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true);
4693-
if (questionDotToken || expression.flags & NodeFlags.OptionalChain) {
4701+
if (questionDotToken || hasOptionalChain(expression)) {
46944702
propertyAccess.flags |= NodeFlags.OptionalChain;
46954703
if (isPrivateIdentifier(propertyAccess.name)) {
46964704
parseErrorAtRange(propertyAccess.name, Diagnostics.An_optional_chain_cannot_contain_private_identifiers);
@@ -4716,7 +4724,7 @@ namespace ts {
47164724
}
47174725

47184726
parseExpected(SyntaxKind.CloseBracketToken);
4719-
if (questionDotToken || expression.flags & NodeFlags.OptionalChain) {
4727+
if (questionDotToken || hasOptionalChain(expression)) {
47204728
indexedAccess.flags |= NodeFlags.OptionalChain;
47214729
}
47224730
return finishNode(indexedAccess);
@@ -4803,7 +4811,7 @@ namespace ts {
48034811
callExpr.questionDotToken = questionDotToken;
48044812
callExpr.typeArguments = typeArguments;
48054813
callExpr.arguments = parseArgumentList();
4806-
if (questionDotToken || expression.flags & NodeFlags.OptionalChain) {
4814+
if (questionDotToken || hasOptionalChain(expression)) {
48074815
callExpr.flags |= NodeFlags.OptionalChain;
48084816
}
48094817
expression = finishNode(callExpr);
@@ -4815,7 +4823,7 @@ namespace ts {
48154823
callExpr.expression = expression;
48164824
callExpr.questionDotToken = questionDotToken;
48174825
callExpr.arguments = parseArgumentList();
4818-
if (questionDotToken || expression.flags & NodeFlags.OptionalChain) {
4826+
if (questionDotToken || hasOptionalChain(expression)) {
48194827
callExpr.flags |= NodeFlags.OptionalChain;
48204828
}
48214829
expression = finishNode(callExpr);

Diff for: src/compiler/transformers/es2020.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ namespace ts {
4444
function flattenChain(chain: OptionalChain) {
4545
const links: OptionalChain[] = [chain];
4646
while (!chain.questionDotToken && !isTaggedTemplateExpression(chain)) {
47-
chain = cast(chain.expression, isOptionalChain);
47+
chain = cast(skipPartiallyEmittedExpressions(chain.expression), isOptionalChain);
4848
links.unshift(chain);
4949
}
5050
return { expression: chain.expression, chain: links };

Diff for: tests/baselines/reference/callChain.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ const v: number | undefined = o4?.(incr);
3535

3636
// GH#33744
3737
declare const o5: <T>() => undefined | (() => void);
38-
o5<number>()?.();
38+
o5<number>()?.();
39+
40+
// GH#36031
41+
o2?.b()!.toString
3942

4043
//// [callChain.js]
4144
"use strict";
@@ -73,3 +76,5 @@ o2 === null || o2 === void 0 ? void 0 : o2["b"].apply(o2, __spreadArrays([1], [2
7376
(_m = o3["b"]) === null || _m === void 0 ? void 0 : _m.call.apply(_m, __spreadArrays([o3, 1], [2, 3], [4])).c;
7477
var v = o4 === null || o4 === void 0 ? void 0 : o4(incr);
7578
(_o = o5()) === null || _o === void 0 ? void 0 : _o();
79+
// GH#36031
80+
o2 === null || o2 === void 0 ? void 0 : o2.b().toString;

Diff for: tests/baselines/reference/callChain.symbols

+8
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,11 @@ declare const o5: <T>() => undefined | (() => void);
156156
o5<number>()?.();
157157
>o5 : Symbol(o5, Decl(callChain.ts, 35, 13))
158158

159+
// GH#36031
160+
o2?.b()!.toString
161+
>o2?.b()!.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --))
162+
>o2?.b : Symbol(b, Decl(callChain.ts, 6, 31))
163+
>o2 : Symbol(o2, Decl(callChain.ts, 6, 13))
164+
>b : Symbol(b, Decl(callChain.ts, 6, 31))
165+
>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --))
166+

Diff for: tests/baselines/reference/callChain.types

+10
Original file line numberDiff line numberDiff line change
@@ -264,3 +264,13 @@ o5<number>()?.();
264264
>o5<number>() : (() => void) | undefined
265265
>o5 : <T>() => (() => void) | undefined
266266

267+
// GH#36031
268+
o2?.b()!.toString
269+
>o2?.b()!.toString : (radix?: number | undefined) => string
270+
>o2?.b()! : number
271+
>o2?.b() : number | undefined
272+
>o2?.b : ((...args: any[]) => number) | undefined
273+
>o2 : { b: (...args: any[]) => number; } | undefined
274+
>b : ((...args: any[]) => number) | undefined
275+
>toString : (radix?: number | undefined) => string
276+

Diff for: tests/baselines/reference/elementAccessChain.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ o5["b"]?.()["c"].d?.["e"];
2222

2323
// GH#33744
2424
declare const o6: <T>() => undefined | ({ x: number });
25-
o6<number>()?.["x"];
25+
o6<number>()?.["x"];
26+
27+
// GH#36031
28+
o2?.["b"]!.c
29+
o2?.["b"]!["c"]
2630

2731
//// [elementAccessChain.js]
2832
"use strict";
@@ -39,3 +43,6 @@ o2 === null || o2 === void 0 ? void 0 : o2.b["c"];
3943
(_m = (_l = o5["b"]) === null || _l === void 0 ? void 0 : _l.call(o5)["c"].d) === null || _m === void 0 ? void 0 : _m.e;
4044
(_p = (_o = o5["b"]) === null || _o === void 0 ? void 0 : _o.call(o5)["c"].d) === null || _p === void 0 ? void 0 : _p["e"];
4145
(_q = o6()) === null || _q === void 0 ? void 0 : _q["x"];
46+
// GH#36031
47+
o2 === null || o2 === void 0 ? void 0 : o2["b"].c;
48+
o2 === null || o2 === void 0 ? void 0 : o2["b"]["c"];

Diff for: tests/baselines/reference/elementAccessChain.symbols

+10
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,13 @@ declare const o6: <T>() => undefined | ({ x: number });
106106
o6<number>()?.["x"];
107107
>o6 : Symbol(o6, Decl(elementAccessChain.ts, 22, 13))
108108

109+
// GH#36031
110+
o2?.["b"]!.c
111+
>o2?.["b"]!.c : Symbol(c, Decl(elementAccessChain.ts, 3, 36))
112+
>o2 : Symbol(o2, Decl(elementAccessChain.ts, 3, 13))
113+
>c : Symbol(c, Decl(elementAccessChain.ts, 3, 36))
114+
115+
o2?.["b"]!["c"]
116+
>o2 : Symbol(o2, Decl(elementAccessChain.ts, 3, 13))
117+
>"c" : Symbol(c, Decl(elementAccessChain.ts, 3, 36))
118+

Diff for: tests/baselines/reference/elementAccessChain.types

+17
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,20 @@ o6<number>()?.["x"];
141141
>o6 : <T>() => { x: number; } | undefined
142142
>"x" : "x"
143143

144+
// GH#36031
145+
o2?.["b"]!.c
146+
>o2?.["b"]!.c : string
147+
>o2?.["b"]! : { c: string; }
148+
>o2?.["b"] : { c: string; } | undefined
149+
>o2 : { b: { c: string; }; } | undefined
150+
>"b" : "b"
151+
>c : string
152+
153+
o2?.["b"]!["c"]
154+
>o2?.["b"]!["c"] : string
155+
>o2?.["b"]! : { c: string; }
156+
>o2?.["b"] : { c: string; } | undefined
157+
>o2 : { b: { c: string; }; } | undefined
158+
>"b" : "b"
159+
>"c" : "c"
160+

Diff for: tests/baselines/reference/propertyAccessChain.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ declare const o6: <T>() => undefined | ({ x: number });
1919
o6<number>()?.x;
2020

2121
// GH#34109
22-
o1?.b ? 1 : 0;
22+
o1?.b ? 1 : 0;
23+
24+
// GH#36031
25+
o2?.b!.c
2326

2427
//// [propertyAccessChain.js]
2528
"use strict";
@@ -32,3 +35,5 @@ o2 === null || o2 === void 0 ? void 0 : o2.b.c;
3235
(_f = o6()) === null || _f === void 0 ? void 0 : _f.x;
3336
// GH#34109
3437
(o1 === null || o1 === void 0 ? void 0 : o1.b) ? 1 : 0;
38+
// GH#36031
39+
o2 === null || o2 === void 0 ? void 0 : o2.b.c;

Diff for: tests/baselines/reference/propertyAccessChain.symbols

+8
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,11 @@ o1?.b ? 1 : 0;
8585
>o1 : Symbol(o1, Decl(propertyAccessChain.ts, 0, 13))
8686
>b : Symbol(b, Decl(propertyAccessChain.ts, 0, 31))
8787

88+
// GH#36031
89+
o2?.b!.c
90+
>o2?.b!.c : Symbol(c, Decl(propertyAccessChain.ts, 3, 36))
91+
>o2?.b : Symbol(b, Decl(propertyAccessChain.ts, 3, 31))
92+
>o2 : Symbol(o2, Decl(propertyAccessChain.ts, 3, 13))
93+
>b : Symbol(b, Decl(propertyAccessChain.ts, 3, 31))
94+
>c : Symbol(c, Decl(propertyAccessChain.ts, 3, 36))
95+

Diff for: tests/baselines/reference/propertyAccessChain.types

+9
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,12 @@ o1?.b ? 1 : 0;
8989
>1 : 1
9090
>0 : 0
9191

92+
// GH#36031
93+
o2?.b!.c
94+
>o2?.b!.c : string
95+
>o2?.b! : { c: string; }
96+
>o2?.b : { c: string; } | undefined
97+
>o2 : { b: { c: string; }; } | undefined
98+
>b : { c: string; } | undefined
99+
>c : string
100+

Diff for: tests/cases/conformance/expressions/optionalChaining/callChain/callChain.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,7 @@ const v: number | undefined = o4?.(incr);
3636

3737
// GH#33744
3838
declare const o5: <T>() => undefined | (() => void);
39-
o5<number>()?.();
39+
o5<number>()?.();
40+
41+
// GH#36031
42+
o2?.b()!.toString

Diff for: tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,8 @@ o5["b"]?.()["c"].d?.["e"];
2323

2424
// GH#33744
2525
declare const o6: <T>() => undefined | ({ x: number });
26-
o6<number>()?.["x"];
26+
o6<number>()?.["x"];
27+
28+
// GH#36031
29+
o2?.["b"]!.c
30+
o2?.["b"]!["c"]

Diff for: tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,7 @@ declare const o6: <T>() => undefined | ({ x: number });
2020
o6<number>()?.x;
2121

2222
// GH#34109
23-
o1?.b ? 1 : 0;
23+
o1?.b ? 1 : 0;
24+
25+
// GH#36031
26+
o2?.b!.c

0 commit comments

Comments
 (0)