Experimental. Perry proves static types to select unboxed representations. --opt-report already surfaces that analysis — but only its negative half: which values it could not type, and why. The positive half is computed and then discarded.
The proposal: a --emit-types mode that writes the inferred types back out as TypeScript, so a JavaScript codebase compiled by Perry gets .d.ts (or inline annotations) derived from whole-program native compilation rather than from a heuristic type-inferencer.
Why the plumbing already exists
opt_report::Entry carries, per named binding:
pub module: String,
pub function: String,
pub name: String, // source-level binding name — HIR keeps names through lowering
pub local_id: Option<u32>,
pub rep: String, // the representation SELECTED — Ptr<Shape>, I32, Boxed, …
pub analysis: Analysis,
pub outcome: Outcome,
The sink is a process-global Mutex<Vec<Entry>> drained by the CLI after codegen, and --opt-report=json already emits a stable schema. This is a new consumer of an existing stream, not new analysis.
The honest scoping caveat, up front
rep is a representation, not a TypeScript type, and the mapping is lossy in both directions:
I32 / typed-f64 → number. Sound and useful.
Ptr<Shape> → an object with a known field set. This is the valuable case: a real interface, recovered from JS.
Boxed → nothing. And --opt-report exists precisely because Boxed is common.
So the deliverable is "emit what we proved, any (or omit) the rest", and its usefulness is bounded by exactly the proof rate --opt-report was built to measure. Do not ship a number for coverage without measuring it on real dependency JS — #7152/#7170/#7234 record that dependency JS behaves very differently from benchmarks here, and #7234 is an open panic on real dependency JS in the report's own renderer.
What would make this worth keeping
- Round-trip check: emit types for a
.ts input whose annotations were erased, and diff against the original. That is a measurable accuracy number rather than a demo.
- Never emit a wrong type. A missing annotation costs nothing; a wrong one poisons a downstream
tsc. Where the proof is conditional (a shape guarded by a versioned loop, say), emit nothing.
- Field-set output for
Ptr<Shape> is the differentiating feature — structural interfaces recovered from untyped JS is something a JS-only inferencer cannot do as well, because it has no representation-selection pressure forcing the question.
Not in scope for the prototype
Editor integration, incremental emission, or wiring into perry check. This is a flag that writes a file, plus an accuracy measurement.
Experimental. Perry proves static types to select unboxed representations.
--opt-reportalready surfaces that analysis — but only its negative half: which values it could not type, and why. The positive half is computed and then discarded.The proposal: a
--emit-typesmode that writes the inferred types back out as TypeScript, so a JavaScript codebase compiled by Perry gets.d.ts(or inline annotations) derived from whole-program native compilation rather than from a heuristic type-inferencer.Why the plumbing already exists
opt_report::Entrycarries, per named binding:The sink is a process-global
Mutex<Vec<Entry>>drained by the CLI after codegen, and--opt-report=jsonalready emits a stable schema. This is a new consumer of an existing stream, not new analysis.The honest scoping caveat, up front
repis a representation, not a TypeScript type, and the mapping is lossy in both directions:I32/ typed-f64 →number. Sound and useful.Ptr<Shape>→ an object with a known field set. This is the valuable case: a real interface, recovered from JS.Boxed→ nothing. And--opt-reportexists precisely becauseBoxedis common.So the deliverable is "emit what we proved,
any(or omit) the rest", and its usefulness is bounded by exactly the proof rate--opt-reportwas built to measure. Do not ship a number for coverage without measuring it on real dependency JS — #7152/#7170/#7234 record that dependency JS behaves very differently from benchmarks here, and #7234 is an open panic on real dependency JS in the report's own renderer.What would make this worth keeping
.tsinput whose annotations were erased, and diff against the original. That is a measurable accuracy number rather than a demo.tsc. Where the proof is conditional (a shape guarded by a versioned loop, say), emit nothing.Ptr<Shape>is the differentiating feature — structural interfaces recovered from untyped JS is something a JS-only inferencer cannot do as well, because it has no representation-selection pressure forcing the question.Not in scope for the prototype
Editor integration, incremental emission, or wiring into
perry check. This is a flag that writes a file, plus an accuracy measurement.