Treat '!' differently inside chain vs end of chain

This commit is contained in:
Ron Buckton
2020-02-14 16:18:07 -08:00
parent 0f8c1f799d
commit d187ca71cc
25 changed files with 229 additions and 101 deletions
+20 -4
View File
@@ -833,6 +833,9 @@ namespace ts {
case SyntaxKind.CallExpression:
bindCallExpressionFlow(<CallExpression>node);
break;
case SyntaxKind.NonNullExpression:
bindNonNullExpressionFlow(<NonNullExpression>node);
break;
case SyntaxKind.JSDocTypedefTag:
case SyntaxKind.JSDocCallbackTag:
case SyntaxKind.JSDocEnumTag:
@@ -1665,18 +1668,22 @@ namespace ts {
}
function bindOptionalChainRest(node: OptionalChain) {
bind(node.questionDotToken);
switch (node.kind) {
case SyntaxKind.PropertyAccessExpression:
bind(node.questionDotToken);
bind(node.name);
break;
case SyntaxKind.ElementAccessExpression:
bind(node.questionDotToken);
bind(node.argumentExpression);
break;
case SyntaxKind.CallExpression:
bind(node.questionDotToken);
bindEach(node.typeArguments);
bindEach(node.arguments);
break;
case SyntaxKind.NonNullExpression:
break;
}
}
@@ -1692,7 +1699,7 @@ namespace ts {
// and build it's CFA graph as if it were the first condition (`a && ...`). Then we bind the rest
// of the node as part of the "true" branch, and continue to do so as we ascend back up to the outermost
// chain node. We then treat the entire node as the right side of the expression.
const preChainLabel = node.questionDotToken ? createBranchLabel() : undefined;
const preChainLabel = isOptionalChainRoot(node) ? createBranchLabel() : undefined;
bindOptionalExpression(node.expression, preChainLabel || trueTarget, falseTarget);
if (preChainLabel) {
currentFlow = finishFlowLabel(preChainLabel);
@@ -1715,7 +1722,7 @@ namespace ts {
}
}
function bindAccessExpressionFlow(node: AccessExpression) {
function bindNonNullExpressionFlow(node: NonNullExpression | NonNullChain) {
if (isOptionalChain(node)) {
bindOptionalChainFlow(node);
}
@@ -1724,7 +1731,16 @@ namespace ts {
}
}
function bindCallExpressionFlow(node: CallExpression) {
function bindAccessExpressionFlow(node: AccessExpression | PropertyAccessChain | ElementAccessChain) {
if (isOptionalChain(node)) {
bindOptionalChainFlow(node);
}
else {
bindEachChild(node);
}
}
function bindCallExpressionFlow(node: CallExpression | CallChain) {
if (isOptionalChain(node)) {
bindOptionalChainFlow(node);
}
+8 -1
View File
@@ -25900,8 +25900,15 @@ namespace ts {
return targetType;
}
function checkNonNullChain(node: NonNullChain) {
const leftType = checkExpression(node.expression);
const nonOptionalType = getOptionalExpressionType(leftType, node.expression);
return propagateOptionalTypeMarker(getNonNullableType(nonOptionalType), node, nonOptionalType !== leftType);
}
function checkNonNullAssertion(node: NonNullExpression) {
return getNonNullableType(checkExpression(node.expression));
return node.flags & NodeFlags.OptionalChain ? checkNonNullChain(node as NonNullChain) :
getNonNullableType(checkExpression(node.expression));
}
function checkMetaProperty(node: MetaProperty): Type {
+11 -7
View File
@@ -189,13 +189,17 @@ namespace ts {
assertNode)
: noop;
export const assertNotNode = shouldAssert(AssertionLevel.Normal)
? (node: Node | undefined, test: ((node: Node | undefined) => boolean) | undefined, message?: string): void => assert(
test === undefined || !test(node),
message || "Unexpected node.",
() => `Node ${formatSyntaxKind(node!.kind)} should not have passed test '${getFunctionName(test!)}'.`,
assertNode)
: noop;
export function assertNotNode<T extends Node, U extends T>(node: T | undefined, test: (node: Node) => node is U, message?: string): asserts node is Exclude<T, U>;
export function assertNotNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string): void;
export function assertNotNode(node: Node | undefined, test: ((node: Node) => boolean) | undefined, message?: string): void {
if (shouldAssert(AssertionLevel.Normal)) {
assert(
test === undefined || node === undefined || !test(node),
message || "Unexpected node.",
() => `Node ${formatSyntaxKind(node!.kind)} should not have passed test '${getFunctionName(test!)}'.`,
assertNotNode);
}
}
export const assertOptionalNode = shouldAssert(AssertionLevel.Normal)
? (node: Node, test: (node: Node) => boolean, message?: string): void => assert(
+9 -24
View File
@@ -1335,9 +1335,11 @@ namespace ts {
export const enum OuterExpressionKinds {
Parentheses = 1 << 0,
Assertions = 1 << 1,
PartiallyEmittedExpressions = 1 << 2,
TypeAssertions = 1 << 1,
NonNullAssertions = 1 << 2,
PartiallyEmittedExpressions = 1 << 3,
Assertions = TypeAssertions | NonNullAssertions,
All = Parentheses | Assertions | PartiallyEmittedExpressions
}
@@ -1349,8 +1351,9 @@ namespace ts {
return (kinds & OuterExpressionKinds.Parentheses) !== 0;
case SyntaxKind.TypeAssertionExpression:
case SyntaxKind.AsExpression:
return (kinds & OuterExpressionKinds.TypeAssertions) !== 0;
case SyntaxKind.NonNullExpression:
return (kinds & OuterExpressionKinds.Assertions) !== 0;
return (kinds & OuterExpressionKinds.NonNullAssertions) !== 0;
case SyntaxKind.PartiallyEmittedExpression:
return (kinds & OuterExpressionKinds.PartiallyEmittedExpressions) !== 0;
}
@@ -1360,34 +1363,16 @@ namespace ts {
export function skipOuterExpressions(node: Expression, kinds?: OuterExpressionKinds): Expression;
export function skipOuterExpressions(node: Node, kinds?: OuterExpressionKinds): Node;
export function skipOuterExpressions(node: Node, kinds = OuterExpressionKinds.All) {
let previousNode: Node;
do {
previousNode = node;
if (kinds & OuterExpressionKinds.Parentheses) {
node = skipParentheses(node);
}
if (kinds & OuterExpressionKinds.Assertions) {
node = skipAssertions(node);
}
if (kinds & OuterExpressionKinds.PartiallyEmittedExpressions) {
node = skipPartiallyEmittedExpressions(node);
}
while (isOuterExpression(node, kinds)) {
node = node.expression;
}
while (previousNode !== node);
return node;
}
export function skipAssertions(node: Expression): Expression;
export function skipAssertions(node: Node): Node;
export function skipAssertions(node: Node): Node {
while (isAssertionExpression(node) || node.kind === SyntaxKind.NonNullExpression) {
node = (<AssertionExpression | NonNullExpression>node).expression;
}
return node;
return skipOuterExpressions(node, OuterExpressionKinds.Assertions);
}
function updateOuterExpression(outerExpression: OuterExpression, expression: Expression) {
+19 -4
View File
@@ -1076,10 +1076,8 @@ namespace ts {
}
export function updatePropertyAccess(node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateIdentifier) {
if (isOptionalChain(node) && isIdentifier(node.name) && isIdentifier(name)) {
// Not sure why this cast was necessary: the previous line should already establish that node.name is an identifier
const theNode = node as (typeof node & { name: Identifier });
return updatePropertyAccessChain(theNode, expression, node.questionDotToken, name);
if (isPropertyAccessChain(node)) {
return updatePropertyAccessChain(node, expression, node.questionDotToken, cast(name, isIdentifier));
}
// Because we are updating existed propertyAccess we want to inherit its emitFlags
// instead of using the default from createPropertyAccess
@@ -1653,11 +1651,28 @@ namespace ts {
}
export function updateNonNullExpression(node: NonNullExpression, expression: Expression) {
if (isNonNullChain(node)) {
return updateNonNullChain(node, expression);
}
return node.expression !== expression
? updateNode(createNonNullExpression(expression), node)
: node;
}
export function createNonNullChain(expression: Expression) {
const node = <NonNullChain>createSynthesizedNode(SyntaxKind.NonNullExpression);
node.flags |= NodeFlags.OptionalChain;
node.expression = parenthesizeForAccess(expression);
return node;
}
export function updateNonNullChain(node: NonNullChain, expression: Expression) {
Debug.assert(!!(node.flags & NodeFlags.OptionalChain), "Cannot update a NonNullExpression using updateNonNullChain. Use updateNonNullExpression instead.");
return node.expression !== expression
? updateNode(createNonNullChain(expression), node)
: node;
}
export function createMetaProperty(keywordToken: MetaProperty["keywordToken"], name: Identifier) {
const node = <MetaProperty>createSynthesizedNode(SyntaxKind.MetaProperty);
node.keywordToken = keywordToken;
+23 -9
View File
@@ -4685,12 +4685,26 @@ 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 tryReparseOptionalChain(node: Expression) {
if (node.flags & NodeFlags.OptionalChain) {
return true;
}
// check for an optional chain in a non-null expression
if (isNonNullExpression(node)) {
let expr = node.expression;
while (isNonNullExpression(expr) && !(expr.flags & NodeFlags.OptionalChain)) {
expr = expr.expression;
}
if (expr.flags & NodeFlags.OptionalChain) {
// this is part of an optional chain. Walk down from `node` to `expression` and set the flag.
while (isNonNullExpression(node)) {
node.flags |= NodeFlags.OptionalChain;
node = node.expression;
}
return true;
}
}
return false;
}
function parsePropertyAccessExpressionRest(expression: LeftHandSideExpression, questionDotToken: QuestionDotToken | undefined) {
@@ -4698,7 +4712,7 @@ namespace ts {
propertyAccess.expression = expression;
propertyAccess.questionDotToken = questionDotToken;
propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true, /*allowPrivateIdentifiers*/ true);
if (questionDotToken || hasOptionalChain(expression)) {
if (questionDotToken || tryReparseOptionalChain(expression)) {
propertyAccess.flags |= NodeFlags.OptionalChain;
if (isPrivateIdentifier(propertyAccess.name)) {
parseErrorAtRange(propertyAccess.name, Diagnostics.An_optional_chain_cannot_contain_private_identifiers);
@@ -4724,7 +4738,7 @@ namespace ts {
}
parseExpected(SyntaxKind.CloseBracketToken);
if (questionDotToken || hasOptionalChain(expression)) {
if (questionDotToken || tryReparseOptionalChain(expression)) {
indexedAccess.flags |= NodeFlags.OptionalChain;
}
return finishNode(indexedAccess);
@@ -4811,7 +4825,7 @@ namespace ts {
callExpr.questionDotToken = questionDotToken;
callExpr.typeArguments = typeArguments;
callExpr.arguments = parseArgumentList();
if (questionDotToken || hasOptionalChain(expression)) {
if (questionDotToken || tryReparseOptionalChain(expression)) {
callExpr.flags |= NodeFlags.OptionalChain;
}
expression = finishNode(callExpr);
@@ -4823,7 +4837,7 @@ namespace ts {
callExpr.expression = expression;
callExpr.questionDotToken = questionDotToken;
callExpr.arguments = parseArgumentList();
if (questionDotToken || hasOptionalChain(expression)) {
if (questionDotToken || tryReparseOptionalChain(expression)) {
callExpr.flags |= NodeFlags.OptionalChain;
}
expression = finishNode(callExpr);
+2
View File
@@ -42,9 +42,11 @@ namespace ts {
}
function flattenChain(chain: OptionalChain) {
Debug.assertNotNode(chain, isNonNullChain);
const links: OptionalChain[] = [chain];
while (!chain.questionDotToken && !isTaggedTemplateExpression(chain)) {
chain = cast(skipPartiallyEmittedExpressions(chain.expression), isOptionalChain);
Debug.assertNotNode(chain, isNonNullChain);
links.unshift(chain);
}
return { expression: chain.expression, chain: links };
+5
View File
@@ -1922,6 +1922,7 @@ namespace ts {
| PropertyAccessChain
| ElementAccessChain
| CallChain
| NonNullChain
;
/* @internal */
@@ -2016,6 +2017,10 @@ namespace ts {
expression: Expression;
}
export interface NonNullChain extends NonNullExpression {
_optionalChainBrand: any;
}
// NOTE: MetaProperty is really a MemberExpression, but we consider it a PrimaryExpression
// for the same reasons we treat NewExpression as a PrimaryExpression.
export interface MetaProperty extends PrimaryExpression {
+1 -5
View File
@@ -2614,11 +2614,7 @@ namespace ts {
export function skipParentheses(node: Expression): Expression;
export function skipParentheses(node: Node): Node;
export function skipParentheses(node: Node): Node {
while (node.kind === SyntaxKind.ParenthesizedExpression) {
node = (node as ParenthesizedExpression).expression;
}
return node;
return skipOuterExpressions(node, OuterExpressionKinds.Parentheses);
}
function skipParenthesesUp(node: Node): Node {
+16 -14
View File
@@ -1076,17 +1076,18 @@ namespace ts {
return isCallExpression(node) && !!(node.flags & NodeFlags.OptionalChain);
}
export function isOptionalChain(node: Node): node is PropertyAccessChain | ElementAccessChain | CallChain {
export function isOptionalChain(node: Node): node is PropertyAccessChain | ElementAccessChain | CallChain | NonNullChain {
const kind = node.kind;
return !!(node.flags & NodeFlags.OptionalChain) &&
(kind === SyntaxKind.PropertyAccessExpression
|| kind === SyntaxKind.ElementAccessExpression
|| kind === SyntaxKind.CallExpression);
|| kind === SyntaxKind.CallExpression
|| kind === SyntaxKind.NonNullExpression);
}
/* @internal */
export function isOptionalChainRoot(node: Node): node is OptionalChainRoot {
return isOptionalChain(node) && !!node.questionDotToken;
return isOptionalChain(node) && !isNonNullExpression(node) && !!node.questionDotToken;
}
/**
@@ -1101,17 +1102,18 @@ namespace ts {
* Determines whether a node is the outermost `OptionalChain` in an ECMAScript `OptionalExpression`:
*
* 1. For `a?.b.c`, the outermost chain is `a?.b.c` (`c` is the end of the chain starting at `a?.`)
* 2. For `(a?.b.c).d`, the outermost chain is `a?.b.c` (`c` is the end of the chain starting at `a?.` since parens end the chain)
* 3. For `a?.b.c?.d`, both `a?.b.c` and `a?.b.c?.d` are outermost (`c` is the end of the chain starting at `a?.`, and `d` is
* 2. For `a?.b!`, the outermost chain is `a?.b!` (`c` is the end of the chain starting at `a?.`)
* 3. For `(a?.b.c).d`, the outermost chain is `a?.b.c` (`c` is the end of the chain starting at `a?.` since parens end the chain)
* 4. For `a?.b.c?.d`, both `a?.b.c` and `a?.b.c?.d` are outermost (`c` is the end of the chain starting at `a?.`, and `d` is
* the end of the chain starting at `c?.`)
* 4. For `a?.(b?.c).d`, both `b?.c` and `a?.(b?.c)d` are outermost (`c` is the end of the chain starting at `b`, and `d` is
* 5. For `a?.(b?.c).d`, both `b?.c` and `a?.(b?.c)d` are outermost (`c` is the end of the chain starting at `b`, and `d` is
* the end of the chain starting at `a?.`)
*/
/* @internal */
export function isOutermostOptionalChain(node: OptionalChain) {
return !isOptionalChain(node.parent) // cases 1 and 2
|| isOptionalChainRoot(node.parent) // case 3
|| node !== node.parent.expression; // case 4
return !isOptionalChain(node.parent) // cases 1, 2, and 3
|| isOptionalChainRoot(node.parent) // case 4
|| node !== node.parent.expression; // case 5
}
export function isNullishCoalesce(node: Node) {
@@ -1142,11 +1144,7 @@ namespace ts {
export function skipPartiallyEmittedExpressions(node: Expression): Expression;
export function skipPartiallyEmittedExpressions(node: Node): Node;
export function skipPartiallyEmittedExpressions(node: Node) {
while (node.kind === SyntaxKind.PartiallyEmittedExpression) {
node = (<PartiallyEmittedExpression>node).expression;
}
return node;
return skipOuterExpressions(node, OuterExpressionKinds.PartiallyEmittedExpressions);
}
export function isFunctionExpression(node: Node): node is FunctionExpression {
@@ -1221,6 +1219,10 @@ namespace ts {
return node.kind === SyntaxKind.NonNullExpression;
}
export function isNonNullChain(node: Node): node is NonNullChain {
return isNonNullExpression(node) && !!(node.flags & NodeFlags.OptionalChain);
}
export function isMetaProperty(node: Node): node is MetaProperty {
return node.kind === SyntaxKind.MetaProperty;
}
+1 -1
View File
@@ -1012,7 +1012,7 @@ namespace ts {
export function getPossibleGenericSignatures(called: Expression, typeArgumentCount: number, checker: TypeChecker): readonly Signature[] {
let type = checker.getTypeAtLocation(called);
if (isOptionalChain(called.parent)) {
type = removeOptionality(type, !!called.parent.questionDotToken, /*isOptionalChain*/ true);
type = removeOptionality(type, isOptionalChainRoot(called.parent), /*isOptionalChain*/ true);
}
const signatures = isNewExpression(called.parent) ? type.getConstructSignatures() : type.getCallSignatures();
+8 -2
View File
@@ -1136,7 +1136,7 @@ declare namespace ts {
export interface CallChain extends CallExpression {
_optionalChainBrand: any;
}
export type OptionalChain = PropertyAccessChain | ElementAccessChain | CallChain;
export type OptionalChain = PropertyAccessChain | ElementAccessChain | CallChain | NonNullChain;
export interface SuperCall extends CallExpression {
expression: SuperExpression;
}
@@ -1176,6 +1176,9 @@ declare namespace ts {
kind: SyntaxKind.NonNullExpression;
expression: Expression;
}
export interface NonNullChain extends NonNullExpression {
_optionalChainBrand: any;
}
export interface MetaProperty extends PrimaryExpression {
kind: SyntaxKind.MetaProperty;
keywordToken: SyntaxKind.NewKeyword | SyntaxKind.ImportKeyword;
@@ -3615,7 +3618,7 @@ declare namespace ts {
function isElementAccessChain(node: Node): node is ElementAccessChain;
function isCallExpression(node: Node): node is CallExpression;
function isCallChain(node: Node): node is CallChain;
function isOptionalChain(node: Node): node is PropertyAccessChain | ElementAccessChain | CallChain;
function isOptionalChain(node: Node): node is PropertyAccessChain | ElementAccessChain | CallChain | NonNullChain;
function isNullishCoalesce(node: Node): boolean;
function isNewExpression(node: Node): node is NewExpression;
function isTaggedTemplateExpression(node: Node): node is TaggedTemplateExpression;
@@ -3642,6 +3645,7 @@ declare namespace ts {
function isExpressionWithTypeArguments(node: Node): node is ExpressionWithTypeArguments;
function isAsExpression(node: Node): node is AsExpression;
function isNonNullExpression(node: Node): node is NonNullExpression;
function isNonNullChain(node: Node): node is NonNullChain;
function isMetaProperty(node: Node): node is MetaProperty;
function isTemplateSpan(node: Node): node is TemplateSpan;
function isSemicolonClassElement(node: Node): node is SemicolonClassElement;
@@ -4130,6 +4134,8 @@ declare namespace ts {
function updateAsExpression(node: AsExpression, expression: Expression, type: TypeNode): AsExpression;
function createNonNullExpression(expression: Expression): NonNullExpression;
function updateNonNullExpression(node: NonNullExpression, expression: Expression): NonNullExpression;
function createNonNullChain(expression: Expression): NonNullChain;
function updateNonNullChain(node: NonNullChain, expression: Expression): NonNullChain;
function createMetaProperty(keywordToken: MetaProperty["keywordToken"], name: Identifier): MetaProperty;
function updateMetaProperty(node: MetaProperty, name: Identifier): MetaProperty;
function createTemplateSpan(expression: Expression, literal: TemplateMiddle | TemplateTail): TemplateSpan;
+8 -2
View File
@@ -1136,7 +1136,7 @@ declare namespace ts {
export interface CallChain extends CallExpression {
_optionalChainBrand: any;
}
export type OptionalChain = PropertyAccessChain | ElementAccessChain | CallChain;
export type OptionalChain = PropertyAccessChain | ElementAccessChain | CallChain | NonNullChain;
export interface SuperCall extends CallExpression {
expression: SuperExpression;
}
@@ -1176,6 +1176,9 @@ declare namespace ts {
kind: SyntaxKind.NonNullExpression;
expression: Expression;
}
export interface NonNullChain extends NonNullExpression {
_optionalChainBrand: any;
}
export interface MetaProperty extends PrimaryExpression {
kind: SyntaxKind.MetaProperty;
keywordToken: SyntaxKind.NewKeyword | SyntaxKind.ImportKeyword;
@@ -3615,7 +3618,7 @@ declare namespace ts {
function isElementAccessChain(node: Node): node is ElementAccessChain;
function isCallExpression(node: Node): node is CallExpression;
function isCallChain(node: Node): node is CallChain;
function isOptionalChain(node: Node): node is PropertyAccessChain | ElementAccessChain | CallChain;
function isOptionalChain(node: Node): node is PropertyAccessChain | ElementAccessChain | CallChain | NonNullChain;
function isNullishCoalesce(node: Node): boolean;
function isNewExpression(node: Node): node is NewExpression;
function isTaggedTemplateExpression(node: Node): node is TaggedTemplateExpression;
@@ -3642,6 +3645,7 @@ declare namespace ts {
function isExpressionWithTypeArguments(node: Node): node is ExpressionWithTypeArguments;
function isAsExpression(node: Node): node is AsExpression;
function isNonNullExpression(node: Node): node is NonNullExpression;
function isNonNullChain(node: Node): node is NonNullChain;
function isMetaProperty(node: Node): node is MetaProperty;
function isTemplateSpan(node: Node): node is TemplateSpan;
function isSemicolonClassElement(node: Node): node is SemicolonClassElement;
@@ -4130,6 +4134,8 @@ declare namespace ts {
function updateAsExpression(node: AsExpression, expression: Expression, type: TypeNode): AsExpression;
function createNonNullExpression(expression: Expression): NonNullExpression;
function updateNonNullExpression(node: NonNullExpression, expression: Expression): NonNullExpression;
function createNonNullChain(expression: Expression): NonNullChain;
function updateNonNullChain(node: NonNullChain, expression: Expression): NonNullChain;
function createMetaProperty(keywordToken: MetaProperty["keywordToken"], name: Identifier): MetaProperty;
function updateMetaProperty(node: MetaProperty, name: Identifier): MetaProperty;
function createTemplateSpan(expression: Expression, literal: TemplateMiddle | TemplateTail): TemplateSpan;
+3 -1
View File
@@ -38,7 +38,8 @@ declare const o5: <T>() => undefined | (() => void);
o5<number>()?.();
// GH#36031
o2?.b()!.toString
o2?.b()!.toString;
o2?.b()!.toString!;
//// [callChain.js]
"use strict";
@@ -78,3 +79,4 @@ 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;
o2 === null || o2 === void 0 ? void 0 : o2.b().toString;
+8 -1
View File
@@ -157,7 +157,14 @@ o5<number>()?.();
>o5 : Symbol(o5, Decl(callChain.ts, 35, 13))
// GH#36031
o2?.b()!.toString
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, --, --))
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))
+14 -4
View File
@@ -265,12 +265,22 @@ o5<number>()?.();
>o5 : <T>() => (() => void) | undefined
// GH#36031
o2?.b()!.toString
>o2?.b()!.toString : (radix?: number | undefined) => string
>o2?.b()! : number
o2?.b()!.toString;
>o2?.b()!.toString : ((radix?: number | undefined) => string) | undefined
>o2?.b()! : number | undefined
>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
>toString : ((radix?: number | undefined) => string) | undefined
o2?.b()!.toString!;
>o2?.b()!.toString! : (radix?: number | undefined) => string
>o2?.b()!.toString : ((radix?: number | undefined) => string) | undefined
>o2?.b()! : number | undefined
>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) | undefined
@@ -25,8 +25,10 @@ declare const o6: <T>() => undefined | ({ x: number });
o6<number>()?.["x"];
// GH#36031
o2?.["b"]!.c
o2?.["b"]!["c"]
o2?.["b"]!.c;
o2?.["b"]!["c"];
o2?.["b"]!.c!;
o2?.["b"]!["c"]!;
//// [elementAccessChain.js]
"use strict";
@@ -46,3 +48,5 @@ o2 === null || o2 === void 0 ? void 0 : o2.b["c"];
// GH#36031
o2 === null || o2 === void 0 ? void 0 : o2["b"].c;
o2 === null || o2 === void 0 ? void 0 : o2["b"]["c"];
o2 === null || o2 === void 0 ? void 0 : o2["b"].c;
o2 === null || o2 === void 0 ? void 0 : o2["b"]["c"];
@@ -107,12 +107,19 @@ o6<number>()?.["x"];
>o6 : Symbol(o6, Decl(elementAccessChain.ts, 22, 13))
// GH#36031
o2?.["b"]!.c
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?.["b"]!["c"];
>o2 : Symbol(o2, Decl(elementAccessChain.ts, 3, 13))
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))
@@ -142,17 +142,35 @@ o6<number>()?.["x"];
>"x" : "x"
// GH#36031
o2?.["b"]!.c
>o2?.["b"]!.c : string
>o2?.["b"]! : { c: string; }
o2?.["b"]!.c;
>o2?.["b"]!.c : string | undefined
>o2?.["b"]! : { c: string; } | undefined
>o2?.["b"] : { c: string; } | undefined
>o2 : { b: { c: string; }; } | undefined
>"b" : "b"
>c : string
>c : string | undefined
o2?.["b"]!["c"]
>o2?.["b"]!["c"] : string
>o2?.["b"]! : { c: string; }
o2?.["b"]!["c"];
>o2?.["b"]!["c"] : string | undefined
>o2?.["b"]! : { c: string; } | undefined
>o2?.["b"] : { c: string; } | undefined
>o2 : { b: { c: string; }; } | undefined
>"b" : "b"
>"c" : "c"
o2?.["b"]!.c!;
>o2?.["b"]!.c! : string
>o2?.["b"]!.c : string | undefined
>o2?.["b"]! : { c: string; } | undefined
>o2?.["b"] : { c: string; } | undefined
>o2 : { b: { c: string; }; } | undefined
>"b" : "b"
>c : string | undefined
o2?.["b"]!["c"]!;
>o2?.["b"]!["c"]! : string
>o2?.["b"]!["c"] : string | undefined
>o2?.["b"]! : { c: string; } | undefined
>o2?.["b"] : { c: string; } | undefined
>o2 : { b: { c: string; }; } | undefined
>"b" : "b"
@@ -22,7 +22,8 @@ o6<number>()?.x;
o1?.b ? 1 : 0;
// GH#36031
o2?.b!.c
o2?.b!.c;
o2?.b!.c!;
//// [propertyAccessChain.js]
"use strict";
@@ -37,3 +38,4 @@ o2 === null || o2 === void 0 ? void 0 : o2.b.c;
(o1 === null || o1 === void 0 ? void 0 : o1.b) ? 1 : 0;
// GH#36031
o2 === null || o2 === void 0 ? void 0 : o2.b.c;
o2 === null || o2 === void 0 ? void 0 : o2.b.c;
@@ -86,7 +86,14 @@ o1?.b ? 1 : 0;
>b : Symbol(b, Decl(propertyAccessChain.ts, 0, 31))
// GH#36031
o2?.b!.c
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))
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))
@@ -90,11 +90,20 @@ o1?.b ? 1 : 0;
>0 : 0
// GH#36031
o2?.b!.c
>o2?.b!.c : string
>o2?.b! : { c: string; }
o2?.b!.c;
>o2?.b!.c : string | undefined
>o2?.b! : { c: string; } | undefined
>o2?.b : { c: string; } | undefined
>o2 : { b: { c: string; }; } | undefined
>b : { c: string; } | undefined
>c : string
>c : string | undefined
o2?.b!.c!;
>o2?.b!.c! : string
>o2?.b!.c : string | undefined
>o2?.b! : { c: string; } | undefined
>o2?.b : { c: string; } | undefined
>o2 : { b: { c: string; }; } | undefined
>b : { c: string; } | undefined
>c : string | undefined
@@ -39,4 +39,5 @@ declare const o5: <T>() => undefined | (() => void);
o5<number>()?.();
// GH#36031
o2?.b()!.toString
o2?.b()!.toString;
o2?.b()!.toString!;
@@ -26,5 +26,7 @@ declare const o6: <T>() => undefined | ({ x: number });
o6<number>()?.["x"];
// GH#36031
o2?.["b"]!.c
o2?.["b"]!["c"]
o2?.["b"]!.c;
o2?.["b"]!["c"];
o2?.["b"]!.c!;
o2?.["b"]!["c"]!;
@@ -23,4 +23,5 @@ o6<number>()?.x;
o1?.b ? 1 : 0;
// GH#36031
o2?.b!.c
o2?.b!.c;
o2?.b!.c!;