From cf306c4dd532aa0053a96cc5425f8d2736513094 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 17 May 2023 07:30:25 -0700 Subject: [PATCH] Update Wasmtime for upcoming WIT changes This PR integrates bytecodealliance/wasm-tools#1027 into Wasmtime. The main changes here are: * WIT syntax is updated with WebAssembly/component-model#193 * Generated bindings in the `bindgen!` macro have been updated to reflect the new structure of WIT. * The accepted component model binary format has been updated to account for changes. This PR disables wasi-http tests and the on-by-default feature because the WIT syntax has been updated but the submodule containing the WITs has not been updated yet so there's no way to get that building temporarily. Once that's updated then this can be reenabled. --- Cargo.lock | 25 +- Cargo.toml | 12 +- ci/run-tests.sh | 4 +- cranelift/wasm/src/code_translator.rs | 2 +- crates/component-macro/src/bindgen.rs | 26 +- crates/component-macro/tests/codegen.rs | 6 - crates/component-macro/tests/codegen/char.wit | 8 +- .../tests/codegen/conventions.wit | 7 +- .../tests/codegen/direct-import.wit | 4 +- .../component-macro/tests/codegen/empty.wit | 3 +- .../component-macro/tests/codegen/flags.wit | 8 +- .../component-macro/tests/codegen/floats.wit | 8 +- .../tests/codegen/function-new.wit | 3 +- .../tests/codegen/integers.wit | 8 +- .../component-macro/tests/codegen/lists.wit | 8 +- .../tests/codegen/many-arguments.wit | 8 +- .../tests/codegen/multi-return.wit | 8 +- .../component-macro/tests/codegen/records.wit | 8 +- .../component-macro/tests/codegen/rename.wit | 10 +- .../tests/codegen/share-types.wit | 8 +- .../tests/codegen/simple-functions.wit | 8 +- .../tests/codegen/simple-lists.wit | 8 +- .../tests/codegen/simple-wasi.wit | 8 +- .../tests/codegen/small-anonymous.wit | 8 +- .../tests/codegen/smoke-default.wit | 4 +- .../tests/codegen/smoke-export.wit | 4 +- .../component-macro/tests/codegen/smoke.wit | 4 +- .../component-macro/tests/codegen/strings.wit | 8 +- .../component-macro/tests/codegen/unions.wit | 8 +- .../tests/codegen/use-paths.wit | 14 +- .../tests/codegen/variants.wit | 8 +- .../tests/codegen/worlds-with-types.wit | 6 +- crates/environ/src/component/translate.rs | 16 +- .../environ/src/component/translate/inline.rs | 13 +- crates/environ/src/component/types.rs | 24 +- crates/test-programs/Cargo.toml | 6 +- crates/wasi-http/Cargo.toml | 4 + crates/wasmtime/src/component/matching.rs | 2 +- crates/wasmtime/src/component/mod.rs | 28 +- crates/wit-bindgen/src/lib.rs | 288 +++++++++++++----- src/commands/run.rs | 1 + tests/all/component_model/bindgen.rs | 8 +- tests/all/component_model/bindgen/results.rs | 41 ++- 43 files changed, 444 insertions(+), 249 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c8c56ec17aae..c50e6c70634e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3639,8 +3639,7 @@ dependencies = [ [[package]] name = "wasm-encoder" version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e77053dc709db790691d3732cfc458adc5acc881dec524965c608effdcd9c581" +source = "git+https://github.com/alexcrichton/wasm-tools?branch=wit-changes#9a557e0e9abdcdb4aa7eb3844c241980b8664fbc" dependencies = [ "leb128", ] @@ -3661,8 +3660,7 @@ dependencies = [ [[package]] name = "wasm-mutate" version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b8c74fd20d97b9ba8b1a6e3ccc6ec715e6c6d4605668926e582e88580180d96" +source = "git+https://github.com/alexcrichton/wasm-tools?branch=wit-changes#9a557e0e9abdcdb4aa7eb3844c241980b8664fbc" dependencies = [ "egg", "log", @@ -3675,8 +3673,7 @@ dependencies = [ [[package]] name = "wasm-smith" version = "0.12.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c11c745f6f4ff2f953d8a94ef056b04b468fc021285cfaf614e77791c05499" +source = "git+https://github.com/alexcrichton/wasm-tools?branch=wit-changes#9a557e0e9abdcdb4aa7eb3844c241980b8664fbc" dependencies = [ "arbitrary", "flagset", @@ -3746,11 +3743,9 @@ dependencies = [ [[package]] name = "wasmparser" version = "0.105.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83be9e0b3f9570dc1979a33ae7b89d032c73211564232b99976553e5c155ec32" +source = "git+https://github.com/alexcrichton/wasm-tools?branch=wit-changes#9a557e0e9abdcdb4aa7eb3844c241980b8664fbc" dependencies = [ "indexmap", - "url", ] [[package]] @@ -3765,8 +3760,7 @@ dependencies = [ [[package]] name = "wasmprinter" version = "0.2.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b0e5ed7a74a065637f0d7798ce5f29cadb064980d24b0c82af5200122fa0d8" +source = "git+https://github.com/alexcrichton/wasm-tools?branch=wit-changes#9a557e0e9abdcdb4aa7eb3844c241980b8664fbc" dependencies = [ "anyhow", "wasmparser 0.105.0", @@ -4306,8 +4300,7 @@ dependencies = [ [[package]] name = "wast" version = "58.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372eecae2d10a5091c2005b32377d7ecd6feecdf2c05838056d02d8b4f07c429" +source = "git+https://github.com/alexcrichton/wasm-tools?branch=wit-changes#9a557e0e9abdcdb4aa7eb3844c241980b8664fbc" dependencies = [ "leb128", "memchr", @@ -4318,8 +4311,7 @@ dependencies = [ [[package]] name = "wat" version = "1.0.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d47446190e112ab1579ab40b3ad7e319d859d74e5134683f04e9f0747bf4173" +source = "git+https://github.com/alexcrichton/wasm-tools?branch=wit-changes#9a557e0e9abdcdb4aa7eb3844c241980b8664fbc" dependencies = [ "wast 58.0.0", ] @@ -4733,8 +4725,7 @@ dependencies = [ [[package]] name = "wit-parser" version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca2581061573ef6d1754983d7a9b3ed5871ef859d52708ea9a0f5af32919172" +source = "git+https://github.com/alexcrichton/wasm-tools?branch=wit-changes#9a557e0e9abdcdb4aa7eb3844c241980b8664fbc" dependencies = [ "anyhow", "id-arena", diff --git a/Cargo.toml b/Cargo.toml index 4a60137e7269..ee0f9d885cfe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -225,7 +225,8 @@ default = [ "vtune", "wasi-nn", "wasi-threads", - "wasi-http", + # TODO: the WIT needs to be updated + #"wasi-http", "pooling-allocator", ] jitdump = ["wasmtime/jitdump"] @@ -288,3 +289,12 @@ debug-assertions = false # string initializers. overflow-checks = false +[patch.crates-io] +wasm-encoder = { git = 'https://github.com/alexcrichton/wasm-tools', branch = 'wit-changes' } +wasm-mutate = { git = 'https://github.com/alexcrichton/wasm-tools', branch = 'wit-changes' } +wasm-smith = { git = 'https://github.com/alexcrichton/wasm-tools', branch = 'wit-changes' } +wasmparser = { git = 'https://github.com/alexcrichton/wasm-tools', branch = 'wit-changes' } +wasmprinter = { git = 'https://github.com/alexcrichton/wasm-tools', branch = 'wit-changes' } +wast = { git = 'https://github.com/alexcrichton/wasm-tools', branch = 'wit-changes' } +wat = { git = 'https://github.com/alexcrichton/wasm-tools', branch = 'wit-changes' } +wit-parser = { git = 'https://github.com/alexcrichton/wasm-tools', branch = 'wit-changes' } diff --git a/ci/run-tests.sh b/ci/run-tests.sh index 67e53eb87b51..cee988e138d2 100755 --- a/ci/run-tests.sh +++ b/ci/run-tests.sh @@ -1,8 +1,10 @@ #!/bin/bash +# TODO: add this flag back in +#--features "test-programs/test_programs_http" \ + cargo test \ --features "test-programs/test_programs" \ - --features "test-programs/test_programs_http" \ --features wasi-threads \ --workspace \ --exclude 'wasmtime-wasi-*' \ diff --git a/cranelift/wasm/src/code_translator.rs b/cranelift/wasm/src/code_translator.rs index 030fe43c3b44..4b02d16ca286 100644 --- a/cranelift/wasm/src/code_translator.rs +++ b/cranelift/wasm/src/code_translator.rs @@ -2348,7 +2348,7 @@ pub fn translate_operator( )); } Operator::I31New | Operator::I31GetS | Operator::I31GetU => { - unimplemented!("GC operators not yet implemented") + return Err(wasm_unsupported!("proposed GC operator {:?}", op)); } }; Ok(()) diff --git a/crates/component-macro/src/bindgen.rs b/crates/component-macro/src/bindgen.rs index 02865920458e..e41e0fa2abcf 100644 --- a/crates/component-macro/src/bindgen.rs +++ b/crates/component-macro/src/bindgen.rs @@ -78,7 +78,16 @@ impl Parse for Config { if inline.is_some() { return Err(Error::new(s.span(), "cannot specify a second source")); } - inline = Some(format!("default world interfaces {{ {} }}", s.value())); + inline = Some(format!( + " + package wasmtime:component-macro-synthesized + + world interfaces {{ + {} + }} + ", + s.value() + )); if world.is_some() { return Err(Error::new( @@ -86,7 +95,7 @@ impl Parse for Config { "cannot specify a world with `interfaces`", )); } - world = Some("macro-input.interfaces".to_string()); + world = Some("interfaces".to_string()); opts.only_interfaces = true; } @@ -130,7 +139,7 @@ fn parse_source( } else { let pkg = UnresolvedPackage::parse_file(path)?; files.extend(pkg.source_files().map(|s| s.to_owned())); - resolve.push(pkg, &Default::default()) + resolve.push(pkg) } }; @@ -141,16 +150,7 @@ fn parse_source( }; let inline_pkg = if let Some(inline) = inline { - let deps = resolve - .packages - .iter() - .map(|(id, p)| (p.name.clone(), id)) - .collect(); - - Some(resolve.push( - UnresolvedPackage::parse("macro-input".as_ref(), &inline)?, - &deps, - )?) + Some(resolve.push(UnresolvedPackage::parse("macro-input".as_ref(), &inline)?)?) } else { None }; diff --git a/crates/component-macro/tests/codegen.rs b/crates/component-macro/tests/codegen.rs index ac39534022c0..616f3253c614 100644 --- a/crates/component-macro/tests/codegen.rs +++ b/crates/component-macro/tests/codegen.rs @@ -4,9 +4,6 @@ macro_rules! gentest { mod sugar { wasmtime::component::bindgen!(in $path); } - mod normal { - wasmtime::component::bindgen!($name in $path); - } mod async_ { wasmtime::component::bindgen!({ path: $path, @@ -16,15 +13,12 @@ macro_rules! gentest { mod tracing { wasmtime::component::bindgen!({ path: $path, - world: $name, tracing: true, duplicate_if_necessary: true, }); } } - // ... }; - } component_macro_test_helpers::foreach!(gentest); diff --git a/crates/component-macro/tests/codegen/char.wit b/crates/component-macro/tests/codegen/char.wit index 01b20f70077f..b49947b38abb 100644 --- a/crates/component-macro/tests/codegen/char.wit +++ b/crates/component-macro/tests/codegen/char.wit @@ -1,3 +1,5 @@ +package foo:foo + interface chars { /// A function that accepts a character take-char: func(x: char) @@ -5,7 +7,7 @@ interface chars { return-char: func() -> char } -default world the-world { - import imports: self.chars - export exports: self.chars +world the-world { + import chars + export chars } diff --git a/crates/component-macro/tests/codegen/conventions.wit b/crates/component-macro/tests/codegen/conventions.wit index 2c5645c66313..a96b5afd3444 100644 --- a/crates/component-macro/tests/codegen/conventions.wit +++ b/crates/component-macro/tests/codegen/conventions.wit @@ -1,4 +1,5 @@ // hello 🐱 world +package foo:foo interface conventions { kebab-case: func() @@ -32,7 +33,7 @@ interface conventions { %bool: func() } -default world the-world { - import imports: self.conventions - export exports: self.conventions +world the-world { + import conventions + export conventions } diff --git a/crates/component-macro/tests/codegen/direct-import.wit b/crates/component-macro/tests/codegen/direct-import.wit index d2b612d6de71..67d252a4a898 100644 --- a/crates/component-macro/tests/codegen/direct-import.wit +++ b/crates/component-macro/tests/codegen/direct-import.wit @@ -1,3 +1,5 @@ -default world foo { +package foo:foo + +world foo { import foo: func() } diff --git a/crates/component-macro/tests/codegen/empty.wit b/crates/component-macro/tests/codegen/empty.wit index 1f99081f58cb..b720c27d628e 100644 --- a/crates/component-macro/tests/codegen/empty.wit +++ b/crates/component-macro/tests/codegen/empty.wit @@ -1 +1,2 @@ -default world empty {} +package foo:foo +world empty {} diff --git a/crates/component-macro/tests/codegen/flags.wit b/crates/component-macro/tests/codegen/flags.wit index b5a2fa2d1c83..8c9c1437169d 100644 --- a/crates/component-macro/tests/codegen/flags.wit +++ b/crates/component-macro/tests/codegen/flags.wit @@ -1,3 +1,5 @@ +package foo:foo + interface flegs { flags flag1 { b0, @@ -47,7 +49,7 @@ interface flegs { roundtrip-flag64: func(x: flag64) -> flag64 } -default world the-flags { - import import-flags: self.flegs - export export-flags: self.flegs +world the-flags { + import flegs + export flegs } diff --git a/crates/component-macro/tests/codegen/floats.wit b/crates/component-macro/tests/codegen/floats.wit index 4a0c67ce2c29..6cd720a8dc39 100644 --- a/crates/component-macro/tests/codegen/floats.wit +++ b/crates/component-macro/tests/codegen/floats.wit @@ -1,3 +1,5 @@ +package foo:foo + interface floats { float32-param: func(x: float32) float64-param: func(x: float64) @@ -5,7 +7,7 @@ interface floats { float64-result: func() -> float64 } -default world the-world { - import imports: self.floats - export exports: self.floats +world the-world { + import floats + export floats } diff --git a/crates/component-macro/tests/codegen/function-new.wit b/crates/component-macro/tests/codegen/function-new.wit index fed79c6633c6..2f4e407566cd 100644 --- a/crates/component-macro/tests/codegen/function-new.wit +++ b/crates/component-macro/tests/codegen/function-new.wit @@ -1,3 +1,4 @@ -default world foo { +package foo:foo +world foo { export new: func() } diff --git a/crates/component-macro/tests/codegen/integers.wit b/crates/component-macro/tests/codegen/integers.wit index bfad272882d0..2f5866bb2ae6 100644 --- a/crates/component-macro/tests/codegen/integers.wit +++ b/crates/component-macro/tests/codegen/integers.wit @@ -1,3 +1,5 @@ +package foo:foo + interface integers { a1: func(x: u8) a2: func(x: s8) @@ -32,7 +34,7 @@ interface integers { pair-ret: func() -> tuple } -default world the-world { - import imports: self.integers - export exports: self.integers +world the-world { + import integers + export integers } diff --git a/crates/component-macro/tests/codegen/lists.wit b/crates/component-macro/tests/codegen/lists.wit index 19b946068706..256a1cdf8fcf 100644 --- a/crates/component-macro/tests/codegen/lists.wit +++ b/crates/component-macro/tests/codegen/lists.wit @@ -1,3 +1,5 @@ +package foo:foo + interface lists { list-u8-param: func(x: list) list-u16-param: func(x: list) @@ -77,7 +79,7 @@ interface lists { load-store-everything: func(a: load-store-all-sizes) -> load-store-all-sizes } -default world the-lists { - import import-lists: self.lists - export export-lists: self.lists +world the-lists { + import lists + export lists } diff --git a/crates/component-macro/tests/codegen/many-arguments.wit b/crates/component-macro/tests/codegen/many-arguments.wit index a5b67b2184b1..cbfc123144fa 100644 --- a/crates/component-macro/tests/codegen/many-arguments.wit +++ b/crates/component-macro/tests/codegen/many-arguments.wit @@ -1,3 +1,5 @@ +package foo:foo + interface manyarg { many-args: func( a1: u64, @@ -44,7 +46,7 @@ interface manyarg { big-argument: func(x: big-struct) } -default world the-world { - import imports: self.manyarg - export exports: self.manyarg +world the-world { + import manyarg + export manyarg } diff --git a/crates/component-macro/tests/codegen/multi-return.wit b/crates/component-macro/tests/codegen/multi-return.wit index 716e77a6c850..69951b2c3393 100644 --- a/crates/component-macro/tests/codegen/multi-return.wit +++ b/crates/component-macro/tests/codegen/multi-return.wit @@ -1,3 +1,5 @@ +package foo:foo + interface multi-return { mra: func() mrb: func() -> () @@ -6,7 +8,7 @@ interface multi-return { mre: func() -> (a: u32, b: float32) } -default world the-world { - import imports: self.multi-return - export exports: self.multi-return +world the-world { + import multi-return + export multi-return } diff --git a/crates/component-macro/tests/codegen/records.wit b/crates/component-macro/tests/codegen/records.wit index 39d5e81694e8..f51bb8f28f75 100644 --- a/crates/component-macro/tests/codegen/records.wit +++ b/crates/component-macro/tests/codegen/records.wit @@ -1,3 +1,5 @@ +package foo:foo + interface records { tuple-arg: func(x: tuple) tuple-result: func() -> tuple @@ -53,7 +55,7 @@ interface records { typedef-inout: func(e: tuple-typedef2) -> s32 } -default world the-world { - import imports: self.records - export exports: self.records +world the-world { + import records + export records } diff --git a/crates/component-macro/tests/codegen/rename.wit b/crates/component-macro/tests/codegen/rename.wit index d60d4f6f9f43..8bfc7f36862b 100644 --- a/crates/component-macro/tests/codegen/rename.wit +++ b/crates/component-macro/tests/codegen/rename.wit @@ -1,5 +1,7 @@ +package foo:foo + interface red { - use self.green.{thing} + use green.{thing} foo: func() -> thing } @@ -8,7 +10,7 @@ interface green { type thing = s32 } -default world neptune { - import blue: self.red - import orange: self.green +world neptune { + import red + import green } diff --git a/crates/component-macro/tests/codegen/share-types.wit b/crates/component-macro/tests/codegen/share-types.wit index 106ee70936d9..8d36d1b0aa88 100644 --- a/crates/component-macro/tests/codegen/share-types.wit +++ b/crates/component-macro/tests/codegen/share-types.wit @@ -1,3 +1,5 @@ +package foo:foo + interface http-types{ record request { method: string @@ -7,13 +9,13 @@ interface http-types{ } } -default world http-interface { +world http-interface { export http-handler: interface { - use self.http-types.{request,response} + use http-types.{request,response} handle-request: func(request: request) -> response } import http-fetch: interface { - use self.http-types.{request,response} + use http-types.{request,response} fetch-request: func(request: request) -> response } } diff --git a/crates/component-macro/tests/codegen/simple-functions.wit b/crates/component-macro/tests/codegen/simple-functions.wit index cdb1183790fa..2593d199e565 100644 --- a/crates/component-macro/tests/codegen/simple-functions.wit +++ b/crates/component-macro/tests/codegen/simple-functions.wit @@ -1,3 +1,5 @@ +package foo:foo + interface simple { f1: func() f2: func(a: u32) @@ -9,7 +11,7 @@ interface simple { f6: func(a: u32, b: u32, c: u32) -> tuple } -default world the-world { - import imports: self.simple - export exports: self.simple +world the-world { + import simple + export simple } diff --git a/crates/component-macro/tests/codegen/simple-lists.wit b/crates/component-macro/tests/codegen/simple-lists.wit index 885cdeb74305..8e082b6e34e7 100644 --- a/crates/component-macro/tests/codegen/simple-lists.wit +++ b/crates/component-macro/tests/codegen/simple-lists.wit @@ -1,3 +1,5 @@ +package foo:foo + interface simple-lists { simple-list1: func(l: list) simple-list2: func() -> list @@ -5,7 +7,7 @@ interface simple-lists { simple-list4: func(l: list>) -> list> } -default world my-world { - import imports: self.simple-lists - export exports: self.simple-lists +world my-world { + import simple-lists + export simple-lists } diff --git a/crates/component-macro/tests/codegen/simple-wasi.wit b/crates/component-macro/tests/codegen/simple-wasi.wit index 02c47dc9b8f4..60192473d99e 100644 --- a/crates/component-macro/tests/codegen/simple-wasi.wit +++ b/crates/component-macro/tests/codegen/simple-wasi.wit @@ -1,3 +1,5 @@ +package foo:foo + interface wasi-filesystem { record descriptor-stat { } @@ -15,7 +17,7 @@ interface wall-clock { } } -default world wasi { - import wasi-filesystem: self.wasi-filesystem - import wall-clock: self.wall-clock +world wasi { + import wasi-filesystem + import wall-clock } diff --git a/crates/component-macro/tests/codegen/small-anonymous.wit b/crates/component-macro/tests/codegen/small-anonymous.wit index 96436091344d..ad9c67287d4e 100644 --- a/crates/component-macro/tests/codegen/small-anonymous.wit +++ b/crates/component-macro/tests/codegen/small-anonymous.wit @@ -1,3 +1,5 @@ +package foo:foo + interface anon { enum error { success, @@ -7,7 +9,7 @@ interface anon { option-test: func() -> result, error> } -default world the-world { - import imports: self.anon - export exports: self.anon +world the-world { + import anon + export anon } diff --git a/crates/component-macro/tests/codegen/smoke-default.wit b/crates/component-macro/tests/codegen/smoke-default.wit index 0d269359063f..90be0b1e3cdc 100644 --- a/crates/component-macro/tests/codegen/smoke-default.wit +++ b/crates/component-macro/tests/codegen/smoke-default.wit @@ -1,3 +1,5 @@ -default world the-world { +package foo:foo + +world the-world { export y: func() } diff --git a/crates/component-macro/tests/codegen/smoke-export.wit b/crates/component-macro/tests/codegen/smoke-export.wit index cefdc19823a0..983f1c35066e 100644 --- a/crates/component-macro/tests/codegen/smoke-export.wit +++ b/crates/component-macro/tests/codegen/smoke-export.wit @@ -1,4 +1,6 @@ -default world the-world { +package foo:foo + +world the-world { export the-name: interface { y: func() } diff --git a/crates/component-macro/tests/codegen/smoke.wit b/crates/component-macro/tests/codegen/smoke.wit index 6d8e80ccea86..0476bd988ec1 100644 --- a/crates/component-macro/tests/codegen/smoke.wit +++ b/crates/component-macro/tests/codegen/smoke.wit @@ -1,4 +1,6 @@ -default world the-world { +package foo:foo + +world the-world { import imports: interface { y: func() } diff --git a/crates/component-macro/tests/codegen/strings.wit b/crates/component-macro/tests/codegen/strings.wit index 7fc1885529bc..650300acfb9d 100644 --- a/crates/component-macro/tests/codegen/strings.wit +++ b/crates/component-macro/tests/codegen/strings.wit @@ -1,10 +1,12 @@ +package foo:foo + interface strings { a: func(x: string) b: func() -> string c: func(a: string, b: string) -> string } -default world the-world { - import imports: self.strings - export exports: self.strings +world the-world { + import strings + export strings } diff --git a/crates/component-macro/tests/codegen/unions.wit b/crates/component-macro/tests/codegen/unions.wit index 07e0f380a0d0..252f513f2de8 100644 --- a/crates/component-macro/tests/codegen/unions.wit +++ b/crates/component-macro/tests/codegen/unions.wit @@ -1,3 +1,5 @@ +package foo:foo + interface unions { /// A union of all of the integral types union all-integers { @@ -58,7 +60,7 @@ interface unions { identify-distinguishable-num: func(num: distinguishable-num) -> u8 } -default world the-unions { - import import-unions: self.unions - export export-unions: self.unions +world the-unions { + import unions + export unions } diff --git a/crates/component-macro/tests/codegen/use-paths.wit b/crates/component-macro/tests/codegen/use-paths.wit index 1e877379caf4..dab6646afac8 100644 --- a/crates/component-macro/tests/codegen/use-paths.wit +++ b/crates/component-macro/tests/codegen/use-paths.wit @@ -1,3 +1,5 @@ +package foo:foo + interface a { record foo {} @@ -5,22 +7,22 @@ interface a { } interface b { - use self.a.{foo} + use a.{foo} a: func() -> foo } interface c { - use self.b.{foo} + use b.{foo} a: func() -> foo } -default world d { - import a: self.a - import b: self.b +world d { + import a + import b import d: interface { - use self.c.{foo} + use c.{foo} b: func() -> foo } diff --git a/crates/component-macro/tests/codegen/variants.wit b/crates/component-macro/tests/codegen/variants.wit index 590675dcf6c0..b6c47d89650e 100644 --- a/crates/component-macro/tests/codegen/variants.wit +++ b/crates/component-macro/tests/codegen/variants.wit @@ -1,3 +1,5 @@ +package foo:foo + interface variants { enum e1 { a, @@ -139,7 +141,7 @@ interface variants { return-named-result: func() -> (a: result) } -default world my-world { - import imports: self.variants - export exports: self.variants +world my-world { + import variants + export variants } diff --git a/crates/component-macro/tests/codegen/worlds-with-types.wit b/crates/component-macro/tests/codegen/worlds-with-types.wit index 25db9036da12..dc4cbddcbabe 100644 --- a/crates/component-macro/tests/codegen/worlds-with-types.wit +++ b/crates/component-macro/tests/codegen/worlds-with-types.wit @@ -1,9 +1,11 @@ +package foo:foo + interface i { type t = u16 } -default world foo { - use self.i.{t as u} +world foo { + use i.{t as u} type t = u32 diff --git a/crates/environ/src/component/translate.rs b/crates/environ/src/component/translate.rs index 5b91622703a1..8ac64ad31286 100644 --- a/crates/environ/src/component/translate.rs +++ b/crates/environ/src/component/translate.rs @@ -7,7 +7,7 @@ use anyhow::{bail, Result}; use indexmap::IndexMap; use std::collections::HashMap; use std::mem; -use wasmparser::{Chunk, Encoding, Parser, Payload, Validator}; +use wasmparser::{Chunk, ComponentImportName, Encoding, Parser, Payload, Validator}; mod adapt; pub use self::adapt::*; @@ -163,7 +163,7 @@ struct Translation<'data> { #[allow(missing_docs)] enum LocalInitializer<'data> { // imports - Import(&'data str, TypeDef), + Import(ComponentImportName<'data>, TypeDef), // canonical function sections Lower(ComponentFuncIndex, LocalCanonicalOptions), @@ -623,7 +623,7 @@ impl<'a, 'data> Translator<'a, 'data> { for export in s { let export = export?; let item = self.kind_to_item(export.kind, export.index); - let prev = self.result.exports.insert(export.name, item); + let prev = self.result.exports.insert(export.name.as_str(), item); assert!(prev.is_none()); self.result .initializers @@ -832,9 +832,9 @@ impl<'a, 'data> Translator<'a, 'data> { ComponentItem::Type(ty) => Some(ComponentItemType::Type(ty)), ComponentItem::Module(_) => None, }; - map.insert(export.name, idx); + map.insert(export.name.as_str(), idx); if let Some(ty) = ty { - types.insert(export.name, ty); + types.insert(export.name.as_str(), ty); } } @@ -901,15 +901,15 @@ impl<'a, 'data> Translator<'a, 'data> { // An imported component instance is being aliased, so the type of // the aliased item is directly available from the instance type. ComponentInstanceType::Index(ty) => { - let (_url, ty) = &self.types[ty].exports[name]; - self.push_typedef(*ty); + let ty = self.types[ty].exports[name]; + self.push_typedef(ty); } // An imported component was instantiated so the type of the aliased // export is available through the type of the export on the // original component. ComponentInstanceType::InstantiatedIndex(ty) => { - let (_, ty) = self.types[ty].exports[name]; + let ty = self.types[ty].exports[name]; self.push_typedef(ty); } diff --git a/crates/environ/src/component/translate/inline.rs b/crates/environ/src/component/translate/inline.rs index 95aa449c1e9b..62a7d007a318 100644 --- a/crates/environ/src/component/translate/inline.rs +++ b/crates/environ/src/component/translate/inline.rs @@ -82,9 +82,12 @@ pub(super) fn run( LocalInitializer::Import(name, ty) => (name, ty), _ => continue, }; - let index = inliner.result.import_types.push((name.to_string(), ty)); + let index = inliner + .result + .import_types + .push((name.as_str().to_string(), ty)); let path = ImportPath::root(index); - args.insert(name, ComponentItemDef::from_import(path, ty)?); + args.insert(name.as_str(), ComponentItemDef::from_import(path, ty)?); } // This will run the inliner to completion after being seeded with the @@ -376,7 +379,7 @@ impl<'a> Inliner<'a> { // but for sub-components this will do resolution to connect what // was provided as an import at the instantiation-site to what was // needed during the component's instantiation. - Import(name, _ty) => match &frame.args[name] { + Import(name, _ty) => match &frame.args[name.as_str()] { ComponentItemDef::Module(i) => { frame.modules.push(i.clone()); } @@ -674,7 +677,7 @@ impl<'a> Inliner<'a> { ComponentInstanceDef::Import(path, ty) => { let mut path = path.clone(); path.path.push(name); - match self.types[*ty].exports[*name].1 { + match self.types[*ty].exports[*name] { TypeDef::ComponentFunc(_) => { frame.component_funcs.push(ComponentFuncDef::Import(path)); } @@ -939,7 +942,7 @@ impl<'a> Inliner<'a> { // Note that for now this would only work with // module-exporting instances. ComponentInstanceDef::Import(path, ty) => { - for (name, (_url, ty)) in self.types[ty].exports.iter() { + for (name, ty) in self.types[ty].exports.iter() { let mut path = path.clone(); path.path.push(name); let def = ComponentItemDef::from_import(path, *ty)?; diff --git a/crates/environ/src/component/types.rs b/crates/environ/src/component/types.rs index 7668cdde3e4d..9ddfb75fa442 100644 --- a/crates/environ/src/component/types.rs +++ b/crates/environ/src/component/types.rs @@ -552,17 +552,13 @@ impl ComponentTypesBuilder { ComponentTypeDeclaration::Type(ty) => self.type_declaration_type(ty)?, ComponentTypeDeclaration::CoreType(ty) => self.type_declaration_core_type(ty)?, ComponentTypeDeclaration::Alias(alias) => self.type_declaration_alias(alias)?, - ComponentTypeDeclaration::Export { name, url, ty } => { + ComponentTypeDeclaration::Export { name, ty } => { let ty = self.type_declaration_define(ty); - result - .exports - .insert(name.to_string(), (url.to_string(), ty)); + result.exports.insert(name.as_str().to_string(), ty); } ComponentTypeDeclaration::Import(import) => { let ty = self.type_declaration_define(&import.ty); - result - .imports - .insert(import.name.to_string(), (import.url.to_string(), ty)); + result.imports.insert(import.name.as_str().to_string(), ty); } } } @@ -584,11 +580,9 @@ impl ComponentTypesBuilder { InstanceTypeDeclaration::Type(ty) => self.type_declaration_type(ty)?, InstanceTypeDeclaration::CoreType(ty) => self.type_declaration_core_type(ty)?, InstanceTypeDeclaration::Alias(alias) => self.type_declaration_alias(alias)?, - InstanceTypeDeclaration::Export { name, url, ty } => { + InstanceTypeDeclaration::Export { name, ty } => { let ty = self.type_declaration_define(ty); - result - .exports - .insert(name.to_string(), (url.to_string(), ty)); + result.exports.insert(name.as_str().to_string(), ty); } } } @@ -635,7 +629,7 @@ impl ComponentTypesBuilder { } => { let ty = self.type_scopes.last().unwrap().instances [ComponentInstanceIndex::from_u32(*instance_index)]; - let (_, ty) = self.component_types[ty].exports[*name]; + let ty = self.component_types[ty].exports[*name]; self.push_component_typedef(ty); } a => unreachable!("invalid alias {a:?}"), @@ -1018,9 +1012,9 @@ pub struct TypeModule { #[derive(Serialize, Deserialize, Default)] pub struct TypeComponent { /// The named values that this component imports. - pub imports: IndexMap, + pub imports: IndexMap, /// The named values that this component exports. - pub exports: IndexMap, + pub exports: IndexMap, } /// The type of a component instance in the component model, or an instantiated @@ -1030,7 +1024,7 @@ pub struct TypeComponent { #[derive(Serialize, Deserialize, Default)] pub struct TypeComponentInstance { /// The list of exports that this component has along with their types. - pub exports: IndexMap, + pub exports: IndexMap, } /// A component function type in the component model. diff --git a/crates/test-programs/Cargo.toml b/crates/test-programs/Cargo.toml index a45cb7587944..703dfe2fda2e 100644 --- a/crates/test-programs/Cargo.toml +++ b/crates/test-programs/Cargo.toml @@ -11,6 +11,9 @@ license = "Apache-2.0 WITH LLVM-exception" cfg-if = "1.0" cargo_metadata = "0.15.3" +[dependencies] +wasmtime-wasi-http = { workspace = true, optional = true } + [dev-dependencies] wasi-common = { workspace = true } wasi-cap-std-sync = { workspace = true } @@ -24,7 +27,6 @@ anyhow = { workspace = true } wat = { workspace = true } cap-std = { workspace = true } tokio = { version = "1.8.0", features = ["net", "rt-multi-thread"] } -wasmtime-wasi-http = { workspace = true } hyper = { version = "1.0.0-rc.3", features = ["full"] } http = { version = "0.2.9" } http-body = "1.0.0-rc.2" @@ -32,4 +34,4 @@ http-body-util = "0.1.0-rc.2" [features] test_programs = [] -test_programs_http = [ "wasmtime/component-model" ] +test_programs_http = [ "wasmtime/component-model", "dep:wasmtime-wasi-http" ] diff --git a/crates/wasi-http/Cargo.toml b/crates/wasi-http/Cargo.toml index d3d2e0957231..1325a33285cd 100644 --- a/crates/wasi-http/Cargo.toml +++ b/crates/wasi-http/Cargo.toml @@ -8,6 +8,10 @@ license = "Apache-2.0 WITH LLVM-exception" description = "Experimental HTTP library for WebAssembly in Wasmtime" readme = "readme.md" +[lib] +test = false +doctest = false + [dependencies] anyhow = { workspace = true } bytes = "1.1.0" diff --git a/crates/wasmtime/src/component/matching.rs b/crates/wasmtime/src/component/matching.rs index 6f2cb5549baa..0f843032b97c 100644 --- a/crates/wasmtime/src/component/matching.rs +++ b/crates/wasmtime/src/component/matching.rs @@ -72,7 +72,7 @@ impl TypeChecker<'_> { // Like modules, every export in the expected type must be present in // the actual type. It's ok, though, to have extra exports in the actual // type. - for (name, (_url, expected)) in expected.exports.iter() { + for (name, expected) in expected.exports.iter() { // Interface types may be exported from a component in order to give them a name, but // they don't have a definition in the sense that this search is interested in, so // ignore them. diff --git a/crates/wasmtime/src/component/mod.rs b/crates/wasmtime/src/component/mod.rs index 671cce9d0bd8..f2066843e44a 100644 --- a/crates/wasmtime/src/component/mod.rs +++ b/crates/wasmtime/src/component/mod.rs @@ -73,7 +73,9 @@ pub(crate) use self::store::ComponentStoreData; /// ```text,ignore /// // wit/my-component.wit /// -/// default world hello-world { +/// package my:project +/// +/// world hello-world { /// import name: func() -> string /// export greet: func() /// } @@ -150,13 +152,15 @@ pub(crate) use self::store::ComponentStoreData; /// ```text,ignore /// // wit/my-component.wit /// +/// package my:project +/// /// interface host { /// gen-random-integer: func() -> u32 /// sha256: func(bytes: list) -> string /// } /// /// default world hello-world { -/// import host: self.host +/// import host /// /// export demo: interface { /// run: func() @@ -169,6 +173,7 @@ pub(crate) use self::store::ComponentStoreData; /// ```rust,ignore /// use wasmtime::component::*; /// use wasmtime::{Config, Engine, Store}; +/// use my::project::host::Host; /// /// bindgen!(); /// @@ -177,7 +182,7 @@ pub(crate) use self::store::ComponentStoreData; /// } /// /// // Note that the trait here is per-interface and within a submodule now. -/// impl host::Host for MyState { +/// impl Host for MyState { /// fn gen_random_integer(&mut self) -> wasmtime::Result { /// Ok(rand::thread_rng().gen()) /// } @@ -228,18 +233,12 @@ pub(crate) use self::store::ComponentStoreData; /// bindgen!(); /// /// // Parse the `wit/` folder adjacent to this crate's `Cargo.toml` and look -/// // for the document `foo`, which must have a `default world` contained -/// // within it. +/// // for the world `foo` contained in it. /// bindgen!("foo"); /// -/// // Parse the `wit/` folder adjacent to `Cargo.toml` and look up the document -/// // `foo` and the world named `bar`. -/// bindgen!("foo.bar"); -/// /// // Parse the folder `other/wit/folder` adjacent to `Cargo.toml`. /// bindgen!(in "other/wit/folder"); /// bindgen!("foo" in "other/wit/folder"); -/// bindgen!("foo.bar" in "other/wit/folder"); /// /// // Parse the file `foo.wit` as a single-file WIT package with no /// // dependencies. @@ -250,8 +249,7 @@ pub(crate) use self::store::ComponentStoreData; /// /// ```rust,ignore /// bindgen!({ -/// world: "foo", // or "foo.bar", same as in `bindgen!("foo")` -/// // not needed if `path` has one `default world` +/// world: "foo", // not needed if `path` has one `world` /// /// // same as in `bindgen!(in "other/wit/folder") /// path: "other/wit/folder", @@ -259,7 +257,9 @@ pub(crate) use self::store::ComponentStoreData; /// // Instead of `path` the WIT document can be provided inline if /// // desired. /// inline: " -/// default world foo { +/// package my:inline +/// +/// world foo { /// // ... /// } /// ", @@ -295,7 +295,7 @@ pub(crate) use self::store::ComponentStoreData; /// // Restrict the code generated to what's needed for the interface /// // imports in the inlined WIT document fragment. /// interfaces: " -/// import foo: package.foo; +/// import package.foo /// ", /// /// // Remap interface names to module names, imported from elsewhere. diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs index a935912aab86..41868b64ce5c 100644 --- a/crates/wit-bindgen/src/lib.rs +++ b/crates/wit-bindgen/src/lib.rs @@ -31,28 +31,35 @@ struct InterfaceName { remapped: bool, /// The string name for this interface. - name: String, + path: String, } #[derive(Default)] struct Wasmtime { src: Source, opts: Opts, - imports: Vec, + import_interfaces: BTreeMap, Vec>, + import_functions: Vec, exports: Exports, types: Types, sizes: SizeAlign, interface_names: HashMap, + with_name_counter: usize, } -enum Import { - Interface { snake: String }, - Function { add_to_linker: String, sig: String }, +struct ImportInterface { + snake: String, + module: String, +} +struct ImportFunction { + add_to_linker: String, + sig: String, } #[derive(Default)] struct Exports { fields: BTreeMap, + modules: BTreeMap, Vec>, funcs: Vec, } @@ -111,16 +118,33 @@ impl Opts { } impl Wasmtime { - fn name_interface(&mut self, id: InterfaceId, name: String) -> bool { - let entry = if let Some(remapped_name) = self.opts.with.get(&name) { + fn name_interface(&mut self, resolve: &Resolve, id: InterfaceId, name: &WorldKey) -> bool { + let with_name = resolve.name_world_key(name); + let entry = if let Some(remapped_path) = self.opts.with.get(&with_name) { + let name = format!("__with_name{}", self.with_name_counter); + self.with_name_counter += 1; + uwriteln!(self.src, "use {remapped_path} as {name};"); InterfaceName { remapped: true, - name: remapped_name.clone(), + path: name, } } else { + let path = match name { + WorldKey::Name(name) => name.to_snake_case(), + WorldKey::Interface(_) => { + let iface = &resolve.interfaces[id]; + let pkgname = &resolve.packages[iface.package.unwrap()].name; + format!( + "{}::{}::{}", + pkgname.namespace.to_snake_case(), + pkgname.name.to_snake_case(), + iface.name.as_ref().unwrap().to_snake_case() + ) + } + }; InterfaceName { remapped: false, - name, + path, } }; @@ -146,30 +170,38 @@ impl Wasmtime { self.finish(resolve, id) } - fn import(&mut self, resolve: &Resolve, name: &str, item: &WorldItem) { - let snake = name.to_snake_case(); + fn import(&mut self, resolve: &Resolve, name: &WorldKey, item: &WorldItem) { let mut gen = InterfaceGenerator::new(self, resolve); - let import = match item { + match item { WorldItem::Function(func) => { gen.generate_function_trait_sig(TypeOwner::None, func); let sig = mem::take(&mut gen.src).into(); gen.generate_add_function_to_linker(TypeOwner::None, func, "linker"); let add_to_linker = gen.src.into(); - Import::Function { sig, add_to_linker } + self.import_functions + .push(ImportFunction { sig, add_to_linker }); } WorldItem::Interface(id) => { - if gen.gen.name_interface(*id, snake.clone()) { + if gen.gen.name_interface(resolve, *id, name) { return; } - gen.current_interface = Some(*id); + gen.current_interface = Some((*id, name, false)); gen.types(*id); gen.generate_trappable_error_types(TypeOwner::Interface(*id)); - gen.generate_add_to_linker(*id, name); + let key_name = resolve.name_world_key(name); + gen.generate_add_to_linker(*id, &key_name); let module = &gen.src[..]; - uwriteln!( - self.src, + let snake = match name { + WorldKey::Name(s) => s.to_snake_case(), + WorldKey::Interface(id) => resolve.interfaces[*id] + .name + .as_ref() + .unwrap() + .to_snake_case(), + }; + let module = format!( " #[allow(clippy::all)] pub mod {snake} {{ @@ -180,40 +212,55 @@ impl Wasmtime { }} " ); - Import::Interface { snake } + let pkg = resolve.interfaces[*id].package.unwrap(); + let pkgname = match name { + WorldKey::Name(_) => None, + WorldKey::Interface(_) => Some(resolve.packages[pkg].name.clone()), + }; + self.import_interfaces + .entry(pkgname) + .or_insert(Vec::new()) + .push(ImportInterface { snake, module }); } WorldItem::Type(ty) => { + let name = match name { + WorldKey::Name(name) => name, + WorldKey::Interface(_) => unreachable!(), + }; gen.define_type(name, *ty); let body = mem::take(&mut gen.src); self.src.push_str(&body); - return; } }; - - self.imports.push(import); } - fn export(&mut self, resolve: &Resolve, name: &str, item: &WorldItem) { - let snake = name.to_snake_case(); + fn export(&mut self, resolve: &Resolve, name: &WorldKey, item: &WorldItem) { let mut gen = InterfaceGenerator::new(self, resolve); - let (ty, getter) = match item { + let (field, ty, getter) = match item { WorldItem::Function(func) => { - gen.define_rust_guest_export(None, func); + gen.define_rust_guest_export(resolve, None, func); let body = mem::take(&mut gen.src).into(); let (_name, getter) = gen.extract_typed_function(func); assert!(gen.src.is_empty()); self.exports.funcs.push(body); - ("wasmtime::component::Func".to_string(), getter) + ( + func.name.to_snake_case(), + "wasmtime::component::Func".to_string(), + getter, + ) } WorldItem::Type(_) => unreachable!(), WorldItem::Interface(id) => { - gen.gen.name_interface(*id, snake.clone()); - gen.current_interface = Some(*id); + gen.gen.name_interface(resolve, *id, name); + gen.current_interface = Some((*id, name, true)); gen.types(*id); gen.generate_trappable_error_types(TypeOwner::Interface(*id)); let iface = &resolve.interfaces[*id]; - - let camel = to_rust_upper_camel_case(name); + let iface_name = match name { + WorldKey::Name(name) => name, + WorldKey::Interface(_) => iface.name.as_ref().unwrap(), + }; + let camel = to_rust_upper_camel_case(iface_name); uwriteln!(gen.src, "pub struct {camel} {{"); for (_, func) in iface.functions.iter() { uwriteln!( @@ -246,14 +293,14 @@ impl Wasmtime { uwriteln!(gen.src, "}})"); uwriteln!(gen.src, "}}"); for (_, func) in iface.functions.iter() { - gen.define_rust_guest_export(Some(name), func); + gen.define_rust_guest_export(resolve, Some(name), func); } uwriteln!(gen.src, "}}"); let module = &gen.src[..]; + let snake = iface_name.to_snake_case(); - uwriteln!( - self.src, + let module = format!( " #[allow(clippy::all)] pub mod {snake} {{ @@ -264,26 +311,54 @@ impl Wasmtime { }} " ); - + let pkgname = match name { + WorldKey::Name(_) => None, + WorldKey::Interface(_) => { + Some(resolve.packages[iface.package.unwrap()].name.clone()) + } + }; + self.exports + .modules + .entry(pkgname.clone()) + .or_insert(Vec::new()) + .push(module); + + let name = resolve.name_world_key(name); + let (path, method_name) = match pkgname { + Some(pkgname) => ( + format!( + "exports::{}::{}::{snake}::{camel}", + pkgname.namespace.to_snake_case(), + pkgname.name.to_snake_case(), + ), + format!( + "{}_{}_{snake}", + pkgname.namespace.to_snake_case(), + pkgname.name.to_snake_case() + ), + ), + None => (format!("exports::{snake}::{camel}"), snake.clone()), + }; let getter = format!( "\ - {snake}::{camel}::new( + {path}::new( &mut __exports.instance(\"{name}\") .ok_or_else(|| anyhow::anyhow!(\"exported instance `{name}` not present\"))? )?\ " ); + let field = format!("interface{}", self.exports.fields.len()); self.exports.funcs.push(format!( " - pub fn {snake}(&self) -> &{snake}::{camel} {{ - &self.{snake} + pub fn {method_name}(&self) -> &{path} {{ + &self.{field} }} - " + ", )); - (format!("{snake}::{camel}"), getter) + (field, path, getter) } }; - let prev = self.exports.fields.insert(snake.clone(), (ty, getter)); + let prev = self.exports.fields.insert(field, (ty, getter)); assert!(prev.is_none()); } @@ -375,6 +450,47 @@ impl Wasmtime { self.build_struct(resolve, world) } + for (pkg, imports) in self.import_interfaces.iter() { + match pkg { + Some(pkg) => { + uwriteln!(self.src, "pub mod {} {{", pkg.namespace.to_snake_case()); + uwriteln!(self.src, "pub mod {} {{", pkg.name.to_snake_case()); + for import in imports { + uwriteln!(self.src, "{}", import.module); + } + uwriteln!(self.src, "}}"); + uwriteln!(self.src, "}}"); + } + None => { + for import in imports { + uwriteln!(self.src, "{}", import.module); + } + } + } + } + if !self.exports.modules.is_empty() { + uwriteln!(self.src, "pub mod exports {{"); + for (pkg, modules) in self.exports.modules.iter() { + match pkg { + Some(pkg) => { + uwriteln!(self.src, "pub mod {} {{", pkg.namespace.to_snake_case()); + uwriteln!(self.src, "pub mod {} {{", pkg.name.to_snake_case()); + for module in modules { + uwriteln!(self.src, "{}", module); + } + uwriteln!(self.src, "}}"); + uwriteln!(self.src, "}}"); + } + None => { + for module in modules { + uwriteln!(self.src, "{}", module); + } + } + } + } + uwriteln!(self.src, "}}"); + } + let mut src = mem::take(&mut self.src); if self.opts.rustfmt { let mut child = Command::new("rustfmt") @@ -406,17 +522,7 @@ impl Wasmtime { impl Wasmtime { fn toplevel_import_trait(&mut self, resolve: &Resolve, world: WorldId) { - let mut functions = Vec::new(); - for import in self.imports.iter() { - match import { - Import::Interface { .. } => continue, - Import::Function { - sig, - add_to_linker: _, - } => functions.push(sig), - } - } - if functions.is_empty() { + if self.import_functions.is_empty() { return; } @@ -425,26 +531,29 @@ impl Wasmtime { uwriteln!(self.src, "#[wasmtime::component::__internal::async_trait]") } uwriteln!(self.src, "pub trait {world_camel}Imports {{"); - for sig in functions { - self.src.push_str(sig); + for f in self.import_functions.iter() { + self.src.push_str(&f.sig); self.src.push_str("\n"); } uwriteln!(self.src, "}}"); } fn toplevel_add_to_linker(&mut self, resolve: &Resolve, world: WorldId) { - if self.imports.is_empty() { + if self.import_interfaces.is_empty() && self.import_functions.is_empty() { return; } - let mut functions = Vec::new(); let mut interfaces = Vec::new(); - for import in self.imports.iter() { - match import { - Import::Interface { snake } => interfaces.push(snake), - Import::Function { - add_to_linker, - sig: _, - } => functions.push(add_to_linker), + for (pkg, imports) in self.import_interfaces.iter() { + for import in imports { + let mut path = String::new(); + if let Some(pkg) = pkg { + path.push_str(&pkg.namespace.to_snake_case()); + path.push_str("::"); + path.push_str(&pkg.name.to_snake_case()); + path.push_str("::"); + } + path.push_str(&import.snake); + interfaces.push(path) } } @@ -463,7 +572,7 @@ impl Wasmtime { for (i, name) in interfaces .iter() .map(|n| format!("{n}::Host")) - .chain(if functions.is_empty() { + .chain(if self.import_functions.is_empty() { None } else { Some(world_trait.clone()) @@ -485,11 +594,11 @@ impl Wasmtime { for name in interfaces.iter() { uwriteln!(self.src, "{name}::add_to_linker(linker, get)?;"); } - if !functions.is_empty() { + if !self.import_functions.is_empty() { uwriteln!(self.src, "Self::add_root_to_linker(linker, get)?;"); } uwriteln!(self.src, "Ok(())\n}}"); - if functions.is_empty() { + if self.import_functions.is_empty() { return; } @@ -505,8 +614,8 @@ impl Wasmtime { let mut linker = linker.root(); ", ); - for add_to_linker in functions { - self.src.push_str(add_to_linker); + for f in self.import_functions.iter() { + self.src.push_str(&f.add_to_linker); self.src.push_str("\n"); } uwriteln!(self.src, "Ok(())\n}}"); @@ -517,7 +626,7 @@ struct InterfaceGenerator<'a> { src: Source, gen: &'a mut Wasmtime, resolve: &'a Resolve, - current_interface: Option, + current_interface: Option<(InterfaceId, &'a WorldKey, bool)>, } impl<'a> InterfaceGenerator<'a> { @@ -1263,7 +1372,12 @@ impl<'a> InterfaceGenerator<'a> { ret } - fn define_rust_guest_export(&mut self, ns: Option<&str>, func: &Function) { + fn define_rust_guest_export( + &mut self, + resolve: &Resolve, + ns: Option<&WorldKey>, + func: &Function, + ) { let (async_, async__, await_) = if self.gen.opts.async_ { ("async", "_async", ".await") } else { @@ -1292,17 +1406,20 @@ impl<'a> InterfaceGenerator<'a> { } if self.gen.opts.tracing { + let ns = match ns { + Some(key) => resolve.name_world_key(key), + None => "default".to_string(), + }; self.src.push_str(&format!( " let span = tracing::span!( tracing::Level::TRACE, \"wit-bindgen export\", - module = \"{}\", + module = \"{ns}\", function = \"{}\", ); let _enter = span.enter(); ", - ns.unwrap_or("default"), func.name, )); } @@ -1466,17 +1583,26 @@ impl<'a> RustGenerator<'a> for InterfaceGenerator<'a> { } fn path_to_interface(&self, interface: InterfaceId) -> Option { - match self.current_interface { - Some(id) if id == interface => None, - _ => { - let InterfaceName { remapped, name } = &self.gen.interface_names[&interface]; - Some(if self.current_interface.is_some() && !remapped { - format!("super::{name}") - } else { - name.clone() - }) + let mut path_to_root = String::new(); + if let Some((cur, key, is_export)) = self.current_interface { + if cur == interface { + return None; + } + match key { + WorldKey::Name(_) => { + path_to_root.push_str("super::"); + } + WorldKey::Interface(_) => { + path_to_root.push_str("super::super::super::"); + } + } + if is_export { + path_to_root.push_str("super::"); } } + let InterfaceName { path, .. } = &self.gen.interface_names[&interface]; + path_to_root.push_str(path); + Some(path_to_root) } fn push_str(&mut self, s: &str) { diff --git a/src/commands/run.rs b/src/commands/run.rs index 95c5fc43ef0b..ea127c743a73 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -844,6 +844,7 @@ fn generate_coredump(err: &anyhow::Error, source_name: &str, coredump_path: &str instanceidx, f.func_index(), u32::try_from(f.func_offset().unwrap_or(0)).unwrap(), + 0, // TODO: this is probably wrong // We don't currently have access to locals/stack values [], [], diff --git a/tests/all/component_model/bindgen.rs b/tests/all/component_model/bindgen.rs index d8c8f3023cd4..c377f08a6579 100644 --- a/tests/all/component_model/bindgen.rs +++ b/tests/all/component_model/bindgen.rs @@ -14,7 +14,9 @@ mod no_imports { wasmtime::component::bindgen!({ inline: " - default world no-imports { + package foo:foo + + world no-imports { export foo: interface { foo: func() } @@ -59,7 +61,9 @@ mod one_import { wasmtime::component::bindgen!({ inline: " - default world one-import { + package foo:foo + + world one-import { import foo: interface { foo: func() } diff --git a/tests/all/component_model/bindgen/results.rs b/tests/all/component_model/bindgen/results.rs index eaec5cc3ac4c..d0c49e40245e 100644 --- a/tests/all/component_model/bindgen/results.rs +++ b/tests/all/component_model/bindgen/results.rs @@ -9,7 +9,8 @@ mod empty_error { use super::*; wasmtime::component::bindgen!({ inline: " - default world result-playground { + package inline:inline + world result-playground { import imports: interface { empty-error: func(a: float64) -> result } @@ -109,7 +110,8 @@ mod string_error { use super::*; wasmtime::component::bindgen!({ inline: " - default world result-playground { + package inline:inline + world result-playground { import imports: interface { string-error: func(a: float64) -> result } @@ -219,14 +221,18 @@ mod string_error { mod enum_error { use super::*; + use exports::foo; + use inline::inline::imports; + wasmtime::component::bindgen!({ inline: " + package inline:inline interface imports { enum e1 { a, b, c } enum-error: func(a: float64) -> result } - default world result-playground { - import imports: self.imports + world result-playground { + import imports export foo: interface { enum e1 { a, b, c } enum-error: func(a: float64) -> result @@ -244,7 +250,7 @@ mod enum_error { r#" (component (type $err' (enum "a" "b" "c")) - (import "imports" (instance $i + (import (interface "inline:inline/imports") (instance $i (export $err "err" (type (eq $err'))) (export "enum-error" (func (param "a" float64) (result (result float64 (error $err))))) )) @@ -357,7 +363,7 @@ mod enum_error { .expect("no trap") .err() .expect("error returned"); - assert_eq!(e, enum_error::foo::E1::A); + assert_eq!(e, foo::E1::A); let e = results .foo() @@ -377,14 +383,18 @@ mod enum_error { mod record_error { use super::*; + use exports::foo; + use inline::inline::imports; + wasmtime::component::bindgen!({ inline: " + package inline:inline interface imports { record e2 { line: u32, col: u32 } record-error: func(a: float64) -> result } - default world result-playground { - import imports: self.imports + world result-playground { + import imports export foo: interface { record e2 { line: u32, col: u32 } record-error: func(a: float64) -> result @@ -407,7 +417,7 @@ mod record_error { (field "line" u32) (field "col" u32) )) - (import "imports" (instance $i + (import (interface "inline:inline/imports") (instance $i (export $e2 "e2" (type (eq $e2'))) (type $result (result float64 (error $e2))) (export "record-error" (func (param "a" float64) (result $result))) @@ -525,16 +535,20 @@ mod record_error { mod variant_error { use super::*; + use exports::foo; + use inline::inline::imports; + wasmtime::component::bindgen!({ inline: " + package inline:inline interface imports { enum e1 { a, b, c } record e2 { line: u32, col: u32 } variant e3 { E1(e1), E2(e2) } variant-error: func(a: float64) -> result } - default world result-playground { - import imports: self.imports + world result-playground { + import imports export foo: interface { enum e1 { a, b, c } record e2 { line: u32, col: u32 } @@ -559,7 +573,7 @@ mod variant_error { (case "E1" $e1') (case "E2" $e2') )) - (import "imports" (instance $i + (import (interface "inline:inline/imports") (instance $i (export $e1 "e1" (type (eq $e1'))) (export $e2 "e2" (type (eq $e2'))) (type $e3' (variant @@ -710,7 +724,8 @@ mod with_remapping { wasmtime::component::bindgen!({ inline: " - default world result-playground { + package inline:inline + world result-playground { import imports: interface { empty-error: func(a: float64) -> result }