Skip to content

Commit 50b799a

Browse files
authored
Add support for named implements in Go (#1657)
* Add support for named implements in Go Signed-off-by: Jeremy Fleitz <jeremy@cosmonic.com> * clippy: use package.clear() Signed-off-by: Jeremy Fleitz <jeremy@cosmonic.com> * support implements for cpp Signed-off-by: Jeremy Fleitz <jeremy@cosmonic.com> * linter fix Signed-off-by: Jeremy Fleitz <jeremy@cosmonic.com> * update to go_package_name Signed-off-by: Jeremy Fleitz <jeremy@cosmonic.com> * linter update Signed-off-by: Jeremy Fleitz <jeremy@cosmonic.com> --------- Signed-off-by: Jeremy Fleitz <jeremy@cosmonic.com>
1 parent 93a5f4e commit 50b799a

4 files changed

Lines changed: 103 additions & 56 deletions

File tree

‎crates/cpp/src/lib.rs‎

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ struct Cpp {
103103
world: String,
104104
world_id: Option<WorldId>,
105105
imported_interfaces: HashSet<InterfaceId>,
106+
instance_names: HashMap<InterfaceId, String>,
106107
user_class_files: HashMap<String, String>,
107108
defined_types: HashSet<(Vec<String>, String)>,
108109
types: Types,
@@ -283,6 +284,17 @@ impl Cpp {
283284
Cpp::default()
284285
}
285286

287+
fn update_instance_name(&mut self, resolve: &Resolve, name: &WorldKey, id: InterfaceId) {
288+
match name {
289+
WorldKey::Name(instance) if resolve.interfaces[id].name.is_some() => {
290+
self.instance_names.insert(id, instance.clone());
291+
}
292+
_ => {
293+
self.instance_names.remove(&id);
294+
}
295+
}
296+
}
297+
286298
pub fn is_first_definition(&mut self, ns: &Vec<String>, name: &str) -> bool {
287299
let owned = (ns.to_owned(), name.to_owned());
288300
if !self.defined_types.contains(&owned) {
@@ -522,6 +534,7 @@ impl WorldGenerator for Cpp {
522534
_files: &mut Files,
523535
) -> anyhow::Result<()> {
524536
self.imported_interfaces.insert(id);
537+
self.update_instance_name(resolve, name, id);
525538

526539
let full_name = resolve.name_world_key(name);
527540
match self.opts.with.iter().find(|e| e.0 == full_name) {
@@ -538,8 +551,7 @@ impl WorldGenerator for Cpp {
538551
let binding = Some(name);
539552
let mut r#gen = self.interface(resolve, binding, true, Some(wasm_import_module));
540553
r#gen.interface = Some(id);
541-
let namespace =
542-
namespace(resolve, &TypeOwner::Interface(id), false, &r#gen.r#gen.opts);
554+
let namespace = namespace(resolve, &TypeOwner::Interface(id), false, &*r#gen.r#gen);
543555
let docs = resolve.interfaces[id].docs.contents.as_deref();
544556
r#gen
545557
.r#gen
@@ -590,11 +602,12 @@ impl WorldGenerator for Cpp {
590602
.src
591603
.push_str(&format!("// export_interface {name:?}\n"));
592604
self.imported_interfaces.remove(&id);
605+
self.update_instance_name(resolve, name, id);
593606
let wasm_import_module = resolve.name_world_key(name);
594607
let binding = Some(name);
595608
let mut r#gen = self.interface(resolve, binding, false, Some(wasm_import_module));
596609
r#gen.interface = Some(id);
597-
let namespace = namespace(resolve, &TypeOwner::Interface(id), true, &r#gen.r#gen.opts);
610+
let namespace = namespace(resolve, &TypeOwner::Interface(id), true, &*r#gen.r#gen);
598611
let docs = resolve.interfaces[id].docs.contents.as_deref();
599612
r#gen
600613
.r#gen
@@ -624,7 +637,7 @@ impl WorldGenerator for Cpp {
624637
let wasm_import_module = resolve.name_world_key(&name);
625638
let binding = Some(name);
626639
let mut r#gen = self.interface(resolve, binding.as_ref(), true, Some(wasm_import_module));
627-
let namespace = namespace(resolve, &TypeOwner::World(world), false, &r#gen.r#gen.opts);
640+
let namespace = namespace(resolve, &TypeOwner::World(world), false, &*r#gen.r#gen);
628641

629642
for (_name, func) in funcs.iter() {
630643
if matches!(func.kind, FunctionKind::Freestanding) {
@@ -644,7 +657,7 @@ impl WorldGenerator for Cpp {
644657
let name = WorldKey::Name(resolve.worlds[world].name.clone());
645658
let binding = Some(name);
646659
let mut r#gen = self.interface(resolve, binding.as_ref(), false, None);
647-
let namespace = namespace(resolve, &TypeOwner::World(world), true, &r#gen.r#gen.opts);
660+
let namespace = namespace(resolve, &TypeOwner::World(world), true, &*r#gen.r#gen);
648661

649662
for (_name, func) in funcs.iter() {
650663
if matches!(func.kind, FunctionKind::Freestanding) {
@@ -779,9 +792,9 @@ impl WorldGenerator for Cpp {
779792
}
780793

781794
// determine namespace (for the lifted C++ function)
782-
fn namespace(resolve: &Resolve, owner: &TypeOwner, guest_export: bool, opts: &Opts) -> Vec<String> {
795+
fn namespace(resolve: &Resolve, owner: &TypeOwner, guest_export: bool, r#gen: &Cpp) -> Vec<String> {
783796
let mut result = Vec::default();
784-
if let Some(prefix) = &opts.internal_prefix {
797+
if let Some(prefix) = &r#gen.opts.internal_prefix {
785798
result.push(prefix.clone());
786799
}
787800
if guest_export {
@@ -790,14 +803,18 @@ fn namespace(resolve: &Resolve, owner: &TypeOwner, guest_export: bool, opts: &Op
790803
match owner {
791804
TypeOwner::World(w) => result.push(to_c_ident(&resolve.worlds[*w].name)),
792805
TypeOwner::Interface(i) => {
793-
let iface = &resolve.interfaces[*i];
794-
let pkg_id = iface.package.unwrap();
795-
let pkg = &resolve.packages[pkg_id];
796-
result.push(to_c_ident(&pkg.name.namespace));
797-
// Use name_package_module to get version-specific package names
798-
result.push(to_c_ident(&name_package_module(resolve, pkg_id)));
799-
if let Some(name) = &iface.name {
800-
result.push(to_c_ident(name));
806+
if let Some(instance) = r#gen.instance_names.get(i) {
807+
result.push(to_c_ident(instance));
808+
} else {
809+
let iface = &resolve.interfaces[*i];
810+
let pkg_id = iface.package.unwrap();
811+
let pkg = &resolve.packages[pkg_id];
812+
result.push(to_c_ident(&pkg.name.namespace));
813+
// Use name_package_module to get version-specific package names
814+
result.push(to_c_ident(&name_package_module(resolve, pkg_id)));
815+
if let Some(name) = &iface.name {
816+
result.push(to_c_ident(name));
817+
}
801818
}
802819
}
803820
TypeOwner::None => (),
@@ -941,7 +958,7 @@ impl CppInterfaceGenerator<'_> {
941958
.map(TypeOwner::Interface)
942959
.unwrap_or(TypeOwner::World(self.r#gen.world_id.unwrap())),
943960
));
944-
let mut namespace = namespace(self.resolve, &owner, guest_export, &self.r#gen.opts);
961+
let mut namespace = namespace(self.resolve, &owner, guest_export, &*self.r#gen);
945962
let is_drop = is_special_method(func);
946963
let func_name_h = if !matches!(&func.kind, FunctionKind::Freestanding) {
947964
namespace.push(object.clone());
@@ -1294,7 +1311,7 @@ impl CppInterfaceGenerator<'_> {
12941311
cifg.resolve,
12951312
&owner.owner,
12961313
matches!(variant, AbiVariant::GuestExport),
1297-
&cifg.r#gen.opts,
1314+
&*cifg.r#gen,
12981315
);
12991316
namespace.push(owner.name.as_ref().unwrap().to_upper_camel_case());
13001317
namespace
@@ -1403,7 +1420,7 @@ impl CppInterfaceGenerator<'_> {
14031420
self.resolve,
14041421
owner,
14051422
matches!(variant, AbiVariant::GuestExport),
1406-
&self.r#gen.opts,
1423+
&*self.r#gen,
14071424
)
14081425
} else {
14091426
let owner = &self.resolve.types[match &func.kind {
@@ -1420,7 +1437,7 @@ impl CppInterfaceGenerator<'_> {
14201437
self.resolve,
14211438
&owner.owner,
14221439
matches!(variant, AbiVariant::GuestExport),
1423-
&self.r#gen.opts,
1440+
&*self.r#gen,
14241441
);
14251442
namespace.push(owner.name.as_ref().unwrap().to_upper_camel_case());
14261443
namespace
@@ -1534,7 +1551,7 @@ impl CppInterfaceGenerator<'_> {
15341551
guest_export: bool,
15351552
) -> String {
15361553
let ty = &self.resolve.types[id];
1537-
let namespc = namespace(self.resolve, &ty.owner, guest_export, &self.r#gen.opts);
1554+
let namespc = namespace(self.resolve, &ty.owner, guest_export, &*self.r#gen);
15381555
let mut relative = SourceWithState {
15391556
namespace: Vec::from(from_namespace),
15401557
..Default::default()
@@ -1882,7 +1899,7 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for CppInterfaceGenerator<'a>
18821899
) {
18831900
let ty = &self.resolve.types[id];
18841901
let guest_export = self.is_exported_type(ty);
1885-
let namespc = namespace(self.resolve, &ty.owner, guest_export, &self.r#gen.opts);
1902+
let namespc = namespace(self.resolve, &ty.owner, guest_export, &*self.r#gen);
18861903

18871904
if self.r#gen.is_first_definition(&namespc, name) {
18881905
self.r#gen.h_src.change_namespace(&namespc);
@@ -1914,7 +1931,7 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for CppInterfaceGenerator<'a>
19141931
let store = self.r#gen.start_new_file(Some(definition));
19151932
let mut world_name = to_c_ident(&self.r#gen.world);
19161933
world_name.push_str("::");
1917-
let namespc = namespace(self.resolve, &type_.owner, !guest_import, &self.r#gen.opts);
1934+
let namespc = namespace(self.resolve, &type_.owner, !guest_import, &*self.r#gen);
19181935
let pascal = name.to_upper_camel_case();
19191936
let mut user_filename = namespc.clone();
19201937
user_filename.push(pascal.clone());
@@ -2087,7 +2104,7 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for CppInterfaceGenerator<'a>
20872104
} else if matches!(type_.owner, TypeOwner::World(_)) {
20882105
// Handle world-level resources - treat as imported resources
20892106
let guest_export = false; // World-level resources are treated as imports
2090-
let namespc = namespace(self.resolve, &type_.owner, guest_export, &self.r#gen.opts);
2107+
let namespc = namespace(self.resolve, &type_.owner, guest_export, &*self.r#gen);
20912108
self.r#gen.h_src.change_namespace(&namespc);
20922109

20932110
let pascal = name.to_upper_camel_case();
@@ -2123,7 +2140,7 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for CppInterfaceGenerator<'a>
21232140
) {
21242141
let ty = &self.resolve.types[id];
21252142
let guest_export = self.is_exported_type(ty);
2126-
let namespc = namespace(self.resolve, &ty.owner, guest_export, &self.r#gen.opts);
2143+
let namespc = namespace(self.resolve, &ty.owner, guest_export, &*self.r#gen);
21272144
if self.r#gen.is_first_definition(&namespc, name) {
21282145
self.r#gen.h_src.change_namespace(&namespc);
21292146
Self::docs(&mut self.r#gen.h_src.src, docs);
@@ -2164,7 +2181,7 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for CppInterfaceGenerator<'a>
21642181
) {
21652182
let ty = &self.resolve.types[id];
21662183
let guest_export = self.is_exported_type(ty);
2167-
let namespc = namespace(self.resolve, &ty.owner, guest_export, &self.r#gen.opts);
2184+
let namespc = namespace(self.resolve, &ty.owner, guest_export, &*self.r#gen);
21682185
if self.r#gen.is_first_definition(&namespc, name) {
21692186
self.r#gen.h_src.change_namespace(&namespc);
21702187
Self::docs(&mut self.r#gen.h_src.src, docs);
@@ -2225,7 +2242,7 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for CppInterfaceGenerator<'a>
22252242
) {
22262243
let ty = &self.resolve.types[id];
22272244
let guest_export = self.is_exported_type(ty);
2228-
let namespc = namespace(self.resolve, &ty.owner, guest_export, &self.r#gen.opts);
2245+
let namespc = namespace(self.resolve, &ty.owner, guest_export, &*self.r#gen);
22292246
if self.r#gen.is_first_definition(&namespc, name) {
22302247
self.r#gen.h_src.change_namespace(&namespc);
22312248
let pascal = name.to_pascal_case();
@@ -2253,7 +2270,7 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for CppInterfaceGenerator<'a>
22532270
) {
22542271
let ty = &self.resolve.types[id];
22552272
let guest_export = self.is_exported_type(ty);
2256-
let namespc = namespace(self.resolve, &ty.owner, guest_export, &self.r#gen.opts);
2273+
let namespc = namespace(self.resolve, &ty.owner, guest_export, &*self.r#gen);
22572274
self.r#gen.h_src.change_namespace(&namespc);
22582275
let pascal = name.to_pascal_case();
22592276
Self::docs(&mut self.r#gen.h_src.src, docs);

‎crates/go/src/lib.rs‎

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,8 @@ struct Go {
221221
interface_names: HashMap<InterfaceId, WorldKey>,
222222
interfaces: BTreeMap<String, InterfaceData>,
223223
export_interfaces: BTreeMap<String, InterfaceData>,
224-
types: HashSet<TypeId>,
224+
// Add String to the types to allow for implements of the same type in different interfaces to be generated.
225+
types: HashSet<(String, TypeId)>,
225226
resources: HashMap<TypeId, Direction>,
226227
futures_and_streams: HashMap<(TypeId, bool), Option<WorldKey>>,
227228
}
@@ -251,7 +252,7 @@ impl Go {
251252
if local == owner && (exported ^ in_import) {
252253
String::new()
253254
} else {
254-
let package = self.interface_name(resolve, owner);
255+
let package = self.go_package_name(resolve, owner);
255256
let package = if exported {
256257
format!("export_{package}")
257258
} else {
@@ -637,7 +638,7 @@ func Lift{upper_kind}{camel}(handle int32) *witTypes.{upper_kind}Reader[{payload
637638
} else {
638639
format!(
639640
"{}_",
640-
self.interface_name(
641+
self.go_package_name(
641642
resolve,
642643
Some(
643644
&self
@@ -738,15 +739,17 @@ impl WorldGenerator for Go {
738739
id: InterfaceId,
739740
_files: &mut Files,
740741
) -> Result<()> {
741-
if let WorldKey::Name(_) = name {
742-
self.interface_names.insert(id, name.clone());
743-
}
742+
self.interface_names.insert(id, name.clone());
744743

744+
let go_package_name = self.go_package_name(resolve, Some(name));
745745
let mut data = {
746746
let mut generator = InterfaceGenerator::new(self, resolve, Some((id, name)), true);
747747
for (name, ty) in resolve.interfaces[id].types.iter() {
748-
if !generator.generator.types.contains(ty) {
749-
generator.generator.types.insert(*ty);
748+
if generator
749+
.generator
750+
.types
751+
.insert((go_package_name.clone(), *ty))
752+
{
750753
generator.define_type(name, *ty);
751754
}
752755
}
@@ -757,7 +760,7 @@ impl WorldGenerator for Go {
757760
data.extend(self.import(resolve, func, Some(name)));
758761
}
759762
self.interfaces
760-
.entry(self.interface_name(resolve, Some(name)))
763+
.entry(go_package_name)
761764
.or_default()
762765
.extend(data);
763766

@@ -776,7 +779,7 @@ impl WorldGenerator for Go {
776779
data.extend(self.import(resolve, func, None));
777780
}
778781
self.interfaces
779-
.entry(self.interface_name(resolve, None))
782+
.entry(self.go_package_name(resolve, None))
780783
.or_default()
781784
.extend(data);
782785
}
@@ -788,30 +791,32 @@ impl WorldGenerator for Go {
788791
id: InterfaceId,
789792
_files: &mut Files,
790793
) -> Result<()> {
791-
if let WorldKey::Name(_) = name {
792-
self.interface_names.insert(id, name.clone());
793-
}
794+
self.interface_names.insert(id, name.clone());
794795

796+
let go_package_name = self.go_package_name(resolve, Some(name));
795797
for (type_name, ty) in &resolve.interfaces[id].types {
796798
let exported = matches!(resolve.types[*ty].kind, TypeDefKind::Resource)
797799
|| self.has_exported_resource(resolve, Type::Id(*ty));
798800

799801
let mut generator = InterfaceGenerator::new(self, resolve, Some((id, name)), false);
800802

801-
if exported || !generator.generator.types.contains(ty) {
802-
generator.generator.types.insert(*ty);
803+
if generator
804+
.generator
805+
.types
806+
.insert((go_package_name.clone(), *ty))
807+
|| exported
808+
{
803809
generator.define_type(type_name, *ty);
804810
}
805811

806812
let data = generator.into();
807813

808-
let name = self.interface_name(resolve, Some(name));
809814
if exported {
810815
&mut self.export_interfaces
811816
} else {
812817
&mut self.interfaces
813818
}
814-
.entry(name)
819+
.entry(go_package_name.clone())
815820
.or_default()
816821
.extend(data);
817822
}
@@ -845,18 +850,15 @@ impl WorldGenerator for Go {
845850
types: &[(&str, TypeId)],
846851
_files: &mut Files,
847852
) {
853+
let package = self.go_package_name(resolve, None);
848854
let mut generator = InterfaceGenerator::new(self, resolve, None, true);
849855
for (name, ty) in types {
850-
if !generator.generator.types.contains(ty) {
851-
generator.generator.types.insert(*ty);
856+
if generator.generator.types.insert((package.clone(), *ty)) {
852857
generator.define_type(name, *ty);
853858
}
854859
}
855860
let data = generator.into();
856-
self.interfaces
857-
.entry(self.interface_name(resolve, None))
858-
.or_default()
859-
.extend(data);
861+
self.interfaces.entry(package).or_default().extend(data);
860862
}
861863

862864
fn finish(&mut self, resolve: &Resolve, id: WorldId, files: &mut Files) -> Result<()> {
@@ -1377,7 +1379,7 @@ func wasm_export_post_return_{name}(result {results}) {{
13771379
let results = self.func_results(resolve, func, interface, false, &mut imports);
13781380

13791381
self.export_interfaces
1380-
.entry(self.interface_name(resolve, interface))
1382+
.entry(self.go_package_name(resolve, interface))
13811383
.or_default()
13821384
.extend(InterfaceData {
13831385
code: format!(
@@ -1496,7 +1498,7 @@ func wasm_export_{name}({params}) {results} {{
14961498
&func.name,
14971499
);
14981500

1499-
let name = self.interface_name(resolve, interface);
1501+
let name = self.go_package_name(resolve, interface);
15001502
if in_import || !exported {
15011503
&mut self.interfaces
15021504
} else {
@@ -1522,7 +1524,7 @@ func wasm_export_{name}({params}) {results} {{
15221524
})
15231525
}
15241526

1525-
fn interface_name(&self, resolve: &Resolve, interface: Option<&WorldKey>) -> String {
1527+
fn go_package_name(&self, resolve: &Resolve, interface: Option<&WorldKey>) -> String {
15261528
match interface {
15271529
Some(WorldKey::Name(name)) => name.to_snake_case(),
15281530
Some(WorldKey::Interface(id)) => {
@@ -1557,7 +1559,7 @@ func wasm_export_{name}({params}) {results} {{
15571559
interface: Option<&WorldKey>,
15581560
func: &Function,
15591561
) -> String {
1560-
let prefix = self.interface_name(resolve, interface);
1562+
let prefix = self.go_package_name(resolve, interface);
15611563
let name = func.name.to_snake_case().replace('.', "_");
15621564

15631565
format!("{prefix}_{name}")
@@ -1853,7 +1855,7 @@ for index := 0; index < int({length}); index++ {{
18531855
let name = func.item_name().to_upper_camel_case();
18541856
let package = format!(
18551857
"export_{}",
1856-
self.generator.interface_name(resolve, self.interface)
1858+
self.generator.go_package_name(resolve, self.interface)
18571859
);
18581860

18591861
let call = match &func.kind {

0 commit comments

Comments
 (0)