@@ -655,12 +655,46 @@ macro_rules! {macro_name} {{
655655 }
656656 }
657657
658+ // `use` statements to bring every named type reachable from the
659+ // payload into scope of the generated `vtable{ordinal}` module.
660+ //
661+ // Without these, a type like `future<result<R, string>>` where
662+ // `R` is brought in via `use t.{r}` at world level emits
663+ // `-> Result<R, super::super::_rt::String>` inside `vtable1`,
664+ // with `R` unresolved: the composite type is anonymous so no
665+ // owner-qualified path is inserted, and the world-level alias
666+ // `pub type R = ...;` lives two modules up. Importing it here
667+ // makes the bare identifier resolve regardless of how deeply
668+ // nested the payload type is.
669+ let mut type_imports = BTreeSet :: new ( ) ;
670+ if let Some ( ty) = payload_type {
671+ collect_named_type_ids ( self . resolve , ty, & mut type_imports) ;
672+ }
673+ let type_imports: String = type_imports
674+ . into_iter ( )
675+ . map ( |id| {
676+ let path = self . type_path ( id, /*owned=*/ true ) ;
677+ // `type_path` emits the full `super::super::...::Name`
678+ // when the type is owned by an interface, but falls
679+ // back to a bare name when the owner is a world (the
680+ // `use interface.{T}` alias case). Bare names need the
681+ // `super::super::` prefix to reach the world-level
682+ // `pub type T = ...;` alias at macro root.
683+ let path = if path. starts_with ( "super::" ) {
684+ path
685+ } else {
686+ format ! ( "super::super::{path}" )
687+ } ;
688+ format ! ( " use {path};\n " )
689+ } )
690+ . collect ( ) ;
691+
658692 let code = format ! (
659693 r#"
660694#[doc(hidden)]
661- #[allow(unused_unsafe)]
695+ #[allow(unused_unsafe, unused_imports )]
662696pub mod vtable{ordinal} {{
663-
697+ {type_imports}
664698 #[cfg(not(target_arch = "wasm32"))]
665699 unsafe extern "C" fn cancel_write(_: u32) -> u32 {{ unreachable!() }}
666700 #[cfg(not(target_arch = "wasm32"))]
@@ -3157,3 +3191,96 @@ impl<'a, 'b> wit_bindgen_core::AnonymousTypeGenerator<'a> for AnonTypeGenerator<
31573191 self . interface . push_str ( & format ! ( "; {size}]" ) ) ;
31583192 }
31593193}
3194+
3195+ /// Walk `ty`'s type tree and insert every named type id into `out`.
3196+ ///
3197+ /// A type id is "named" if `resolve.types[id].name` is set, i.e. it is
3198+ /// a user-defined type (record, variant, enum, flags, resource, type
3199+ /// alias) as opposed to an anonymous structural one (`result<_, _>`,
3200+ /// `tuple<_, _>`, `list<_>`, etc.). We still recurse through the
3201+ /// anonymous composites to collect their inner named types — that's
3202+ /// the whole reason this exists: `future<result<R, _>>` hides `R` one
3203+ /// level below an anonymous `result` that the emitter never flags.
3204+ ///
3205+ /// Used by stream/future payload emission to pre-compute `use`
3206+ /// statements for every named type the emitted `vtable{ordinal}`
3207+ /// module will reference, so bare identifiers inside the `fn lift` /
3208+ /// `fn lower` / `impl StreamPayload` bodies resolve even when the
3209+ /// type lives at macro-root via a world-level `use` alias.
3210+ fn collect_named_type_ids ( resolve : & Resolve , ty : & Type , out : & mut BTreeSet < TypeId > ) {
3211+ let Type :: Id ( id) = ty else { return } ;
3212+ collect_named_type_ids_from_id ( resolve, * id, out) ;
3213+ }
3214+
3215+ fn collect_named_type_ids_from_id ( resolve : & Resolve , id : TypeId , out : & mut BTreeSet < TypeId > ) {
3216+ // Avoid cycles: a named type we've already queued doesn't need a
3217+ // second walk through its structure.
3218+ if out. contains ( & id) {
3219+ return ;
3220+ }
3221+ let ty = & resolve. types [ id] ;
3222+ let named = ty. name . is_some ( ) ;
3223+ if named {
3224+ out. insert ( id) ;
3225+ // A named alias (e.g. `use t.{r};` or `type x = r;`) is what
3226+ // the emitter references verbatim — its target is a separate
3227+ // type def reachable by its own name. Walking through the
3228+ // alias would import both the alias and its target under the
3229+ // same Rust identifier and trip E0252. Stop at the alias.
3230+ if matches ! ( ty. kind, TypeDefKind :: Type ( _) ) {
3231+ return ;
3232+ }
3233+ }
3234+ match & ty. kind {
3235+ TypeDefKind :: Record ( r) => {
3236+ for field in & r. fields {
3237+ collect_named_type_ids ( resolve, & field. ty , out) ;
3238+ }
3239+ }
3240+ TypeDefKind :: Variant ( v) => {
3241+ for case in & v. cases {
3242+ if let Some ( ty) = & case. ty {
3243+ collect_named_type_ids ( resolve, ty, out) ;
3244+ }
3245+ }
3246+ }
3247+ TypeDefKind :: Tuple ( t) => {
3248+ for ty in & t. types {
3249+ collect_named_type_ids ( resolve, ty, out) ;
3250+ }
3251+ }
3252+ TypeDefKind :: Option ( t)
3253+ | TypeDefKind :: List ( t)
3254+ | TypeDefKind :: FixedLengthList ( t, _)
3255+ | TypeDefKind :: Type ( t) => {
3256+ collect_named_type_ids ( resolve, t, out) ;
3257+ }
3258+ TypeDefKind :: Result ( r) => {
3259+ if let Some ( ty) = & r. ok {
3260+ collect_named_type_ids ( resolve, ty, out) ;
3261+ }
3262+ if let Some ( ty) = & r. err {
3263+ collect_named_type_ids ( resolve, ty, out) ;
3264+ }
3265+ }
3266+ TypeDefKind :: Map ( k, v) => {
3267+ collect_named_type_ids ( resolve, k, out) ;
3268+ collect_named_type_ids ( resolve, v, out) ;
3269+ }
3270+ TypeDefKind :: Future ( inner) | TypeDefKind :: Stream ( inner) => {
3271+ if let Some ( ty) = inner {
3272+ collect_named_type_ids ( resolve, ty, out) ;
3273+ }
3274+ }
3275+ TypeDefKind :: Handle ( h) => {
3276+ let resource_id = match h {
3277+ Handle :: Own ( id) | Handle :: Borrow ( id) => * id,
3278+ } ;
3279+ collect_named_type_ids_from_id ( resolve, resource_id, out) ;
3280+ }
3281+ TypeDefKind :: Enum ( _)
3282+ | TypeDefKind :: Flags ( _)
3283+ | TypeDefKind :: Resource
3284+ | TypeDefKind :: Unknown => { }
3285+ }
3286+ }
0 commit comments