Skip to content

repsel: dependency JS is walled by rule 1 (unbound allocations), not containment — 506 of 746 candidates #7152

Description

@proggeramlug

#7139 recovered rule-5 eligibility for 84 of 85 CommonJS dependency modules and
recorded that of the ~103 Ptr<Shape> candidates it freed, 100 were
immediately re-denied by rule 2
— reading as "containment is the wall in
dependency JS". Track D (#7034 §3, PR #7149) was scheduled on that basis.

Measured, it is not containment. Two compiler arms — #7139 alone, and
#7139 + #7149 — over 180 real __esModule CJS modules from
real-apps/scriptc/node_modules (perry compile m.js --opt-report --no-link,
180/180 compiled in both, every count identical between arms):

bucket candidates
rule 1 — allocated in expression position, never bound to a local 506
rule 5 — module barrier still armed 99
rule 2 — bare reference 130
rule 2 — call argument 5
rule 2 — array element 1
rule 2 — closure capture 1
rule 2 — undeclared property 1
total candidates 746
selected / consumed 3 / 0

Two things fall out.

1. Rule 1 is the wall, and its shape is known

The 506 unbound allocations break down by position:

position count
constructor argument 182
statement 162
call argument 84
return 64
array element 8
initializer 6

new X(…) written directly into an argument, a statement, or a return, never
bound to a let/const. Rule 1 needs a local to anchor the proof to, and
transpiled/minified code does not create one. This is the .map(x => ({…})) /
return {…} idiom the report already names — at 68% of all candidates it is
larger than every containment position combined by a factor of ~3.5.

2. The rule-2 "bare reference" denials are Perry's own scaffolding

All 130 are the local __cjs_module. That is the CommonJS wrapper's own
binding, not user code — the same family #7139 was narrowing. Whether it is
worth exempting depends on whether __cjs_module's object is ever a useful
Ptr<Shape> candidate at all; if it is not, it should not be a candidate,
and the 130 denials are noise in every report.

Caveat on the corpus

This is not #7139's exact 85-module set (that selection was
"self-contained __esModule leaves"; this one is every third __esModule file
by sorted path, requires allowed). A tighter 82-module self-contained set gave
the same shape: 185 candidates, 100 rule 1, 82 rule 2 — all 82 __cjs_module
bare references, 0 element. The conclusion does not depend on the sample.

What this changes

Nothing about #7149 — it pays on app-shaped TypeScript, where it removes every
guard diamond from a build-then-consume loop. But call argument (#7034 §1)
should not be scheduled on the assumption that it unlocks dependency JS
either
: it is 5 of 746. The dependency-JS lever is rule 1, and its fix is a
different mechanism — anchoring the proof to an allocation site rather than to
a binding.

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