Skip to content

Commit 4a48c99

Browse files
authored
fix(rust): Restrict equal types to the current world (#1549)
* move name_interface to preprocess phase; restrict equal types to the current world * add test * remove stale failed tests * include primitive types * add back wasi-http-borrowed * comments * use LiveTypes * fix
1 parent 18f858a commit 4a48c99

File tree

5 files changed

+35
-19
lines changed

5 files changed

+35
-19
lines changed

crates/core/src/types.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,7 @@ impl Types {
9595
}
9696
}
9797

98-
/// Populates the return value of [`Types::get_representative_type`] with
99-
/// the `resolve` passed in.
98+
/// Identify all the structurally equal types reachable from the `world_id`.
10099
///
101100
/// The `may_alias_another_type` closure is used to determine whether the
102101
/// language's definition of the provided `TypeId` might possibly alias
@@ -109,19 +108,22 @@ impl Types {
109108
pub fn collect_equal_types(
110109
&mut self,
111110
resolve: &Resolve,
111+
world_id: WorldId,
112112
may_alias_another_type: &dyn Fn(TypeId) -> bool,
113113
) {
114-
for (i, (ty, _)) in resolve.types.iter().enumerate() {
114+
let mut live_types = wit_parser::LiveTypes::default();
115+
live_types.add_world(resolve, world_id);
116+
for (i, ty) in live_types.iter().enumerate() {
115117
if !may_alias_another_type(ty) {
116118
continue;
117119
}
118120
// TODO: we could define a hash function for TypeDefKind to prevent the inner loop.
119-
for (earlier, _) in resolve.types.iter().take(i) {
121+
for earlier in live_types.iter().take(i) {
120122
if self.equal_types.find(ty) == self.equal_types.find(earlier) {
121123
continue;
122124
}
123125
// The correctness of is_structurally_equal relies on the fact
124-
// that resolve.types.iter() is in topological order.
126+
// that live_types.iter() is in topological order.
125127
if self.is_structurally_equal(resolve, ty, earlier) {
126128
self.equal_types.union(ty, earlier);
127129
break;

crates/rust/src/interface.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -556,10 +556,7 @@ macro_rules! {macro_name} {{
556556
}
557557

558558
// Use the original (non-canonicalized) type for generating the
559-
// type name and code. The canonical representative may belong to
560-
// an interface that hasn't been processed yet (when world import
561-
// order differs from WIT definition order), which would cause
562-
// `path_to_interface` to panic. Since structurally equal types
559+
// type name and code. Since structurally equal types
563560
// resolve to the same Rust type, it doesn't matter which alias
564561
// path we use in the generated `impl`.
565562
let payload_type = match payload_type {
@@ -2431,7 +2428,11 @@ unsafe fn call_import(&mut self, _params: Self::ParamsLower, _results: *mut u8)
24312428
}
24322429

24332430
fn path_to_interface(&self, interface: InterfaceId) -> Option<String> {
2434-
let InterfaceName { path, remapped } = &self.r#gen.interface_names[&interface];
2431+
let Some(InterfaceName { path, remapped }) = &self.r#gen.interface_names.get(&interface)
2432+
else {
2433+
let name = self.resolve.interfaces[interface].name.as_ref().unwrap();
2434+
panic!("Cannot find interface {interface:?}: {name}");
2435+
};
24352436
if *remapped {
24362437
let mut path_to_root = self.path_to_root();
24372438
path_to_root.push_str(path);

crates/rust/src/lib.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,7 +1129,7 @@ impl WorldGenerator for RustWasm {
11291129
uwriteln!(self.src_preamble, "// * async: {opt}");
11301130
}
11311131
self.types.analyze(resolve);
1132-
self.types.collect_equal_types(resolve, &|a| {
1132+
self.types.collect_equal_types(resolve, world, &|a| {
11331133
// If `--merge-structurally-equal-types` is enabled then any type
11341134
// anywhere can be generated as a type alias to anything else.
11351135
if self.opts.merge_structurally_equal_types() {
@@ -1194,6 +1194,16 @@ impl WorldGenerator for RustWasm {
11941194
self.with.insert(k.clone(), v.clone().into());
11951195
}
11961196
self.with.generate_by_default = self.opts.generate_all;
1197+
for (key, item) in world.imports.iter() {
1198+
if let WorldItem::Interface { id, .. } = item {
1199+
self.name_interface(resolve, *id, &key, false).unwrap();
1200+
}
1201+
}
1202+
for (key, item) in world.exports.iter() {
1203+
if let WorldItem::Interface { id, .. } = item {
1204+
self.name_interface(resolve, *id, &key, true).unwrap();
1205+
}
1206+
}
11971207
}
11981208

11991209
fn import_interface(
@@ -1225,7 +1235,7 @@ impl WorldGenerator for RustWasm {
12251235
true,
12261236
);
12271237
let (snake, module_path) = r#gen.start_append_submodule(name);
1228-
if r#gen.r#gen.name_interface(resolve, id, name, false)? {
1238+
if r#gen.r#gen.interface_names[&id].remapped {
12291239
return Ok(());
12301240
}
12311241

@@ -1281,7 +1291,7 @@ impl WorldGenerator for RustWasm {
12811291
false,
12821292
);
12831293
let (snake, module_path) = r#gen.start_append_submodule(name);
1284-
if r#gen.r#gen.name_interface(resolve, id, name, true)? {
1294+
if r#gen.r#gen.interface_names[&id].remapped {
12851295
return Ok(());
12861296
}
12871297

crates/test/src/rust.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,6 @@ impl LanguageMethods for Rust {
7676
return true;
7777
}
7878

79-
// The merge-structurally-equal-types flag panics on wasi-filesystem
80-
// due to missing interface_names entries after type merging.
81-
if name == "wasi-filesystem-merge-equal" {
82-
return true;
83-
}
84-
8579
// Named fixed-length lists don't work with async yet.
8680
if name == "named-fixed-length-list.wit-async" {
8781
return true;

tests/codegen/merge-structurally-equal-types.wit

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
package test:merge-equal;
22

3+
// This interface is not reachable from the test world,
4+
// so it cannot be used as a representative type
5+
interface unreachable {
6+
record payload {
7+
data: list<u8>,
8+
tag: string,
9+
}
10+
}
11+
312
interface importer {
413
record payload {
514
data: list<u8>,

0 commit comments

Comments
 (0)