Unstable error variant in unstable function leads to compilation error
The following WIT world fails to compile with wit-bindgen==0.42.1 and the tool feature not being active. This error comes after introducing the tool-error variant and changing the return type of invoke-tool to a result:
error: found a reference to a type which is excluded due to its feature not being activated
--> .../wit-unstable/skill.wit:27:39
|
27 | invoke-tool: func(request: u8) -> result<list<u8>, error>;
| ^-----
--> src/main.rs:3:1
|
3 | generate!({ path: "skill.wit", world: "skill" });
It appears like a bug, as only small changes to the WIT world (changing the unrelated type of output-schema from a list<u8> to a u8) will lead to a successful compilation. My expectation would have been that it is possible to have unstable types in the signature of unstable functions.
package pharia:[email protected];
world skill {
import tool;
export skill-handler;
}
@since(version = 0.3.0)
interface skill-handler {
@since(version = 0.3.0)
record skill-metadata {
output-schema: list<u8>,
}
@since(version = 0.3.0)
metadata: func() -> skill-metadata;
}
interface tool {
@unstable(feature = tool)
variant error {
other(string)
}
@unstable(feature = tool)
invoke-tool: func(request: u8) -> result<list<u8>, error>;
}
A minimum reproducable example can be achieved with the following main:
use wit_bindgen::generate;
generate!({ path: "skill.wit", world: "skill" });
fn main() {
println!("Hello, world!");
}
I've transferred this to the wasm-tools repository since here is where the issue lies, and this can additionally be reproduced with wasm-tools component wit over the above WIT package as well.
This points to subpar handling of "anonymous types" (in this case result<list<u8>, error>) and gated types. The problem here is that the anonymous type definition result<list<u8>, error> refers to a gated type (error) but the anonymous type is itself not gated (and has no means of being gated). This is very much an (unforseen) limitation of WIT. Thank you for the report!
One possible workaround is something like:
@unstable(feature = tool)
type result-list = result<list<u8>, error>;
@unstable(feature = tool)
invoke-tool: func(request: u8) -> result-list;
but that's just a workaround and I realize it's not great
Thanks for getting back so quickly and for pointing me to the workaround. With the knowledge about the "anonymous type" I can see where the limitation comes from.
The thing that threw me off was that I can get it compiling with unrelated changes. E.g. the following WIT world with some changes to the skill-handler interface works fine:
package pharia:[email protected];
world skill {
import tool;
export skill-handler;
}
@since(version = 0.3.0)
interface skill-handler {
@since(version = 0.3.0)
metadata: func() -> u8;
}
interface tool {
@unstable(feature = tool)
variant error {
other(string)
}
@unstable(feature = tool)
invoke-tool: func(request: u8) -> result<list<u8>, error>;
}
Oh wow ok yeah that is indeed very weird! I think that may have to do with the fact that list<u8> is deduplicated across packages to point to the same type, but that may also point to a possible solution where we don't deduplicate in the face of differing stability annotations... Worth digging into!