Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Rust-source probe evidence and adoption criteria

This accompanies the proposal and semantic contract. Results are bounded evidence, not a completed backend or a performance comparison.

The subsequent checked-emitter spike adds actual checked-IR generation and compile/link measurements. The hand-lowered ownership results below remain separate evidence; they are not implemented by that scalar emitter.

What is already generated

The Rust dependency experiment has an actual restricted emitter in experiments/rust-crates/run.py. It checks Plenty against declared API stubs, reparses a small accepted subset and emits calls, borrows and checked arithmetic to Rust source. A real regex owner and synthetic future execute through that path. That establishes feasibility of source emission with native Rust owners; it does not consume checked compiler IR or implement the language. Its earlier results were not rerun for this proposal and should retain their original measurement qualifications.

New semantic probes

experiments/rust-source-backend/ contains dependency-free Rust candidate implementations, a separate Rust-host integration test, paired real Plenty programs and a runner. The Rust is hand-lowered, deliberately isolating semantic questions from implementing a second parser or a production emitter. Run python3 run.py --plenty /absolute/path/to/plenty from that directory. Inputs, expected observations and the recorded snapshot are in its README and RESULTS.md; machine-readable observations are written under ignored target/.

Tested on x86_64 Linux with Plenty 0.3.0 from main 00d32a13, rustc 1.99.0 (b940084d7, LLVM 23.1.1), edition 2024. The local Rust checkout inspected for Vec reservation and panic/abort implementation was 080cc27146389dbb5c8772c476b1937be9c6110f, distinct from the tested compiler revision. It was used as source evidence, not built or assumed identical to the installed toolchain.

QuestionObservationLimit
Can Rust consume native-looking APIs?Separate Rust test crate passes a native vector borrow, Cursor and consuming closure; returned element points into the original vector.API declarations are handwritten, not inferred. No general Rust crate importer.
Do scope cleanup and propagation align?Both ordinary/debug and release Plenty/Rust print 33, 2, 1, 3, 4: numeric result, reverse lexical cleanup on ?, explicit moved-owner drop, final marker.One concrete control-flow path; not closure/generator/recursive cleanup coverage.
Does checked overflow preserve fatal behavior?Explicit checked-add/abort fails in both modes with no destructor output, as Plenty does.Trap formatting, exact exit status, stack guard and source attribution are not reproduced.
Can ordinary Rust panic stand in for a trap?No: default panic prints destructor trace 99; separate panic=abort build does not.Does not qualify arbitrary dependencies, callbacks or unwinding Rust hosts.
Does native fallible reservation help?Impossible capacity fails before any element callback; normal construction succeeds.Capacity overflow only; no allocator fault injection or Plenty owner/error representation parity.
Can all admitted loans be printed literally?No: distinct constant list-index loans pass Plenty but naive Rust fails E0499; safe split translation passes.Only a two-element constant-index case.
Does Rust still check owner misuse?Moved-vector access is rejected with E0382.Redundant checking cannot replace Plenty checks or prove the emitter correct.

Two library tests and one Rust-host integration test pass in debug and release. The runner checks four differential executions, two rejected Rust sources and three panic observations. Cargo formatting and Clippy with warnings denied pass. No production compiler source changed, no external dependencies were added, and no cross-target or performance result is claimed.

Decision gate for a first backend slice

The checked-emitter experiment now satisfies the scalar part of the original gate: real checked-frontend emission, native companion calls, source mapping and build measurements. The remaining ownership-bearing gate is to admit simple move-only scalar records, named enums/Results, structured branches/loops, local borrows and a returned first-parameter borrow. Expose monomorphic exports and a small explicitly declared Rust companion API. Exercise a genuine Rust host that calls an exported Plenty function which in turn calls that companion. Restrict recursion and resource features until their contracts have a translation; unsupported cases must fail explicitly.

The adoption decision should require all of the following evidence:

  • Differential tests against Cranelift for admitted semantics, including overflow, early exits, drop order, moves, aliases and fault-injected allocation if owned dynamic storage is admitted.
  • A public Rust API usable without unsafe calls or per-call marshalling glue, with documented ownership and panic behavior and no hidden copy workaround.
  • Source-located Plenty diagnostics for unsupported inputs, plus at least one generated rustc error mapped back to the triggering Plenty source.
  • Cold/warm/edit build and representative runtime measurements, separately attributing source generation, Rust checking/optimization, dependency builds and linking. Compare the same accepted workloads, not tiny warm Cargo no-ops.
  • A documented list of retained frontend facts, support-runtime dependencies, unsafe helper invariants if any, and costs of keeping both backends correct.

If useful native APIs require broadly changing Plenty’s semantics or pervasive unchecked lowering, stop expansion and prefer the generated-adapter route. If safe monomorphic library exports work with a small support layer, that alone can be worthwhile without committing to a whole-language compiler replacement. This gate describes the technical decision; scheduling remains in B20.