From 12b8c6cdb97eaf0e2c70c64155ebf95e9a5b1b90 Mon Sep 17 00:00:00 2001 From: Oleksandr Tarasiuk Date: Thu, 24 Sep 2026 12:28:00 +0300 Subject: [PATCH] fix(64421): convert nested rest bindings to assignment targets --- tsc/internal/transformers/utilities.go | 4 +-- .../compiler/exportDestructuringIterator.js | 8 ++++- .../exportDestructuringIterator.symbols | 14 ++++++++ .../exportDestructuringIterator.types | 19 +++++++++++ .../compiler/usingDeclarationsNestedRest.js | 26 ++++++++++++++ .../usingDeclarationsNestedRest.symbols | 23 +++++++++++++ .../usingDeclarationsNestedRest.types | 34 +++++++++++++++++++ .../compiler/exportDestructuringIterator.ts | 3 ++ .../compiler/usingDeclarationsNestedRest.ts | 8 +++++ 9 files changed, 136 insertions(+), 3 deletions(-) create mode 100644 tsc/testdata/baselines/reference/compiler/usingDeclarationsNestedRest.js create mode 100644 tsc/testdata/baselines/reference/compiler/usingDeclarationsNestedRest.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/usingDeclarationsNestedRest.types create mode 100644 tsc/testdata/tests/cases/compiler/usingDeclarationsNestedRest.ts diff --git a/tsc/internal/transformers/utilities.go b/tsc/internal/transformers/utilities.go index 949fdbda5e8ba..af826b85a6c20 100644 --- a/tsc/internal/transformers/utilities.go +++ b/tsc/internal/transformers/utilities.go @@ -116,13 +116,13 @@ func convertBindingElementToArrayAssignmentElement(emitContext *printer.EmitCont emitContext.AssignCommentAndSourceMapRanges(elision, element.AsNode()) return elision } + expression := convertBindingNameToAssignmentElementTarget(emitContext, element.Name()) if element.DotDotDotToken != nil { - spread := emitContext.Factory.NewSpreadElement(element.Name()) + spread := emitContext.Factory.NewSpreadElement(expression) emitContext.SetOriginal(spread, element.AsNode()) emitContext.AssignCommentAndSourceMapRanges(spread, element.AsNode()) return spread } - expression := convertBindingNameToAssignmentElementTarget(emitContext, element.Name()) if element.Initializer != nil { assignment := emitContext.Factory.NewAssignmentExpression(expression, element.Initializer) emitContext.SetOriginal(assignment, element.AsNode()) diff --git a/tsc/testdata/baselines/reference/compiler/exportDestructuringIterator.js b/tsc/testdata/baselines/reference/compiler/exportDestructuringIterator.js index f8fcfaee2b489..e91b631e269ba 100644 --- a/tsc/testdata/baselines/reference/compiler/exportDestructuringIterator.js +++ b/tsc/testdata/baselines/reference/compiler/exportDestructuringIterator.js @@ -9,12 +9,15 @@ export const [c, ...d] = foo(); export const [, e, , f] = foo(); export const [[g, h], { i, j: k }] = foo(); export const { m: [n, o], p: { q } } = foo(); +export const [...[r, s]] = foo(); +export const [...{ length: t }] = foo(); +export const [...[u = 1, , ...[v]]] = foo(); //// [exportDestructuringIterator.js] "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.q = exports.o = exports.n = exports.k = exports.i = exports.h = exports.g = exports.f = exports.e = exports.d = exports.c = exports.b = exports.a = exports.y = exports.x = exports.V = exports.A = void 0; +exports.v = exports.u = exports.t = exports.s = exports.r = exports.q = exports.o = exports.n = exports.k = exports.i = exports.h = exports.g = exports.f = exports.e = exports.d = exports.c = exports.b = exports.a = exports.y = exports.x = exports.V = exports.A = void 0; [exports.A, exports.V] = foo(); ({ x: exports.x, y: exports.y } = foo()); [exports.a = 1, exports.b = 2] = foo(); @@ -22,3 +25,6 @@ exports.q = exports.o = exports.n = exports.k = exports.i = exports.h = exports. [, exports.e, , exports.f] = foo(); [[exports.g, exports.h], { i: exports.i, j: exports.k }] = foo(); ({ m: [exports.n, exports.o], p: { q: exports.q } } = foo()); +[...[exports.r, exports.s]] = foo(); +[...{ length: exports.t }] = foo(); +[...[exports.u = 1, , ...[exports.v]]] = foo(); diff --git a/tsc/testdata/baselines/reference/compiler/exportDestructuringIterator.symbols b/tsc/testdata/baselines/reference/compiler/exportDestructuringIterator.symbols index e69cbd17b382c..d3bf00f37f79d 100644 --- a/tsc/testdata/baselines/reference/compiler/exportDestructuringIterator.symbols +++ b/tsc/testdata/baselines/reference/compiler/exportDestructuringIterator.symbols @@ -42,3 +42,17 @@ export const { m: [n, o], p: { q } } = foo(); >q : Symbol(q, Decl(exportDestructuringIterator.ts, 7, 30)) >foo : Symbol(foo, Decl(exportDestructuringIterator.ts, 0, 0)) +export const [...[r, s]] = foo(); +>r : Symbol(r, Decl(exportDestructuringIterator.ts, 8, 18)) +>s : Symbol(s, Decl(exportDestructuringIterator.ts, 8, 20)) +>foo : Symbol(foo, Decl(exportDestructuringIterator.ts, 0, 0)) + +export const [...{ length: t }] = foo(); +>t : Symbol(t, Decl(exportDestructuringIterator.ts, 9, 18)) +>foo : Symbol(foo, Decl(exportDestructuringIterator.ts, 0, 0)) + +export const [...[u = 1, , ...[v]]] = foo(); +>u : Symbol(u, Decl(exportDestructuringIterator.ts, 10, 18)) +>v : Symbol(v, Decl(exportDestructuringIterator.ts, 10, 31)) +>foo : Symbol(foo, Decl(exportDestructuringIterator.ts, 0, 0)) + diff --git a/tsc/testdata/baselines/reference/compiler/exportDestructuringIterator.types b/tsc/testdata/baselines/reference/compiler/exportDestructuringIterator.types index 3e6634b1a4e98..9b96058642c6e 100644 --- a/tsc/testdata/baselines/reference/compiler/exportDestructuringIterator.types +++ b/tsc/testdata/baselines/reference/compiler/exportDestructuringIterator.types @@ -54,3 +54,22 @@ export const { m: [n, o], p: { q } } = foo(); >foo() : any >foo : () => any +export const [...[r, s]] = foo(); +>r : any +>s : any +>foo() : any +>foo : () => any + +export const [...{ length: t }] = foo(); +>length : any +>t : any +>foo() : any +>foo : () => any + +export const [...[u = 1, , ...[v]]] = foo(); +>u : any +>1 : 1 +>v : any +>foo() : any +>foo : () => any + diff --git a/tsc/testdata/baselines/reference/compiler/usingDeclarationsNestedRest.js b/tsc/testdata/baselines/reference/compiler/usingDeclarationsNestedRest.js new file mode 100644 index 0000000000000..2c7a7020c2d6f --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/usingDeclarationsNestedRest.js @@ -0,0 +1,26 @@ +//// [tests/cases/compiler/usingDeclarationsNestedRest.ts] //// + +//// [usingDeclarationsNestedRest.ts] +using z = { [Symbol.dispose]() {} }; +var [...[a, b]] = [0, 1]; +var [...{ length: c }] = [0, 1]; +var [...[d = 2, , ...[e]]] = [undefined, 1, 3]; + + +//// [usingDeclarationsNestedRest.js] +"use strict"; +var z, a, b, c, d, e; +const env_1 = { stack: [], error: void 0, hasError: false }; +try { + z = __addDisposableResource(env_1, { [Symbol.dispose]() { } }, false); + [...[a, b]] = [0, 1]; + [...{ length: c }] = [0, 1]; + [...[d = 2, , ...[e]]] = [undefined, 1, 3]; +} +catch (e_1) { + env_1.error = e_1; + env_1.hasError = true; +} +finally { + __disposeResources(env_1); +} diff --git a/tsc/testdata/baselines/reference/compiler/usingDeclarationsNestedRest.symbols b/tsc/testdata/baselines/reference/compiler/usingDeclarationsNestedRest.symbols new file mode 100644 index 0000000000000..8233523b18fb5 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/usingDeclarationsNestedRest.symbols @@ -0,0 +1,23 @@ +//// [tests/cases/compiler/usingDeclarationsNestedRest.ts] //// + +=== usingDeclarationsNestedRest.ts === +using z = { [Symbol.dispose]() {} }; +>z : Symbol(z, Decl(usingDeclarationsNestedRest.ts, 0, 5)) +>[Symbol.dispose] : Symbol([Symbol.dispose], Decl(usingDeclarationsNestedRest.ts, 0, 11)) +>Symbol.dispose : Symbol(SymbolConstructor.dispose, Decl(lib.esnext.disposable.d.ts, --, --)) +>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --)) +>dispose : Symbol(SymbolConstructor.dispose, Decl(lib.esnext.disposable.d.ts, --, --)) + +var [...[a, b]] = [0, 1]; +>a : Symbol(a, Decl(usingDeclarationsNestedRest.ts, 1, 9)) +>b : Symbol(b, Decl(usingDeclarationsNestedRest.ts, 1, 11)) + +var [...{ length: c }] = [0, 1]; +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>c : Symbol(c, Decl(usingDeclarationsNestedRest.ts, 2, 9)) + +var [...[d = 2, , ...[e]]] = [undefined, 1, 3]; +>d : Symbol(d, Decl(usingDeclarationsNestedRest.ts, 3, 9)) +>e : Symbol(e, Decl(usingDeclarationsNestedRest.ts, 3, 22)) +>undefined : Symbol(undefined) + diff --git a/tsc/testdata/baselines/reference/compiler/usingDeclarationsNestedRest.types b/tsc/testdata/baselines/reference/compiler/usingDeclarationsNestedRest.types new file mode 100644 index 0000000000000..6abe974506982 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/usingDeclarationsNestedRest.types @@ -0,0 +1,34 @@ +//// [tests/cases/compiler/usingDeclarationsNestedRest.ts] //// + +=== usingDeclarationsNestedRest.ts === +using z = { [Symbol.dispose]() {} }; +>z : { [Symbol.dispose](): void; } +>{ [Symbol.dispose]() {} } : { [Symbol.dispose](): void; } +>[Symbol.dispose] : () => void +>Symbol.dispose : unique symbol +>Symbol : SymbolConstructor +>dispose : unique symbol + +var [...[a, b]] = [0, 1]; +>a : number +>b : number +>[0, 1] : number[] +>0 : 0 +>1 : 1 + +var [...{ length: c }] = [0, 1]; +>length : any +>c : number +>[0, 1] : number[] +>0 : 0 +>1 : 1 + +var [...[d = 2, , ...[e]]] = [undefined, 1, 3]; +>d : number +>2 : 2 +>e : number | undefined +>[undefined, 1, 3] : (number | undefined)[] +>undefined : undefined +>1 : 1 +>3 : 3 + diff --git a/tsc/testdata/tests/cases/compiler/exportDestructuringIterator.ts b/tsc/testdata/tests/cases/compiler/exportDestructuringIterator.ts index 4c21141e7d816..3686d3d44ac5e 100644 --- a/tsc/testdata/tests/cases/compiler/exportDestructuringIterator.ts +++ b/tsc/testdata/tests/cases/compiler/exportDestructuringIterator.ts @@ -10,3 +10,6 @@ export const [c, ...d] = foo(); export const [, e, , f] = foo(); export const [[g, h], { i, j: k }] = foo(); export const { m: [n, o], p: { q } } = foo(); +export const [...[r, s]] = foo(); +export const [...{ length: t }] = foo(); +export const [...[u = 1, , ...[v]]] = foo(); diff --git a/tsc/testdata/tests/cases/compiler/usingDeclarationsNestedRest.ts b/tsc/testdata/tests/cases/compiler/usingDeclarationsNestedRest.ts new file mode 100644 index 0000000000000..27d627b69fabd --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/usingDeclarationsNestedRest.ts @@ -0,0 +1,8 @@ +// @target: es2022 +// @lib: esnext,dom +// @noEmitHelpers: true + +using z = { [Symbol.dispose]() {} }; +var [...[a, b]] = [0, 1]; +var [...{ length: c }] = [0, 1]; +var [...[d = 2, , ...[e]]] = [undefined, 1, 3];