Skip to content

regression(#6054): shared-mutable-capture desugar 500s every Next.js standalone route — uninitialized let array-boxed without an array #6089

Description

@proggeramlug

Summary

ce3eed1 (#6054, the #5951 shared-mutable-capture one-element-array-box desugar) regressed the compiled Next.js standalone server from 5/8 byte-identical routes to 0/8: every route (pages AND api) returns a 21-byte 500, server log shows TypeError: Cannot convert undefined or null to object per request.

Bisected on the #5437 matrix app: a868c7516 + the #6055 boot fix = 5/8; ce3eed163 + same = 0/8. Confirmed via the pass's own PERRY_NO_5951=1 escape hatch on current main: with the pass disabled the app is back to 5/8.

Root cause

The declaring-Let array-wrap skips a let with no initializer (if let Some(e) = init.take()), but every use of the flagged id is still rewritten to id[0]. SWC emits exactly this shape for hoisted computed-property temps:

let prop;
class NodeNextRequest extends BaseNextRequest {
    static #_ = prop = _NEXT_REQUEST_META = ...;   // mutates `prop`
}

(next/dist/server/base-http/node.js — the wrapper classes for every request/response.) prop is flagged shared-mutable, its uses become prop[0], but no array is ever allocated — the static initializer's prop[0] = ... is an IndexSet on undefined and throws the observed TypeError when Next lazy-requires the module during the first request. Every route uses these wrappers → uniform 500.

Found along the way (real unsoundness, hardened in the fix PR though neither caused this app's breakage): the pass applied one module-global LocalId set to every body in the module, but LocalIds are not unique across function scopes (member params/lets and nested closures restart their id spaces) — a numeric rewrite is only sound for ids declared exactly once in the rewritten region.

Fix

PR incoming: wrap a None init as [undefined] (preserves let x; semantics through the box), plus per-body scoping + a declared-exactly-once ambiguity guard, plus PERRY_5951_SKIP_MODS / PERRY_5951_TRACE compile-time diagnostics.

References

#6054 / ce3eed1 (the regressing merge), #5951 (the semantics the pass fixes), #6055 (boot fix needed to test this window), #5437 (the Next.js matrix).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions