Skip to content

Commit 5300663

Browse files
authored
add CloneMaps type and parameter to Resolve::merge_worlds (#2361)
This allows the caller to determine which types and/or interfaces were cloned as part of the merge operation. Note that I made this an `&mut` parameter to `Resolve::merge_worlds` rather than a return value in order to make it a bit more efficient when calling `Resolve::merge_worlds` multiple times and collecting the clones across all those calls. Signed-off-by: Joel Dice <[email protected]>
1 parent 2f25c9a commit 5300663

File tree

3 files changed

+49
-9
lines changed

3 files changed

+49
-9
lines changed

crates/wit-component/src/metadata.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ use wasm_encoder::{
5050
};
5151
use wasm_metadata::Producers;
5252
use wasmparser::{BinaryReader, Encoding, Parser, Payload};
53-
use wit_parser::{Package, PackageName, Resolve, World, WorldId, WorldItem, WorldKey};
53+
use wit_parser::{CloneMaps, Package, PackageName, Resolve, World, WorldId, WorldItem, WorldKey};
5454

5555
const CURRENT_VERSION: u8 = 0x04;
5656
const CUSTOM_SECTION_NAME: &str = "wit-component-encoding";
@@ -413,7 +413,7 @@ impl Bindgen {
413413
let world = remap.map_world(world, None)?;
414414
let exports = self.resolve.worlds[world].exports.keys().cloned().collect();
415415
self.resolve
416-
.merge_worlds(world, self.world)
416+
.merge_worlds(world, self.world, &mut CloneMaps::default())
417417
.context("failed to merge worlds from two documents")?;
418418

419419
self.metadata.import_encodings.merge(import_encodings)?;

crates/wit-parser/src/resolve.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ use crate::{
2323
UnresolvedPackageGroup, World, WorldId, WorldItem, WorldKey, WorldSpan,
2424
};
2525

26+
pub use clone::CloneMaps;
27+
2628
mod clone;
2729

2830
/// Representation of a fully resolved set of WIT packages.
@@ -866,8 +868,17 @@ package {name} is defined in two different locations:\n\
866868
/// producing a singular world that will be the final component's
867869
/// interface.
868870
///
871+
/// During the merge operation, some of the types and/or interfaces in
872+
/// `from` might need to be cloned so that backreferences point to `into`
873+
/// instead of `from`. Any such clones will be added to `clone_maps`.
874+
///
869875
/// This operation can fail if the imports/exports overlap.
870-
pub fn merge_worlds(&mut self, from: WorldId, into: WorldId) -> Result<()> {
876+
pub fn merge_worlds(
877+
&mut self,
878+
from: WorldId,
879+
into: WorldId,
880+
clone_maps: &mut CloneMaps,
881+
) -> Result<()> {
871882
let mut new_imports = Vec::new();
872883
let mut new_exports = Vec::new();
873884

@@ -960,9 +971,11 @@ package {name} is defined in two different locations:\n\
960971
let mut cloner = clone::Cloner::new(self, TypeOwner::World(from), TypeOwner::World(into));
961972
cloner.register_world_type_overlap(from, into);
962973
for (name, item) in new_imports.iter_mut().chain(&mut new_exports) {
963-
cloner.world_item(name, item);
974+
cloner.world_item(name, item, clone_maps);
964975
}
965976

977+
clone_maps.types.extend(cloner.types);
978+
966979
// Insert any new imports and new exports found first.
967980
let into_world = &mut self.worlds[into];
968981
for (name, import) in new_imports {
@@ -3654,7 +3667,7 @@ impl Remap {
36543667
// in the function itself.
36553668
let mut new_item = item.1.clone();
36563669
let key = WorldKey::Name(n.clone());
3657-
cloner.world_item(&key, &mut new_item);
3670+
cloner.world_item(&key, &mut new_item, &mut CloneMaps::default());
36583671
match &mut new_item {
36593672
WorldItem::Function(f) => f.name = n.clone(),
36603673
WorldItem::Type(id) => cloner.resolve.types[*id].name = Some(n.clone()),

crates/wit-parser/src/resolve/clone.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,30 @@
2020
use crate::*;
2121
use std::collections::HashMap;
2222

23+
/// Represents the results of cloning types and/or interfaces as part of a
24+
/// `Resolve::merge_worlds` operation.
25+
#[derive(Default)]
26+
pub struct CloneMaps {
27+
pub(super) types: HashMap<TypeId, TypeId>,
28+
pub(super) interfaces: HashMap<InterfaceId, InterfaceId>,
29+
}
30+
31+
impl CloneMaps {
32+
/// The types cloned during a `Resolve::merge_worlds` operation.
33+
///
34+
/// The key is the original type, and the value is the clone.
35+
pub fn types(&self) -> &HashMap<TypeId, TypeId> {
36+
&self.types
37+
}
38+
39+
/// The interfaces cloned during a `Resolve::merge_worlds` operation.
40+
///
41+
/// The key is the original interface, and the value is the clone.
42+
pub fn interfaces(&self) -> &HashMap<InterfaceId, InterfaceId> {
43+
&self.interfaces
44+
}
45+
}
46+
2347
pub struct Cloner<'a> {
2448
pub resolve: &'a mut Resolve,
2549
prev_owner: TypeOwner,
@@ -28,7 +52,7 @@ pub struct Cloner<'a> {
2852
/// This map keeps track, in the current scope of types, of all copied
2953
/// types. This deduplicates copying types to ensure that they're only
3054
/// copied at most once.
31-
types: HashMap<TypeId, TypeId>,
55+
pub types: HashMap<TypeId, TypeId>,
3256

3357
/// If `None` then it's inferred from `self.new_owner`.
3458
pub new_package: Option<PackageId>,
@@ -64,7 +88,7 @@ impl<'a> Cloner<'a> {
6488
}
6589
}
6690

67-
pub fn world_item(&mut self, key: &WorldKey, item: &mut WorldItem) {
91+
pub fn world_item(&mut self, key: &WorldKey, item: &mut WorldItem, clone_maps: &mut CloneMaps) {
6892
match key {
6993
WorldKey::Name(_) => {}
7094
WorldKey::Interface(_) => return,
@@ -78,7 +102,9 @@ impl<'a> Cloner<'a> {
78102
self.function(f);
79103
}
80104
WorldItem::Interface { id, .. } => {
81-
self.interface(id);
105+
let old = *id;
106+
self.interface(id, &mut clone_maps.types);
107+
clone_maps.interfaces.insert(old, *id);
82108
}
83109
}
84110
}
@@ -171,7 +197,7 @@ impl<'a> Cloner<'a> {
171197
}
172198
}
173199

174-
fn interface(&mut self, id: &mut InterfaceId) {
200+
fn interface(&mut self, id: &mut InterfaceId, cloned_types: &mut HashMap<TypeId, TypeId>) {
175201
let mut new = self.resolve.interfaces[*id].clone();
176202
let next_id = self.resolve.interfaces.next_id();
177203
let mut clone = Cloner::new(
@@ -185,6 +211,7 @@ impl<'a> Cloner<'a> {
185211
for func in new.functions.values_mut() {
186212
clone.function(func);
187213
}
214+
cloned_types.extend(clone.types);
188215
new.package = Some(self.new_package.unwrap_or_else(|| match self.new_owner {
189216
TypeOwner::Interface(id) => self.resolve.interfaces[id].package.unwrap(),
190217
TypeOwner::World(id) => self.resolve.worlds[id].package.unwrap(),

0 commit comments

Comments
 (0)