Skip to content

compat(nestjs): .prototype of a capturing class expression is undefined — tslib __decorate crashes @nestjs/common module init #4949

Description

@TheHypnoo

Context

I'm running a NestJS compatibility probe to map the current Perry → NestJS state, using the existing tests/release/packages/nestjs-hello fixture (@nestjs/common + @nestjs/core + @nestjs/platform-express 11.1.x, compiled via perry.compilePackages). After #4872 the fixture links (42.1 MB executable), but the binary dies during module init, before the server starts:

TypeError: Cannot convert undefined or null to object
    at <anonymous>

Reproduced today on main (6378dbd). This is "Wall 2" in the fixture's WALLS.md, previously bisected to @nestjs/common/services/logger.service.js: tsc's class-decorator output calls Object.getOwnPropertyDescriptor(Logger.prototype, "error") inside tslib.__decorate, and Logger.prototype reads as undefined while typeof Logger is "function".

Minimal repro (no node_modules)

const r = (function () {
    var L_1: any;
    let L: any = (L_1 = class L {
        get gi() { return L_1.staticRef; } // member captures outer var → ClassExprFresh
        e(m: any) { return m; }
    });
    return [typeof L, typeof L.prototype];
})();
console.log(JSON.stringify(r));
Node (--experimental-strip-types) Perry (main, 6378dbd)
output ["function","object"] ["function","undefined"]

Trigger matrix (narrows WALLS.md)

The trigger is any class member capturing an outer variable — not just getters:

variant Node Perry
class expr, no capture object object
plain method captures outer var object undefined
getter captures outer var object undefined
Object.getOwnPropertyDescriptor(L.prototype, "error") (tslib __decorate shape) descriptor object throws Cannot convert undefined or null to object ← the exact NestJS crash

Root cause / fix direction

A capturing member routes the class through the ClassExprFresh lowering (captured_args: [LocalGet(..)] in HIR), and .prototype access on a ClassExprFresh value is not wired. The fix needs to give ClassExprFresh values a live .prototype object — and since tslib's __decorate then mutates it via Object.defineProperty, instances must observe the decorated methods (a read-only snapshot prototype is not enough).

This is the single remaining blocker between "links" and "boots" for the NestJS hello fixture; once fixed, the next wall (if any) surfaces at runtime.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugConfirmed defect or regressionparityCompatibility gap with Node.js, ECMAScript, or the supported ecosystem

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions