From 27576a18f616df27fceb11b356f6ffdbea95d202 Mon Sep 17 00:00:00 2001 From: Daniel Macovei Date: Wed, 26 Jun 2024 14:27:55 -0500 Subject: [PATCH] explicit packages encoded as nested components --- crates/wasm-encoder/src/component/builder.rs | 4 + crates/wasm-encoder/src/component/names.rs | 3 + crates/wit-component/src/encoding/wit/mod.rs | 2 +- crates/wit-component/src/encoding/wit/v1.rs | 124 +++--- crates/wit-component/src/encoding/wit/v2.rs | 98 +++-- crates/wit-component/src/metadata.rs | 3 +- crates/wit-component/src/printing.rs | 2 - crates/wit-component/tests/interfaces.rs | 49 ++- .../tests/interfaces/multiple-packages.wat | 62 +++ .../tests/interfaces/multiple-packages.wit | 26 ++ .../interfaces/multiple-packages.wit.print | 28 ++ crates/wit-parser/src/ast.rs | 7 +- crates/wit-parser/src/ast/resolve.rs | 39 +- crates/wit-parser/src/decoding.rs | 398 +++++++++++++----- crates/wit-parser/src/lib.rs | 5 +- crates/wit-parser/src/metadata.rs | 5 + crates/wit-parser/src/resolve.rs | 12 +- crates/wit-parser/tests/ui/comments.wit.json | 1 + .../tests/ui/complex-include.wit.json | 3 + .../tests/ui/cross-package-resource.wit.json | 2 + crates/wit-parser/tests/ui/diamond1.wit.json | 3 + .../tests/ui/disambiguate-diamond.wit.json | 1 + crates/wit-parser/tests/ui/empty.wit.json | 1 + .../tests/ui/feature-gates.wit.json | 1 + .../tests/ui/foreign-deps-union.wit.json | 7 + .../wit-parser/tests/ui/foreign-deps.wit.json | 7 + crates/wit-parser/tests/ui/functions.wit.json | 1 + .../tests/ui/ignore-files-deps.wit.json | 2 + .../tests/ui/import-export-overlap1.wit.json | 1 + .../tests/ui/import-export-overlap2.wit.json | 1 + .../wit-parser/tests/ui/include-reps.wit.json | 1 + .../tests/ui/kebab-name-include-with.wit.json | 1 + .../tests/ui/kinds-of-deps.wit.json | 5 + .../wit-parser/tests/ui/many-names.wit.json | 1 + .../ui/multi-file-multi-package.wit.json | 4 + .../wit-parser/tests/ui/multi-file.wit.json | 1 + .../ui/multi-package-shared-deps.wit.json | 4 + .../ui/multi-package-transitive-deps.wit.json | 4 + .../ui/name-both-resource-and-type.wit.json | 2 + .../tests/ui/package-syntax1.wit.json | 1 + .../tests/ui/package-syntax3.wit.json | 1 + .../tests/ui/package-syntax4.wit.json | 1 + ...ges-explicit-colliding-decl-names.wit.json | 2 + ...ages-explicit-internal-references.wit.json | 2 + .../ui/packages-explicit-with-semver.wit.json | 2 + .../ui/packages-multiple-explicit.wit.json | 2 + .../ui/packages-single-explicit.wit.json | 1 + crates/wit-parser/tests/ui/random.wit.json | 1 + .../tests/ui/resources-empty.wit.json | 1 + .../resources-multiple-returns-own.wit.json | 1 + .../tests/ui/resources-multiple.wit.json | 1 + .../tests/ui/resources-return-own.wit.json | 1 + crates/wit-parser/tests/ui/resources.wit.json | 1 + .../wit-parser/tests/ui/resources1.wit.json | 1 + .../tests/ui/same-name-import-export.wit.json | 1 + .../wit-parser/tests/ui/shared-types.wit.json | 1 + .../tests/ui/simple-wasm-text.wit.json | 1 + .../tests/ui/since-and-unstable.wit.json | 1 + .../tests/ui/stress-export-elaborate.wit.json | 1 + .../tests/ui/type-then-eof.wit.json | 1 + crates/wit-parser/tests/ui/types.wit.json | 1 + .../wit-parser/tests/ui/union-fuzz-1.wit.json | 1 + .../wit-parser/tests/ui/union-fuzz-2.wit.json | 1 + crates/wit-parser/tests/ui/use-chain.wit.json | 1 + crates/wit-parser/tests/ui/use.wit.json | 1 + crates/wit-parser/tests/ui/versions.wit.json | 3 + crates/wit-parser/tests/ui/wasi.wit.json | 1 + .../tests/ui/world-diamond.wit.json | 1 + .../tests/ui/world-iface-no-collide.wit.json | 1 + .../tests/ui/world-implicit-import1.wit.json | 1 + .../tests/ui/world-implicit-import2.wit.json | 1 + .../tests/ui/world-implicit-import3.wit.json | 1 + .../tests/ui/world-same-fields4.wit.json | 1 + .../tests/ui/world-top-level-funcs.wit.json | 1 + .../ui/world-top-level-resources.wit.json | 1 + .../tests/ui/worlds-union-dedup.wit.json | 1 + .../tests/ui/worlds-with-types.wit.json | 1 + .../wit-stability-in-binary-format.wit.stdout | 14 - 78 files changed, 722 insertions(+), 257 deletions(-) create mode 100644 crates/wit-component/tests/interfaces/multiple-packages.wat create mode 100644 crates/wit-component/tests/interfaces/multiple-packages.wit create mode 100644 crates/wit-component/tests/interfaces/multiple-packages.wit.print diff --git a/crates/wasm-encoder/src/component/builder.rs b/crates/wasm-encoder/src/component/builder.rs index 27c39ac8a0..58cfa28c6a 100644 --- a/crates/wasm-encoder/src/component/builder.rs +++ b/crates/wasm-encoder/src/component/builder.rs @@ -41,6 +41,10 @@ pub struct ComponentBuilder { } impl ComponentBuilder { + /// Adds sub component names + pub fn names(&mut self, names: &ComponentNameSection) { + self.component.section(names); + } /// Returns the current number of core modules. pub fn core_module_count(&self) -> u32 { self.core_modules diff --git a/crates/wasm-encoder/src/component/names.rs b/crates/wasm-encoder/src/component/names.rs index 1cbb1062c6..0939984440 100644 --- a/crates/wasm-encoder/src/component/names.rs +++ b/crates/wasm-encoder/src/component/names.rs @@ -16,6 +16,9 @@ enum Subsection { } impl ComponentNameSection { + /// Human readable component names + pub const SECTION_NAME: &'static str = "component-name"; + /// Creates a new blank `name` custom section. pub fn new() -> Self { Self::default() diff --git a/crates/wit-component/src/encoding/wit/mod.rs b/crates/wit-component/src/encoding/wit/mod.rs index d78706e64d..71c2b4f54c 100644 --- a/crates/wit-component/src/encoding/wit/mod.rs +++ b/crates/wit-component/src/encoding/wit/mod.rs @@ -48,7 +48,7 @@ pub fn encode_component( if use_v2.unwrap_or_else(use_v2_encoding) { v2::encode_component(resolve, packages) } else { - v1::encode_component(resolve, packages) + v1::encode_component(resolve, packages[0]) } } diff --git a/crates/wit-component/src/encoding/wit/v1.rs b/crates/wit-component/src/encoding/wit/v1.rs index b2dfb009fe..ed6c39a35f 100644 --- a/crates/wit-component/src/encoding/wit/v1.rs +++ b/crates/wit-component/src/encoding/wit/v1.rs @@ -24,21 +24,19 @@ use wit_parser::*; /// /// The binary returned can be [`decode`d](crate::decode) to recover the WIT /// package provided. -pub fn encode_component(resolve: &Resolve, packages: &[PackageId]) -> Result { +pub fn encode_component(resolve: &Resolve, package: PackageId) -> Result { let mut encoder = Encoder { component: ComponentBuilder::default(), resolve, - packages, + package, }; encoder.run()?; - for package in packages { - let package_metadata = PackageMetadata::extract(resolve, *package); - encoder.component.custom_section(&CustomSection { - name: PackageMetadata::SECTION_NAME.into(), - data: package_metadata.encode()?.into(), - }); - } + let package_metadata = PackageMetadata::extract(resolve, package); + encoder.component.custom_section(&CustomSection { + name: PackageMetadata::SECTION_NAME.into(), + data: package_metadata.encode()?.into(), + }); Ok(encoder.component) } @@ -46,7 +44,7 @@ pub fn encode_component(resolve: &Resolve, packages: &[PackageId]) -> Result { component: ComponentBuilder, resolve: &'a Resolve, - packages: &'a [PackageId], + package: PackageId, } impl Encoder<'_> { @@ -59,69 +57,67 @@ impl Encoder<'_> { // decoding process where everyone's view of a foreign document agrees // notably on the order that types are defined in to assist with // roundtripping. - for pkg in self.packages { - let mut interfaces = IndexSet::new(); - for (_, id) in self.resolve.packages[*pkg].interfaces.iter() { - self.add_live_interfaces(&mut interfaces, *id); - } + let mut interfaces = IndexSet::new(); + for (_, id) in self.resolve.packages[self.package].interfaces.iter() { + self.add_live_interfaces(&mut interfaces, *id); + } - // Seed the set of used names with all exported interfaces to ensure - // that imported interfaces choose different names as the import names - // aren't used during decoding. - let mut used_names = IndexSet::new(); - for id in interfaces.iter() { - let iface = &self.resolve.interfaces[*id]; - if iface.package == Some(*pkg) { - let first = used_names.insert(iface.name.as_ref().unwrap().clone()); - assert!(first); - } - } - for (name, _world) in self.resolve.packages[*pkg].worlds.iter() { - let first = used_names.insert(name.clone()); + // Seed the set of used names with all exported interfaces to ensure + // that imported interfaces choose different names as the import names + // aren't used during decoding. + let mut used_names = IndexSet::new(); + for id in interfaces.iter() { + let iface = &self.resolve.interfaces[*id]; + if iface.package == Some(self.package) { + let first = used_names.insert(iface.name.as_ref().unwrap().clone()); assert!(first); } + } + for (name, _world) in self.resolve.packages[self.package].worlds.iter() { + let first = used_names.insert(name.clone()); + assert!(first); + } - // Encode all interfaces, foreign and local, into this component type. - // Local interfaces get their functions defined as well and are - // exported. Foreign interfaces are imported and only have their types - // encoded. - let mut encoder = InterfaceEncoder::new(self.resolve); - for interface in interfaces { - encoder.interface = Some(interface); - let iface = &self.resolve.interfaces[interface]; - let name = self.resolve.id_of(interface).unwrap(); - log::trace!("encoding interface {name}"); - if iface.package == Some(*pkg) { - let idx = encoder.encode_instance(interface)?; - encoder.outer.export(&name, ComponentTypeRef::Instance(idx)); - } else { - encoder.push_instance(); - for (_, id) in iface.types.iter() { - encoder.encode_valtype(self.resolve, &Type::Id(*id))?; - } - let instance = encoder.pop_instance(); - let idx = encoder.outer.type_count(); - encoder.outer.ty().instance(&instance); - encoder.import_map.insert(interface, encoder.instances); - encoder.instances += 1; - encoder.outer.import(&name, ComponentTypeRef::Instance(idx)); + // Encode all interfaces, foreign and local, into this component type. + // Local interfaces get their functions defined as well and are + // exported. Foreign interfaces are imported and only have their types + // encoded. + let mut encoder = InterfaceEncoder::new(self.resolve); + for interface in interfaces { + encoder.interface = Some(interface); + let iface = &self.resolve.interfaces[interface]; + let name = self.resolve.id_of(interface).unwrap(); + log::trace!("encoding interface {name}"); + if iface.package == Some(self.package) { + let idx = encoder.encode_instance(interface)?; + encoder.outer.export(&name, ComponentTypeRef::Instance(idx)); + } else { + encoder.push_instance(); + for (_, id) in iface.types.iter() { + encoder.encode_valtype(self.resolve, &Type::Id(*id))?; } - } - encoder.interface = None; - - for (name, world) in self.resolve.packages[*pkg].worlds.iter() { - let component_ty = encode_world(self.resolve, *world)?; + let instance = encoder.pop_instance(); let idx = encoder.outer.type_count(); - encoder.outer.ty().component(&component_ty); - let id = self.resolve.packages[*pkg].name.interface_id(name); - encoder.outer.export(&id, ComponentTypeRef::Component(idx)); + encoder.outer.ty().instance(&instance); + encoder.import_map.insert(interface, encoder.instances); + encoder.instances += 1; + encoder.outer.import(&name, ComponentTypeRef::Instance(idx)); } + } + encoder.interface = None; - let ty = self.component.type_component(&encoder.outer); - let id = self.resolve.packages[*pkg].name.interface_id("wit"); - self.component - .export(&id, ComponentExportKind::Type, ty, None); + for (name, world) in self.resolve.packages[self.package].worlds.iter() { + let component_ty = encode_world(self.resolve, *world)?; + let idx = encoder.outer.type_count(); + encoder.outer.ty().component(&component_ty); + let id = self.resolve.packages[self.package].name.interface_id(name); + encoder.outer.export(&id, ComponentTypeRef::Component(idx)); } + + let ty = self.component.type_component(&encoder.outer); + let id = self.resolve.packages[self.package].name.interface_id("wit"); + self.component + .export(&id, ComponentExportKind::Type, ty, None); Ok(()) } diff --git a/crates/wit-component/src/encoding/wit/v2.rs b/crates/wit-component/src/encoding/wit/v2.rs index a4de81880b..a9fb022dce 100644 --- a/crates/wit-component/src/encoding/wit/v2.rs +++ b/crates/wit-component/src/encoding/wit/v2.rs @@ -32,14 +32,6 @@ pub fn encode_component(resolve: &Resolve, packages: &[PackageId]) -> Result { // decoding process where everyone's view of a foreign document agrees // notably on the order that types are defined in to assist with // roundtripping. + let mut names = NameMap::new(); for pkg in self.packages { - for (name, &id) in self.resolve.packages[*pkg].interfaces.iter() { - let component_ty = self.encode_interface(id, pkg)?; - let ty = self.component.type_component(&component_ty); - self.component - .export(name.as_ref(), ComponentExportKind::Type, ty, None); - } - - for (name, &world) in self.resolve.packages[*pkg].worlds.iter() { - // Encode the `world` directly as a component, then create a wrapper - // component that exports that component. - let component_ty = super::encode_world(self.resolve, world)?; - - let world = &self.resolve.worlds[world]; - let mut wrapper = ComponentType::new(); - wrapper.ty().component(&component_ty); - let pkg = &self.resolve.packages[world.package.unwrap()]; - wrapper.export(&pkg.name.interface_id(name), ComponentTypeRef::Component(0)); + let package = &self.resolve.packages[*pkg]; + if let PackageKind::Explicit = package.kind { + let mut sub_encoder = Encoder { + component: ComponentBuilder::default(), + resolve: self.resolve, + packages: self.packages, + }; + let package_metadata = PackageMetadata::extract(self.resolve, *pkg); + sub_encoder.component.custom_section(&CustomSection { + name: PackageMetadata::SECTION_NAME.into(), + data: package_metadata.encode()?.into(), + }); + for (name, &id) in self.resolve.packages[*pkg].interfaces.iter() { + let component_ty = sub_encoder.encode_interface(id, pkg)?; + let ty = sub_encoder.component.type_component(&component_ty); + sub_encoder.component.export( + name.as_ref(), + ComponentExportKind::Type, + ty, + None, + ); + } + for (name, &world) in self.resolve.packages[*pkg].worlds.iter() { + // Encode the `world` directly as a component, then create a wrapper + // component that exports that component. + let component_ty = super::encode_world(self.resolve, world)?; - let ty = self.component.type_component(&wrapper); - self.component - .export(name.as_ref(), ComponentExportKind::Type, ty, None); + let world = &sub_encoder.resolve.worlds[world]; + let mut wrapper = ComponentType::new(); + wrapper.ty().component(&component_ty); + let pkg = &sub_encoder.resolve.packages[world.package.unwrap()]; + wrapper.export(&pkg.name.interface_id(name), ComponentTypeRef::Component(0)); + let ty = sub_encoder.component.type_component(&wrapper); + sub_encoder.component.export( + name.as_ref(), + ComponentExportKind::Type, + ty, + None, + ); + } + let sub = self.component.component(sub_encoder.component); + names.append(sub, &package.name.to_string()); + } else { + for (name, &id) in self.resolve.packages[*pkg].interfaces.iter() { + let component_ty = self.encode_interface(id, pkg)?; + let ty = self.component.type_component(&component_ty); + self.component + .export(name.as_ref(), ComponentExportKind::Type, ty, None); + } + for (name, &world) in self.resolve.packages[*pkg].worlds.iter() { + // Encode the `world` directly as a component, then create a wrapper + // component that exports that component. + let component_ty = super::encode_world(self.resolve, world)?; + let world = &self.resolve.worlds[world]; + let mut wrapper = ComponentType::new(); + wrapper.ty().component(&component_ty); + let pkg = &self.resolve.packages[world.package.unwrap()]; + wrapper.export(&pkg.name.interface_id(name), ComponentTypeRef::Component(0)); + let ty = self.component.type_component(&wrapper); + self.component + .export(name.as_ref(), ComponentExportKind::Type, ty, None); + } + let package_metadata = PackageMetadata::extract(self.resolve, *pkg); + self.component.custom_section(&CustomSection { + name: PackageMetadata::SECTION_NAME.into(), + data: package_metadata.encode()?.into(), + }); } } + let mut final_names = ComponentNameSection::new(); + final_names.components(&names); + self.component.names(&final_names); Ok(()) } diff --git a/crates/wit-component/src/metadata.rs b/crates/wit-component/src/metadata.rs index 59cb7353ee..1128216dcb 100644 --- a/crates/wit-component/src/metadata.rs +++ b/crates/wit-component/src/metadata.rs @@ -51,7 +51,7 @@ use wasm_encoder::{ }; use wasm_metadata::Producers; use wasmparser::{BinaryReader, Encoding, Parser, Payload, WasmFeatures}; -use wit_parser::{Package, PackageName, Resolve, World, WorldId, WorldItem}; +use wit_parser::{Package, PackageKind, PackageName, Resolve, World, WorldId, WorldItem}; const CURRENT_VERSION: u8 = 0x04; const CUSTOM_SECTION_NAME: &str = "wit-component-encoding"; @@ -80,6 +80,7 @@ impl Default for Bindgen { name: "root".to_string(), version: None, }, + kind: PackageKind::Implicit, docs: Default::default(), interfaces: Default::default(), worlds: Default::default(), diff --git a/crates/wit-component/src/printing.rs b/crates/wit-component/src/printing.rs index 7b863419df..daad8ef67e 100644 --- a/crates/wit-component/src/printing.rs +++ b/crates/wit-component/src/printing.rs @@ -70,7 +70,6 @@ impl WitPrinter { if has_multiple_packages { self.output.push_str(" {\n"); - self.output.indent += 1 } else { self.print_semicolon(); self.output.push_str("\n\n"); @@ -98,7 +97,6 @@ impl WitPrinter { if has_multiple_packages { self.output.push_str("}"); - self.output.indent -= 1 } } diff --git a/crates/wit-component/tests/interfaces.rs b/crates/wit-component/tests/interfaces.rs index 63dbbc1c8a..c4ca27468c 100644 --- a/crates/wit-component/tests/interfaces.rs +++ b/crates/wit-component/tests/interfaces.rs @@ -54,38 +54,37 @@ fn run_test(path: &Path, is_dir: bool) -> Result<()> { resolve.append(UnresolvedPackageGroup::parse_file(path)?)? }; - for package in packages { - assert_print(&resolve, &[package], path, is_dir)?; + assert_print(&resolve, &packages, path, is_dir)?; - let features = WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL; + let features = WasmFeatures::default() | WasmFeatures::COMPONENT_MODEL; - // First convert the WIT package to a binary WebAssembly output, then - // convert that binary wasm to textual wasm, then assert it matches the - // expectation. - let wasm = wit_component::encode(Some(true), &resolve, &[package])?; - let wat = wasmprinter::print_bytes(&wasm)?; - assert_output(&path.with_extension("wat"), &wat)?; - wasmparser::Validator::new_with_features(features) - .validate_all(&wasm) - .context("failed to validate wasm output")?; + // First convert the WIT package to a binary WebAssembly output, then + // convert that binary wasm to textual wasm, then assert it matches the + // expectation. + let wasm = wit_component::encode(Some(true), &resolve, &packages)?; + let wat = wasmprinter::print_bytes(&wasm)?; + assert_output(&path.with_extension("wat"), &wat)?; + wasmparser::Validator::new_with_features(features) + .validate_all(&wasm) + .context("failed to validate wasm output")?; - // Next decode a fresh WIT package from the WebAssembly generated. Print - // this package's documents and assert they all match the expectations. - let decoded = wit_component::decode(&wasm)?; + // Next decode a fresh WIT package from the WebAssembly generated. Print + // this package's documents and assert they all match the expectations. + let decoded = wit_component::decode(&wasm)?; - let decoded_package = decoded.packages()[0]; - let resolve = decoded.resolve(); + let decoded_package = decoded.packages()[0]; + let resolve = decoded.resolve(); - assert_print(resolve, decoded.packages(), path, is_dir)?; + assert_print(resolve, decoded.packages(), path, is_dir)?; - // Finally convert the decoded package to wasm again and make sure it - // matches the prior wasm. - let wasm2 = wit_component::encode(Some(true), resolve, &[decoded_package])?; - if wasm != wasm2 { - let wat2 = wasmprinter::print_bytes(&wasm)?; - assert_eq!(wat, wat2, "document did not roundtrip correctly"); - } + // Finally convert the decoded package to wasm again and make sure it + // matches the prior wasm. + let wasm2 = wit_component::encode(Some(true), resolve, &[decoded_package])?; + if wasm != wasm2 { + let wat2 = wasmprinter::print_bytes(&wasm)?; + assert_eq!(wat, wat2, "document did not roundtrip correctly"); } + // } Ok(()) } diff --git a/crates/wit-component/tests/interfaces/multiple-packages.wat b/crates/wit-component/tests/interfaces/multiple-packages.wat new file mode 100644 index 0000000000..66cbafbff7 --- /dev/null +++ b/crates/wit-component/tests/interfaces/multiple-packages.wat @@ -0,0 +1,62 @@ +(component + (component $another:thing (;0;) + (@custom "package-docs" "\01{\22interfaces\22:{\22something\22:{\22docs\22:\22documenting an interface\22,\22types\22:{\22my-record\22:{\22stability\22:{\22stable\22:{\22since\22:\221.2.3\22}}}}}}}") + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (record (field "foo" string))) + (export (;1;) "my-record" (type (eq 0))) + ) + ) + (export (;0;) "another:thing/something" (instance (type 0))) + ) + ) + (export (;1;) "something" (type 0)) + ) + (component $third:pkg (;1;) + (@custom "package-docs" "\01{\22interfaces\22:{\22things\22:{\22stability\22:{\22stable\22:{\22since\22:\221.2.3\22}},\22types\22:{\22other-record\22:{\22docs\22:\22documenting an type\22}}}}}") + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (record (field "foo" string))) + (export (;1;) "other-record" (type (eq 0))) + ) + ) + (export (;0;) "third:pkg/things" (instance (type 0))) + ) + ) + (export (;1;) "things" (type 0)) + ) + (component $foo:bar (;2;) + (@custom "package-docs" "\00{}") + (type (;0;) + (component + (type (;0;) + (component + (type (;0;) + (instance + (type (;0;) (record (field "foo" string))) + (export (;1;) "my-record" (type (eq 0))) + ) + ) + (import "another:thing/something" (instance (;0;) (type 0))) + (type (;1;) + (instance + (type (;0;) (record (field "foo" string))) + (export (;1;) "other-record" (type (eq 0))) + ) + ) + (import "third:pkg/things" (instance (;1;) (type 1))) + ) + ) + (export (;0;) "foo:bar/this-world" (component (type 0))) + ) + ) + (export (;1;) "this-world" (type 0)) + ) + (@producers + (processed-by "wit-component" "$CARGO_PKG_VERSION") + ) +) diff --git a/crates/wit-component/tests/interfaces/multiple-packages.wit b/crates/wit-component/tests/interfaces/multiple-packages.wit new file mode 100644 index 0000000000..fb9b0e933a --- /dev/null +++ b/crates/wit-component/tests/interfaces/multiple-packages.wit @@ -0,0 +1,26 @@ +package foo:bar { + world this-world { + import another:thing/something; + import third:pkg/things; + } +} + +package another:thing { + // documenting an interface + interface something { + @since(version = 1.2.3) + record my-record { + foo: string + } + } +} + +package third:pkg { + @since(version = 1.2.3) + interface things { + // documenting an type + record other-record { + foo: string + } + } +} \ No newline at end of file diff --git a/crates/wit-component/tests/interfaces/multiple-packages.wit.print b/crates/wit-component/tests/interfaces/multiple-packages.wit.print new file mode 100644 index 0000000000..50aa8e9356 --- /dev/null +++ b/crates/wit-component/tests/interfaces/multiple-packages.wit.print @@ -0,0 +1,28 @@ +package another:thing { + /// documenting an interface + interface something { + @since(version = 1.2.3) + record my-record { + foo: string, + } + } + +} + +package third:pkg { + @since(version = 1.2.3) + interface things { + /// documenting an type + record other-record { + foo: string, + } + } + +} + +package foo:bar { + world this-world { + import another:thing/something; + import third:pkg/things; + } +} \ No newline at end of file diff --git a/crates/wit-parser/src/ast.rs b/crates/wit-parser/src/ast.rs index d65d5fed4f..d9dfbdbb18 100644 --- a/crates/wit-parser/src/ast.rs +++ b/crates/wit-parser/src/ast.rs @@ -1592,6 +1592,11 @@ enum ResolverKind<'a> { PartialImplicit(Resolver<'a>), } +pub(crate) enum ResolverKindTag { + Explicit, + Implicit, +} + fn parse_package( unparsed_pkgs: Vec, src: &Source, @@ -1724,7 +1729,7 @@ impl SourceMap { match resolver_kind { ResolverKind::Unknown => bail!("No WIT packages found in the supplied source"), ResolverKind::Explicit(pkgs) => Ok(pkgs), - ResolverKind::PartialImplicit(mut resolver) => match resolver.resolve()? { + ResolverKind::PartialImplicit(mut resolver) => match resolver.resolve(ResolverKindTag::Implicit)? { Some(pkg) => Ok(vec![pkg]), None => bail!("No WIT packages found in the supplied source"), }, diff --git a/crates/wit-parser/src/ast/resolve.rs b/crates/wit-parser/src/ast/resolve.rs index 0d3465a602..6fc6dc9e63 100644 --- a/crates/wit-parser/src/ast/resolve.rs +++ b/crates/wit-parser/src/ast/resolve.rs @@ -1,4 +1,4 @@ -use super::{ParamList, ResultList, WorldOrInterface}; +use super::{ParamList, ResolverKindTag, ResultList, WorldOrInterface}; use crate::ast::toposort::toposort; use crate::*; use anyhow::bail; @@ -14,7 +14,7 @@ pub struct Resolver<'a> { package_docs: Docs, /// All non-`package` WIT decls are going to be resolved together. - decl_lists: Vec>, + decl_lists: Vec<(PackageKind, ast::DeclList<'a>)>, // Arenas that get plumbed to the final `UnresolvedPackage` types: Arena, @@ -140,11 +140,12 @@ impl<'a> Resolver<'a> { self.package_docs = docs; } } - self.decl_lists.push(partial.decl_list); + self.decl_lists + .push((PackageKind::Implicit, partial.decl_list)); Ok(()) } - pub(crate) fn resolve(&mut self) -> Result> { + pub(crate) fn resolve(&mut self, kind: ResolverKindTag) -> Result> { // At least one of the WIT files must have a `package` annotation. let name = match &self.package_name { Some(name) => name.clone(), @@ -171,7 +172,7 @@ impl<'a> Resolver<'a> { let mut iface_id_to_ast = IndexMap::new(); let mut world_id_to_ast = IndexMap::new(); for (i, decl_list) in decl_lists.iter().enumerate() { - for item in decl_list.items.iter() { + for item in decl_list.1.items.iter() { match item { ast::AstItem::Interface(iface) => { let id = match self.ast_items[i][iface.name.name] { @@ -206,6 +207,10 @@ impl<'a> Resolver<'a> { Ok(Some(UnresolvedPackage { name, + kind: match kind { + ResolverKindTag::Explicit => PackageKind::Explicit, + ResolverKindTag::Implicit => PackageKind::Implicit, + }, docs: mem::take(&mut self.package_docs), worlds: mem::take(&mut self.worlds), types: mem::take(&mut self.types), @@ -237,20 +242,21 @@ impl<'a> Resolver<'a> { ) -> Result> { self.package_name = Some(package.package_id.package_name()); self.docs(&package.package_id.docs); - self.decl_lists = vec![package.decl_list]; - self.resolve() + self.decl_lists = vec![(PackageKind::Explicit, package.decl_list)]; + self.resolve(ResolverKindTag::Explicit) } /// Registers all foreign dependencies made within the ASTs provided. /// /// This will populate the `self.foreign_{deps,interfaces,worlds}` maps with all /// `UsePath::Package` entries. - fn populate_foreign_deps(&mut self, decl_lists: &[ast::DeclList<'a>]) { + fn populate_foreign_deps(&mut self, decl_lists: &[(PackageKind, ast::DeclList<'a>)]) { let mut foreign_deps = mem::take(&mut self.foreign_deps); let mut foreign_interfaces = mem::take(&mut self.foreign_interfaces); let mut foreign_worlds = mem::take(&mut self.foreign_worlds); for decl_list in decl_lists { decl_list + .1 .for_each_path(|_, path, _names, world_or_iface| { let (id, name) = match path { ast::UsePath::Package { id, name } => (id, name), @@ -338,7 +344,7 @@ impl<'a> Resolver<'a> { /// generated for resolving use-paths later on. fn populate_ast_items( &mut self, - decl_lists: &[ast::DeclList<'a>], + decl_lists: &[(PackageKind, ast::DeclList<'a>)], ) -> Result<(Vec, Vec)> { let mut package_items = IndexMap::new(); @@ -349,7 +355,7 @@ impl<'a> Resolver<'a> { let mut order = IndexMap::new(); for decl_list in decl_lists { let mut decl_list_ns = IndexMap::new(); - for item in decl_list.items.iter() { + for item in decl_list.1.items.iter() { match item { ast::AstItem::Interface(i) => { if package_items.insert(i.name.name, i.name.span).is_some() { @@ -401,7 +407,7 @@ impl<'a> Resolver<'a> { // package or foreign items. Foreign deps are ignored for // topological ordering. let mut decl_list_ns = IndexMap::new(); - for item in decl_list.items.iter() { + for item in decl_list.1.items.iter() { let (name, src) = match item { ast::AstItem::Use(u) => { let name = u.as_.as_ref().unwrap_or(u.item.name()); @@ -424,7 +430,7 @@ impl<'a> Resolver<'a> { // With this file's namespace information look at all `use` paths // and record dependencies between interfaces. - decl_list.for_each_path(|iface, path, _names, _| { + decl_list.1.for_each_path(|iface, path, _names, _| { // If this import isn't contained within an interface then it's // in a world and it doesn't need to participate in our // topo-sort. @@ -490,7 +496,7 @@ impl<'a> Resolver<'a> { } for decl_list in decl_lists { let mut items = IndexMap::new(); - for item in decl_list.items.iter() { + for item in decl_list.1.items.iter() { let (name, ast_item) = match item { ast::AstItem::Use(u) => { if !u.attributes.is_empty() { @@ -548,10 +554,13 @@ impl<'a> Resolver<'a> { /// This is done after all interfaces are generated so `self.resolve_path` /// can be used to determine if what's being imported from is a foreign /// interface or not. - fn populate_foreign_types(&mut self, decl_lists: &[ast::DeclList<'a>]) -> Result<()> { + fn populate_foreign_types( + &mut self, + decl_lists: &[(PackageKind, ast::DeclList<'a>)], + ) -> Result<()> { for (i, decl_list) in decl_lists.iter().enumerate() { self.cur_ast_index = i; - decl_list.for_each_path(|_, path, names, _| { + decl_list.1.for_each_path(|_, path, names, _| { let names = match names { Some(names) => names, None => return Ok(()), diff --git a/crates/wit-parser/src/decoding.rs b/crates/wit-parser/src/decoding.rs index dfd169fcde..69038da014 100644 --- a/crates/wit-parser/src/decoding.rs +++ b/crates/wit-parser/src/decoding.rs @@ -1,11 +1,14 @@ +use crate::resolve::PackageKind; use crate::*; use anyhow::{anyhow, bail}; use indexmap::IndexSet; -use std::collections::HashSet; use std::mem; use std::slice; use std::{collections::HashMap, io::Read}; use wasmparser::Chunk; +use wasmparser::ComponentNameSectionReader; +use wasmparser::KnownCustom; +use wasmparser::NameMap; use wasmparser::{ names::{ComponentName, ComponentNameKind}, types, @@ -21,10 +24,28 @@ struct ComponentInfo { types: types::Types, /// List of all imports and exports from this component. externs: Vec<(String, Extern)>, + /// Packages + explicit: Vec, + /// Packages + packages: Vec, /// Decoded package metadata package_metadata: Option, } +/// Represents information about a decoded WebAssembly component. +#[derive(Default)] +struct ExplicitPackageInfo { + /// Package name + name: Option, + /// Wasmparser-defined type information learned after a component is fully + /// validated. + types: Option, + /// List of all imports and exports from this component. + externs: Vec<(String, Extern)>, + // / Decoded package metadata + package_metadata: Option, +} + struct DecodingExport { name: String, kind: ComponentExternalKind, @@ -42,15 +63,50 @@ enum WitEncodingVersion { V2, } +fn register_names( + names: ComponentNameSectionReader, + explicit: &mut ExplicitPackageInfo, +) -> Result> { + let mut packages = Vec::new(); + for section in names { + match section? { + wasmparser::ComponentName::Components(s) => { + let map: NameMap = s.into(); + for item in map { + let name = item?; + let mut parts = name.name.split(":"); + let namespace = parts.next().expect("expected identifier"); + let id = parts.next(); + if let Some(id) = id { + let pkg_name = PackageName { + namespace: namespace.to_string(), + name: id.to_string(), + version: None, + }; + explicit.name = Some(pkg_name.clone()); + packages.push(pkg_name); + } + } + } + _ => {} + } + } + Ok(packages) +} + impl ComponentInfo { /// Creates a new component info by parsing the given WebAssembly component bytes. fn from_reader(mut reader: impl Read) -> Result { + let mut packages = Vec::new(); + let mut explicit = Vec::new(); + let mut cur_package = ExplicitPackageInfo::default(); + let mut is_implicit = true; let mut validator = Validator::new_with_features(WasmFeatures::all()); let mut externs = Vec::new(); let mut depth = 1; let mut types = None; - let mut _package_metadata = None; + let mut package_metadata = None; let mut cur = Parser::new(0); let mut eof = false; let mut stack = Vec::new(); @@ -82,45 +138,83 @@ impl ComponentInfo { ValidPayload::Parser(_) => depth += 1, ValidPayload::End(t) => { depth -= 1; - if depth == 0 { + if depth == 1 { + is_implicit = true; + cur_package.types = Some(t); + explicit.push(mem::take(&mut cur_package)); + } else if depth == 0 { types = Some(t); + } else { + cur_package.types = Some(t); + explicit.push(mem::take(&mut cur_package)); } } ValidPayload::Func(..) => {} } match payload { - Payload::ComponentImportSection(s) if depth == 1 => { + Payload::ComponentImportSection(s) => { for import in s { let import = import?; - externs.push(( - import.name.0.to_string(), - Extern::Import(import.name.0.to_string()), - )); + if is_implicit { + externs.push(( + import.name.0.to_string(), + Extern::Import(import.name.0.to_string()), + )); + } else { + cur_package.externs.push(( + import.name.0.to_string(), + Extern::Import(import.name.0.to_string()), + )); + } } } - Payload::ComponentExportSection(s) if depth == 1 => { + Payload::ComponentExportSection(s) => { for export in s { let export = export?; - externs.push(( - export.name.0.to_string(), - Extern::Export(DecodingExport { - name: export.name.0.to_string(), - kind: export.kind, - index: export.index, - }), - )); + if is_implicit { + externs.push(( + export.name.0.to_string(), + Extern::Export(DecodingExport { + name: export.name.0.to_string(), + kind: export.kind, + index: export.index, + }), + )); + } else { + cur_package.externs.push(( + export.name.0.to_string(), + Extern::Export(DecodingExport { + name: export.name.0.to_string(), + kind: export.kind, + index: export.index, + }), + )); + } } } #[cfg(feature = "serde")] - Payload::CustomSection(s) if s.name() == PackageMetadata::SECTION_NAME => { - if _package_metadata.is_some() { - bail!("multiple {:?} sections", PackageMetadata::SECTION_NAME); + Payload::CustomSection(s) => { + if s.name() == PackageMetadata::SECTION_NAME { + package_metadata = Some(PackageMetadata::decode(s.data())?); + cur_package.package_metadata = package_metadata.clone(); + } else if s.name() == "component-name" { + if let KnownCustom::ComponentName(reader) = s.as_known() { + packages = register_names(reader, &mut cur_package)?; + if packages.len() == explicit.len() { + for (i, exp) in explicit.iter_mut().enumerate() { + exp.name = Some(packages[i].clone()); + } + } + } else { + bail!("Expected component name section") + } } - _package_metadata = Some(PackageMetadata::decode(s.data())?); } Payload::ModuleSection { parser, .. } | Payload::ComponentSection { parser, .. } => { + is_implicit = false; + cur_package = ExplicitPackageInfo::default(); stack.push(cur.clone()); cur = parser.clone(); } @@ -141,14 +235,19 @@ impl ComponentInfo { Ok(Self { types: types.unwrap(), + explicit, + packages, externs, - package_metadata: _package_metadata, + package_metadata, }) } fn is_wit_package(&self) -> Option { // all wit package exports must be component types, and there must be at // least one + if !self.packages.is_empty() { + return Some(WitEncodingVersion::V2); + } if self.externs.is_empty() { return None; } @@ -177,12 +276,11 @@ impl ComponentInfo { ComponentNameKind::Interface(name) if name.interface().as_str() == "wit" => { Some(WitEncodingVersion::V1) } - ComponentNameKind::Label(_) => Some(WitEncodingVersion::V2), - _ => None, + _ => Some(WitEncodingVersion::V2), } } - fn decode_wit_v1_package(&self) -> Result<(Resolve, Vec)> { + fn decode_wit_v1_package(&self) -> Result<(Resolve, PackageId)> { let mut decoder = WitPackageDecoder::new(&self.types); let mut pkg = None; @@ -205,27 +303,23 @@ impl ComponentInfo { } let pkg = pkg.ok_or_else(|| anyhow!("no exported component type found"))?; - let (mut resolve, packages) = decoder.finish(&[pkg]); - for package in &packages { - if let Some(package_metadata) = &self.package_metadata { - package_metadata.inject(&mut resolve, *package)?; - } + let (mut resolve, packages) = decoder.finish(&mut [pkg]); + if let Some(package_metadata) = &self.package_metadata { + package_metadata.inject(&mut resolve, packages[0])?; } - Ok((resolve, packages)) + Ok((resolve, packages[0])) } fn decode_wit_v2_packages(&self) -> Result<(Resolve, Vec)> { let mut decoder = WitPackageDecoder::new(&self.types); - let mut pkg_names = HashSet::new(); + let mut pkg_names = Vec::new(); - let mut interfaces = IndexMap::new(); - let mut worlds = IndexMap::new(); let mut fields = PackageFields { - interfaces: &mut interfaces, - worlds: &mut worlds, + interfaces: &mut IndexMap::new(), + worlds: &mut IndexMap::new(), }; - + let mut pkg_ids: Vec = Vec::new(); for (_, item) in self.externs.iter() { let export = match item { Extern::Export(e) => e, @@ -264,24 +358,119 @@ impl ComponentInfo { } _ => unreachable!(), }; + if !pkg_names.contains(&name) { + pkg_names.push(name.clone()); + let pkg = Package { + name: name.clone(), + kind: PackageKind::Implicit, + docs: Docs::default(), + interfaces: fields.interfaces.clone(), + worlds: fields.worlds.clone(), + }; + if !pkg_ids.contains(&pkg) { + pkg_ids.push(pkg); + } + } else { + let pkg = Package { + name: name.clone(), + kind: PackageKind::Implicit, + docs: Docs::default(), + interfaces: fields.interfaces.clone(), + worlds: fields.worlds.clone(), + }; + let pkg_id = pkg_ids.iter_mut().find(|p| p.name == pkg.name).unwrap(); + pkg_id.interfaces = pkg.interfaces; + pkg_id.worlds = pkg.worlds; + } + } - pkg_names.insert(name); + for explicit in &self.explicit { + fields.interfaces.clear(); + fields.worlds.clear(); + for (_, item) in explicit.externs.iter() { + let export = match item { + Extern::Export(e) => e, + _ => unreachable!(), + }; + + let index = export.index; + let id = explicit.types.as_ref().unwrap().component_type_at(index); + let component = &explicit.types.as_ref().unwrap()[id]; + + // The single export of this component will determine if it's a world or an interface: + // worlds export a component, while interfaces export an instance. + if component.exports.len() != 1 { + bail!( + "Expected a single export, but found {} instead", + component.exports.len() + ); + } + + let name = component.exports.keys().nth(0).unwrap(); + + let name = match component.exports[name] { + types::ComponentEntityType::Component(ty) => { + let package_name = + decoder.decode_world(name.as_str(), &self.types[ty], &mut fields)?; + package_name + } + types::ComponentEntityType::Instance(ty) => { + let package_name = decoder.decode_interface( + name.as_str(), + &component.imports, + &self.types[ty], + &mut fields, + )?; + package_name + } + _ => unreachable!(), + }; + + if !pkg_names.contains(&name) { + pkg_names.push(name.clone()); + let pkg = Package { + name: name.clone(), + kind: PackageKind::Implicit, + docs: Docs::default(), + interfaces: fields.interfaces.clone(), + worlds: fields.worlds.clone(), + }; + if !pkg_ids.contains(&pkg) { + pkg_ids.push(pkg); + } + } else { + let pkg = Package { + name: name.clone(), + kind: PackageKind::Implicit, + docs: Docs::default(), + interfaces: fields.interfaces.clone(), + worlds: fields.worlds.clone(), + }; + let pkg_id = pkg_ids.iter_mut().find(|p| p.name == pkg.name).unwrap(); + pkg_id.interfaces = pkg.interfaces; + pkg_id.worlds = pkg.worlds; + } + } } - let mut pkg_ids = Vec::new(); - for pkg_name in pkg_names { - let pkg = Package { - name: pkg_name, - docs: Docs::default(), - interfaces: interfaces.clone(), - worlds: worlds.clone(), - }; - pkg_ids.push(pkg); + let (mut resolve, packages) = decoder.finish(&mut pkg_ids); + let copy = resolve.clone(); + for package in &self.explicit { + if let Some(package_metadata) = &package.package_metadata { + let name = package.name.as_ref().unwrap(); + let pkg = copy.package_names.get(&name.clone()); + if let Some(pkg) = pkg { + package_metadata.inject(&mut resolve, *pkg)?; + } + } } - let (mut resolve, packages) = decoder.finish(&pkg_ids); - for package in &packages { + // For now this is a sufficient condition to know that we're working with + // an implicit package declaration. This will need to be reworked when + // mixed package declarations are supported + if self.explicit.len() == 0 { + let package = packages[0]; if let Some(package_metadata) = &self.package_metadata { - package_metadata.inject(&mut resolve, package.clone())?; + package_metadata.inject(&mut resolve, package)?; } } Ok((resolve, packages)) @@ -313,6 +502,7 @@ impl ComponentInfo { version: None, name: "component".to_string(), }, + kind: PackageKind::Implicit, docs: Default::default(), worlds: [(world_name.to_string(), world)].into_iter().collect(), interfaces: Default::default(), @@ -334,7 +524,7 @@ impl ComponentInfo { } } - let (resolve, _) = decoder.finish(&[package]); + let (resolve, _) = decoder.finish(&mut [package]); Ok((resolve, world)) } } @@ -382,7 +572,7 @@ pub fn decode_reader(reader: impl Read) -> Result { WitEncodingVersion::V1 => { log::debug!("decoding a v1 WIT package encoded as wasm"); let (resolve, pkg) = info.decode_wit_v1_package()?; - Ok(DecodedWasm::WitPackages(resolve, pkg.to_vec())) + Ok(DecodedWasm::WitPackages(resolve, vec![pkg])) } WitEncodingVersion::V2 => { log::debug!("decoding a v2 WIT package encoded as wasm"); @@ -470,18 +660,16 @@ pub fn decode_world(wasm: &[u8]) -> Result<(Resolve, WorldId)> { types::ComponentEntityType::Component(ty) => ty, _ => unreachable!(), }; - let name = decoder.decode_world( - name, - &types[ty], - &mut PackageFields { - interfaces: &mut interfaces, - worlds: &mut worlds, - }, - )?; - let (resolve, pkgs) = decoder.finish(&[Package { + let mut fields = PackageFields { + interfaces: &mut interfaces, + worlds: &mut worlds, + }; + let name = decoder.decode_world(name, &types[ty], &mut fields)?; + let (resolve, pkgs) = decoder.finish(&mut [Package { name, - interfaces, - worlds, + kind: PackageKind::Implicit, + interfaces: fields.interfaces.clone(), + worlds: fields.worlds.clone(), docs: Default::default(), }]); // The package decoded here should only have a single world so extract that @@ -554,6 +742,7 @@ impl WitPackageDecoder<'_> { } _ => bail!("package name is not a valid id: {name}"), }, + kind: PackageKind::Implicit, docs: Default::default(), interfaces: Default::default(), worlds: Default::default(), @@ -579,7 +768,7 @@ impl WitPackageDecoder<'_> { _ => bail!("component export `{name}` is not an instance or component"), } } - Ok(package) + Ok(package.clone()) } fn decode_interface<'a>( @@ -587,7 +776,7 @@ impl WitPackageDecoder<'_> { name: &str, imports: &wasmparser::collections::IndexMap, ty: &types::ComponentInstanceType, - fields: &mut PackageFields<'a>, + fields: &mut PackageFields, ) -> Result { let component_name = self .parse_component_name(name) @@ -616,7 +805,7 @@ impl WitPackageDecoder<'_> { &mut self, name: &str, ty: &types::ComponentType, - fields: &mut PackageFields<'a>, + fields: &mut PackageFields, ) -> Result { let kebab_name = self .parse_component_name(name) @@ -636,7 +825,7 @@ impl WitPackageDecoder<'_> { &mut self, name: &str, world: WorldId, - package: &mut PackageFields<'a>, + package: &mut PackageFields, ) -> Result<()> { log::debug!("decoding component import `{name}`"); let ty = self.types.component_entity_type_of_import(name).unwrap(); @@ -686,7 +875,7 @@ impl WitPackageDecoder<'_> { &mut self, export: &DecodingExport, world: WorldId, - package: &mut PackageFields<'a>, + package: &mut PackageFields, ) -> Result<()> { let name = &export.name; log::debug!("decoding component export `{name}`"); @@ -882,6 +1071,7 @@ impl WitPackageDecoder<'_> { .entry(package_name.to_string()) .or_insert_with(|| Package { name: package_name.clone(), + kind: PackageKind::Implicit, docs: Default::default(), interfaces: Default::default(), worlds: Default::default(), @@ -930,7 +1120,7 @@ impl WitPackageDecoder<'_> { &mut self, name: &str, ty: &types::ComponentInstanceType, - package: &mut PackageFields<'a>, + package: &mut PackageFields, ) -> Result<(WorldKey, InterfaceId)> { // If this interface's name is already known then that means this is an // interface that's both imported and exported. Use `register_import` @@ -1071,7 +1261,7 @@ impl WitPackageDecoder<'_> { &mut self, name: &str, ty: &types::ComponentType, - package: &mut PackageFields<'a>, + package: &mut PackageFields, ) -> Result { let name = self .extract_interface_name_from_component_name(name)? @@ -1429,51 +1619,50 @@ impl WitPackageDecoder<'_> { /// their topological ordering within the returned `Resolve`. /// /// Takes the root package as an argument to insert. - fn finish(mut self, packages: &[Package]) -> (Resolve, Vec) { - // Build a topological ordering is then calculated by visiting all the - // transitive dependencies of packages. - let mut order = IndexSet::new(); - for i in 0..self.foreign_packages.len() { - self.visit_package(i, &mut order); - } - - // Using the topological ordering create a temporary map from - // index-in-`foreign_packages` to index-in-`order` - let mut idx_to_pos = vec![0; self.foreign_packages.len()]; - for (pos, idx) in order.iter().enumerate() { - idx_to_pos[*idx] = pos; - } - // .. and then using `idx_to_pos` sort the `foreign_packages` array based - // on the position it's at in the topological ordering - let mut deps = mem::take(&mut self.foreign_packages) - .into_iter() - .enumerate() - .collect::>(); - deps.sort_by_key(|(idx, _)| idx_to_pos[*idx]); - - // .. and finally insert the packages, in their final topological - // ordering, into the returned array. - for (_idx, (_url, pkg)) in deps { - self.insert_package(pkg); - } - + fn finish(mut self, packages: &mut [Package]) -> (Resolve, Vec) { let mut resolved = Vec::new(); for package in packages { + // Build a topological ordering is then calculated by visiting all the + // transitive dependencies of packages. + let mut order = IndexSet::new(); + for i in 0..self.foreign_packages.len() { + self.visit_package(i, &mut order); + } + // Using the topological ordering create a temporary map from + // index-in-`foreign_packages` to index-in-`order` + let mut idx_to_pos = vec![0; self.foreign_packages.len()]; + for (pos, idx) in order.iter().enumerate() { + idx_to_pos[*idx] = pos; + } + // .. and then using `idx_to_pos` sort the `foreign_packages` array based + // on the position it's at in the topological ordering + let mut deps = mem::take(&mut self.foreign_packages) + .into_iter() + .enumerate() + .collect::>(); + deps.sort_by_key(|(idx, _)| idx_to_pos[*idx]); + + // .. and finally insert the packages, in their final topological + // ordering, into the returned array. + for (_idx, (_url, pkg)) in deps { + self.insert_package(pkg); + } let id = self.insert_package(package.clone()); - assert!(self.resolve.worlds.iter().all(|(_, w)| w.package.is_some())); - assert!(self - .resolve - .interfaces - .iter() - .all(|(_, i)| i.package.is_some())); resolved.push(id); } + assert!(self.resolve.worlds.iter().all(|(_, w)| w.package.is_some())); + assert!(self + .resolve + .interfaces + .iter() + .all(|(_, i)| i.package.is_some())); (self.resolve, resolved) } fn insert_package(&mut self, package: Package) -> PackageId { let Package { name, + kind, interfaces, worlds, docs, @@ -1492,6 +1681,7 @@ impl WitPackageDecoder<'_> { .unwrap_or_else(|| { let id = self.resolve.packages.alloc(Package { name: name.clone(), + kind: kind.clone(), interfaces: Default::default(), worlds: Default::default(), docs, diff --git a/crates/wit-parser/src/lib.rs b/crates/wit-parser/src/lib.rs index 72e0857bce..96230f6030 100644 --- a/crates/wit-parser/src/lib.rs +++ b/crates/wit-parser/src/lib.rs @@ -21,7 +21,7 @@ pub use ast::{parse_use_path, ParsedUsePath}; mod sizealign; pub use sizealign::*; mod resolve; -pub use resolve::{Package, PackageId, Remap, Resolve}; +pub use resolve::{Package, PackageId, PackageKind, Remap, Resolve}; mod live; pub use live::LiveTypes; @@ -72,6 +72,9 @@ pub struct UnresolvedPackage { /// The namespace, name, and version information for this package. pub name: PackageName, + /// Kind + pub kind: PackageKind, + /// All worlds from all documents within this package. /// /// Each world lists the document that it is from. diff --git a/crates/wit-parser/src/metadata.rs b/crates/wit-parser/src/metadata.rs index 103e3d03af..78554a3ad0 100644 --- a/crates/wit-parser/src/metadata.rs +++ b/crates/wit-parser/src/metadata.rs @@ -48,6 +48,7 @@ const TRY_TO_EMIT_V0_BY_DEFAULT: bool = true; /// Represents serializable doc comments parsed from a WIT package. #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(deny_unknown_fields))] +#[derive(Clone)] pub struct PackageMetadata { #[cfg_attr( feature = "serde", @@ -163,6 +164,7 @@ impl PackageMetadata { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(deny_unknown_fields))] +#[derive(Clone)] struct WorldMetadata { #[cfg_attr( feature = "serde", @@ -500,6 +502,7 @@ impl WorldMetadata { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(deny_unknown_fields))] +#[derive(Clone)] struct InterfaceMetadata { #[cfg_attr( feature = "serde", @@ -586,6 +589,7 @@ impl InterfaceMetadata { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(untagged, deny_unknown_fields))] +#[derive(Clone)] enum FunctionMetadata { /// In the v0 format function metadata was only a string so this variant /// is preserved for the v0 format. In the future this can be removed @@ -656,6 +660,7 @@ impl FunctionMetadata { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(deny_unknown_fields))] +#[derive(Clone)] struct TypeMetadata { #[cfg_attr( feature = "serde", diff --git a/crates/wit-parser/src/resolve.rs b/crates/wit-parser/src/resolve.rs index 8a34a8e667..b0ab727fae 100644 --- a/crates/wit-parser/src/resolve.rs +++ b/crates/wit-parser/src/resolve.rs @@ -76,17 +76,26 @@ pub struct Resolve { pub features: IndexSet, } +#[derive(PartialEq, Clone, Debug, Serialize)] +pub enum PackageKind { + Explicit, + Implicit, +} + /// A WIT package within a `Resolve`. /// /// A package is a collection of interfaces and worlds. Packages additionally /// have a unique identifier that affects generated components and uniquely /// identifiers this particular package. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize))] pub struct Package { /// A unique name corresponding to this package. pub name: PackageName, + /// Kind + pub kind: PackageKind, + /// Documentation associated with this package. #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))] pub docs: Docs, @@ -1213,6 +1222,7 @@ impl Remap { let pkgid = resolve.packages.alloc(Package { name: unresolved.name.clone(), + kind: unresolved.kind.clone(), docs: unresolved.docs.clone(), interfaces: Default::default(), worlds: Default::default(), diff --git a/crates/wit-parser/tests/ui/comments.wit.json b/crates/wit-parser/tests/ui/comments.wit.json index f2a04f9d39..2f18314f36 100644 --- a/crates/wit-parser/tests/ui/comments.wit.json +++ b/crates/wit-parser/tests/ui/comments.wit.json @@ -40,6 +40,7 @@ "packages": [ { "name": "foo:comments", + "kind": "Implicit", "interfaces": { "foo": 0 }, diff --git a/crates/wit-parser/tests/ui/complex-include.wit.json b/crates/wit-parser/tests/ui/complex-include.wit.json index f9b17f2792..38b0df2172 100644 --- a/crates/wit-parser/tests/ui/complex-include.wit.json +++ b/crates/wit-parser/tests/ui/complex-include.wit.json @@ -165,6 +165,7 @@ "packages": [ { "name": "foo:bar", + "kind": "Implicit", "interfaces": { "a": 0, "b": 1 @@ -175,6 +176,7 @@ }, { "name": "foo:baz", + "kind": "Implicit", "interfaces": { "a": 2, "b": 3 @@ -185,6 +187,7 @@ }, { "name": "foo:root", + "kind": "Implicit", "interfaces": { "ai": 4, "bi": 5 diff --git a/crates/wit-parser/tests/ui/cross-package-resource.wit.json b/crates/wit-parser/tests/ui/cross-package-resource.wit.json index 51ab92795d..f49163415e 100644 --- a/crates/wit-parser/tests/ui/cross-package-resource.wit.json +++ b/crates/wit-parser/tests/ui/cross-package-resource.wit.json @@ -51,6 +51,7 @@ "packages": [ { "name": "some:dep", + "kind": "Implicit", "interfaces": { "foo": 0 }, @@ -58,6 +59,7 @@ }, { "name": "foo:bar", + "kind": "Implicit", "interfaces": { "foo": 1 }, diff --git a/crates/wit-parser/tests/ui/diamond1.wit.json b/crates/wit-parser/tests/ui/diamond1.wit.json index 54e87e7b04..c524224815 100644 --- a/crates/wit-parser/tests/ui/diamond1.wit.json +++ b/crates/wit-parser/tests/ui/diamond1.wit.json @@ -36,6 +36,7 @@ "packages": [ { "name": "foo:dep1", + "kind": "Implicit", "interfaces": { "types": 0 }, @@ -43,6 +44,7 @@ }, { "name": "foo:dep2", + "kind": "Implicit", "interfaces": { "types": 1 }, @@ -50,6 +52,7 @@ }, { "name": "foo:foo", + "kind": "Implicit", "interfaces": {}, "worlds": { "foo": 0 diff --git a/crates/wit-parser/tests/ui/disambiguate-diamond.wit.json b/crates/wit-parser/tests/ui/disambiguate-diamond.wit.json index 34f675da51..47bfdbe8a2 100644 --- a/crates/wit-parser/tests/ui/disambiguate-diamond.wit.json +++ b/crates/wit-parser/tests/ui/disambiguate-diamond.wit.json @@ -103,6 +103,7 @@ "packages": [ { "name": "foo:diamond", + "kind": "Implicit", "interfaces": { "shared1": 0, "shared2": 1 diff --git a/crates/wit-parser/tests/ui/empty.wit.json b/crates/wit-parser/tests/ui/empty.wit.json index 092abe5e1d..00ba7a6102 100644 --- a/crates/wit-parser/tests/ui/empty.wit.json +++ b/crates/wit-parser/tests/ui/empty.wit.json @@ -5,6 +5,7 @@ "packages": [ { "name": "foo:empty", + "kind": "Implicit", "interfaces": {}, "worlds": {} } diff --git a/crates/wit-parser/tests/ui/feature-gates.wit.json b/crates/wit-parser/tests/ui/feature-gates.wit.json index 9cdb44c582..45490954b2 100644 --- a/crates/wit-parser/tests/ui/feature-gates.wit.json +++ b/crates/wit-parser/tests/ui/feature-gates.wit.json @@ -291,6 +291,7 @@ "packages": [ { "name": "a:b", + "kind": "Implicit", "interfaces": { "ungated": 0, "ungated2": 1, diff --git a/crates/wit-parser/tests/ui/foreign-deps-union.wit.json b/crates/wit-parser/tests/ui/foreign-deps-union.wit.json index 419d62e7ce..32cbd8e6fa 100644 --- a/crates/wit-parser/tests/ui/foreign-deps-union.wit.json +++ b/crates/wit-parser/tests/ui/foreign-deps-union.wit.json @@ -346,6 +346,7 @@ "packages": [ { "name": "foo:another-pkg", + "kind": "Implicit", "interfaces": { "other-interface": 0 }, @@ -353,6 +354,7 @@ }, { "name": "foo:corp", + "kind": "Implicit", "interfaces": { "saas": 1 }, @@ -360,6 +362,7 @@ }, { "name": "foo:different-pkg", + "kind": "Implicit", "interfaces": { "i": 2 }, @@ -367,6 +370,7 @@ }, { "name": "foo:foreign-pkg", + "kind": "Implicit", "interfaces": { "the-default": 3 }, @@ -374,6 +378,7 @@ }, { "name": "foo:some-pkg", + "kind": "Implicit", "interfaces": { "the-default": 4, "some-interface": 5, @@ -383,6 +388,7 @@ }, { "name": "foo:wasi", + "kind": "Implicit", "interfaces": { "clocks": 7, "filesystem": 8 @@ -393,6 +399,7 @@ }, { "name": "foo:root", + "kind": "Implicit", "interfaces": { "foo": 9, "bar": 10, diff --git a/crates/wit-parser/tests/ui/foreign-deps.wit.json b/crates/wit-parser/tests/ui/foreign-deps.wit.json index 503c1b32c9..132fcdd301 100644 --- a/crates/wit-parser/tests/ui/foreign-deps.wit.json +++ b/crates/wit-parser/tests/ui/foreign-deps.wit.json @@ -301,6 +301,7 @@ "packages": [ { "name": "foo:another-pkg", + "kind": "Implicit", "interfaces": { "other-interface": 0 }, @@ -308,6 +309,7 @@ }, { "name": "foo:corp", + "kind": "Implicit", "interfaces": { "saas": 1 }, @@ -315,6 +317,7 @@ }, { "name": "foo:different-pkg", + "kind": "Implicit", "interfaces": { "i": 2 }, @@ -322,6 +325,7 @@ }, { "name": "foo:foreign-pkg", + "kind": "Implicit", "interfaces": { "the-default": 3 }, @@ -329,6 +333,7 @@ }, { "name": "foo:some-pkg", + "kind": "Implicit", "interfaces": { "the-default": 4, "some-interface": 5, @@ -338,6 +343,7 @@ }, { "name": "foo:wasi", + "kind": "Implicit", "interfaces": { "clocks": 7, "filesystem": 8 @@ -346,6 +352,7 @@ }, { "name": "foo:root", + "kind": "Implicit", "interfaces": { "foo": 9, "bar": 10, diff --git a/crates/wit-parser/tests/ui/functions.wit.json b/crates/wit-parser/tests/ui/functions.wit.json index 902fe35709..a5afc8eb43 100644 --- a/crates/wit-parser/tests/ui/functions.wit.json +++ b/crates/wit-parser/tests/ui/functions.wit.json @@ -157,6 +157,7 @@ "packages": [ { "name": "foo:functions", + "kind": "Implicit", "interfaces": { "functions": 0 }, diff --git a/crates/wit-parser/tests/ui/ignore-files-deps.wit.json b/crates/wit-parser/tests/ui/ignore-files-deps.wit.json index 7a812dbecf..27805e9468 100644 --- a/crates/wit-parser/tests/ui/ignore-files-deps.wit.json +++ b/crates/wit-parser/tests/ui/ignore-files-deps.wit.json @@ -25,6 +25,7 @@ "packages": [ { "name": "foo:bar", + "kind": "Implicit", "interfaces": { "types": 0 }, @@ -32,6 +33,7 @@ }, { "name": "foo:foo", + "kind": "Implicit", "interfaces": {}, "worlds": { "foo": 0 diff --git a/crates/wit-parser/tests/ui/import-export-overlap1.wit.json b/crates/wit-parser/tests/ui/import-export-overlap1.wit.json index 0c88a177b2..77d0c44838 100644 --- a/crates/wit-parser/tests/ui/import-export-overlap1.wit.json +++ b/crates/wit-parser/tests/ui/import-export-overlap1.wit.json @@ -30,6 +30,7 @@ "packages": [ { "name": "foo:foo", + "kind": "Implicit", "interfaces": {}, "worlds": { "foo": 0 diff --git a/crates/wit-parser/tests/ui/import-export-overlap2.wit.json b/crates/wit-parser/tests/ui/import-export-overlap2.wit.json index 0c991269c5..046c5af444 100644 --- a/crates/wit-parser/tests/ui/import-export-overlap2.wit.json +++ b/crates/wit-parser/tests/ui/import-export-overlap2.wit.json @@ -34,6 +34,7 @@ "packages": [ { "name": "foo:foo", + "kind": "Implicit", "interfaces": {}, "worlds": { "foo": 0 diff --git a/crates/wit-parser/tests/ui/include-reps.wit.json b/crates/wit-parser/tests/ui/include-reps.wit.json index 21debef2fe..b77c9a640e 100644 --- a/crates/wit-parser/tests/ui/include-reps.wit.json +++ b/crates/wit-parser/tests/ui/include-reps.wit.json @@ -55,6 +55,7 @@ "packages": [ { "name": "foo:foo", + "kind": "Implicit", "interfaces": { "a": 0, "b": 1 diff --git a/crates/wit-parser/tests/ui/kebab-name-include-with.wit.json b/crates/wit-parser/tests/ui/kebab-name-include-with.wit.json index 14c6d0d048..64c15833dd 100644 --- a/crates/wit-parser/tests/ui/kebab-name-include-with.wit.json +++ b/crates/wit-parser/tests/ui/kebab-name-include-with.wit.json @@ -59,6 +59,7 @@ "packages": [ { "name": "foo:foo", + "kind": "Implicit", "interfaces": {}, "worlds": { "foo": 0, diff --git a/crates/wit-parser/tests/ui/kinds-of-deps.wit.json b/crates/wit-parser/tests/ui/kinds-of-deps.wit.json index f13afe6301..d044bdd3ab 100644 --- a/crates/wit-parser/tests/ui/kinds-of-deps.wit.json +++ b/crates/wit-parser/tests/ui/kinds-of-deps.wit.json @@ -58,6 +58,7 @@ "packages": [ { "name": "d:d", + "kind": "Implicit", "interfaces": { "d": 0 }, @@ -65,6 +66,7 @@ }, { "name": "e:e", + "kind": "Implicit", "interfaces": { "e": 1 }, @@ -72,6 +74,7 @@ }, { "name": "b:b", + "kind": "Implicit", "interfaces": { "b": 2 }, @@ -79,6 +82,7 @@ }, { "name": "c:c", + "kind": "Implicit", "interfaces": { "c": 3 }, @@ -86,6 +90,7 @@ }, { "name": "a:a", + "kind": "Implicit", "interfaces": {}, "worlds": { "a": 0 diff --git a/crates/wit-parser/tests/ui/many-names.wit.json b/crates/wit-parser/tests/ui/many-names.wit.json index 590c68471a..1c47f69f77 100644 --- a/crates/wit-parser/tests/ui/many-names.wit.json +++ b/crates/wit-parser/tests/ui/many-names.wit.json @@ -31,6 +31,7 @@ "packages": [ { "name": "foo:name", + "kind": "Implicit", "interfaces": { "x": 0 }, diff --git a/crates/wit-parser/tests/ui/multi-file-multi-package.wit.json b/crates/wit-parser/tests/ui/multi-file-multi-package.wit.json index a2dea31719..a20a0c78ec 100644 --- a/crates/wit-parser/tests/ui/multi-file-multi-package.wit.json +++ b/crates/wit-parser/tests/ui/multi-file-multi-package.wit.json @@ -212,6 +212,7 @@ "packages": [ { "name": "bar:name", + "kind": "Explicit", "interfaces": { "i2": 0 }, @@ -221,6 +222,7 @@ }, { "name": "baz:name", + "kind": "Explicit", "interfaces": { "i3": 2 }, @@ -230,6 +232,7 @@ }, { "name": "foo:name", + "kind": "Explicit", "interfaces": { "i1": 4 }, @@ -239,6 +242,7 @@ }, { "name": "qux:name", + "kind": "Explicit", "interfaces": { "i4": 6 }, diff --git a/crates/wit-parser/tests/ui/multi-file.wit.json b/crates/wit-parser/tests/ui/multi-file.wit.json index 45af0f5d32..6da127c468 100644 --- a/crates/wit-parser/tests/ui/multi-file.wit.json +++ b/crates/wit-parser/tests/ui/multi-file.wit.json @@ -283,6 +283,7 @@ "packages": [ { "name": "foo:multi-file", + "kind": "Implicit", "interfaces": { "irrelevant-name": 0, "depend-on-me": 1, diff --git a/crates/wit-parser/tests/ui/multi-package-shared-deps.wit.json b/crates/wit-parser/tests/ui/multi-package-shared-deps.wit.json index d3434da0c5..43cd97987a 100644 --- a/crates/wit-parser/tests/ui/multi-package-shared-deps.wit.json +++ b/crates/wit-parser/tests/ui/multi-package-shared-deps.wit.json @@ -53,6 +53,7 @@ "packages": [ { "name": "foo:dep1", + "kind": "Implicit", "interfaces": { "types": 0 }, @@ -60,6 +61,7 @@ }, { "name": "foo:dep2", + "kind": "Implicit", "interfaces": { "types": 1 }, @@ -67,6 +69,7 @@ }, { "name": "foo:bar", + "kind": "Explicit", "interfaces": {}, "worlds": { "w-bar": 0 @@ -74,6 +77,7 @@ }, { "name": "foo:qux", + "kind": "Explicit", "interfaces": {}, "worlds": { "w-qux": 1 diff --git a/crates/wit-parser/tests/ui/multi-package-transitive-deps.wit.json b/crates/wit-parser/tests/ui/multi-package-transitive-deps.wit.json index ece4cdade9..0fdb4dd5a9 100644 --- a/crates/wit-parser/tests/ui/multi-package-transitive-deps.wit.json +++ b/crates/wit-parser/tests/ui/multi-package-transitive-deps.wit.json @@ -86,6 +86,7 @@ "packages": [ { "name": "foo:dep2", + "kind": "Implicit", "interfaces": { "types": 0 }, @@ -93,6 +94,7 @@ }, { "name": "foo:dep1", + "kind": "Implicit", "interfaces": { "types": 1 }, @@ -100,6 +102,7 @@ }, { "name": "foo:bar", + "kind": "Explicit", "interfaces": {}, "worlds": { "w-bar": 0 @@ -107,6 +110,7 @@ }, { "name": "foo:qux", + "kind": "Explicit", "interfaces": {}, "worlds": { "w-qux": 1 diff --git a/crates/wit-parser/tests/ui/name-both-resource-and-type.wit.json b/crates/wit-parser/tests/ui/name-both-resource-and-type.wit.json index 1dad5120b5..ac93129918 100644 --- a/crates/wit-parser/tests/ui/name-both-resource-and-type.wit.json +++ b/crates/wit-parser/tests/ui/name-both-resource-and-type.wit.json @@ -73,6 +73,7 @@ "packages": [ { "name": "some:dep", + "kind": "Implicit", "interfaces": { "foo": 0 }, @@ -80,6 +81,7 @@ }, { "name": "foo:bar", + "kind": "Implicit", "interfaces": { "foo": 1 }, diff --git a/crates/wit-parser/tests/ui/package-syntax1.wit.json b/crates/wit-parser/tests/ui/package-syntax1.wit.json index 80af0cbb3b..5bf7712909 100644 --- a/crates/wit-parser/tests/ui/package-syntax1.wit.json +++ b/crates/wit-parser/tests/ui/package-syntax1.wit.json @@ -5,6 +5,7 @@ "packages": [ { "name": "foo:foo", + "kind": "Implicit", "interfaces": {}, "worlds": {} } diff --git a/crates/wit-parser/tests/ui/package-syntax3.wit.json b/crates/wit-parser/tests/ui/package-syntax3.wit.json index e0323c511b..8ff0a1ea2a 100644 --- a/crates/wit-parser/tests/ui/package-syntax3.wit.json +++ b/crates/wit-parser/tests/ui/package-syntax3.wit.json @@ -5,6 +5,7 @@ "packages": [ { "name": "foo:bar", + "kind": "Implicit", "interfaces": {}, "worlds": {} } diff --git a/crates/wit-parser/tests/ui/package-syntax4.wit.json b/crates/wit-parser/tests/ui/package-syntax4.wit.json index 7bacc86f03..280678ddd5 100644 --- a/crates/wit-parser/tests/ui/package-syntax4.wit.json +++ b/crates/wit-parser/tests/ui/package-syntax4.wit.json @@ -5,6 +5,7 @@ "packages": [ { "name": "foo:bar@2.0.0", + "kind": "Implicit", "interfaces": {}, "worlds": {} } diff --git a/crates/wit-parser/tests/ui/packages-explicit-colliding-decl-names.wit.json b/crates/wit-parser/tests/ui/packages-explicit-colliding-decl-names.wit.json index f4c9e7055c..3b925bee34 100644 --- a/crates/wit-parser/tests/ui/packages-explicit-colliding-decl-names.wit.json +++ b/crates/wit-parser/tests/ui/packages-explicit-colliding-decl-names.wit.json @@ -110,6 +110,7 @@ "packages": [ { "name": "bar:name", + "kind": "Explicit", "interfaces": { "i": 0 }, @@ -119,6 +120,7 @@ }, { "name": "foo:name", + "kind": "Explicit", "interfaces": { "i": 2 }, diff --git a/crates/wit-parser/tests/ui/packages-explicit-internal-references.wit.json b/crates/wit-parser/tests/ui/packages-explicit-internal-references.wit.json index 1d59a07e3a..8edc232bd2 100644 --- a/crates/wit-parser/tests/ui/packages-explicit-internal-references.wit.json +++ b/crates/wit-parser/tests/ui/packages-explicit-internal-references.wit.json @@ -71,6 +71,7 @@ "packages": [ { "name": "foo:name", + "kind": "Explicit", "interfaces": { "i1": 0 }, @@ -78,6 +79,7 @@ }, { "name": "bar:name", + "kind": "Explicit", "interfaces": {}, "worlds": { "w1": 0 diff --git a/crates/wit-parser/tests/ui/packages-explicit-with-semver.wit.json b/crates/wit-parser/tests/ui/packages-explicit-with-semver.wit.json index 23a10462aa..fdbd064be1 100644 --- a/crates/wit-parser/tests/ui/packages-explicit-with-semver.wit.json +++ b/crates/wit-parser/tests/ui/packages-explicit-with-semver.wit.json @@ -110,6 +110,7 @@ "packages": [ { "name": "foo:name@1.0.0", + "kind": "Explicit", "interfaces": { "i1": 0 }, @@ -119,6 +120,7 @@ }, { "name": "foo:name@1.0.1", + "kind": "Explicit", "interfaces": { "i1": 2 }, diff --git a/crates/wit-parser/tests/ui/packages-multiple-explicit.wit.json b/crates/wit-parser/tests/ui/packages-multiple-explicit.wit.json index de73c51de3..c770931d30 100644 --- a/crates/wit-parser/tests/ui/packages-multiple-explicit.wit.json +++ b/crates/wit-parser/tests/ui/packages-multiple-explicit.wit.json @@ -110,6 +110,7 @@ "packages": [ { "name": "bar:name", + "kind": "Explicit", "interfaces": { "i2": 0 }, @@ -119,6 +120,7 @@ }, { "name": "foo:name", + "kind": "Explicit", "interfaces": { "i1": 2 }, diff --git a/crates/wit-parser/tests/ui/packages-single-explicit.wit.json b/crates/wit-parser/tests/ui/packages-single-explicit.wit.json index 3eefde2810..667eadfdaa 100644 --- a/crates/wit-parser/tests/ui/packages-single-explicit.wit.json +++ b/crates/wit-parser/tests/ui/packages-single-explicit.wit.json @@ -59,6 +59,7 @@ "packages": [ { "name": "foo:name", + "kind": "Explicit", "interfaces": { "i1": 0 }, diff --git a/crates/wit-parser/tests/ui/random.wit.json b/crates/wit-parser/tests/ui/random.wit.json index 5d46664671..977e824bb1 100644 --- a/crates/wit-parser/tests/ui/random.wit.json +++ b/crates/wit-parser/tests/ui/random.wit.json @@ -55,6 +55,7 @@ "packages": [ { "name": "wasi:random", + "kind": "Implicit", "interfaces": { "random": 0 }, diff --git a/crates/wit-parser/tests/ui/resources-empty.wit.json b/crates/wit-parser/tests/ui/resources-empty.wit.json index 6c40c61dfc..2adbff8138 100644 --- a/crates/wit-parser/tests/ui/resources-empty.wit.json +++ b/crates/wit-parser/tests/ui/resources-empty.wit.json @@ -63,6 +63,7 @@ "packages": [ { "name": "foo:resources-empty", + "kind": "Implicit", "interfaces": { "resources-empty": 0 }, diff --git a/crates/wit-parser/tests/ui/resources-multiple-returns-own.wit.json b/crates/wit-parser/tests/ui/resources-multiple-returns-own.wit.json index e7234f7ed8..f0bd001ecc 100644 --- a/crates/wit-parser/tests/ui/resources-multiple-returns-own.wit.json +++ b/crates/wit-parser/tests/ui/resources-multiple-returns-own.wit.json @@ -74,6 +74,7 @@ "packages": [ { "name": "foo:resources1", + "kind": "Implicit", "interfaces": { "resources1": 0 }, diff --git a/crates/wit-parser/tests/ui/resources-multiple.wit.json b/crates/wit-parser/tests/ui/resources-multiple.wit.json index 2914ab99d9..9a54b96240 100644 --- a/crates/wit-parser/tests/ui/resources-multiple.wit.json +++ b/crates/wit-parser/tests/ui/resources-multiple.wit.json @@ -272,6 +272,7 @@ "packages": [ { "name": "foo:resources-multiple", + "kind": "Implicit", "interfaces": { "resources-multiple": 0 }, diff --git a/crates/wit-parser/tests/ui/resources-return-own.wit.json b/crates/wit-parser/tests/ui/resources-return-own.wit.json index 3e44fc106c..0b2f0103d8 100644 --- a/crates/wit-parser/tests/ui/resources-return-own.wit.json +++ b/crates/wit-parser/tests/ui/resources-return-own.wit.json @@ -69,6 +69,7 @@ "packages": [ { "name": "foo:resources1", + "kind": "Implicit", "interfaces": { "resources1": 0 }, diff --git a/crates/wit-parser/tests/ui/resources.wit.json b/crates/wit-parser/tests/ui/resources.wit.json index 169fb02110..28b845fd30 100644 --- a/crates/wit-parser/tests/ui/resources.wit.json +++ b/crates/wit-parser/tests/ui/resources.wit.json @@ -328,6 +328,7 @@ "packages": [ { "name": "foo:bar", + "kind": "Implicit", "interfaces": { "foo": 0, "i": 1 diff --git a/crates/wit-parser/tests/ui/resources1.wit.json b/crates/wit-parser/tests/ui/resources1.wit.json index 447e5ec2b9..1883d6f6ef 100644 --- a/crates/wit-parser/tests/ui/resources1.wit.json +++ b/crates/wit-parser/tests/ui/resources1.wit.json @@ -87,6 +87,7 @@ "packages": [ { "name": "foo:resources1", + "kind": "Implicit", "interfaces": { "resources1": 0 }, diff --git a/crates/wit-parser/tests/ui/same-name-import-export.wit.json b/crates/wit-parser/tests/ui/same-name-import-export.wit.json index 3cf1798d93..a440e633d3 100644 --- a/crates/wit-parser/tests/ui/same-name-import-export.wit.json +++ b/crates/wit-parser/tests/ui/same-name-import-export.wit.json @@ -38,6 +38,7 @@ "packages": [ { "name": "demo:greeter", + "kind": "Implicit", "interfaces": {}, "worlds": { "greeter": 0 diff --git a/crates/wit-parser/tests/ui/shared-types.wit.json b/crates/wit-parser/tests/ui/shared-types.wit.json index 569f6d3861..7a0875d84e 100644 --- a/crates/wit-parser/tests/ui/shared-types.wit.json +++ b/crates/wit-parser/tests/ui/shared-types.wit.json @@ -78,6 +78,7 @@ "packages": [ { "name": "foo:shared-items", + "kind": "Implicit", "interfaces": {}, "worlds": { "foo": 0 diff --git a/crates/wit-parser/tests/ui/simple-wasm-text.wit.json b/crates/wit-parser/tests/ui/simple-wasm-text.wit.json index 969c13a506..5e575b16c1 100644 --- a/crates/wit-parser/tests/ui/simple-wasm-text.wit.json +++ b/crates/wit-parser/tests/ui/simple-wasm-text.wit.json @@ -12,6 +12,7 @@ "packages": [ { "name": "a:b", + "kind": "Implicit", "interfaces": { "x": 0 }, diff --git a/crates/wit-parser/tests/ui/since-and-unstable.wit.json b/crates/wit-parser/tests/ui/since-and-unstable.wit.json index 31c4fa0c4b..c27dad3e43 100644 --- a/crates/wit-parser/tests/ui/since-and-unstable.wit.json +++ b/crates/wit-parser/tests/ui/since-and-unstable.wit.json @@ -566,6 +566,7 @@ "packages": [ { "name": "a:b@1.0.1", + "kind": "Implicit", "interfaces": { "foo1": 0, "foo2": 1, diff --git a/crates/wit-parser/tests/ui/stress-export-elaborate.wit.json b/crates/wit-parser/tests/ui/stress-export-elaborate.wit.json index d77812776b..55d6f68e0b 100644 --- a/crates/wit-parser/tests/ui/stress-export-elaborate.wit.json +++ b/crates/wit-parser/tests/ui/stress-export-elaborate.wit.json @@ -1136,6 +1136,7 @@ "packages": [ { "name": "foo:bar", + "kind": "Implicit", "interfaces": { "i1": 0, "i2": 1, diff --git a/crates/wit-parser/tests/ui/type-then-eof.wit.json b/crates/wit-parser/tests/ui/type-then-eof.wit.json index beb0a7adca..85a5688d5e 100644 --- a/crates/wit-parser/tests/ui/type-then-eof.wit.json +++ b/crates/wit-parser/tests/ui/type-then-eof.wit.json @@ -23,6 +23,7 @@ "packages": [ { "name": "foo:foo", + "kind": "Implicit", "interfaces": { "foo": 0 }, diff --git a/crates/wit-parser/tests/ui/types.wit.json b/crates/wit-parser/tests/ui/types.wit.json index 8874e3541d..d428f7f671 100644 --- a/crates/wit-parser/tests/ui/types.wit.json +++ b/crates/wit-parser/tests/ui/types.wit.json @@ -765,6 +765,7 @@ "packages": [ { "name": "foo:types", + "kind": "Implicit", "interfaces": { "types": 0 }, diff --git a/crates/wit-parser/tests/ui/union-fuzz-1.wit.json b/crates/wit-parser/tests/ui/union-fuzz-1.wit.json index 31c7c82687..705cd46134 100644 --- a/crates/wit-parser/tests/ui/union-fuzz-1.wit.json +++ b/crates/wit-parser/tests/ui/union-fuzz-1.wit.json @@ -24,6 +24,7 @@ "packages": [ { "name": "foo:bar", + "kind": "Implicit", "interfaces": {}, "worlds": { "xo": 0, diff --git a/crates/wit-parser/tests/ui/union-fuzz-2.wit.json b/crates/wit-parser/tests/ui/union-fuzz-2.wit.json index 6d1bc4ffd4..c722de0429 100644 --- a/crates/wit-parser/tests/ui/union-fuzz-2.wit.json +++ b/crates/wit-parser/tests/ui/union-fuzz-2.wit.json @@ -62,6 +62,7 @@ "packages": [ { "name": "foo:bar", + "kind": "Implicit", "interfaces": {}, "worlds": { "foo": 0, diff --git a/crates/wit-parser/tests/ui/use-chain.wit.json b/crates/wit-parser/tests/ui/use-chain.wit.json index bd942bb8cd..824f2e646e 100644 --- a/crates/wit-parser/tests/ui/use-chain.wit.json +++ b/crates/wit-parser/tests/ui/use-chain.wit.json @@ -43,6 +43,7 @@ "packages": [ { "name": "foo:name", + "kind": "Implicit", "interfaces": { "foo": 0, "name": 1 diff --git a/crates/wit-parser/tests/ui/use.wit.json b/crates/wit-parser/tests/ui/use.wit.json index 43cc16b4a7..c3dce34734 100644 --- a/crates/wit-parser/tests/ui/use.wit.json +++ b/crates/wit-parser/tests/ui/use.wit.json @@ -157,6 +157,7 @@ "packages": [ { "name": "foo:foo", + "kind": "Implicit", "interfaces": { "bar": 0, "foo": 1, diff --git a/crates/wit-parser/tests/ui/versions.wit.json b/crates/wit-parser/tests/ui/versions.wit.json index febd55be51..daaaf6fec0 100644 --- a/crates/wit-parser/tests/ui/versions.wit.json +++ b/crates/wit-parser/tests/ui/versions.wit.json @@ -68,6 +68,7 @@ "packages": [ { "name": "a:a@1.0.0", + "kind": "Implicit", "interfaces": { "foo": 0 }, @@ -75,6 +76,7 @@ }, { "name": "a:a@2.0.0", + "kind": "Implicit", "interfaces": { "foo": 1 }, @@ -82,6 +84,7 @@ }, { "name": "foo:versions", + "kind": "Implicit", "interfaces": { "foo": 2 }, diff --git a/crates/wit-parser/tests/ui/wasi.wit.json b/crates/wit-parser/tests/ui/wasi.wit.json index e784fbd207..c0fa5b6ba3 100644 --- a/crates/wit-parser/tests/ui/wasi.wit.json +++ b/crates/wit-parser/tests/ui/wasi.wit.json @@ -530,6 +530,7 @@ "packages": [ { "name": "wasi:filesystem", + "kind": "Implicit", "interfaces": { "wasi": 0 }, diff --git a/crates/wit-parser/tests/ui/world-diamond.wit.json b/crates/wit-parser/tests/ui/world-diamond.wit.json index 6dba45edb9..e5155cdc76 100644 --- a/crates/wit-parser/tests/ui/world-diamond.wit.json +++ b/crates/wit-parser/tests/ui/world-diamond.wit.json @@ -111,6 +111,7 @@ "packages": [ { "name": "foo:foo", + "kind": "Implicit", "interfaces": { "shared-items": 0, "i1": 1, diff --git a/crates/wit-parser/tests/ui/world-iface-no-collide.wit.json b/crates/wit-parser/tests/ui/world-iface-no-collide.wit.json index fffc11557e..2417a6adae 100644 --- a/crates/wit-parser/tests/ui/world-iface-no-collide.wit.json +++ b/crates/wit-parser/tests/ui/world-iface-no-collide.wit.json @@ -57,6 +57,7 @@ "packages": [ { "name": "foo:foo", + "kind": "Implicit", "interfaces": { "foo": 0 }, diff --git a/crates/wit-parser/tests/ui/world-implicit-import1.wit.json b/crates/wit-parser/tests/ui/world-implicit-import1.wit.json index 708c339b40..d155847021 100644 --- a/crates/wit-parser/tests/ui/world-implicit-import1.wit.json +++ b/crates/wit-parser/tests/ui/world-implicit-import1.wit.json @@ -70,6 +70,7 @@ "packages": [ { "name": "foo:foo", + "kind": "Implicit", "interfaces": { "foo": 0 }, diff --git a/crates/wit-parser/tests/ui/world-implicit-import2.wit.json b/crates/wit-parser/tests/ui/world-implicit-import2.wit.json index 97049842a4..d48070dead 100644 --- a/crates/wit-parser/tests/ui/world-implicit-import2.wit.json +++ b/crates/wit-parser/tests/ui/world-implicit-import2.wit.json @@ -61,6 +61,7 @@ "packages": [ { "name": "foo:foo", + "kind": "Implicit", "interfaces": { "foo": 0 }, diff --git a/crates/wit-parser/tests/ui/world-implicit-import3.wit.json b/crates/wit-parser/tests/ui/world-implicit-import3.wit.json index 159bee7738..3fd6405789 100644 --- a/crates/wit-parser/tests/ui/world-implicit-import3.wit.json +++ b/crates/wit-parser/tests/ui/world-implicit-import3.wit.json @@ -62,6 +62,7 @@ "packages": [ { "name": "foo:foo", + "kind": "Implicit", "interfaces": { "foo": 0 }, diff --git a/crates/wit-parser/tests/ui/world-same-fields4.wit.json b/crates/wit-parser/tests/ui/world-same-fields4.wit.json index 3be16acf9b..b7eac1c81b 100644 --- a/crates/wit-parser/tests/ui/world-same-fields4.wit.json +++ b/crates/wit-parser/tests/ui/world-same-fields4.wit.json @@ -71,6 +71,7 @@ "packages": [ { "name": "foo:foo", + "kind": "Implicit", "interfaces": { "shared-items": 0 }, diff --git a/crates/wit-parser/tests/ui/world-top-level-funcs.wit.json b/crates/wit-parser/tests/ui/world-top-level-funcs.wit.json index b7866aa12d..0c164071ec 100644 --- a/crates/wit-parser/tests/ui/world-top-level-funcs.wit.json +++ b/crates/wit-parser/tests/ui/world-top-level-funcs.wit.json @@ -77,6 +77,7 @@ "packages": [ { "name": "foo:foo", + "kind": "Implicit", "interfaces": {}, "worlds": { "foo": 0 diff --git a/crates/wit-parser/tests/ui/world-top-level-resources.wit.json b/crates/wit-parser/tests/ui/world-top-level-resources.wit.json index 794e699f45..4ba6711832 100644 --- a/crates/wit-parser/tests/ui/world-top-level-resources.wit.json +++ b/crates/wit-parser/tests/ui/world-top-level-resources.wit.json @@ -225,6 +225,7 @@ "packages": [ { "name": "foo:foo", + "kind": "Implicit", "interfaces": { "types": 0, "handler": 1 diff --git a/crates/wit-parser/tests/ui/worlds-union-dedup.wit.json b/crates/wit-parser/tests/ui/worlds-union-dedup.wit.json index d1e24e97b6..e1d37c8927 100644 --- a/crates/wit-parser/tests/ui/worlds-union-dedup.wit.json +++ b/crates/wit-parser/tests/ui/worlds-union-dedup.wit.json @@ -94,6 +94,7 @@ "packages": [ { "name": "foo:foo", + "kind": "Implicit", "interfaces": { "a1": 0, "a2": 1, diff --git a/crates/wit-parser/tests/ui/worlds-with-types.wit.json b/crates/wit-parser/tests/ui/worlds-with-types.wit.json index 70e857d68b..fed7ae5e77 100644 --- a/crates/wit-parser/tests/ui/worlds-with-types.wit.json +++ b/crates/wit-parser/tests/ui/worlds-with-types.wit.json @@ -191,6 +191,7 @@ "packages": [ { "name": "foo:foo", + "kind": "Implicit", "interfaces": { "disambiguate": 0 }, diff --git a/tests/cli/wit-stability-in-binary-format.wit.stdout b/tests/cli/wit-stability-in-binary-format.wit.stdout index f3191af2d4..d9bf5d5dae 100644 --- a/tests/cli/wit-stability-in-binary-format.wit.stdout +++ b/tests/cli/wit-stability-in-binary-format.wit.stdout @@ -1,39 +1,25 @@ -/// RUN: component wit % --wasm | component wit package a:b; -@since(version = 1.0.0) interface foo { - @since(version = 1.0.0) type t = u32; - @since(version = 1.0.0) resource r { - @since(version = 1.0.0) constructor(); } - @since(version = 1.0.0) f: func(); } -@since(version = 1.0.0) world w { - @since(version = 1.0.0) import foo; - @since(version = 1.0.0) import a: interface { } - @since(version = 1.0.0) import f: func(); - @since(version = 1.0.0) type t = u32; - @since(version = 1.0.0) export f: func(); - @since(version = 1.0.0) export foo; - @since(version = 1.0.0) export a: interface { } }