diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index af1da33ac92..e7314eaafa5 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -1065,7 +1065,9 @@ namespace ts { } export function updatePropertyAccess(node: PropertyAccessExpression, expression: Expression, name: Identifier) { - Debug.assert(!(node.flags & NodeFlags.OptionalChain), "Cannot update a PropertyAccessChain using updatePropertyAccess. Use updatePropertyAccessChain instead."); + if (isOptionalChain(node)) { + return updatePropertyAccessChain(node, expression, node.questionDotToken, name); + } // Because we are updating existed propertyAccess we want to inherit its emitFlags // instead of using the default from createPropertyAccess return node.expression !== expression @@ -1103,7 +1105,9 @@ namespace ts { } export function updateElementAccess(node: ElementAccessExpression, expression: Expression, argumentExpression: Expression) { - Debug.assert(!(node.flags & NodeFlags.OptionalChain), "Cannot update an ElementAccessChain using updateElementAccess. Use updateElementAccessChain instead."); + if (isOptionalChain(node)) { + return updateElementAccessChain(node, expression, node.questionDotToken, argumentExpression); + } return node.expression !== expression || node.argumentExpression !== argumentExpression ? updateNode(createElementAccess(expression, argumentExpression), node) @@ -1137,7 +1141,9 @@ namespace ts { } export function updateCall(node: CallExpression, expression: Expression, typeArguments: readonly TypeNode[] | undefined, argumentsArray: readonly Expression[]) { - Debug.assert(!(node.flags & NodeFlags.OptionalChain), "Cannot update a CallChain using updateCall. Use updateCallChain instead."); + if (isOptionalChain(node)) { + return updateCallChain(node, expression, node.questionDotToken, typeArguments, argumentsArray); + } return node.expression !== expression || node.typeArguments !== typeArguments || node.arguments !== argumentsArray diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index c9aff842c8c..fbda386b04b 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -5906,9 +5906,11 @@ namespace ts { } export function isOptionalChain(node: Node): node is PropertyAccessChain | ElementAccessChain | CallChain { - return isPropertyAccessChain(node) - || isElementAccessChain(node) - || isCallChain(node); + const kind = node.kind; + return !!(node.flags & NodeFlags.OptionalChain) && + (kind === SyntaxKind.PropertyAccessExpression + || kind === SyntaxKind.ElementAccessExpression + || kind === SyntaxKind.CallExpression); } export function isNewExpression(node: Node): node is NewExpression { diff --git a/tests/baselines/reference/callChain.js b/tests/baselines/reference/callChain.js index 1ef797b5ad1..439c38e8b83 100644 --- a/tests/baselines/reference/callChain.js +++ b/tests/baselines/reference/callChain.js @@ -31,7 +31,11 @@ o3["b"]?.(1, ...[2, 3], 4).c; declare const o4: undefined | ((f: (a: T) => T) => T); declare function incr(x: number): number; -const v: number | undefined = o4?.(incr); +const v: number | undefined = o4?.(incr); + +// GH#33744 +declare const o5: () => undefined | (() => void); +o5()?.(); //// [callChain.js] "use strict"; @@ -42,7 +46,7 @@ var __spreadArrays = (this && this.__spreadArrays) || function () { r[k] = a[j]; return r; }; -var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12; +var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13; (_a = o1) === null || _a === void 0 ? void 0 : _a(); (_b = o1) === null || _b === void 0 ? void 0 : _b(1); (_c = o1) === null || _c === void 0 ? void 0 : _c.apply(void 0, [1, 2]); @@ -68,3 +72,4 @@ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, (_9 = (_8 = o3)["b"]) === null || _9 === void 0 ? void 0 : _9.call.apply(_9, __spreadArrays([_8], [1, 2])).c; (_11 = (_10 = o3)["b"]) === null || _11 === void 0 ? void 0 : _11.call.apply(_11, __spreadArrays([_10, 1], [2, 3], [4])).c; var v = (_12 = o4) === null || _12 === void 0 ? void 0 : _12(incr); +(_13 = o5()) === null || _13 === void 0 ? void 0 : _13(); diff --git a/tests/baselines/reference/callChain.symbols b/tests/baselines/reference/callChain.symbols index dd52388bda6..d0a266c41ea 100644 --- a/tests/baselines/reference/callChain.symbols +++ b/tests/baselines/reference/callChain.symbols @@ -148,3 +148,11 @@ const v: number | undefined = o4?.(incr); >o4 : Symbol(o4, Decl(callChain.ts, 30, 13)) >incr : Symbol(incr, Decl(callChain.ts, 30, 57)) +// GH#33744 +declare const o5: () => undefined | (() => void); +>o5 : Symbol(o5, Decl(callChain.ts, 35, 13)) +>T : Symbol(T, Decl(callChain.ts, 35, 19)) + +o5()?.(); +>o5 : Symbol(o5, Decl(callChain.ts, 35, 13)) + diff --git a/tests/baselines/reference/callChain.types b/tests/baselines/reference/callChain.types index 70f835bf568..6ba17855cb3 100644 --- a/tests/baselines/reference/callChain.types +++ b/tests/baselines/reference/callChain.types @@ -255,3 +255,12 @@ const v: number | undefined = o4?.(incr); >o4 : ((f: (a: T) => T) => T) | undefined >incr : (x: number) => number +// GH#33744 +declare const o5: () => undefined | (() => void); +>o5 : () => (() => void) | undefined + +o5()?.(); +>o5()?.() : void | undefined +>o5() : (() => void) | undefined +>o5 : () => (() => void) | undefined + diff --git a/tests/baselines/reference/elementAccessChain.js b/tests/baselines/reference/elementAccessChain.js index bf7804ff2cf..e01480eb68b 100644 --- a/tests/baselines/reference/elementAccessChain.js +++ b/tests/baselines/reference/elementAccessChain.js @@ -19,11 +19,14 @@ o5.b?.()["c"].d?.e; o5.b?.()["c"].d?.["e"]; o5["b"]?.()["c"].d?.e; o5["b"]?.()["c"].d?.["e"]; - + +// GH#33744 +declare const o6: () => undefined | ({ x: number }); +o6()?.["x"]; //// [elementAccessChain.js] "use strict"; -var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w; +var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x; (_a = o1) === null || _a === void 0 ? void 0 : _a["b"]; (_b = o2) === null || _b === void 0 ? void 0 : _b["b"].c; (_c = o2) === null || _c === void 0 ? void 0 : _c.b["c"]; @@ -35,3 +38,4 @@ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, (_q = (_p = (_o = o5).b) === null || _p === void 0 ? void 0 : _p.call(_o)["c"].d) === null || _q === void 0 ? void 0 : _q["e"]; (_t = (_s = (_r = o5)["b"]) === null || _s === void 0 ? void 0 : _s.call(_r)["c"].d) === null || _t === void 0 ? void 0 : _t.e; (_w = (_v = (_u = o5)["b"]) === null || _v === void 0 ? void 0 : _v.call(_u)["c"].d) === null || _w === void 0 ? void 0 : _w["e"]; +(_x = o6()) === null || _x === void 0 ? void 0 : _x["x"]; diff --git a/tests/baselines/reference/elementAccessChain.symbols b/tests/baselines/reference/elementAccessChain.symbols index af253ccd4bf..5e892012173 100644 --- a/tests/baselines/reference/elementAccessChain.symbols +++ b/tests/baselines/reference/elementAccessChain.symbols @@ -97,3 +97,12 @@ o5["b"]?.()["c"].d?.["e"]; >"b" : Symbol(b, Decl(elementAccessChain.ts, 15, 19)) >d : Symbol(d, Decl(elementAccessChain.ts, 15, 32)) +// GH#33744 +declare const o6: () => undefined | ({ x: number }); +>o6 : Symbol(o6, Decl(elementAccessChain.ts, 22, 13)) +>T : Symbol(T, Decl(elementAccessChain.ts, 22, 19)) +>x : Symbol(x, Decl(elementAccessChain.ts, 22, 41)) + +o6()?.["x"]; +>o6 : Symbol(o6, Decl(elementAccessChain.ts, 22, 13)) + diff --git a/tests/baselines/reference/elementAccessChain.types b/tests/baselines/reference/elementAccessChain.types index 0d99166ba0f..a186074e86b 100644 --- a/tests/baselines/reference/elementAccessChain.types +++ b/tests/baselines/reference/elementAccessChain.types @@ -130,3 +130,14 @@ o5["b"]?.()["c"].d?.["e"]; >d : { e: string; } | undefined >"e" : "e" +// GH#33744 +declare const o6: () => undefined | ({ x: number }); +>o6 : () => { x: number; } | undefined +>x : number + +o6()?.["x"]; +>o6()?.["x"] : number | undefined +>o6() : { x: number; } | undefined +>o6 : () => { x: number; } | undefined +>"x" : "x" + diff --git a/tests/baselines/reference/propertyAccessChain.js b/tests/baselines/reference/propertyAccessChain.js index 0c15856b15c..14579efb191 100644 --- a/tests/baselines/reference/propertyAccessChain.js +++ b/tests/baselines/reference/propertyAccessChain.js @@ -13,13 +13,17 @@ o4.b?.c.d?.e; declare const o5: { b?(): { c: { d?: { e: string } } } }; o5.b?.().c.d?.e; - + +// GH#33744 +declare const o6: () => undefined | ({ x: number }); +o6()?.x; //// [propertyAccessChain.js] "use strict"; -var _a, _b, _c, _d, _e, _f, _g, _h; +var _a, _b, _c, _d, _e, _f, _g, _h, _j; (_a = o1) === null || _a === void 0 ? void 0 : _a.b; (_b = o2) === null || _b === void 0 ? void 0 : _b.b.c; (_c = o3.b) === null || _c === void 0 ? void 0 : _c.c; (_e = (_d = o4.b) === null || _d === void 0 ? void 0 : _d.c.d) === null || _e === void 0 ? void 0 : _e.e; (_h = (_g = (_f = o5).b) === null || _g === void 0 ? void 0 : _g.call(_f).c.d) === null || _h === void 0 ? void 0 : _h.e; +(_j = o6()) === null || _j === void 0 ? void 0 : _j.x; diff --git a/tests/baselines/reference/propertyAccessChain.symbols b/tests/baselines/reference/propertyAccessChain.symbols index 8b5cea9fe67..b10785d0edb 100644 --- a/tests/baselines/reference/propertyAccessChain.symbols +++ b/tests/baselines/reference/propertyAccessChain.symbols @@ -68,3 +68,14 @@ o5.b?.().c.d?.e; >d : Symbol(d, Decl(propertyAccessChain.ts, 12, 32)) >e : Symbol(e, Decl(propertyAccessChain.ts, 12, 38)) +// GH#33744 +declare const o6: () => undefined | ({ x: number }); +>o6 : Symbol(o6, Decl(propertyAccessChain.ts, 16, 13)) +>T : Symbol(T, Decl(propertyAccessChain.ts, 16, 19)) +>x : Symbol(x, Decl(propertyAccessChain.ts, 16, 41)) + +o6()?.x; +>o6()?.x : Symbol(x, Decl(propertyAccessChain.ts, 16, 41)) +>o6 : Symbol(o6, Decl(propertyAccessChain.ts, 16, 13)) +>x : Symbol(x, Decl(propertyAccessChain.ts, 16, 41)) + diff --git a/tests/baselines/reference/propertyAccessChain.types b/tests/baselines/reference/propertyAccessChain.types index 2cb030ac3f6..00fb070bf3a 100644 --- a/tests/baselines/reference/propertyAccessChain.types +++ b/tests/baselines/reference/propertyAccessChain.types @@ -69,3 +69,14 @@ o5.b?.().c.d?.e; >d : { e: string; } | undefined >e : string | undefined +// GH#33744 +declare const o6: () => undefined | ({ x: number }); +>o6 : () => { x: number; } | undefined +>x : number + +o6()?.x; +>o6()?.x : number | undefined +>o6() : { x: number; } | undefined +>o6 : () => { x: number; } | undefined +>x : number | undefined + diff --git a/tests/cases/conformance/expressions/optionalChaining/callChain/callChain.ts b/tests/cases/conformance/expressions/optionalChaining/callChain/callChain.ts index fa24d920a19..bbfc3aa42f9 100644 --- a/tests/cases/conformance/expressions/optionalChaining/callChain/callChain.ts +++ b/tests/cases/conformance/expressions/optionalChaining/callChain/callChain.ts @@ -32,4 +32,8 @@ o3["b"]?.(1, ...[2, 3], 4).c; declare const o4: undefined | ((f: (a: T) => T) => T); declare function incr(x: number): number; -const v: number | undefined = o4?.(incr); \ No newline at end of file +const v: number | undefined = o4?.(incr); + +// GH#33744 +declare const o5: () => undefined | (() => void); +o5()?.(); \ No newline at end of file diff --git a/tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.ts b/tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.ts index 6718c050a03..20dfaab0c86 100644 --- a/tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.ts +++ b/tests/cases/conformance/expressions/optionalChaining/elementAccessChain/elementAccessChain.ts @@ -20,3 +20,7 @@ o5.b?.()["c"].d?.e; o5.b?.()["c"].d?.["e"]; o5["b"]?.()["c"].d?.e; o5["b"]?.()["c"].d?.["e"]; + +// GH#33744 +declare const o6: () => undefined | ({ x: number }); +o6()?.["x"]; \ No newline at end of file diff --git a/tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.ts b/tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.ts index e76d95b4540..7a0c6bc11a0 100644 --- a/tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.ts +++ b/tests/cases/conformance/expressions/optionalChaining/propertyAccessChain/propertyAccessChain.ts @@ -14,3 +14,7 @@ o4.b?.c.d?.e; declare const o5: { b?(): { c: { d?: { e: string } } } }; o5.b?.().c.d?.e; + +// GH#33744 +declare const o6: () => undefined | ({ x: number }); +o6()?.x; \ No newline at end of file