Skip to content

Explicit HIR marker for appended class-capture args at new-sites (replace shape inference from #6537) #6538

Description

@proggeramlug

Summary

Follow-up to #6530 / PR #6537 (CodeRabbit finding). The codegen currently identifies HIR-appended capture forwards at bare-identifier new C(...) sites by shape: the trailing args must each be Expr::LocalGet(id) whose id equals the one embedded in the matching synthesized __perry_cap_<id> ctor param (exact ids, declaration order, all-or-nothing) — see new_site_args_carry_appended_caps in crates/perry-codegen/src/lower_call/new.rs.

LocalIds are module-unique (single fresh_local counter), so a user expression can only produce the matching ids by referencing the captured locals themselves. That leaves one theoretical false positive: a FORWARD-referenced capture-class constructed inside an earlier closure of the declaring scope, passing exactly its captured locals (in capture order) as the final user args — there the HIR appends nothing (lookup_class_captures misses pre-declaration) and the codegen would strip those user args as cap fallbacks.

Why this is currently unreachable

Fixtures for that shape (CJS module function: const h = ...; const mk = () => new Later(h); class Later extends Base { /* captures h */ } ...) fail module init on main before the construction site ever runs — require() yields undefined exports (pre-existing, reproduces identically on a pre-#6537 main build; both the forward-arrow and even backward-arrow variants of this fixture fail init). So the ambiguity cannot currently be observed end-to-end.

Proposed fix

Make the provenance explicit instead of inferred: either

  • a dedicated HIR marker for appended capture forwards (e.g. an Expr::ClassCaptureForward(LocalId) variant, or a cap_args_appended: bool / count field on Expr::New), emitted at the two append sites in crates/perry-hir/src/lower/expr_new.rs (+ expr_new/non_ident.rs), consumed by lower_new_impl; then delete the shape check, or
  • fix the init failure family above first, then extend the gap suite with the adversarial shapes and revisit.

Blast radius of the HIR variant is the main cost (many exhaustive Expr matches across perry-codegen collectors/transform), which is why it was split out of #6537.

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