Skip to content

Commit

Permalink
Require root packages when defining nested packages in wit (#1700)
Browse files Browse the repository at this point in the history
* first bit

* round trip mixed

* multi file packages

* multi file deps

* package group root isnt optional

* select_world takes single package id

* update embed behavior

* handle out-dir

* clearer names and tidy

* test modifications

* tests

* Convert tests to `Resolve::push_str`

* Handle some review feedback

* Remove `&mut` argument, make it owned
* Remove new `visit_group`
* Refactor `sort_unresolved_groups` and use it in `push_dir`
* Fix signature of `push_dir`

* Better error when a package is defined twice

* Refactor parsing nested files

* Use a normal AST node for nested packages
* Remove some complexity around nested/inlined/etc
* Remove some resolver complexity

* Disallow nested-in-nested

* Go back to asserting new packages

Merging doesn't work in this location so don't try to handle it.

* Fix parsing revealed in merging with main

* Update interface to printing to explicitly have a main package

* Fix fuzzer build

* Update fuzzing to use nested package statements

Test this new feature in the roundtrip fuzzer.

---------

Co-authored-by: Alex Crichton <[email protected]>
  • Loading branch information
macovedj and alexcrichton authored Jul 31, 2024
1 parent 36edf4a commit e9c71d9
Show file tree
Hide file tree
Showing 96 changed files with 1,564 additions and 924 deletions.
57 changes: 25 additions & 32 deletions crates/wasm-wave/src/value/wit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,27 +149,23 @@ impl<'a> TypeResolver<'a> {

#[cfg(test)]
mod tests {
use wit_parser::UnresolvedPackageGroup;

use super::*;

#[test]
fn resolve_wit_type_smoke_test() {
let UnresolvedPackageGroup {
mut packages,
source_map,
} = UnresolvedPackageGroup::parse(
"test.wit",
r#"
package test:types;
interface types {
type uint8 = u8;
}
"#,
)
.unwrap();
let mut resolve = Resolve::new();
resolve.push(packages.remove(0), &source_map).unwrap();
resolve
.push_str(
"test.wit",
"
package test:types;
interface types {
type uint8 = u8;
}
",
)
.unwrap();

let (type_id, _) = resolve.types.iter().next().unwrap();
let ty = resolve_wit_type(&resolve, type_id).unwrap();
Expand All @@ -178,24 +174,21 @@ mod tests {

#[test]
fn resolve_wit_func_type_smoke_test() {
let UnresolvedPackageGroup {
mut packages,
source_map,
} = UnresolvedPackageGroup::parse(
"test.wit",
r#"
package test:types;
interface types {
type uint8 = u8;
no-results: func(a: uint8, b: string);
one-result: func(c: uint8, d: string) -> uint8;
named-results: func(e: uint8, f: string) -> (x: u8, y: string);
}
"#,
)
.unwrap();
let mut resolve = Resolve::new();
resolve.push(packages.remove(0), &source_map).unwrap();
resolve
.push_str(
"test.wit",
r#"
package test:types;
interface types {
type uint8 = u8;
no-results: func(a: uint8, b: string);
one-result: func(c: uint8, d: string) -> uint8;
named-results: func(e: uint8, f: string) -> (x: u8, y: string);
}
"#,
)
.unwrap();

for (func_name, expected_display) in [
("no-results", "func(a: u8, b: string)"),
Expand Down
4 changes: 2 additions & 2 deletions crates/wit-component/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2136,7 +2136,7 @@ mod test {
#[test]
fn it_renames_imports() {
let mut resolve = Resolve::new();
let pkgs = resolve
let pkg = resolve
.push_str(
"test.wit",
r#"
Expand All @@ -2155,7 +2155,7 @@ world test {
"#,
)
.unwrap();
let world = resolve.select_world(&pkgs, None).unwrap();
let world = resolve.select_world(pkg, None).unwrap();

let mut module = dummy_module(&resolve, world);

Expand Down
4 changes: 2 additions & 2 deletions crates/wit-component/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ world test-world {}

// Parse pre-canned WIT to build resolver
let mut resolver = Resolve::default();
let pkgs = resolver.push_str("in-code.wit", COMPONENT_WIT)?;
let world = resolver.select_world(&pkgs, Some("test-world"))?;
let pkg = resolver.push_str("in-code.wit", COMPONENT_WIT)?;
let world = resolver.select_world(pkg, Some("test-world"))?;

// Embed component metadata
embed_component_metadata(&mut bytes, &resolver, world, StringEncoding::UTF8)?;
Expand Down
6 changes: 3 additions & 3 deletions crates/wit-component/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,12 +259,12 @@ impl Bindgen {
let world_name = reader.read_string()?;
wasm = &data[reader.original_position()..];

let (r, pkgs) = match crate::decode(wasm)? {
DecodedWasm::WitPackages(resolve, pkgs) => (resolve, pkgs),
let (r, pkg) = match crate::decode(wasm)? {
DecodedWasm::WitPackage(resolve, pkgs) => (resolve, pkgs),
DecodedWasm::Component(..) => bail!("expected encoded wit package(s)"),
};
resolve = r;
world = resolve.select_world(&pkgs, Some(world_name.into()))?;
world = resolve.select_world(pkg, Some(world_name.into()))?;
}

// Current format where `data` is a wasm component itself.
Expand Down
92 changes: 51 additions & 41 deletions crates/wit-component/src/printing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,62 +50,72 @@ impl WitPrinter {
self
}

/// Print a set of one or more WIT packages into a string.
/// Prints the specified `pkg` which is located in `resolve` to a string.
///
/// The `nested` list of packages are other packages to include at the end
/// of the output in `package ... { ... }` syntax.
pub fn print(
&mut self,
resolve: &Resolve,
pkg_ids: &[PackageId],
force_print_package_in_curlies: bool,
pkg: PackageId,
nested: &[PackageId],
) -> Result<String> {
let print_package_in_curlies = force_print_package_in_curlies || pkg_ids.len() > 1;
for (i, pkg_id) in pkg_ids.into_iter().enumerate() {
self.print_package(resolve, pkg, true)?;
for (i, pkg_id) in nested.iter().enumerate() {
if i > 0 {
self.output.push_str("\n\n");
}
self.print_package(resolve, *pkg_id, false)?;
}

let pkg = &resolve.packages[*pkg_id];
self.print_docs(&pkg.docs);
self.output.push_str("package ");
self.print_name(&pkg.name.namespace);
self.output.push_str(":");
self.print_name(&pkg.name.name);
if let Some(version) = &pkg.name.version {
self.output.push_str(&format!("@{version}"));
}
Ok(std::mem::take(&mut self.output).into())
}

if print_package_in_curlies {
self.output.push_str(" {\n");
} else {
self.print_semicolon();
self.output.push_str("\n\n");
}
fn print_package(&mut self, resolve: &Resolve, pkg: PackageId, is_main: bool) -> Result<()> {
let pkg = &resolve.packages[pkg];
self.print_docs(&pkg.docs);
self.output.push_str("package ");
self.print_name(&pkg.name.namespace);
self.output.push_str(":");
self.print_name(&pkg.name.name);
if let Some(version) = &pkg.name.version {
self.output.push_str(&format!("@{version}"));
}

for (name, id) in pkg.interfaces.iter() {
self.print_docs(&resolve.interfaces[*id].docs);
self.print_stability(&resolve.interfaces[*id].stability);
self.output.push_str("interface ");
self.print_name(name);
self.output.push_str(" {\n");
self.print_interface(resolve, *id)?;
writeln!(&mut self.output, "}}\n")?;
}
if is_main {
self.print_semicolon();
self.output.push_str("\n\n");
} else {
self.output.push_str(" {\n");
}

for (name, id) in pkg.worlds.iter() {
self.print_docs(&resolve.worlds[*id].docs);
self.print_stability(&resolve.worlds[*id].stability);
self.output.push_str("world ");
self.print_name(name);
self.output.push_str(" {\n");
self.print_world(resolve, *id)?;
for (name, id) in pkg.interfaces.iter() {
self.print_docs(&resolve.interfaces[*id].docs);
self.print_stability(&resolve.interfaces[*id].stability);
self.output.push_str("interface ");
self.print_name(name);
self.output.push_str(" {\n");
self.print_interface(resolve, *id)?;
if is_main {
writeln!(&mut self.output, "}}\n")?;
} else {
writeln!(&mut self.output, "}}")?;
}

if print_package_in_curlies {
self.output.push_str("}\n");
}
}

Ok(std::mem::take(&mut self.output).into())
for (name, id) in pkg.worlds.iter() {
self.print_docs(&resolve.worlds[*id].docs);
self.print_stability(&resolve.worlds[*id].stability);
self.output.push_str("world ");
self.print_name(name);
self.output.push_str(" {\n");
self.print_world(resolve, *id)?;
writeln!(&mut self.output, "}}")?;
}
if !is_main {
writeln!(&mut self.output, "}}")?;
}
Ok(())
}

fn print_semicolon(&mut self) {
Expand Down
Loading

0 comments on commit e9c71d9

Please sign in to comment.