Emit explicit per-module use declarations in typed Rust
ober
de4279a79529036ff41cda39b50615af0052d52a
--- a/docs/jerboa-to-rust.md +++ b/docs/jerboa-to-rust.md @@ -113,20 +113,21 @@ Done in subsequent phases: `/* source: path:line:column */` block comment so the compiler-reported Rust line can be mapped back to typed source. - Per-module file layout. The crate emitter now writes a thin `src/lib.rs` - that `pub mod`s each module and `pub use`s its items at the crate root, plus - one `src/<module>.rs` per typed module containing that module's records, - variants, resources, defs, and ABI wrappers. Runtime helpers - (`jt_return_bytes`, `jt_clone_handle`, panic capture, the handle registry) - live in `lib.rs` with `pub(crate)` visibility so per-module files can - reach them via `use crate::*;`. Cross-module bare-name calls keep working - because of the crate-root `pub use` re-exports. + that `pub mod`s each module, plus one `src/<module>.rs` per typed module + containing that module's records, variants, resources, defs, and ABI + wrappers. Runtime helpers (`jt_return_bytes`, `jt_clone_handle`, panic + capture, the handle registry) live in `lib.rs` with `pub(crate)` visibility. +- Explicit per-module `use` declarations driven by the typed `import` graph. + Each per-module file imports exactly the runtime helpers it uses + (`use crate::{jt_capture_panic, jt_return_bytes, ...};`) and exactly the + sibling modules its source declared via `(import (other-mod))` + (`use crate::other_mod::*;`). No wildcard `use crate::*;` and no + crate-root `pub use module::*;` re-exports. Still open: - Direct `rustc` / static binary integration polish and eventual LLVM parity tests. Today the build goes through `cargo build` only. -- Explicit per-module `use` declarations driven by the typed `import` graph - (today every module imports `crate::*;`). ## Output Layout --- a/docs/typed-jerboa.md +++ b/docs/typed-jerboa.md @@ -302,10 +302,11 @@ Highest-value next steps: elaboration, so cross-module record/variant/def references compile into a single Rust crate. `typed-modules->rust-crate-files` now writes one `src/<module>.rs` per typed module plus a thin `src/lib.rs` that - `pub mod`s and `pub use`s each module so cross-module bare-name calls - still resolve via the crate root. Explicit per-module `use` declarations - driven by the typed `import` graph (instead of `use crate::*;`) remain - future work. + `pub mod`s each module. Each per-module file emits explicit + `use crate::{...helpers...};` for the runtime helpers it actually uses + and `use crate::<other_mod>::*;` for every module its source declared via + `(import (other-mod))`, so the typed import graph drives the Rust use + graph one-for-one. 3. Improve boundary semantics for Option/Result (Done). `(Option <Scalar>)` for Scalar in `{Bool, Char, Int, Nat, Fixnum, Float}` crosses the FFI boundary as a tagged Scheme value (`#f` or `(cons 'some V)`): the Rust ABI --- a/lib/jerboa/typed/rust.ss +++ b/lib/jerboa/typed/rust.ss @@ -1706,20 +1706,44 @@ (string-append "pub mod " (module-abi-prefix module) ";"))) modules) (unless (null? modules) (newline port)) - (for-each - (lambda (module) - (write-line port 0 - (string-append "pub use " (module-abi-prefix module) "::*;"))) - modules) - (unless (null? modules) (newline port)) (emit-runtime-helpers modules port)) + (def (module-name->prefix name) + (join-strings (map rust-symbol-name name) "_")) + + (def (module-runtime-helpers-used module) + ;; Returns a sorted list of crate-level helper symbol names that this + ;; module's emitted Rust body actually references. Used to drive precise + ;; `use crate::{...};` declarations in per-module files. + (let ([safe? (module-has-safe-exports? module)] + [bytes? (module-needs-byte-buffer-runtime? module)] + [handles? (module-needs-handle-registry? module)]) + (let ([out '()]) + (when handles? + (set! out (cons "jt_clone_handle" out)) + (set! out (cons "jt_store_handle" out))) + (when bytes? + (set! out (cons "jt_return_bytes" out))) + (when safe? + (set! out (cons "jt_capture_panic" out))) + out))) + (def (emit-module-file module ir-env port) (write-line port 0 "// Generated by Jerboa's typed Rust backend. Do not edit.") (write-line port 0 "#![allow(unused_imports)]") (newline port) - (write-line port 0 "use crate::*;") - (newline port) + (let ([helpers (module-runtime-helpers-used module)] + [imports (typed-module-imports module)]) + (unless (null? helpers) + (write-line port 0 + (string-append "use crate::{" (join-strings helpers ", ") "};"))) + (for-each + (lambda (import-name) + (write-line port 0 + (string-append "use crate::" (module-name->prefix import-name) "::*;"))) + imports) + (unless (and (null? helpers) (null? imports)) + (newline port))) (parameterize ([*rust-ir-env* ir-env]) (emit-module-declarations module port))) --- a/tests/test-typed-rust.ss +++ b/tests/test-typed-rust.ss @@ -612,21 +612,26 @@ (test "rust crate lib.rs declares each module" (let ([lib (assoc-string "src/lib.rs" crate-files)]) (and (substring? lib "pub mod rust_import_provider;") - (substring? lib "pub mod rust_import_consumer;") - (substring? lib "pub use rust_import_provider::*;") - (substring? lib "pub use rust_import_consumer::*;"))) + (substring? lib "pub mod rust_import_consumer;"))) + #t) + +(test "rust crate lib.rs does not blanket re-export module items" + (let ([lib (assoc-string "src/lib.rs" crate-files)]) + (and (not (substring? lib "pub use rust_import_provider::*;")) + (not (substring? lib "pub use rust_import_consumer::*;")))) #t) (test "rust crate provider module file holds provider defs" (let ([provider (assoc-string "src/rust_import_provider.rs" crate-files)]) - (and (substring? provider "use crate::*;") + (and (not (substring? provider "use crate::*;")) (substring? provider "pub fn inc(x: u64) -> u64") (substring? provider "pub struct Pt {"))) #t) -(test "rust crate consumer module file calls into provider via bare names" +(test "rust crate consumer module file imports its provider explicitly" (let ([consumer (assoc-string "src/rust_import_consumer.rs" crate-files)]) - (and (substring? consumer "use crate::*;") + (and (substring? consumer "use crate::rust_import_provider::*;") + (not (substring? consumer "use crate::*;")) (substring? consumer "pub fn bump_pair_x(p: Pt) -> Pt") (substring? consumer "inc("))) #t)