Description
When a single variable declaration contains multiple declarators that use object rest, the ES2018 object-rest transform can remove the first rest binding and emit a moved-from declarator as {} = null.
This was originally reported through Vite: vitejs/vite#23298
Versions
Reproduced with Oxc 0.144.0, 0.145.0, and the current main branch. It is exposed by targets that require object-rest lowering, such as Safari 11 / ES2017.
Input
function merge(e, t) {
const { a, ...x } = e, { b, ...y } = t
return [a, x, b, y]
}
Transforming this with target: "safari11" produces no diagnostics.
Actual output
const _excluded = ["a"], _excluded2 = ["b"];
var _objectWithoutProperties = require("@oxc-project/runtime/helpers/objectWithoutProperties");
function merge(e, t) {
const { a } = e, { b } = t, y = _objectWithoutProperties(t, _excluded2), {} = null;
return [a, x, b, y];
}
The generated code throws while evaluating {} = null, and x is never declared.
Expected behavior
Both rest bindings should be preserved, equivalent to:
function merge(e, t) {
const { a } = e,
x = _objectWithoutProperties(e, ["a"]),
{ b } = t,
y = _objectWithoutProperties(t, ["b"])
return [a, x, b, y]
}
Root cause
transform_variable_declaration collects replacements using the declarators original indices, then applies splice from left to right. Expanding the first object-rest declarator shifts every following index, so the next splice targets the wrong declarator.
Applying the queued replacements from right to left keeps the original indices valid. A fix and regression fixture are available in #25904.
Workaround
Splitting the destructuring into separate variable declarations avoids the index shift. Disabling minification does not avoid the bug.
AI assistance
Codex assisted with reproduction and root-cause analysis. The behavior, affected transform stage, and proposed fix were verified with focused conformance tests and transformer unit tests.
Description
When a single variable declaration contains multiple declarators that use object rest, the ES2018 object-rest transform can remove the first rest binding and emit a moved-from declarator as
{} = null.This was originally reported through Vite: vitejs/vite#23298
Versions
Reproduced with Oxc 0.144.0, 0.145.0, and the current
mainbranch. It is exposed by targets that require object-rest lowering, such as Safari 11 / ES2017.Input
Transforming this with
target: "safari11"produces no diagnostics.Actual output
The generated code throws while evaluating
{} = null, andxis never declared.Expected behavior
Both rest bindings should be preserved, equivalent to:
Root cause
transform_variable_declarationcollects replacements using the declarators original indices, then appliessplicefrom left to right. Expanding the first object-rest declarator shifts every following index, so the next splice targets the wrong declarator.Applying the queued replacements from right to left keeps the original indices valid. A fix and regression fixture are available in #25904.
Workaround
Splitting the destructuring into separate variable declarations avoids the index shift. Disabling minification does not avoid the bug.
AI assistance
Codex assisted with reproduction and root-cause analysis. The behavior, affected transform stage, and proposed fix were verified with focused conformance tests and transformer unit tests.