Skip to content

Commit cee2581

Browse files
shawntabriziclaude
andauthored
Stop #[contract] injecting alloc use-imports into caller's crate root (#117)
* Stop #[contract] injecting alloc use-imports into caller's crate root The alloc_setup block emitted at the caller's crate root (sibling of the contract mod) injected `use alloc::vec;`, `use alloc::vec::Vec;`, and `use alloc::string::String;` alongside `extern crate alloc;`, gated to non-abi-gen riscv builds in allocator modes. These three imports are dead weight: - They don't reach the contract mod (Rust modules don't inherit a parent module's `use`); in-mod user code that needs Vec/String brings its own import, which the macro already cfg-gates via use_tree_imports_alloc. - No generated code consumes them. Every generated allocation uses fully qualified paths already (`alloc::vec![..]`, `alloc::vec::Vec<u8>` in the dispatch/decode/router codegen), resolved through `extern crate alloc;`. Their only effect was polluting the caller's crate root, so contract authors with crate-root helper code that imports Vec/String hit a confusing E0252/E0259 pointing at the macro invocation line rather than their own import. Drop the three imports from both allocator arms; keep `extern crate alloc;` (load-bearing for the qualified paths). No behavior change for any contract that compiles today. Verified: pvm-contract-macros test suite (171 unit + all integration + trybuild) passes, and all 7 example-mytoken contracts build via the CLI, including the pico-alloc and bump-alloc variants that exercise this path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Document the no-use-injection codegen convention at the emission site Add a comment explaining why alloc_setup keeps `extern crate alloc;` but must not inject `use alloc::...` imports, so the deleted imports aren't reintroduced. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Retry transient null-response deploy failures in e2e cast harness CI flaked twice on this branch with 'cast deploy failed: Error: server returned a null response when a non-null response was expected', hitting a different test each run (error_call, then dynamic_bytes_length + dynamic_echo_string). A freshly started anvil-polkadot occasionally answers a JSON-RPC request with null; retry that specific transient error up to 3 times before failing the test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Revert "Retry transient null-response deploy failures in e2e cast harness" This reverts commit b83acf8. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent fa53855 commit cee2581

1 file changed

Lines changed: 9 additions & 18 deletions

File tree

crates/pvm-contract-macros/src/codegen/contract.rs

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,22 +1223,22 @@ pub fn expand_contract(args: ContractArgs, input: ItemMod) -> syn::Result<TokenS
12231223

12241224
let mod_content = strip_pvm_attrs(&input, struct_name)?;
12251225

1226+
// `alloc_setup` is emitted at the caller's crate root (sibling of the
1227+
// contract mod). Keep `extern crate alloc;` here, but do NOT add
1228+
// `use alloc::vec::Vec;` / `use alloc::string::String;` etc.: a `use` at
1229+
// the crate root pollutes the caller's namespace (colliding with the
1230+
// author's own crate-root imports, surfacing as E0252/E0259 pointed at the
1231+
// macro line) and is never consumed — it doesn't reach the contract mod
1232+
// (modules don't inherit a parent's `use`), and all generated allocations
1233+
// are fully qualified (`alloc::vec![..]`, `alloc::vec::Vec<u8>`). Codegen
1234+
// convention: reference external items by absolute path, never inject `use`.
12261235
let alloc_setup = match args.allocator {
12271236
Some(AllocatorKind::Pico) => {
12281237
let allocator_size = args.allocator_size;
12291238
quote! {
12301239
#[cfg(not(feature = "abi-gen"))]
12311240
extern crate alloc;
12321241

1233-
#[cfg(all(not(feature = "abi-gen"), any(target_arch = "riscv32", target_arch = "riscv64")))]
1234-
use alloc::vec;
1235-
1236-
#[cfg(all(not(feature = "abi-gen"), any(target_arch = "riscv32", target_arch = "riscv64")))]
1237-
use alloc::vec::Vec;
1238-
1239-
#[cfg(all(not(feature = "abi-gen"), any(target_arch = "riscv32", target_arch = "riscv64")))]
1240-
use alloc::string::String;
1241-
12421242
#[cfg(all(not(feature = "abi-gen"), any(target_arch = "riscv32", target_arch = "riscv64")))]
12431243
#[global_allocator]
12441244
static mut ALLOC: picoalloc::Mutex<picoalloc::Allocator<picoalloc::ArrayPointer<#allocator_size>>> = {
@@ -1256,15 +1256,6 @@ pub fn expand_contract(args: ContractArgs, input: ItemMod) -> syn::Result<TokenS
12561256
#[cfg(not(feature = "abi-gen"))]
12571257
extern crate alloc;
12581258

1259-
#[cfg(all(not(feature = "abi-gen"), any(target_arch = "riscv32", target_arch = "riscv64")))]
1260-
use alloc::vec;
1261-
1262-
#[cfg(all(not(feature = "abi-gen"), any(target_arch = "riscv32", target_arch = "riscv64")))]
1263-
use alloc::vec::Vec;
1264-
1265-
#[cfg(all(not(feature = "abi-gen"), any(target_arch = "riscv32", target_arch = "riscv64")))]
1266-
use alloc::string::String;
1267-
12681259
#[cfg(all(not(feature = "abi-gen"), any(target_arch = "riscv32", target_arch = "riscv64")))]
12691260
#[global_allocator]
12701261
static ALLOC: pvm_bump_allocator::BumpAllocator<#allocator_size> =

0 commit comments

Comments
 (0)