|
1 | 1 | use crate::PackageId; |
2 | 2 | use indexmap::IndexMap; |
3 | 3 | use petgraph::graph::NodeIndex; |
| 4 | +use std::borrow::Cow; |
4 | 5 | use std::collections::HashMap; |
5 | 6 | use wac_types::{ |
6 | 7 | CoreExtern, DefinedType, DefinedTypeId, Enum, Flags, FuncTypeId, InterfaceId, ItemKind, |
7 | 8 | ModuleTypeId, PrimitiveType, Record, ResourceId, Type, Types, UsedType, ValueType, Variant, |
8 | 9 | WorldId, |
9 | 10 | }; |
10 | 11 | use wasm_encoder::{ |
11 | | - Alias, ComponentBuilder, ComponentCoreTypeEncoder, ComponentExportKind, |
| 12 | + Alias, ComponentBuilder, ComponentCoreTypeEncoder, ComponentExportKind, ComponentExternName, |
12 | 13 | ComponentOuterAliasKind, ComponentType, ComponentTypeEncoder, ComponentTypeRef, |
13 | 14 | ComponentValType, EntityType, GlobalType, InstanceType, MemoryType, ModuleType, TableType, |
14 | 15 | TagKind, TagType, TypeBounds, |
15 | 16 | }; |
| 17 | +use wasmparser::names::{ComponentName, ComponentNameKind}; |
| 18 | + |
| 19 | +/// Returns the `(implements "I")` interface id for an instance import or export, |
| 20 | +/// if its extern name is a plain-name label rather than an interface name. |
| 21 | +/// |
| 22 | +/// A component model `(implements "I")` import/export is an instance whose |
| 23 | +/// extern name is a plain-name label (e.g. `primary`) rather than an interface |
| 24 | +/// name, while the interface it implements has its own id (e.g. `foo:bar/iface`). |
| 25 | +/// A regular interface import/export instead uses the interface name itself as |
| 26 | +/// its extern name. |
| 27 | +pub(crate) fn implements_of<'a>(types: &'a Types, name: &str, id: InterfaceId) -> Option<&'a str> { |
| 28 | + types[id].id.as_deref().filter(|_| { |
| 29 | + matches!( |
| 30 | + ComponentName::new(name, 0).as_ref().map(|n| n.kind()), |
| 31 | + Ok(ComponentNameKind::Label(_)) |
| 32 | + ) |
| 33 | + }) |
| 34 | +} |
16 | 35 |
|
17 | 36 | /// A type used to abstract the API differences between a component builder, |
18 | 37 | /// component type, and instance type from `wasm-encoder`. |
@@ -65,7 +84,8 @@ impl Encodable { |
65 | 84 | } |
66 | 85 | } |
67 | 86 |
|
68 | | - fn import_type(&mut self, name: &str, ty: ComponentTypeRef) { |
| 87 | + fn import_type<'a>(&mut self, name: impl Into<ComponentExternName<'a>>, ty: ComponentTypeRef) { |
| 88 | + let name = name.into(); |
69 | 89 | match self { |
70 | 90 | Encodable::Component(t) => { |
71 | 91 | t.import(name, ty); |
@@ -730,13 +750,22 @@ impl<'a> TypeEncoder<'a> { |
730 | 750 | } |
731 | 751 | ItemKind::Instance(id) => { |
732 | 752 | let import_index = state.current.encodable.instance_count(); |
| 753 | + let implements = implements_of(self.0, name, id); |
| 754 | + let extern_name = ComponentExternName { |
| 755 | + name: Cow::Borrowed(name), |
| 756 | + implements: implements.map(Cow::Borrowed), |
| 757 | + }; |
733 | 758 | state |
734 | 759 | .current |
735 | 760 | .encodable |
736 | | - .import_type(name, ComponentTypeRef::Instance(index)); |
737 | | - if let Some(iid) = &self.0[id].id { |
738 | | - log::debug!("instance index {import_index} ({iid}) is available for aliasing"); |
739 | | - state.current.instances.insert(iid.clone(), import_index); |
| 761 | + .import_type(extern_name, ComponentTypeRef::Instance(index)); |
| 762 | + if implements.is_none() { |
| 763 | + if let Some(iid) = &self.0[id].id { |
| 764 | + log::debug!( |
| 765 | + "instance index {import_index} ({iid}) is available for aliasing" |
| 766 | + ); |
| 767 | + state.current.instances.insert(iid.clone(), import_index); |
| 768 | + } |
740 | 769 | } |
741 | 770 | } |
742 | 771 | _ => panic!("expected only types, functions, and instance types"), |
@@ -827,9 +856,19 @@ impl<'a> TypeEncoder<'a> { |
827 | 856 |
|
828 | 857 | let ty = kind.ty(); |
829 | 858 | let index = self.ty(state, ty, Some(name)); |
| 859 | + // Preserve the `(implements "I")` directive when re-encoding an |
| 860 | + // instance export that uses a plain-name label. |
| 861 | + let implements = match kind { |
| 862 | + ItemKind::Instance(id) => implements_of(self.0, name, id), |
| 863 | + _ => None, |
| 864 | + }; |
| 865 | + let extern_name = ComponentExternName { |
| 866 | + name: Cow::Borrowed(name), |
| 867 | + implements: implements.map(Cow::Borrowed), |
| 868 | + }; |
830 | 869 | let index = Self::export_type( |
831 | 870 | state, |
832 | | - name, |
| 871 | + extern_name, |
833 | 872 | match kind { |
834 | 873 | ItemKind::Type(_) => ComponentTypeRef::Type(TypeBounds::Eq(index)), |
835 | 874 | ItemKind::Func(_) => ComponentTypeRef::Func(index), |
@@ -880,7 +919,12 @@ impl<'a> TypeEncoder<'a> { |
880 | 919 | index |
881 | 920 | } |
882 | 921 |
|
883 | | - fn export_type(state: &mut State, name: &str, ty: ComponentTypeRef) -> u32 { |
| 922 | + fn export_type<'b>( |
| 923 | + state: &mut State, |
| 924 | + name: impl Into<ComponentExternName<'b>>, |
| 925 | + ty: ComponentTypeRef, |
| 926 | + ) -> u32 { |
| 927 | + let name = name.into(); |
884 | 928 | match &mut state.current.encodable { |
885 | 929 | Encodable::Component(t) => { |
886 | 930 | let index = t.type_count(); |
|
0 commit comments