Skip to content

Commit 974e0fd

Browse files
authored
Add support for include to wit-smith (#2161)
* Test fuzzers with `cargo test --workspace` * Add `include` to `wit-smith` generation Updates the generator to generate `include` statements in worlds to help fuzz the `include` directive. * Pre-sort WIT worlds at rest, update printing This commit moves a sort that previously happened during translation to wasm to happening during general elaboration instead, meaning that at-rest worlds are now pre-sorted in this order. Additionally printing of WIT worlds was updated to manually respect this order where interfaces are printed first, then types, then functions. As a result of this change many test expectations have been updated to shuffle items around. The motivation for this commit is to fix fuzz failures about round-tripping WIT documents through wasm. With `include` now supported more test cases are showing up which stress new paths of when items are added as they weren't tested before. This ensures that when throwing `include` into the mix documents are still round-trip-able. * Re-bless some tests * Fix test build on Windows
1 parent 5681a6c commit 974e0fd

38 files changed

+497
-202
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ rust-2024-incompatible-pat = 'warn'
6565
missing-unsafe-on-extern = 'warn'
6666
unsafe-op-in-unsafe-fn = 'warn'
6767

68+
unexpected_cfgs = { level = 'warn', check-cfg = ['cfg(fuzzing)'] }
69+
6870
[workspace.lints.clippy]
6971
# The default set of lints in Clippy is viewed as "too noisy" right now so
7072
# they're all turned off by default. Selective lints are then enabled below as

crates/wit-component/src/encoding/wit.rs

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -71,30 +71,8 @@ pub fn encode_world(resolve: &Resolve, world_id: WorldId) -> Result<ComponentTyp
7171
let world = &resolve.worlds[world_id];
7272
log::trace!("encoding world {}", world.name);
7373

74-
// This sort is similar in purpose to the sort below in
75-
// `encode_instance`, but different in its sort. The purpose here is
76-
// to ensure that when a document is either printed as WIT or
77-
// encoded as wasm that decoding from those artifacts produces the
78-
// same WIT package. Namely both encoding processes should encode
79-
// things in the same order.
80-
//
81-
// When printing worlds in WIT freestanding function imports are
82-
// printed first, then types. Resource functions are attached to
83-
// types which means that they all come last. Sort all
84-
// resource-related functions here to the back of the `imports` list
85-
// while keeping everything else in front, using a stable sort to
86-
// preserve preexisting ordering.
87-
let mut imports = world.imports.iter().collect::<Vec<_>>();
88-
imports.sort_by_key(|(_name, import)| match import {
89-
WorldItem::Function(f) => match f.kind {
90-
FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => 0,
91-
_ => 1,
92-
},
93-
_ => 0,
94-
});
95-
9674
// Encode the imports
97-
for (name, import) in imports {
75+
for (name, import) in world.imports.iter() {
9876
let name = resolve.name_world_key(name);
9977
log::trace!("encoding import {name}");
10078
let ty = match import {

crates/wit-component/src/printing.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,12 +383,32 @@ impl<O: Output> WitPrinter<O> {
383383
Ok(())
384384
}
385385

386+
/// Prints the world `id` within `resolve`.
387+
///
388+
/// This is a little tricky to preserve round-tripping that WIT wants. This
389+
/// function inherently can't preserve ordering of imports because resource
390+
/// functions aren't guaranteed to be all adjacent to the resource itself
391+
/// they're attached to. That means that at the very least, when printing
392+
/// resource functions, items may be printed out-of-order.
393+
///
394+
/// To help solve this the printing here is kept in sync with WIT encoding
395+
/// of worlds which is to print items in the order of:
396+
///
397+
/// * Any imported interface. Ordering between interfaces is preserved.
398+
/// * Any types, including resource functions on those types. Ordering
399+
/// between types is preserved.
400+
/// * Any functions, which may refer to those types. Ordering between
401+
/// functions is preserved.
402+
///
403+
/// This keeps things printed in a roughly topological fashion and makes
404+
/// round-tripping a bit more reliable.
386405
fn print_world(&mut self, resolve: &Resolve, id: WorldId) -> Result<()> {
387406
let prev_items = mem::replace(&mut self.any_items, false);
388407
let world = &resolve.worlds[id];
389408
let pkgid = world.package.unwrap();
390409
let mut types = Vec::new();
391410
let mut resource_funcs = HashMap::new();
411+
let mut function_imports_to_print = Vec::new();
392412
for (name, import) in world.imports.iter() {
393413
match import {
394414
WorldItem::Type(t) => match name {
@@ -401,6 +421,8 @@ impl<O: Output> WitPrinter<O> {
401421
resource_funcs.entry(id).or_insert(Vec::new()).push(f);
402422
continue;
403423
}
424+
function_imports_to_print.push((name, import));
425+
continue;
404426
}
405427
self.print_world_item(resolve, name, import, pkgid, "import")?;
406428
// Don't put a blank line between imports, but count
@@ -416,6 +438,11 @@ impl<O: Output> WitPrinter<O> {
416438
types.into_iter(),
417439
&resource_funcs,
418440
)?;
441+
442+
for (name, import) in function_imports_to_print {
443+
self.print_world_item(resolve, name, import, pkgid, "import")?;
444+
self.any_items = true;
445+
}
419446
if !world.exports.is_empty() {
420447
self.new_item();
421448
}

crates/wit-component/tests/interfaces/doc-comments/foo.wit.print

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,10 @@ interface other-comment-forms {
6060

6161
/// world docs
6262
world coverage-world {
63-
/// world func import docs
64-
import imp: func();
65-
6663
/// world typedef docs
6764
type t = u32;
65+
/// world func import docs
66+
import imp: func();
6867

6968
/// world func export docs
7069
export exp: func();

crates/wit-component/tests/interfaces/resources.wat

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,20 @@
100100
(type (;0;)
101101
(component
102102
(type (;0;)
103+
(instance
104+
(export (;0;) "a" (type (sub resource)))
105+
(type (;1;) (own 0))
106+
(type (;2;) (func (result 1)))
107+
(export (;0;) "[constructor]a" (func (type 2)))
108+
(type (;3;) (func))
109+
(export (;1;) "[static]a.b" (func (type 3)))
110+
(type (;4;) (borrow 0))
111+
(type (;5;) (func (param "self" 4)))
112+
(export (;2;) "[method]a.c" (func (type 5)))
113+
)
114+
)
115+
(import "anon" (instance (;0;) (type 0)))
116+
(type (;1;)
103117
(instance
104118
(export (;0;) "bar" (type (sub resource)))
105119
(export (;1;) "t" (type (eq 0)))
@@ -117,14 +131,14 @@
117131
(export (;3;) "a" (func (type 9)))
118132
)
119133
)
120-
(import "foo:bar/foo" (instance (;0;) (type 0)))
121-
(alias export 0 "bar" (type (;1;)))
122-
(alias export 0 "t" (type (;2;)))
123-
(type (;3;)
134+
(import "foo:bar/foo" (instance (;1;) (type 1)))
135+
(alias export 1 "bar" (type (;2;)))
136+
(alias export 1 "t" (type (;3;)))
137+
(type (;4;)
124138
(instance
125-
(alias outer 1 1 (type (;0;)))
139+
(alias outer 1 2 (type (;0;)))
126140
(export (;1;) "bar" (type (eq 0)))
127-
(alias outer 1 2 (type (;2;)))
141+
(alias outer 1 3 (type (;2;)))
128142
(export (;3;) "t" (type (eq 2)))
129143
(type (;4;) (own 1))
130144
(type (;5;) (func (param "x" 4) (result 4)))
@@ -134,29 +148,15 @@
134148
(export (;1;) "b" (func (type 7)))
135149
)
136150
)
137-
(import "foo:bar/baz" (instance (;1;) (type 3)))
138-
(alias export 1 "bar" (type (;4;)))
139-
(import "bar" (type (;5;) (eq 4)))
140-
(import "a" (type (;6;) (sub resource)))
141-
(type (;7;)
142-
(instance
143-
(export (;0;) "a" (type (sub resource)))
144-
(type (;1;) (own 0))
145-
(type (;2;) (func (result 1)))
146-
(export (;0;) "[constructor]a" (func (type 2)))
147-
(type (;3;) (func))
148-
(export (;1;) "[static]a.b" (func (type 3)))
149-
(type (;4;) (borrow 0))
150-
(type (;5;) (func (param "self" 4)))
151-
(export (;2;) "[method]a.c" (func (type 5)))
152-
)
153-
)
154-
(import "anon" (instance (;2;) (type 7)))
155-
(type (;8;) (own 6))
151+
(import "foo:bar/baz" (instance (;2;) (type 4)))
152+
(alias export 2 "bar" (type (;5;)))
153+
(import "bar" (type (;6;) (eq 5)))
154+
(import "a" (type (;7;) (sub resource)))
155+
(type (;8;) (own 7))
156156
(type (;9;) (func (result 8)))
157157
(import "[constructor]a" (func (;0;) (type 9)))
158158
(export (;1;) "x" (func (type 9)))
159-
(type (;10;) (own 5))
159+
(type (;10;) (own 6))
160160
(type (;11;) (func (result 10)))
161161
(export (;2;) "y" (func (type 11)))
162162
)

crates/wit-component/tests/interfaces/resources.wit.print

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,15 @@ interface implicit-own-handles2 {
5050
}
5151

5252
world some-world {
53-
import foo;
54-
import baz;
5553
import anon: interface {
5654
resource a {
5755
constructor();
5856
b: static func();
5957
c: func();
6058
}
6159
}
60+
import foo;
61+
import baz;
6262
use baz.{bar};
6363

6464
resource a {

crates/wit-component/tests/interfaces/world-top-level.wat

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
(component
44
(type (;0;)
55
(component
6-
(type (;0;) (func))
7-
(import "foo" (func (;0;) (type 0)))
8-
(type (;1;) (func (param "arg" u32)))
9-
(import "bar" (func (;1;) (type 1)))
10-
(type (;2;)
6+
(type (;0;)
117
(instance)
128
)
13-
(import "some-interface" (instance (;0;) (type 2)))
14-
(export (;2;) "foo2" (func (type 0)))
9+
(import "some-interface" (instance (;0;) (type 0)))
10+
(type (;1;) (func))
11+
(import "foo" (func (;0;) (type 1)))
12+
(type (;2;) (func (param "arg" u32)))
13+
(import "bar" (func (;1;) (type 2)))
14+
(export (;2;) "foo2" (func (type 1)))
1515
(type (;3;) (func (result u32)))
1616
(export (;3;) "bar2" (func (type 3)))
1717
(type (;4;)

crates/wit-component/tests/interfaces/world-top-level.wit.print

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package foo:foo;
22

33
world foo {
4-
import foo: func();
5-
import bar: func(arg: u32);
64
import some-interface: interface {
75
}
6+
import foo: func();
7+
import bar: func(arg: u32);
88

99
export foo2: func();
1010
export bar2: func() -> u32;

crates/wit-component/tests/interfaces/worlds-with-types.wit.print

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,19 @@ interface import-me {
55
}
66

77
world simple {
8-
import a: func(a: foo) -> bar;
9-
108
record foo {
119
f: u8,
1210
}
1311

1412
type bar = foo;
13+
import a: func(a: foo) -> bar;
1514

1615
export b: func(a: foo) -> bar;
1716
}
1817
world with-imports {
1918
import import-me;
20-
import a: func(a: foo);
2119
use import-me.{foo};
20+
import a: func(a: foo);
2221

2322
export b: func(a: foo);
2423
}

0 commit comments

Comments
 (0)