Skip to content

Commit

Permalink
Fix emit for optional chain with non-null assertion
Browse files Browse the repository at this point in the history
  • Loading branch information
rbuckton committed Jan 31, 2020
1 parent ad8feb5 commit 0f8c1f7
Show file tree
Hide file tree
Showing 14 changed files with 108 additions and 11 deletions.
16 changes: 12 additions & 4 deletions src/compiler/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4685,12 +4685,20 @@ namespace ts {
&& lookAhead(nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate);
}

function hasOptionalChain(node: Node) {
while (true) {
if (node.flags & NodeFlags.OptionalChain) return true;
if (!isNonNullExpression(node)) return false;
node = node.expression;
}
}

function parsePropertyAccessExpressionRest(expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) {
const propertyAccess = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
propertyAccess.expression = expression;
propertyAccess.questionDotToken = questionDotToken;
propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true);
if (questionDotToken || expression.flags & NodeFlags.OptionalChain) {
if (questionDotToken || hasOptionalChain(expression)) {
propertyAccess.flags |= NodeFlags.OptionalChain;
if (isPrivateIdentifier(propertyAccess.name)) {
parseErrorAtRange(propertyAccess.name, Diagnostics.An_optional_chain_cannot_contain_private_identifiers);
Expand All @@ -4716,7 +4724,7 @@ namespace ts {
}

parseExpected(SyntaxKind.CloseBracketToken);
if (questionDotToken || expression.flags & NodeFlags.OptionalChain) {
if (questionDotToken || hasOptionalChain(expression)) {
indexedAccess.flags |= NodeFlags.OptionalChain;
}
return finishNode(indexedAccess);
Expand Down Expand Up @@ -4803,7 +4811,7 @@ namespace ts {
callExpr.questionDotToken = questionDotToken;
callExpr.typeArguments = typeArguments;
callExpr.arguments = parseArgumentList();
if (questionDotToken || expression.flags & NodeFlags.OptionalChain) {
if (questionDotToken || hasOptionalChain(expression)) {
callExpr.flags |= NodeFlags.OptionalChain;
}
expression = finishNode(callExpr);
Expand All @@ -4815,7 +4823,7 @@ namespace ts {
callExpr.expression = expression;
callExpr.questionDotToken = questionDotToken;
callExpr.arguments = parseArgumentList();
if (questionDotToken || expression.flags & NodeFlags.OptionalChain) {
if (questionDotToken || hasOptionalChain(expression)) {
callExpr.flags |= NodeFlags.OptionalChain;
}
expression = finishNode(callExpr);
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/transformers/es2020.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ namespace ts {
function flattenChain(chain: OptionalChain) {
const links: OptionalChain[] = [chain];
while (!chain.questionDotToken && !isTaggedTemplateExpression(chain)) {
chain = cast(chain.expression, isOptionalChain);
chain = cast(skipPartiallyEmittedExpressions(chain.expression), isOptionalChain);
links.unshift(chain);
}
return { expression: chain.expression, chain: links };
Expand Down
7 changes: 6 additions & 1 deletion tests/baselines/reference/callChain.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ const v: number | undefined = o4?.(incr);

// GH#33744
declare const o5: <T>() => undefined | (() => void);
o5<number>()?.();
o5<number>()?.();

// GH#36031
o2?.b()!.toString

//// [callChain.js]
"use strict";
Expand Down Expand Up @@ -73,3 +76,5 @@ o2 === null || o2 === void 0 ? void 0 : o2["b"].apply(o2, __spreadArrays([1], [2
(_m = o3["b"]) === null || _m === void 0 ? void 0 : _m.call.apply(_m, __spreadArrays([o3, 1], [2, 3], [4])).c;
var v = o4 === null || o4 === void 0 ? void 0 : o4(incr);
(_o = o5()) === null || _o === void 0 ? void 0 : _o();
// GH#36031
o2 === null || o2 === void 0 ? void 0 : o2.b().toString;
8 changes: 8 additions & 0 deletions tests/baselines/reference/callChain.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,11 @@ declare const o5: <T>() => undefined | (() => void);
o5<number>()?.();
>o5 : Symbol(o5, Decl(callChain.ts, 35, 13))

// GH#36031
o2?.b()!.toString
>o2?.b()!.toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --))
>o2?.b : Symbol(b, Decl(callChain.ts, 6, 31))
>o2 : Symbol(o2, Decl(callChain.ts, 6, 13))
>b : Symbol(b, Decl(callChain.ts, 6, 31))
>toString : Symbol(Number.toString, Decl(lib.es5.d.ts, --, --))

10 changes: 10 additions & 0 deletions tests/baselines/reference/callChain.types
Original file line number Diff line number Diff line change
Expand Up @@ -264,3 +264,13 @@ o5<number>()?.();
>o5<number>() : (() => void) | undefined
>o5 : <T>() => (() => void) | undefined

// GH#36031
o2?.b()!.toString
>o2?.b()!.toString : (radix?: number | undefined) => string
>o2?.b()! : number
>o2?.b() : number | undefined
>o2?.b : ((...args: any[]) => number) | undefined
>o2 : { b: (...args: any[]) => number; } | undefined
>b : ((...args: any[]) => number) | undefined
>toString : (radix?: number | undefined) => string

9 changes: 8 additions & 1 deletion tests/baselines/reference/elementAccessChain.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ o5["b"]?.()["c"].d?.["e"];

// GH#33744
declare const o6: <T>() => undefined | ({ x: number });
o6<number>()?.["x"];
o6<number>()?.["x"];

// GH#36031
o2?.["b"]!.c
o2?.["b"]!["c"]

//// [elementAccessChain.js]
"use strict";
Expand All @@ -39,3 +43,6 @@ o2 === null || o2 === void 0 ? void 0 : o2.b["c"];
(_m = (_l = o5["b"]) === null || _l === void 0 ? void 0 : _l.call(o5)["c"].d) === null || _m === void 0 ? void 0 : _m.e;
(_p = (_o = o5["b"]) === null || _o === void 0 ? void 0 : _o.call(o5)["c"].d) === null || _p === void 0 ? void 0 : _p["e"];
(_q = o6()) === null || _q === void 0 ? void 0 : _q["x"];
// GH#36031
o2 === null || o2 === void 0 ? void 0 : o2["b"].c;
o2 === null || o2 === void 0 ? void 0 : o2["b"]["c"];
10 changes: 10 additions & 0 deletions tests/baselines/reference/elementAccessChain.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,13 @@ declare const o6: <T>() => undefined | ({ x: number });
o6<number>()?.["x"];
>o6 : Symbol(o6, Decl(elementAccessChain.ts, 22, 13))

// GH#36031
o2?.["b"]!.c
>o2?.["b"]!.c : Symbol(c, Decl(elementAccessChain.ts, 3, 36))
>o2 : Symbol(o2, Decl(elementAccessChain.ts, 3, 13))
>c : Symbol(c, Decl(elementAccessChain.ts, 3, 36))

o2?.["b"]!["c"]
>o2 : Symbol(o2, Decl(elementAccessChain.ts, 3, 13))
>"c" : Symbol(c, Decl(elementAccessChain.ts, 3, 36))

17 changes: 17 additions & 0 deletions tests/baselines/reference/elementAccessChain.types
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,20 @@ o6<number>()?.["x"];
>o6 : <T>() => { x: number; } | undefined
>"x" : "x"

// GH#36031
o2?.["b"]!.c
>o2?.["b"]!.c : string
>o2?.["b"]! : { c: string; }
>o2?.["b"] : { c: string; } | undefined
>o2 : { b: { c: string; }; } | undefined
>"b" : "b"
>c : string

o2?.["b"]!["c"]
>o2?.["b"]!["c"] : string
>o2?.["b"]! : { c: string; }
>o2?.["b"] : { c: string; } | undefined
>o2 : { b: { c: string; }; } | undefined
>"b" : "b"
>"c" : "c"

7 changes: 6 additions & 1 deletion tests/baselines/reference/propertyAccessChain.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ declare const o6: <T>() => undefined | ({ x: number });
o6<number>()?.x;

// GH#34109
o1?.b ? 1 : 0;
o1?.b ? 1 : 0;

// GH#36031
o2?.b!.c

//// [propertyAccessChain.js]
"use strict";
Expand All @@ -32,3 +35,5 @@ o2 === null || o2 === void 0 ? void 0 : o2.b.c;
(_f = o6()) === null || _f === void 0 ? void 0 : _f.x;
// GH#34109
(o1 === null || o1 === void 0 ? void 0 : o1.b) ? 1 : 0;
// GH#36031
o2 === null || o2 === void 0 ? void 0 : o2.b.c;
8 changes: 8 additions & 0 deletions tests/baselines/reference/propertyAccessChain.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,11 @@ o1?.b ? 1 : 0;
>o1 : Symbol(o1, Decl(propertyAccessChain.ts, 0, 13))
>b : Symbol(b, Decl(propertyAccessChain.ts, 0, 31))

// GH#36031
o2?.b!.c
>o2?.b!.c : Symbol(c, Decl(propertyAccessChain.ts, 3, 36))
>o2?.b : Symbol(b, Decl(propertyAccessChain.ts, 3, 31))
>o2 : Symbol(o2, Decl(propertyAccessChain.ts, 3, 13))
>b : Symbol(b, Decl(propertyAccessChain.ts, 3, 31))
>c : Symbol(c, Decl(propertyAccessChain.ts, 3, 36))

9 changes: 9 additions & 0 deletions tests/baselines/reference/propertyAccessChain.types
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,12 @@ o1?.b ? 1 : 0;
>1 : 1
>0 : 0

// GH#36031
o2?.b!.c
>o2?.b!.c : string
>o2?.b! : { c: string; }
>o2?.b : { c: string; } | undefined
>o2 : { b: { c: string; }; } | undefined
>b : { c: string; } | undefined
>c : string

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

// GH#33744
declare const o5: <T>() => undefined | (() => void);
o5<number>()?.();
o5<number>()?.();

// GH#36031
o2?.b()!.toString
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,8 @@ o5["b"]?.()["c"].d?.["e"];

// GH#33744
declare const o6: <T>() => undefined | ({ x: number });
o6<number>()?.["x"];
o6<number>()?.["x"];

// GH#36031
o2?.["b"]!.c
o2?.["b"]!["c"]
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ declare const o6: <T>() => undefined | ({ x: number });
o6<number>()?.x;

// GH#34109
o1?.b ? 1 : 0;
o1?.b ? 1 : 0;

// GH#36031
o2?.b!.c

0 comments on commit 0f8c1f7

Please sign in to comment.