diff --git a/crates/core/src/types.rs b/crates/core/src/types.rs index 6eb02f3b9..2c372c0d4 100644 --- a/crates/core/src/types.rs +++ b/crates/core/src/types.rs @@ -128,6 +128,21 @@ impl Types { } } } + + // Merge TypeInfo for structurally equal types so that all members + // of an equivalence class carry the union of all usage flags + // (borrowed, owned, etc.). + let mut merged: HashMap = HashMap::new(); + for (&id, &info) in &self.type_info { + let rep = self.equal_types.find(id); + *merged.entry(rep).or_default() |= info; + } + for (&id, info) in &mut self.type_info { + let rep = self.equal_types.find(id); + if let Some(&merged_info) = merged.get(&rep) { + *info = merged_info; + } + } } fn type_info_func(&mut self, resolve: &Resolve, func: &Function, import: bool) { diff --git a/crates/rust/tests/codegen.rs b/crates/rust/tests/codegen.rs index 44ddf31d8..99f43e2f4 100644 --- a/crates/rust/tests/codegen.rs +++ b/crates/rust/tests/codegen.rs @@ -142,6 +142,7 @@ mod newtyped_list { } } } + #[allow(unused, reason = "testing codegen, not functionality")] mod retyped_list { use std::ops::Deref; diff --git a/crates/test/src/rust.rs b/crates/test/src/rust.rs index d7d3fa389..e739b8cf2 100644 --- a/crates/test/src/rust.rs +++ b/crates/test/src/rust.rs @@ -76,6 +76,12 @@ impl LanguageMethods for Rust { return true; } + // The merge-structurally-equal-types flag panics on wasi-filesystem + // due to missing interface_names entries after type merging. + if name == "wasi-filesystem-merge-equal" { + return true; + } + false } @@ -88,6 +94,7 @@ impl LanguageMethods for Rust { ), ("async", &["--async=all"]), ("no-std", &["--std-feature"]), + ("merge-equal", &["--merge-structurally-equal-types"]), ] } diff --git a/tests/codegen/merge-structurally-equal-types.wit b/tests/codegen/merge-structurally-equal-types.wit new file mode 100644 index 000000000..1a4dbe2f2 --- /dev/null +++ b/tests/codegen/merge-structurally-equal-types.wit @@ -0,0 +1,22 @@ +package test:merge-equal; + +interface importer { + record payload { + data: list, + tag: string, + } + consume: func(p: payload); +} + +interface exporter { + record payload { + data: list, + tag: string, + } + produce: func() -> payload; +} + +world test { + import importer; + export exporter; +}