Skip to content

Commit 3c7046d

Browse files
committed
[wit-smith] Add implements interface generation
Teach wit-smith to generate `ImplementsInterface` items in worlds, producing `%label: path;` WIT syntax which encodes as `[implements=<I>]L` in the component binary. This enables fuzzing of the implements feature through the existing roundtrip_wit fuzzer.
1 parent 71da44a commit 3c7046d

File tree

4 files changed

+55
-5
lines changed

4 files changed

+55
-5
lines changed

crates/wit-parser/src/resolve/mod.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1580,11 +1580,18 @@ package {name} is defined in two different locations:\n\
15801580
for (name, item) in world.imports.iter().chain(world.exports.iter()) {
15811581
log::debug!("validating world item: {}", self.name_world_key(name));
15821582
match item {
1583-
WorldItem::Interface { id, .. } => {
1584-
// anonymous interfaces must belong to the same package
1585-
// as the world's package.
1583+
WorldItem::Interface { id, implements, .. } => {
15861584
if matches!(name, WorldKey::Name(_)) {
1587-
assert_eq!(self.interfaces[*id].package, world.package);
1585+
if implements.is_none() {
1586+
// Anonymous interfaces must belong to the same
1587+
// package as the world's package.
1588+
assert_eq!(self.interfaces[*id].package, world.package);
1589+
} else {
1590+
// Implements items use `WorldKey::Name` but can
1591+
// reference interfaces from other packages.
1592+
// Verify the target interface exists.
1593+
assert!(self.interfaces.get(*id).is_some());
1594+
}
15881595
}
15891596
}
15901597
WorldItem::Function(f) => {

crates/wit-smith/src/config.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ pub struct Config {
3131
pub fixed_length_lists: bool,
3232
#[cfg_attr(feature = "clap", clap(long, default_value_t = Config::default().world_include))]
3333
pub world_include: bool,
34+
#[cfg_attr(feature = "clap", clap(long, default_value_t = Config::default().implements))]
35+
pub implements: bool,
3436
}
3537

3638
impl Default for Config {
@@ -50,6 +52,7 @@ impl Default for Config {
5052
error_context: false,
5153
fixed_length_lists: false,
5254
world_include: false,
55+
implements: false,
5356
}
5457
}
5558
}
@@ -71,6 +74,7 @@ impl Arbitrary<'_> for Config {
7174
error_context: u.arbitrary()?,
7275
fixed_length_lists: u.arbitrary()?,
7376
world_include: false,
77+
implements: u.arbitrary()?,
7478
})
7579
}
7680
}

crates/wit-smith/src/generate.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,7 @@ impl<'a> InterfaceGenerator<'a> {
647647
Func(Direction),
648648
Interface(Direction),
649649
AnonInterface(Direction),
650+
ImplementsInterface(Direction),
650651
Type,
651652
Use,
652653
Include,
@@ -666,9 +667,18 @@ impl<'a> InterfaceGenerator<'a> {
666667
&& u.arbitrary()?
667668
{
668669
let kind = u.arbitrary::<ItemKind>()?;
670+
671+
// Gate config-disabled features early, before consuming any
672+
// more random bytes, to keep byte consumption deterministic
673+
// when a feature is toggled off.
674+
if matches!(kind, ItemKind::ImplementsInterface(_)) && !self.generator.config.implements
675+
{
676+
continue;
677+
}
678+
669679
let (direction, named) = match kind {
670680
ItemKind::Func(dir) | ItemKind::AnonInterface(dir) => (Some(dir), true),
671-
ItemKind::Interface(dir) => (Some(dir), false),
681+
ItemKind::Interface(dir) | ItemKind::ImplementsInterface(dir) => (Some(dir), false),
672682
ItemKind::Type => (None, true),
673683
ItemKind::Use => (None, false),
674684
ItemKind::Include => (None, false),
@@ -750,6 +760,34 @@ impl<'a> InterfaceGenerator<'a> {
750760
}
751761
part.push_str(";");
752762
}
763+
ItemKind::ImplementsInterface(dir) => {
764+
let names = match dir {
765+
Direction::Import => &mut self.unique_names,
766+
Direction::Export => &mut export_names,
767+
};
768+
let label = gen_unique_name(u, names)?;
769+
770+
let mut path_str = String::new();
771+
if self
772+
.generator
773+
.gen_interface_path(u, self.file, &mut path_str)?
774+
.is_none()
775+
{
776+
continue;
777+
}
778+
779+
self.generator.packages.add_name(
780+
self.package_name.to_string(),
781+
world_name.to_string(),
782+
label.to_string(),
783+
);
784+
785+
part.push_str("%");
786+
part.push_str(&label);
787+
part.push_str(": ");
788+
part.push_str(&path_str);
789+
part.push_str(";");
790+
}
753791
ItemKind::AnonInterface(_) => {
754792
let iface =
755793
InterfaceGenerator::new(self.generator, self.file, self.package_name, None)

crates/wit-smith/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,6 @@ pub fn smith(config: &Config, u: &mut Unstructured<'_>) -> Result<Vec<u8>> {
5555
return Err(arbitrary::Error::IncorrectFormat);
5656
}
5757
}
58+
5859
Ok(wasm)
5960
}

0 commit comments

Comments
 (0)