This is a question related to implementing a Component Model bindings generator (specially wit-bindgen-go):
Let’s say you have an interface that defines a resource type “fd” and a world that both imports and exports that interface, and a second exported interface “utils” that contains functions that accept an fd argument.
Which fd type does utils actually use? Is the CM spec ambiguous or is there a heuristic? Should the choice be represented in the wit-parser Resolve struct?
For imported functions, this is easy—use the imported fd type.
Randy Reddig has marked this topic as resolved.
Randy Reddig has marked this topic as unresolved.
What ends up happening here is a bit subtle and it's generally related to WIT conventions. The CM itself has no ambiguity, the problem arises when WIT is mapped back to the component model. To answer your question the cases are:
utils is imported, then it uses the imported fdutils is exported, and fd is not exported, then it uses an imported fd utils is exported, and fd is exported, then it will use the exported fdthere's also implicit insertion of interfaces to handle here too, for example wasm-tools component wit ./my-wit will show the "elaborated" version of a world. For example if you do export utils; that'll implicitly insert import fd;. If you have export fd; export utils;, however, then no implicit insertion happens and utils uses the exported fd.
Interesting, thanks. Is (or was) it the intention to allow WIT to express explicitly which fd to use?
Would it make sense for this logic to live in the wit-parser crate, so the Resolve structure can express whether a type is imported or exported?
Thinking about this a little more: if a component exports a type, but there is no exported constructor nor any exported functions that return that type, then is the type actually exported?
(I was down this rabbit hole thinking about structural types like record that might include an exported resource. Resolving those types would have a similar challenge, e.g. which fd to use.)
Yes the intention is to eventuall enable WIT to describe this all more explicitly as a sort of "power user" syntax, there's related discussion on https://github.com/WebAssembly/component-model/pull/308 and I think one or two other locations too.
Would it make sense for this logic to live in the wit-parser crate, so the Resolve structure can express whether a type is imported or exported?
Definitely! In retrospect this is a major design flaw of wit-parser today. The interface fd is mistakenly represented as a single interface in Resolve when in fact it should be duplicated for when it's both imported-and-exported.
if a component exports a type, but there is no exported
constructornor any exported functions that return that type, then is the type actually exported?
I think this only comes up with resources since all other types are "nominal" and can be constructed at any time. In such a situation as you describe the type isn't useful since no one can create it, but it's still an exported type and can participate in type-checking and such.
I was wondering if it would be possible to fix this discrepancy with resource types by making them duck-typed, and adding a new canon function that resolves a duck-typed resource to a locally-defined resource type.
While it might fix this particular issue, I believe that duck-typed resources would erode many guarantees you currently get with resources and perhaps create a lot of other conundrums, so I don't think it's quite so simple
I could be wrong though! That's probably best discussed in an issue
OK!
I’ve been thinking about duck-typed resources as a way to resolve the ambiguity between WIT/CM for resource types or any type that includes resource
Definitely! In retrospect this is a major design flaw of wit-parser today. The interface
fdis mistakenly represented as a single interface inResolvewhen in fact it should be duplicated for when it's both imported-and-exported.
Where would it make sense for the wit-parser crate to represent the imported vs exported attribute? At the type (and function) level, or at the interface level?
It seems like this could be a backwards-compatible change to wit-parser, in the sense that it would potentially duplicate interfaces/types/functions, with an additional attribute to signal whether they’re imported or exported?
I think this would be best represented at the interface level right now since that's the unit of import/export, and yeah I agree it should largely be backwards-compatible and would end up probably deleting more code downstream of wit-parser than would need to be added to wit-parser
To simplify the carrying of state, could we also add the attribute to TypeDef and Function?
I think that'd be reasonable yeah
I can file an issue on wasm-tools repo describing this. That work?
I’d implement it, but I don’t feel confident enough in my Rust chops
mind opening an issue to start off? I've been meaning to track this for awhile
https://github.com/bytecodealliance/wasm-tools/issues/1497
Circuling back to this issue:
world exports-use-from-interface {
use a.{fd}
export b: func(f: fd);
}
it seems strange to me taht the WIT parser resolve to import the entirety of interface a even though we only specify a.{fd}.
In an actual component that exports b it should only import the parts of a it actually needs, but at the WIT layer (e.g. Resolve) there's no way to represent a partial interface so the only option is to have an import for the whole interface
Thanks, that makes sense, @Alex Crichton . I'd like to stress the proposal that adds attribute to TypeDef and Function more. Imo, adding direction to Interface is suffice to differentiate what type to use in exported functions. Is there any particular reason for adding direction to Function and Types?
Sorry I'm not sure I quite understand, can you clarify what you mean about direction and the "adds attribute" part?
Alex Crichton said:
Sorry I'm not sure I quite understand, can you clarify what you mean about
directionand the "adds attribute" part?
Oh sorry, yes I can clarify. I was referring to this issue where it proposes to add an attribute to the Interface, Function, and TypeDef structs to indicate whether it is imported or exported. I assumed the name of that attribute to be direction.
ah ok yeah no definitely makes sense to add still!
Last updated: Jan 10 2026 at 20:04 UTC