| 1 | use std::cmp::Ordering; | 
| 2 | use std::collections::hash_map; | 
|---|
| 3 | use std::collections::{BTreeMap, HashMap, HashSet}; | 
|---|
| 4 | use std::fmt; | 
|---|
| 5 | use std::mem; | 
|---|
| 6 | use std::path::{Path, PathBuf}; | 
|---|
| 7 |  | 
|---|
| 8 | use anyhow::{anyhow, bail, ensure, Context, Result}; | 
|---|
| 9 | use id_arena::{Arena, Id}; | 
|---|
| 10 | use indexmap::{IndexMap, IndexSet}; | 
|---|
| 11 | use semver::Version; | 
|---|
| 12 | #[ cfg(feature = "serde")] | 
|---|
| 13 | use serde_derive::Serialize; | 
|---|
| 14 |  | 
|---|
| 15 | use crate::ast::lex::Span; | 
|---|
| 16 | use crate::ast::{parse_use_path, ParsedUsePath}; | 
|---|
| 17 | #[ cfg(feature = "serde")] | 
|---|
| 18 | use crate::serde_::{serialize_arena, serialize_id_map}; | 
|---|
| 19 | use crate::{ | 
|---|
| 20 | AstItem, Docs, Error, Function, FunctionKind, Handle, IncludeName, Interface, InterfaceId, | 
|---|
| 21 | InterfaceSpan, LiftLowerAbi, ManglingAndAbi, PackageName, PackageNotFoundError, Results, | 
|---|
| 22 | SourceMap, Stability, Type, TypeDef, TypeDefKind, TypeId, TypeIdVisitor, TypeOwner, | 
|---|
| 23 | UnresolvedPackage, UnresolvedPackageGroup, World, WorldId, WorldItem, WorldKey, WorldSpan, | 
|---|
| 24 | }; | 
|---|
| 25 |  | 
|---|
| 26 | mod clone; | 
|---|
| 27 |  | 
|---|
| 28 | /// Representation of a fully resolved set of WIT packages. | 
|---|
| 29 | /// | 
|---|
| 30 | /// This structure contains a graph of WIT packages and all of their contents | 
|---|
| 31 | /// merged together into the contained arenas. All items are sorted | 
|---|
| 32 | /// topologically and everything here is fully resolved, so with a `Resolve` no | 
|---|
| 33 | /// name lookups are necessary and instead everything is index-based. | 
|---|
| 34 | /// | 
|---|
| 35 | /// Working with a WIT package requires inserting it into a `Resolve` to ensure | 
|---|
| 36 | /// that all of its dependencies are satisfied. This will give the full picture | 
|---|
| 37 | /// of that package's types and such. | 
|---|
| 38 | /// | 
|---|
| 39 | /// Each item in a `Resolve` has a parent link to trace it back to the original | 
|---|
| 40 | /// package as necessary. | 
|---|
| 41 | #[ derive(Default, Clone, Debug)] | 
|---|
| 42 | #[ cfg_attr(feature = "serde", derive(Serialize))] | 
|---|
| 43 | pub struct Resolve { | 
|---|
| 44 | /// All known worlds within this `Resolve`. | 
|---|
| 45 | /// | 
|---|
| 46 | /// Each world points at a `PackageId` which is stored below. No ordering is | 
|---|
| 47 | /// guaranteed between this list of worlds. | 
|---|
| 48 | #[ cfg_attr(feature = "serde", serde(serialize_with = "serialize_arena"))] | 
|---|
| 49 | pub worlds: Arena<World>, | 
|---|
| 50 |  | 
|---|
| 51 | /// All known interfaces within this `Resolve`. | 
|---|
| 52 | /// | 
|---|
| 53 | /// Each interface points at a `PackageId` which is stored below. No | 
|---|
| 54 | /// ordering is guaranteed between this list of interfaces. | 
|---|
| 55 | #[ cfg_attr(feature = "serde", serde(serialize_with = "serialize_arena"))] | 
|---|
| 56 | pub interfaces: Arena<Interface>, | 
|---|
| 57 |  | 
|---|
| 58 | /// All known types within this `Resolve`. | 
|---|
| 59 | /// | 
|---|
| 60 | /// Types are topologically sorted such that any type referenced from one | 
|---|
| 61 | /// type is guaranteed to be defined previously. Otherwise though these are | 
|---|
| 62 | /// not sorted by interface for example. | 
|---|
| 63 | #[ cfg_attr(feature = "serde", serde(serialize_with = "serialize_arena"))] | 
|---|
| 64 | pub types: Arena<TypeDef>, | 
|---|
| 65 |  | 
|---|
| 66 | /// All known packages within this `Resolve`. | 
|---|
| 67 | /// | 
|---|
| 68 | /// This list of packages is not sorted. Sorted packages can be queried | 
|---|
| 69 | /// through [`Resolve::topological_packages`]. | 
|---|
| 70 | #[ cfg_attr(feature = "serde", serde(serialize_with = "serialize_arena"))] | 
|---|
| 71 | pub packages: Arena<Package>, | 
|---|
| 72 |  | 
|---|
| 73 | /// A map of package names to the ID of the package with that name. | 
|---|
| 74 | #[ cfg_attr(feature = "serde", serde(skip))] | 
|---|
| 75 | pub package_names: IndexMap<PackageName, PackageId>, | 
|---|
| 76 |  | 
|---|
| 77 | /// Activated features for this [`Resolve`]. | 
|---|
| 78 | /// | 
|---|
| 79 | /// This set of features is empty by default. This is consulted for | 
|---|
| 80 | /// `@unstable` annotations in loaded WIT documents. Any items with | 
|---|
| 81 | /// `@unstable` are filtered out unless their feature is present within this | 
|---|
| 82 | /// set. | 
|---|
| 83 | #[ cfg_attr(feature = "serde", serde(skip))] | 
|---|
| 84 | pub features: IndexSet<String>, | 
|---|
| 85 |  | 
|---|
| 86 | /// Activate all features for this [`Resolve`]. | 
|---|
| 87 | #[ cfg_attr(feature = "serde", serde(skip))] | 
|---|
| 88 | pub all_features: bool, | 
|---|
| 89 | } | 
|---|
| 90 |  | 
|---|
| 91 | /// A WIT package within a `Resolve`. | 
|---|
| 92 | /// | 
|---|
| 93 | /// A package is a collection of interfaces and worlds. Packages additionally | 
|---|
| 94 | /// have a unique identifier that affects generated components and uniquely | 
|---|
| 95 | /// identifiers this particular package. | 
|---|
| 96 | #[ derive(Clone, Debug)] | 
|---|
| 97 | #[ cfg_attr(feature = "serde", derive(Serialize))] | 
|---|
| 98 | pub struct Package { | 
|---|
| 99 | /// A unique name corresponding to this package. | 
|---|
| 100 | pub name: PackageName, | 
|---|
| 101 |  | 
|---|
| 102 | /// Documentation associated with this package. | 
|---|
| 103 | #[ cfg_attr(feature = "serde", serde(skip_serializing_if = "Docs::is_empty"))] | 
|---|
| 104 | pub docs: Docs, | 
|---|
| 105 |  | 
|---|
| 106 | /// All interfaces contained in this packaged, keyed by the interface's | 
|---|
| 107 | /// name. | 
|---|
| 108 | #[ cfg_attr(feature = "serde", serde(serialize_with = "serialize_id_map"))] | 
|---|
| 109 | pub interfaces: IndexMap<String, InterfaceId>, | 
|---|
| 110 |  | 
|---|
| 111 | /// All worlds contained in this package, keyed by the world's name. | 
|---|
| 112 | #[ cfg_attr(feature = "serde", serde(serialize_with = "serialize_id_map"))] | 
|---|
| 113 | pub worlds: IndexMap<String, WorldId>, | 
|---|
| 114 | } | 
|---|
| 115 |  | 
|---|
| 116 | pub type PackageId = Id<Package>; | 
|---|
| 117 |  | 
|---|
| 118 | /// All the sources used during resolving a directory or path. | 
|---|
| 119 | #[ derive(Clone, Debug)] | 
|---|
| 120 | pub struct PackageSourceMap { | 
|---|
| 121 | sources: Vec<Vec<PathBuf>>, | 
|---|
| 122 | package_id_to_source_map_idx: BTreeMap<PackageId, usize>, | 
|---|
| 123 | } | 
|---|
| 124 |  | 
|---|
| 125 | impl PackageSourceMap { | 
|---|
| 126 | fn from_single_source(package_id: PackageId, source: &Path) -> Self { | 
|---|
| 127 | Self { | 
|---|
| 128 | sources: vec![vec![source.to_path_buf()]], | 
|---|
| 129 | package_id_to_source_map_idx: BTreeMap::from([(package_id, 0)]), | 
|---|
| 130 | } | 
|---|
| 131 | } | 
|---|
| 132 |  | 
|---|
| 133 | fn from_source_maps( | 
|---|
| 134 | source_maps: Vec<SourceMap>, | 
|---|
| 135 | package_id_to_source_map_idx: BTreeMap<PackageId, usize>, | 
|---|
| 136 | ) -> PackageSourceMap { | 
|---|
| 137 | for (package_id, idx) in &package_id_to_source_map_idx { | 
|---|
| 138 | if *idx >= source_maps.len() { | 
|---|
| 139 | panic!( | 
|---|
| 140 | "Invalid source map index: {} , package id: {:?} , source maps size: {} ", | 
|---|
| 141 | idx, | 
|---|
| 142 | package_id, | 
|---|
| 143 | source_maps.len() | 
|---|
| 144 | ) | 
|---|
| 145 | } | 
|---|
| 146 | } | 
|---|
| 147 |  | 
|---|
| 148 | Self { | 
|---|
| 149 | sources: source_maps | 
|---|
| 150 | .into_iter() | 
|---|
| 151 | .map(|source_map| { | 
|---|
| 152 | source_map | 
|---|
| 153 | .source_files() | 
|---|
| 154 | .map(|path| path.to_path_buf()) | 
|---|
| 155 | .collect() | 
|---|
| 156 | }) | 
|---|
| 157 | .collect(), | 
|---|
| 158 | package_id_to_source_map_idx, | 
|---|
| 159 | } | 
|---|
| 160 | } | 
|---|
| 161 |  | 
|---|
| 162 | /// All unique source paths. | 
|---|
| 163 | pub fn paths(&self) -> impl Iterator<Item = &Path> { | 
|---|
| 164 | // Usually any two source map should not have duplicated source paths, | 
|---|
| 165 | // but it can happen, e.g. with using [`Resolve::push_str`] directly. | 
|---|
| 166 | // To be sure we use a set for deduplication here. | 
|---|
| 167 | self.sources | 
|---|
| 168 | .iter() | 
|---|
| 169 | .flatten() | 
|---|
| 170 | .map(|path_buf| path_buf.as_ref()) | 
|---|
| 171 | .collect::<HashSet<&Path>>() | 
|---|
| 172 | .into_iter() | 
|---|
| 173 | } | 
|---|
| 174 |  | 
|---|
| 175 | /// Source paths for package | 
|---|
| 176 | pub fn package_paths(&self, id: PackageId) -> Option<impl Iterator<Item = &Path>> { | 
|---|
| 177 | self.package_id_to_source_map_idx | 
|---|
| 178 | .get(&id) | 
|---|
| 179 | .map(|&idx| self.sources[idx].iter().map(|path_buf| path_buf.as_ref())) | 
|---|
| 180 | } | 
|---|
| 181 | } | 
|---|
| 182 |  | 
|---|
| 183 | enum ParsedFile { | 
|---|
| 184 | #[ cfg(feature = "decoding")] | 
|---|
| 185 | Package(PackageId), | 
|---|
| 186 | Unresolved(UnresolvedPackageGroup), | 
|---|
| 187 | } | 
|---|
| 188 |  | 
|---|
| 189 | /// Visitor helper for performing topological sort on a group of packages. | 
|---|
| 190 | fn visit<'a>( | 
|---|
| 191 | pkg: &'a UnresolvedPackage, | 
|---|
| 192 | pkg_details_map: &'a BTreeMap<PackageName, (UnresolvedPackage, usize)>, | 
|---|
| 193 | order: &mut IndexSet<PackageName>, | 
|---|
| 194 | visiting: &mut HashSet<&'a PackageName>, | 
|---|
| 195 | source_maps: &[SourceMap], | 
|---|
| 196 | ) -> Result<()> { | 
|---|
| 197 | if order.contains(&pkg.name) { | 
|---|
| 198 | return Ok(()); | 
|---|
| 199 | } | 
|---|
| 200 |  | 
|---|
| 201 | match pkg_details_map.get(&pkg.name) { | 
|---|
| 202 | Some(pkg_details) => { | 
|---|
| 203 | let (_, source_maps_index) = pkg_details; | 
|---|
| 204 | source_maps[*source_maps_index].rewrite_error(|| { | 
|---|
| 205 | for (i, (dep, _)) in pkg.foreign_deps.iter().enumerate() { | 
|---|
| 206 | let span = pkg.foreign_dep_spans[i]; | 
|---|
| 207 | if !visiting.insert(dep) { | 
|---|
| 208 | bail!(Error::new(span, "package depends on itself")); | 
|---|
| 209 | } | 
|---|
| 210 | if let Some(dep) = pkg_details_map.get(dep) { | 
|---|
| 211 | let (dep_pkg, _) = dep; | 
|---|
| 212 | visit(dep_pkg, pkg_details_map, order, visiting, source_maps)?; | 
|---|
| 213 | } | 
|---|
| 214 | assert!(visiting.remove(dep)); | 
|---|
| 215 | } | 
|---|
| 216 | assert!(order.insert(pkg.name.clone())); | 
|---|
| 217 | Ok(()) | 
|---|
| 218 | }) | 
|---|
| 219 | } | 
|---|
| 220 | None => panic!( "No pkg_details found for package when doing topological sort"), | 
|---|
| 221 | } | 
|---|
| 222 | } | 
|---|
| 223 |  | 
|---|
| 224 | impl Resolve { | 
|---|
| 225 | /// Creates a new [`Resolve`] with no packages/items inside of it. | 
|---|
| 226 | pub fn new() -> Resolve { | 
|---|
| 227 | Resolve::default() | 
|---|
| 228 | } | 
|---|
| 229 |  | 
|---|
| 230 | /// Parse WIT packages from the input `path`. | 
|---|
| 231 | /// | 
|---|
| 232 | /// The input `path` can be one of: | 
|---|
| 233 | /// | 
|---|
| 234 | /// * A directory containing a WIT package with an optional `deps` directory | 
|---|
| 235 | ///   for any dependent WIT packages it references. | 
|---|
| 236 | /// * A single standalone WIT file. | 
|---|
| 237 | /// * A wasm-encoded WIT package as a single file in the wasm binary format. | 
|---|
| 238 | /// * A wasm-encoded WIT package as a single file in the wasm text format. | 
|---|
| 239 | /// | 
|---|
| 240 | /// In all of these cases packages are allowed to depend on previously | 
|---|
| 241 | /// inserted packages into this `Resolve`. Resolution for packages is based | 
|---|
| 242 | /// on the name of each package and reference. | 
|---|
| 243 | /// | 
|---|
| 244 | /// This method returns a `PackageId` and additionally a `PackageSourceMap`. | 
|---|
| 245 | /// The `PackageId` represent the main package that was parsed. For example if a single WIT | 
|---|
| 246 | /// file was specified  this will be the main package found in the file. For a directory this | 
|---|
| 247 | /// will be all the main package in the directory itself. The `PackageId` value is useful | 
|---|
| 248 | /// to pass to [`Resolve::select_world`] to take a user-specified world in a | 
|---|
| 249 | /// conventional fashion and select which to use for bindings generation. | 
|---|
| 250 | /// | 
|---|
| 251 | /// The returned [`PackageSourceMap`] contains all the sources used during this operation. | 
|---|
| 252 | /// This can be useful for systems that want to rebuild or regenerate bindings based on files modified, | 
|---|
| 253 | /// or for ones which like to identify the used files for a package. | 
|---|
| 254 | /// | 
|---|
| 255 | /// More information can also be found at [`Resolve::push_dir`] and | 
|---|
| 256 | /// [`Resolve::push_file`]. | 
|---|
| 257 | pub fn push_path(&mut self, path: impl AsRef<Path>) -> Result<(PackageId, PackageSourceMap)> { | 
|---|
| 258 | self._push_path(path.as_ref()) | 
|---|
| 259 | } | 
|---|
| 260 |  | 
|---|
| 261 | fn _push_path(&mut self, path: &Path) -> Result<(PackageId, PackageSourceMap)> { | 
|---|
| 262 | if path.is_dir() { | 
|---|
| 263 | self.push_dir(path).with_context(|| { | 
|---|
| 264 | format!( | 
|---|
| 265 | "failed to resolve directory while parsing WIT for path [{} ]", | 
|---|
| 266 | path.display() | 
|---|
| 267 | ) | 
|---|
| 268 | }) | 
|---|
| 269 | } else { | 
|---|
| 270 | let id = self.push_file(path)?; | 
|---|
| 271 | Ok((id, PackageSourceMap::from_single_source(id, path))) | 
|---|
| 272 | } | 
|---|
| 273 | } | 
|---|
| 274 |  | 
|---|
| 275 | fn sort_unresolved_packages( | 
|---|
| 276 | &mut self, | 
|---|
| 277 | main: UnresolvedPackageGroup, | 
|---|
| 278 | deps: Vec<UnresolvedPackageGroup>, | 
|---|
| 279 | ) -> Result<(PackageId, PackageSourceMap)> { | 
|---|
| 280 | let mut pkg_details_map = BTreeMap::new(); | 
|---|
| 281 | let mut source_maps = Vec::new(); | 
|---|
| 282 |  | 
|---|
| 283 | let mut insert = |group: UnresolvedPackageGroup| { | 
|---|
| 284 | let UnresolvedPackageGroup { | 
|---|
| 285 | main, | 
|---|
| 286 | nested, | 
|---|
| 287 | source_map, | 
|---|
| 288 | } = group; | 
|---|
| 289 | let i = source_maps.len(); | 
|---|
| 290 | source_maps.push(source_map); | 
|---|
| 291 |  | 
|---|
| 292 | for pkg in nested.into_iter().chain([main]) { | 
|---|
| 293 | let name = pkg.name.clone(); | 
|---|
| 294 | let my_span = pkg.package_name_span; | 
|---|
| 295 | let (prev_pkg, prev_i) = match pkg_details_map.insert(name.clone(), (pkg, i)) { | 
|---|
| 296 | Some(pair) => pair, | 
|---|
| 297 | None => continue, | 
|---|
| 298 | }; | 
|---|
| 299 | let loc1 = source_maps[i].render_location(my_span); | 
|---|
| 300 | let loc2 = source_maps[prev_i].render_location(prev_pkg.package_name_span); | 
|---|
| 301 | bail!( | 
|---|
| 302 | "\ | 
|---|
| 303 | package {name}  is defined in two different locations:\n \ | 
|---|
| 304 |   * {loc1}\n \ | 
|---|
| 305 |   * {loc2}\n \ | 
|---|
| 306 |                      " | 
|---|
| 307 | ) | 
|---|
| 308 | } | 
|---|
| 309 | Ok(()) | 
|---|
| 310 | }; | 
|---|
| 311 |  | 
|---|
| 312 | let main_name = main.main.name.clone(); | 
|---|
| 313 | insert(main)?; | 
|---|
| 314 | for dep in deps { | 
|---|
| 315 | insert(dep)?; | 
|---|
| 316 | } | 
|---|
| 317 |  | 
|---|
| 318 | // Perform a simple topological sort which will bail out on cycles | 
|---|
| 319 | // and otherwise determine the order that packages must be added to | 
|---|
| 320 | // this `Resolve`. | 
|---|
| 321 | let mut order = IndexSet::new(); | 
|---|
| 322 | let mut visiting = HashSet::new(); | 
|---|
| 323 | for pkg_details in pkg_details_map.values() { | 
|---|
| 324 | let (pkg, _) = pkg_details; | 
|---|
| 325 | visit( | 
|---|
| 326 | pkg, | 
|---|
| 327 | &pkg_details_map, | 
|---|
| 328 | &mut order, | 
|---|
| 329 | &mut visiting, | 
|---|
| 330 | &source_maps, | 
|---|
| 331 | )?; | 
|---|
| 332 | } | 
|---|
| 333 |  | 
|---|
| 334 | // Ensure that the final output is topologically sorted. Use a set to ensure that we render | 
|---|
| 335 | // the buffers for each `SourceMap` only once, even though multiple packages may reference | 
|---|
| 336 | // the same `SourceMap`. | 
|---|
| 337 | let mut package_id_to_source_map_idx = BTreeMap::new(); | 
|---|
| 338 | let mut main_pkg_id = None; | 
|---|
| 339 | for name in order { | 
|---|
| 340 | let (pkg, source_map_index) = pkg_details_map.remove(&name).unwrap(); | 
|---|
| 341 | let source_map = &source_maps[source_map_index]; | 
|---|
| 342 | let is_main = pkg.name == main_name; | 
|---|
| 343 | let id = self.push(pkg, source_map)?; | 
|---|
| 344 | if is_main { | 
|---|
| 345 | assert!(main_pkg_id.is_none()); | 
|---|
| 346 | main_pkg_id = Some(id); | 
|---|
| 347 | } | 
|---|
| 348 | package_id_to_source_map_idx.insert(id, source_map_index); | 
|---|
| 349 | } | 
|---|
| 350 |  | 
|---|
| 351 | Ok(( | 
|---|
| 352 | main_pkg_id.unwrap(), | 
|---|
| 353 | PackageSourceMap::from_source_maps(source_maps, package_id_to_source_map_idx), | 
|---|
| 354 | )) | 
|---|
| 355 | } | 
|---|
| 356 |  | 
|---|
| 357 | /// Parses the filesystem directory at `path` as a WIT package and returns | 
|---|
| 358 | /// a fully resolved [`PackageId`] list as a result. | 
|---|
| 359 | /// | 
|---|
| 360 | /// The directory itself is parsed with [`UnresolvedPackageGroup::parse_dir`] | 
|---|
| 361 | /// and then all packages found are inserted into this `Resolve`. The `path` | 
|---|
| 362 | /// specified may have a `deps` subdirectory which is probed automatically | 
|---|
| 363 | /// for any other WIT dependencies. | 
|---|
| 364 | /// | 
|---|
| 365 | /// The `deps` folder may contain: | 
|---|
| 366 | /// | 
|---|
| 367 | /// * `$path/deps/my-package/*.wit` - a directory that may contain multiple | 
|---|
| 368 | ///   WIT files. This is parsed with [`UnresolvedPackageGroup::parse_dir`] | 
|---|
| 369 | ///   and then inserted into this [`Resolve`]. Note that cannot recursively | 
|---|
| 370 | ///   contain a `deps` directory. | 
|---|
| 371 | /// * `$path/deps/my-package.wit` - a single-file WIT package. This is | 
|---|
| 372 | ///   parsed with [`Resolve::push_file`] and then added to `self` for | 
|---|
| 373 | ///   name reoslution. | 
|---|
| 374 | /// * `$path/deps/my-package.{wasm,wat}` - a wasm-encoded WIT package either | 
|---|
| 375 | ///   in the text for binary format. | 
|---|
| 376 | /// | 
|---|
| 377 | /// In all cases entries in the `deps` folder are added to `self` first | 
|---|
| 378 | /// before adding files found in `path` itself. All WIT packages found are | 
|---|
| 379 | /// candidates for name-based resolution that other packages may use. | 
|---|
| 380 | /// | 
|---|
| 381 | /// This function returns a tuple of two values. The first value is a | 
|---|
| 382 | /// [`PackageId`], which represents the main WIT package found within | 
|---|
| 383 | /// `path`. This argument is useful for passing to [`Resolve::select_world`] | 
|---|
| 384 | /// for choosing something to bindgen with. | 
|---|
| 385 | /// | 
|---|
| 386 | /// The second value returned is a [`PackageSourceMap`], which contains all the sources | 
|---|
| 387 | /// that were parsed during resolving. This can be useful for: | 
|---|
| 388 | /// * build systems that want to rebuild bindings whenever one of the files changed | 
|---|
| 389 | /// * or other tools, which want to identify the sources for the resolved packages | 
|---|
| 390 | pub fn push_dir(&mut self, path: impl AsRef<Path>) -> Result<(PackageId, PackageSourceMap)> { | 
|---|
| 391 | self._push_dir(path.as_ref()) | 
|---|
| 392 | } | 
|---|
| 393 |  | 
|---|
| 394 | fn _push_dir(&mut self, path: &Path) -> Result<(PackageId, PackageSourceMap)> { | 
|---|
| 395 | let top_pkg = UnresolvedPackageGroup::parse_dir(path) | 
|---|
| 396 | .with_context(|| format!( "failed to parse package: {} ", path.display()))?; | 
|---|
| 397 | let deps = path.join( "deps"); | 
|---|
| 398 | let deps = self | 
|---|
| 399 | .parse_deps_dir(&deps) | 
|---|
| 400 | .with_context(|| format!( "failed to parse dependency directory: {} ", deps.display()))?; | 
|---|
| 401 |  | 
|---|
| 402 | self.sort_unresolved_packages(top_pkg, deps) | 
|---|
| 403 | } | 
|---|
| 404 |  | 
|---|
| 405 | fn parse_deps_dir(&mut self, path: &Path) -> Result<Vec<UnresolvedPackageGroup>> { | 
|---|
| 406 | let mut ret = Vec::new(); | 
|---|
| 407 | if !path.exists() { | 
|---|
| 408 | return Ok(ret); | 
|---|
| 409 | } | 
|---|
| 410 | let mut entries = path | 
|---|
| 411 | .read_dir() | 
|---|
| 412 | .and_then(|i| i.collect::<std::io::Result<Vec<_>>>()) | 
|---|
| 413 | .context( "failed to read directory")?; | 
|---|
| 414 | entries.sort_by_key(|e| e.file_name()); | 
|---|
| 415 | for dep in entries { | 
|---|
| 416 | let path = dep.path(); | 
|---|
| 417 | let pkg = if dep.file_type()?.is_dir() || path.metadata()?.is_dir() { | 
|---|
| 418 | // If this entry is a directory or a symlink point to a | 
|---|
| 419 | // directory then always parse it as an `UnresolvedPackage` | 
|---|
| 420 | // since it's intentional to not support recursive `deps` | 
|---|
| 421 | // directories. | 
|---|
| 422 | UnresolvedPackageGroup::parse_dir(&path) | 
|---|
| 423 | .with_context(|| format!( "failed to parse package: {} ", path.display()))? | 
|---|
| 424 | } else { | 
|---|
| 425 | // If this entry is a file then we may want to ignore it but | 
|---|
| 426 | // this may also be a standalone WIT file or a `*.wasm` or | 
|---|
| 427 | // `*.wat` encoded package. | 
|---|
| 428 | let filename = dep.file_name(); | 
|---|
| 429 | match Path::new(&filename).extension().and_then(|s| s.to_str()) { | 
|---|
| 430 | Some( "wit") | Some( "wat") | Some( "wasm") => match self._push_file(&path)? { | 
|---|
| 431 | #[ cfg(feature = "decoding")] | 
|---|
| 432 | ParsedFile::Package(_) => continue, | 
|---|
| 433 | ParsedFile::Unresolved(pkg) => pkg, | 
|---|
| 434 | }, | 
|---|
| 435 |  | 
|---|
| 436 | // Other files in deps dir are ignored for now to avoid | 
|---|
| 437 | // accidentally including things like `.DS_Store` files in | 
|---|
| 438 | // the call below to `parse_dir`. | 
|---|
| 439 | _ => continue, | 
|---|
| 440 | } | 
|---|
| 441 | }; | 
|---|
| 442 | ret.push(pkg); | 
|---|
| 443 | } | 
|---|
| 444 | Ok(ret) | 
|---|
| 445 | } | 
|---|
| 446 |  | 
|---|
| 447 | /// Parses the contents of `path` from the filesystem and pushes the result | 
|---|
| 448 | /// into this `Resolve`. | 
|---|
| 449 | /// | 
|---|
| 450 | /// The `path` referenced here can be one of: | 
|---|
| 451 | /// | 
|---|
| 452 | /// * A WIT file. Note that in this case this single WIT file will be the | 
|---|
| 453 | ///   entire package and any dependencies it has must already be in `self`. | 
|---|
| 454 | /// * A WIT package encoded as WebAssembly, either in text or binary form. | 
|---|
| 455 | ///   In this the package and all of its dependencies are automatically | 
|---|
| 456 | ///   inserted into `self`. | 
|---|
| 457 | /// | 
|---|
| 458 | /// In both situations the `PackageId`s of the resulting resolved packages | 
|---|
| 459 | /// are returned from this method. The return value is mostly useful in | 
|---|
| 460 | /// conjunction with [`Resolve::select_world`]. | 
|---|
| 461 | pub fn push_file(&mut self, path: impl AsRef<Path>) -> Result<PackageId> { | 
|---|
| 462 | match self._push_file(path.as_ref())? { | 
|---|
| 463 | #[ cfg(feature = "decoding")] | 
|---|
| 464 | ParsedFile::Package(id) => Ok(id), | 
|---|
| 465 | ParsedFile::Unresolved(pkg) => self.push_group(pkg), | 
|---|
| 466 | } | 
|---|
| 467 | } | 
|---|
| 468 |  | 
|---|
| 469 | fn _push_file(&mut self, path: &Path) -> Result<ParsedFile> { | 
|---|
| 470 | let contents = std::fs::read(path) | 
|---|
| 471 | .with_context(|| format!( "failed to read path for WIT [{} ]", path.display()))?; | 
|---|
| 472 |  | 
|---|
| 473 | // If decoding is enabled at compile time then try to see if this is a | 
|---|
| 474 | // wasm file. | 
|---|
| 475 | #[ cfg(feature = "decoding")] | 
|---|
| 476 | { | 
|---|
| 477 | use crate::decoding::{decode, DecodedWasm}; | 
|---|
| 478 |  | 
|---|
| 479 | #[ cfg(feature = "wat")] | 
|---|
| 480 | let is_wasm = wat::Detect::from_bytes(&contents).is_wasm(); | 
|---|
| 481 | #[ cfg(not(feature = "wat"))] | 
|---|
| 482 | let is_wasm = wasmparser::Parser::is_component(&contents); | 
|---|
| 483 |  | 
|---|
| 484 | if is_wasm { | 
|---|
| 485 | #[ cfg(feature = "wat")] | 
|---|
| 486 | let contents = wat::parse_bytes(&contents).map_err(|mut e| { | 
|---|
| 487 | e.set_path(path); | 
|---|
| 488 | e | 
|---|
| 489 | })?; | 
|---|
| 490 |  | 
|---|
| 491 | match decode(&contents)? { | 
|---|
| 492 | DecodedWasm::Component(..) => { | 
|---|
| 493 | bail!( "found an actual component instead of an encoded WIT package in wasm") | 
|---|
| 494 | } | 
|---|
| 495 | DecodedWasm::WitPackage(resolve, pkg) => { | 
|---|
| 496 | let remap = self.merge(resolve)?; | 
|---|
| 497 | return Ok(ParsedFile::Package(remap.packages[pkg.index()])); | 
|---|
| 498 | } | 
|---|
| 499 | } | 
|---|
| 500 | } | 
|---|
| 501 | } | 
|---|
| 502 |  | 
|---|
| 503 | // If this wasn't a wasm file then assume it's a WIT file. | 
|---|
| 504 | let text = match std::str::from_utf8(&contents) { | 
|---|
| 505 | Ok(s) => s, | 
|---|
| 506 | Err(_) => bail!( "input file is not valid utf-8 [{} ]", path.display()), | 
|---|
| 507 | }; | 
|---|
| 508 | let pkgs = UnresolvedPackageGroup::parse(path, text)?; | 
|---|
| 509 | Ok(ParsedFile::Unresolved(pkgs)) | 
|---|
| 510 | } | 
|---|
| 511 |  | 
|---|
| 512 | /// Appends a new [`UnresolvedPackage`] to this [`Resolve`], creating a | 
|---|
| 513 | /// fully resolved package with no dangling references. | 
|---|
| 514 | /// | 
|---|
| 515 | /// All the dependencies of `unresolved` must already have been loaded | 
|---|
| 516 | /// within this `Resolve` via previous calls to `push` or other methods such | 
|---|
| 517 | /// as [`Resolve::push_path`]. | 
|---|
| 518 | /// | 
|---|
| 519 | /// Any dependency resolution error or otherwise world-elaboration error | 
|---|
| 520 | /// will be returned here, if successful a package identifier is returned | 
|---|
| 521 | /// which corresponds to the package that was just inserted. | 
|---|
| 522 | pub fn push( | 
|---|
| 523 | &mut self, | 
|---|
| 524 | unresolved: UnresolvedPackage, | 
|---|
| 525 | source_map: &SourceMap, | 
|---|
| 526 | ) -> Result<PackageId> { | 
|---|
| 527 | source_map.rewrite_error(|| Remap::default().append(self, unresolved)) | 
|---|
| 528 | } | 
|---|
| 529 |  | 
|---|
| 530 | /// Appends new [`UnresolvedPackageGroup`] to this [`Resolve`], creating a | 
|---|
| 531 | /// fully resolved package with no dangling references. | 
|---|
| 532 | /// | 
|---|
| 533 | /// Any dependency resolution error or otherwise world-elaboration error | 
|---|
| 534 | /// will be returned here, if successful a package identifier is returned | 
|---|
| 535 | /// which corresponds to the package that was just inserted. | 
|---|
| 536 | /// | 
|---|
| 537 | /// The returned [`PackageId`]s are listed in topologically sorted order. | 
|---|
| 538 | pub fn push_group(&mut self, unresolved_group: UnresolvedPackageGroup) -> Result<PackageId> { | 
|---|
| 539 | let (pkg_id, _) = self.sort_unresolved_packages(unresolved_group, Vec::new())?; | 
|---|
| 540 | Ok(pkg_id) | 
|---|
| 541 | } | 
|---|
| 542 |  | 
|---|
| 543 | /// Convenience method for combining [`UnresolvedPackageGroup::parse`] and | 
|---|
| 544 | /// [`Resolve::push_group`]. | 
|---|
| 545 | /// | 
|---|
| 546 | /// The `path` provided is used for error messages but otherwise is not | 
|---|
| 547 | /// read. This method does not touch the filesystem. The `contents` provided | 
|---|
| 548 | /// are the contents of a WIT package. | 
|---|
| 549 | pub fn push_str(&mut self, path: impl AsRef<Path>, contents: &str) -> Result<PackageId> { | 
|---|
| 550 | self.push_group(UnresolvedPackageGroup::parse(path.as_ref(), contents)?) | 
|---|
| 551 | } | 
|---|
| 552 |  | 
|---|
| 553 | pub fn all_bits_valid(&self, ty: &Type) -> bool { | 
|---|
| 554 | match ty { | 
|---|
| 555 | Type::U8 | 
|---|
| 556 | | Type::S8 | 
|---|
| 557 | | Type::U16 | 
|---|
| 558 | | Type::S16 | 
|---|
| 559 | | Type::U32 | 
|---|
| 560 | | Type::S32 | 
|---|
| 561 | | Type::U64 | 
|---|
| 562 | | Type::S64 | 
|---|
| 563 | | Type::F32 | 
|---|
| 564 | | Type::F64 => true, | 
|---|
| 565 |  | 
|---|
| 566 | Type::Bool | Type::Char | Type::String => false, | 
|---|
| 567 |  | 
|---|
| 568 | Type::Id(id) => match &self.types[*id].kind { | 
|---|
| 569 | TypeDefKind::List(_) | 
|---|
| 570 | | TypeDefKind::Variant(_) | 
|---|
| 571 | | TypeDefKind::Enum(_) | 
|---|
| 572 | | TypeDefKind::Option(_) | 
|---|
| 573 | | TypeDefKind::Result(_) | 
|---|
| 574 | | TypeDefKind::Future(_) | 
|---|
| 575 | | TypeDefKind::Stream(_) | 
|---|
| 576 | | TypeDefKind::ErrorContext => false, | 
|---|
| 577 | TypeDefKind::Type(t) => self.all_bits_valid(t), | 
|---|
| 578 |  | 
|---|
| 579 | TypeDefKind::Handle(h) => match h { | 
|---|
| 580 | crate::Handle::Own(_) => true, | 
|---|
| 581 | crate::Handle::Borrow(_) => true, | 
|---|
| 582 | }, | 
|---|
| 583 |  | 
|---|
| 584 | TypeDefKind::Resource => false, | 
|---|
| 585 | TypeDefKind::Record(r) => r.fields.iter().all(|f| self.all_bits_valid(&f.ty)), | 
|---|
| 586 | TypeDefKind::Tuple(t) => t.types.iter().all(|t| self.all_bits_valid(t)), | 
|---|
| 587 |  | 
|---|
| 588 | // FIXME: this could perhaps be `true` for multiples-of-32 but | 
|---|
| 589 | // seems better to probably leave this as unconditionally | 
|---|
| 590 | // `false` for now, may want to reconsider later? | 
|---|
| 591 | TypeDefKind::Flags(_) => false, | 
|---|
| 592 |  | 
|---|
| 593 | TypeDefKind::Unknown => unreachable!(), | 
|---|
| 594 | }, | 
|---|
| 595 | } | 
|---|
| 596 | } | 
|---|
| 597 |  | 
|---|
| 598 | /// Merges all the contents of a different `Resolve` into this one. The | 
|---|
| 599 | /// `Remap` structure returned provides a mapping from all old indices to | 
|---|
| 600 | /// new indices | 
|---|
| 601 | /// | 
|---|
| 602 | /// This operation can fail if `resolve` disagrees with `self` about the | 
|---|
| 603 | /// packages being inserted. Otherwise though this will additionally attempt | 
|---|
| 604 | /// to "union" packages found in `resolve` with those found in `self`. | 
|---|
| 605 | /// Unioning packages is keyed on the name/url of packages for those with | 
|---|
| 606 | /// URLs present. If found then it's assumed that both `Resolve` instances | 
|---|
| 607 | /// were originally created from the same contents and are two views | 
|---|
| 608 | /// of the same package. | 
|---|
| 609 | pub fn merge(&mut self, resolve: Resolve) -> Result<Remap> { | 
|---|
| 610 | log::trace!( | 
|---|
| 611 | "merging {}  packages into {}  packages", | 
|---|
| 612 | resolve.packages.len(), | 
|---|
| 613 | self.packages.len() | 
|---|
| 614 | ); | 
|---|
| 615 |  | 
|---|
| 616 | let mut map = MergeMap::new(&resolve, &self); | 
|---|
| 617 | map.build()?; | 
|---|
| 618 | let MergeMap { | 
|---|
| 619 | package_map, | 
|---|
| 620 | interface_map, | 
|---|
| 621 | type_map, | 
|---|
| 622 | world_map, | 
|---|
| 623 | interfaces_to_add, | 
|---|
| 624 | worlds_to_add, | 
|---|
| 625 | .. | 
|---|
| 626 | } = map; | 
|---|
| 627 |  | 
|---|
| 628 | // With a set of maps from ids in `resolve` to ids in `self` the next | 
|---|
| 629 | // operation is to start moving over items and building a `Remap` to | 
|---|
| 630 | // update ids. | 
|---|
| 631 | // | 
|---|
| 632 | // Each component field of `resolve` is moved into `self` so long as | 
|---|
| 633 | // its ID is not within one of the maps above. If it's present in a map | 
|---|
| 634 | // above then that means the item is already present in `self` so a new | 
|---|
| 635 | // one need not be added. If it's not present in a map that means it's | 
|---|
| 636 | // not present in `self` so it must be added to an arena. | 
|---|
| 637 | // | 
|---|
| 638 | // When adding an item to an arena one of the `remap.update_*` methods | 
|---|
| 639 | // is additionally called to update all identifiers from pointers within | 
|---|
| 640 | // `resolve` to becoming pointers within `self`. | 
|---|
| 641 | // | 
|---|
| 642 | // Altogether this should weave all the missing items in `self` from | 
|---|
| 643 | // `resolve` into one structure while updating all identifiers to | 
|---|
| 644 | // be local within `self`. | 
|---|
| 645 |  | 
|---|
| 646 | let mut remap = Remap::default(); | 
|---|
| 647 | let Resolve { | 
|---|
| 648 | types, | 
|---|
| 649 | worlds, | 
|---|
| 650 | interfaces, | 
|---|
| 651 | packages, | 
|---|
| 652 | package_names, | 
|---|
| 653 | features: _, | 
|---|
| 654 | .. | 
|---|
| 655 | } = resolve; | 
|---|
| 656 |  | 
|---|
| 657 | let mut moved_types = Vec::new(); | 
|---|
| 658 | for (id, mut ty) in types { | 
|---|
| 659 | let new_id = match type_map.get(&id).copied() { | 
|---|
| 660 | Some(id) => { | 
|---|
| 661 | update_stability(&ty.stability, &mut self.types[id].stability)?; | 
|---|
| 662 | id | 
|---|
| 663 | } | 
|---|
| 664 | None => { | 
|---|
| 665 | log::debug!( "moving type {:?} ", ty.name); | 
|---|
| 666 | moved_types.push(id); | 
|---|
| 667 | remap.update_typedef(self, &mut ty, None)?; | 
|---|
| 668 | self.types.alloc(ty) | 
|---|
| 669 | } | 
|---|
| 670 | }; | 
|---|
| 671 | assert_eq!(remap.types.len(), id.index()); | 
|---|
| 672 | remap.types.push(Some(new_id)); | 
|---|
| 673 | } | 
|---|
| 674 |  | 
|---|
| 675 | let mut moved_interfaces = Vec::new(); | 
|---|
| 676 | for (id, mut iface) in interfaces { | 
|---|
| 677 | let new_id = match interface_map.get(&id).copied() { | 
|---|
| 678 | Some(id) => { | 
|---|
| 679 | update_stability(&iface.stability, &mut self.interfaces[id].stability)?; | 
|---|
| 680 | id | 
|---|
| 681 | } | 
|---|
| 682 | None => { | 
|---|
| 683 | log::debug!( "moving interface {:?} ", iface.name); | 
|---|
| 684 | moved_interfaces.push(id); | 
|---|
| 685 | remap.update_interface(self, &mut iface, None)?; | 
|---|
| 686 | self.interfaces.alloc(iface) | 
|---|
| 687 | } | 
|---|
| 688 | }; | 
|---|
| 689 | assert_eq!(remap.interfaces.len(), id.index()); | 
|---|
| 690 | remap.interfaces.push(Some(new_id)); | 
|---|
| 691 | } | 
|---|
| 692 |  | 
|---|
| 693 | let mut moved_worlds = Vec::new(); | 
|---|
| 694 | for (id, mut world) in worlds { | 
|---|
| 695 | let new_id = match world_map.get(&id).copied() { | 
|---|
| 696 | Some(id) => { | 
|---|
| 697 | update_stability(&world.stability, &mut self.worlds[id].stability)?; | 
|---|
| 698 | id | 
|---|
| 699 | } | 
|---|
| 700 | None => { | 
|---|
| 701 | log::debug!( "moving world {} ", world.name); | 
|---|
| 702 | moved_worlds.push(id); | 
|---|
| 703 | let mut update = |map: &mut IndexMap<WorldKey, WorldItem>| -> Result<_> { | 
|---|
| 704 | for (mut name, mut item) in mem::take(map) { | 
|---|
| 705 | remap.update_world_key(&mut name, None)?; | 
|---|
| 706 | match &mut item { | 
|---|
| 707 | WorldItem::Function(f) => remap.update_function(self, f, None)?, | 
|---|
| 708 | WorldItem::Interface { id, .. } => { | 
|---|
| 709 | *id = remap.map_interface(*id, None)? | 
|---|
| 710 | } | 
|---|
| 711 | WorldItem::Type(i) => *i = remap.map_type(*i, None)?, | 
|---|
| 712 | } | 
|---|
| 713 | map.insert(name, item); | 
|---|
| 714 | } | 
|---|
| 715 | Ok(()) | 
|---|
| 716 | }; | 
|---|
| 717 | update(&mut world.imports)?; | 
|---|
| 718 | update(&mut world.exports)?; | 
|---|
| 719 | self.worlds.alloc(world) | 
|---|
| 720 | } | 
|---|
| 721 | }; | 
|---|
| 722 | assert_eq!(remap.worlds.len(), id.index()); | 
|---|
| 723 | remap.worlds.push(Some(new_id)); | 
|---|
| 724 | } | 
|---|
| 725 |  | 
|---|
| 726 | for (id, mut pkg) in packages { | 
|---|
| 727 | let new_id = match package_map.get(&id).copied() { | 
|---|
| 728 | Some(id) => id, | 
|---|
| 729 | None => { | 
|---|
| 730 | for (_, id) in pkg.interfaces.iter_mut() { | 
|---|
| 731 | *id = remap.map_interface(*id, None)?; | 
|---|
| 732 | } | 
|---|
| 733 | for (_, id) in pkg.worlds.iter_mut() { | 
|---|
| 734 | *id = remap.map_world(*id, None)?; | 
|---|
| 735 | } | 
|---|
| 736 | self.packages.alloc(pkg) | 
|---|
| 737 | } | 
|---|
| 738 | }; | 
|---|
| 739 | assert_eq!(remap.packages.len(), id.index()); | 
|---|
| 740 | remap.packages.push(new_id); | 
|---|
| 741 | } | 
|---|
| 742 |  | 
|---|
| 743 | for (name, id) in package_names { | 
|---|
| 744 | let id = remap.packages[id.index()]; | 
|---|
| 745 | if let Some(prev) = self.package_names.insert(name, id) { | 
|---|
| 746 | assert_eq!(prev, id); | 
|---|
| 747 | } | 
|---|
| 748 | } | 
|---|
| 749 |  | 
|---|
| 750 | // Fixup all "parent" links now. | 
|---|
| 751 | // | 
|---|
| 752 | // Note that this is only done for items that are actually moved from | 
|---|
| 753 | // `resolve` into `self`, which is tracked by the various `moved_*` | 
|---|
| 754 | // lists built incrementally above. The ids in the `moved_*` lists | 
|---|
| 755 | // are ids within `resolve`, so they're translated through `remap` to | 
|---|
| 756 | // ids within `self`. | 
|---|
| 757 | for id in moved_worlds { | 
|---|
| 758 | let id = remap.map_world(id, None)?; | 
|---|
| 759 | if let Some(pkg) = self.worlds[id].package.as_mut() { | 
|---|
| 760 | *pkg = remap.packages[pkg.index()]; | 
|---|
| 761 | } | 
|---|
| 762 | } | 
|---|
| 763 | for id in moved_interfaces { | 
|---|
| 764 | let id = remap.map_interface(id, None)?; | 
|---|
| 765 | if let Some(pkg) = self.interfaces[id].package.as_mut() { | 
|---|
| 766 | *pkg = remap.packages[pkg.index()]; | 
|---|
| 767 | } | 
|---|
| 768 | } | 
|---|
| 769 | for id in moved_types { | 
|---|
| 770 | let id = remap.map_type(id, None)?; | 
|---|
| 771 | match &mut self.types[id].owner { | 
|---|
| 772 | TypeOwner::Interface(id) => *id = remap.map_interface(*id, None)?, | 
|---|
| 773 | TypeOwner::World(id) => *id = remap.map_world(*id, None)?, | 
|---|
| 774 | TypeOwner::None => {} | 
|---|
| 775 | } | 
|---|
| 776 | } | 
|---|
| 777 |  | 
|---|
| 778 | // And finally process items that were present in `resolve` but were | 
|---|
| 779 | // not present in `self`. This is only done for merged packages as | 
|---|
| 780 | // documents may be added to `self.documents` but wouldn't otherwise be | 
|---|
| 781 | // present in the `documents` field of the corresponding package. | 
|---|
| 782 | for (name, pkg, iface) in interfaces_to_add { | 
|---|
| 783 | let prev = self.packages[pkg] | 
|---|
| 784 | .interfaces | 
|---|
| 785 | .insert(name, remap.map_interface(iface, None)?); | 
|---|
| 786 | assert!(prev.is_none()); | 
|---|
| 787 | } | 
|---|
| 788 | for (name, pkg, world) in worlds_to_add { | 
|---|
| 789 | let prev = self.packages[pkg] | 
|---|
| 790 | .worlds | 
|---|
| 791 | .insert(name, remap.map_world(world, None)?); | 
|---|
| 792 | assert!(prev.is_none()); | 
|---|
| 793 | } | 
|---|
| 794 |  | 
|---|
| 795 | log::trace!( "now have {}  packages", self.packages.len()); | 
|---|
| 796 |  | 
|---|
| 797 | #[ cfg(debug_assertions)] | 
|---|
| 798 | self.assert_valid(); | 
|---|
| 799 | Ok(remap) | 
|---|
| 800 | } | 
|---|
| 801 |  | 
|---|
| 802 | /// Merges the world `from` into the world `into`. | 
|---|
| 803 | /// | 
|---|
| 804 | /// This will attempt to merge one world into another, unioning all of its | 
|---|
| 805 | /// imports and exports together. This is an operation performed by | 
|---|
| 806 | /// `wit-component`, for example where two different worlds from two | 
|---|
| 807 | /// different libraries were linked into the same core wasm file and are | 
|---|
| 808 | /// producing a singular world that will be the final component's | 
|---|
| 809 | /// interface. | 
|---|
| 810 | /// | 
|---|
| 811 | /// This operation can fail if the imports/exports overlap. | 
|---|
| 812 | pub fn merge_worlds(&mut self, from: WorldId, into: WorldId) -> Result<()> { | 
|---|
| 813 | let mut new_imports = Vec::new(); | 
|---|
| 814 | let mut new_exports = Vec::new(); | 
|---|
| 815 |  | 
|---|
| 816 | let from_world = &self.worlds[from]; | 
|---|
| 817 | let into_world = &self.worlds[into]; | 
|---|
| 818 |  | 
|---|
| 819 | log::trace!( "merging {}  into {} ", from_world.name, into_world.name); | 
|---|
| 820 |  | 
|---|
| 821 | // First walk over all the imports of `from` world and figure out what | 
|---|
| 822 | // to do with them. | 
|---|
| 823 | // | 
|---|
| 824 | // If the same item exists in `from` and `into` then merge it together | 
|---|
| 825 | // below with `merge_world_item` which basically asserts they're the | 
|---|
| 826 | // same. Otherwise queue up a new import since if `from` has more | 
|---|
| 827 | // imports than `into` then it's fine to add new imports. | 
|---|
| 828 | for (name, from_import) in from_world.imports.iter() { | 
|---|
| 829 | let name_str = self.name_world_key(name); | 
|---|
| 830 | match into_world.imports.get(name) { | 
|---|
| 831 | Some(into_import) => { | 
|---|
| 832 | log::trace!( "info/from shared import on `{name_str} `"); | 
|---|
| 833 | self.merge_world_item(from_import, into_import) | 
|---|
| 834 | .with_context(|| format!( "failed to merge world import {name_str} "))?; | 
|---|
| 835 | } | 
|---|
| 836 | None => { | 
|---|
| 837 | log::trace!( "new import: `{name_str} `"); | 
|---|
| 838 | new_imports.push((name.clone(), from_import.clone())); | 
|---|
| 839 | } | 
|---|
| 840 | } | 
|---|
| 841 | } | 
|---|
| 842 |  | 
|---|
| 843 | // Build a set of interfaces which are required to be imported because | 
|---|
| 844 | // of `into`'s exports. This set is then used below during | 
|---|
| 845 | // `ensure_can_add_world_export`. | 
|---|
| 846 | // | 
|---|
| 847 | // This is the set of interfaces which exports depend on that are | 
|---|
| 848 | // themselves not exports. | 
|---|
| 849 | let mut must_be_imported = HashMap::new(); | 
|---|
| 850 | for (key, export) in into_world.exports.iter() { | 
|---|
| 851 | for dep in self.world_item_direct_deps(export) { | 
|---|
| 852 | if into_world.exports.contains_key(&WorldKey::Interface(dep)) { | 
|---|
| 853 | continue; | 
|---|
| 854 | } | 
|---|
| 855 | self.foreach_interface_dep(dep, &mut |id| { | 
|---|
| 856 | must_be_imported.insert(id, key.clone()); | 
|---|
| 857 | }); | 
|---|
| 858 | } | 
|---|
| 859 | } | 
|---|
| 860 |  | 
|---|
| 861 | // Next walk over exports of `from` and process these similarly to | 
|---|
| 862 | // imports. | 
|---|
| 863 | for (name, from_export) in from_world.exports.iter() { | 
|---|
| 864 | let name_str = self.name_world_key(name); | 
|---|
| 865 | match into_world.exports.get(name) { | 
|---|
| 866 | Some(into_export) => { | 
|---|
| 867 | log::trace!( "info/from shared export on `{name_str} `"); | 
|---|
| 868 | self.merge_world_item(from_export, into_export) | 
|---|
| 869 | .with_context(|| format!( "failed to merge world export {name_str} "))?; | 
|---|
| 870 | } | 
|---|
| 871 | None => { | 
|---|
| 872 | log::trace!( "new export `{name_str} `"); | 
|---|
| 873 | // See comments in `ensure_can_add_world_export` for why | 
|---|
| 874 | // this is slightly different than imports. | 
|---|
| 875 | self.ensure_can_add_world_export( | 
|---|
| 876 | into_world, | 
|---|
| 877 | name, | 
|---|
| 878 | from_export, | 
|---|
| 879 | &must_be_imported, | 
|---|
| 880 | ) | 
|---|
| 881 | .with_context(|| { | 
|---|
| 882 | format!( "failed to add export `{} `", self.name_world_key(name)) | 
|---|
| 883 | })?; | 
|---|
| 884 | new_exports.push((name.clone(), from_export.clone())); | 
|---|
| 885 | } | 
|---|
| 886 | } | 
|---|
| 887 | } | 
|---|
| 888 |  | 
|---|
| 889 | // For all the new imports and exports they may need to be "cloned" to | 
|---|
| 890 | // be able to belong to the new world. For example: | 
|---|
| 891 | // | 
|---|
| 892 | // * Anonymous interfaces have a `package` field which points to the | 
|---|
| 893 | //   package of the containing world, but `from` and `into` may not be | 
|---|
| 894 | //   in the same package. | 
|---|
| 895 | // | 
|---|
| 896 | // * Type imports have an `owner` field that point to `from`, but they | 
|---|
| 897 | //   now need to point to `into` instead. | 
|---|
| 898 | // | 
|---|
| 899 | // Cloning is no trivial task, however, so cloning is delegated to a | 
|---|
| 900 | // submodule to perform a "deep" clone and copy items into new arena | 
|---|
| 901 | // entries as necessary. | 
|---|
| 902 | let mut cloner = clone::Cloner::new(self, TypeOwner::World(from), TypeOwner::World(into)); | 
|---|
| 903 | cloner.register_world_type_overlap(from, into); | 
|---|
| 904 | for (name, item) in new_imports.iter_mut().chain(&mut new_exports) { | 
|---|
| 905 | cloner.world_item(name, item); | 
|---|
| 906 | } | 
|---|
| 907 |  | 
|---|
| 908 | // Insert any new imports and new exports found first. | 
|---|
| 909 | let into_world = &mut self.worlds[into]; | 
|---|
| 910 | for (name, import) in new_imports { | 
|---|
| 911 | let prev = into_world.imports.insert(name, import); | 
|---|
| 912 | assert!(prev.is_none()); | 
|---|
| 913 | } | 
|---|
| 914 | for (name, export) in new_exports { | 
|---|
| 915 | let prev = into_world.exports.insert(name, export); | 
|---|
| 916 | assert!(prev.is_none()); | 
|---|
| 917 | } | 
|---|
| 918 |  | 
|---|
| 919 | #[ cfg(debug_assertions)] | 
|---|
| 920 | self.assert_valid(); | 
|---|
| 921 | Ok(()) | 
|---|
| 922 | } | 
|---|
| 923 |  | 
|---|
| 924 | fn merge_world_item(&self, from: &WorldItem, into: &WorldItem) -> Result<()> { | 
|---|
| 925 | let mut map = MergeMap::new(self, self); | 
|---|
| 926 | match (from, into) { | 
|---|
| 927 | (WorldItem::Interface { id: from, .. }, WorldItem::Interface { id: into, .. }) => { | 
|---|
| 928 | // If these imports are the same that can happen, for | 
|---|
| 929 | // example, when both worlds to `import foo:bar/baz;`. That | 
|---|
| 930 | // foreign interface will point to the same interface within | 
|---|
| 931 | // `Resolve`. | 
|---|
| 932 | if from == into { | 
|---|
| 933 | return Ok(()); | 
|---|
| 934 | } | 
|---|
| 935 |  | 
|---|
| 936 | // .. otherwise this MUST be a case of | 
|---|
| 937 | // `import foo: interface { ... }`. If `from != into` but | 
|---|
| 938 | // both `from` and `into` have the same name then the | 
|---|
| 939 | // `WorldKey::Interface` case is ruled out as otherwise | 
|---|
| 940 | // they'd have different names. | 
|---|
| 941 | // | 
|---|
| 942 | // In the case of an anonymous interface all we can do is | 
|---|
| 943 | // ensure that the interfaces both match, so use `MergeMap` | 
|---|
| 944 | // for that. | 
|---|
| 945 | map.build_interface(*from, *into) | 
|---|
| 946 | .context( "failed to merge interfaces")?; | 
|---|
| 947 | } | 
|---|
| 948 |  | 
|---|
| 949 | // Like `WorldKey::Name` interfaces for functions and types the | 
|---|
| 950 | // structure is asserted to be the same. | 
|---|
| 951 | (WorldItem::Function(from), WorldItem::Function(into)) => { | 
|---|
| 952 | map.build_function(from, into) | 
|---|
| 953 | .context( "failed to merge functions")?; | 
|---|
| 954 | } | 
|---|
| 955 | (WorldItem::Type(from), WorldItem::Type(into)) => { | 
|---|
| 956 | map.build_type_id(*from, *into) | 
|---|
| 957 | .context( "failed to merge types")?; | 
|---|
| 958 | } | 
|---|
| 959 |  | 
|---|
| 960 | // Kind-level mismatches are caught here. | 
|---|
| 961 | (WorldItem::Interface { .. }, _) | 
|---|
| 962 | | (WorldItem::Function { .. }, _) | 
|---|
| 963 | | (WorldItem::Type { .. }, _) => { | 
|---|
| 964 | bail!( "different kinds of items"); | 
|---|
| 965 | } | 
|---|
| 966 | } | 
|---|
| 967 | assert!(map.interfaces_to_add.is_empty()); | 
|---|
| 968 | assert!(map.worlds_to_add.is_empty()); | 
|---|
| 969 | Ok(()) | 
|---|
| 970 | } | 
|---|
| 971 |  | 
|---|
| 972 | /// This method ensures that the world export of `name` and `item` can be | 
|---|
| 973 | /// added to the world `into` without changing the meaning of `into`. | 
|---|
| 974 | /// | 
|---|
| 975 | /// All dependencies of world exports must either be: | 
|---|
| 976 | /// | 
|---|
| 977 | /// * An export themselves | 
|---|
| 978 | /// * An import with all transitive dependencies of the import also imported | 
|---|
| 979 | /// | 
|---|
| 980 | /// It's not possible to depend on an import which then also depends on an | 
|---|
| 981 | /// export at some point, for example. This method ensures that if `name` | 
|---|
| 982 | /// and `item` are added that this property is upheld. | 
|---|
| 983 | fn ensure_can_add_world_export( | 
|---|
| 984 | &self, | 
|---|
| 985 | into: &World, | 
|---|
| 986 | name: &WorldKey, | 
|---|
| 987 | item: &WorldItem, | 
|---|
| 988 | must_be_imported: &HashMap<InterfaceId, WorldKey>, | 
|---|
| 989 | ) -> Result<()> { | 
|---|
| 990 | assert!(!into.exports.contains_key(name)); | 
|---|
| 991 | let name = self.name_world_key(name); | 
|---|
| 992 |  | 
|---|
| 993 | // First make sure that all of this item's dependencies are either | 
|---|
| 994 | // exported or the entire chain of imports rooted at that dependency are | 
|---|
| 995 | // all imported. | 
|---|
| 996 | for dep in self.world_item_direct_deps(item) { | 
|---|
| 997 | if into.exports.contains_key(&WorldKey::Interface(dep)) { | 
|---|
| 998 | continue; | 
|---|
| 999 | } | 
|---|
| 1000 | self.ensure_not_exported(into, dep) | 
|---|
| 1001 | .with_context(|| format!( "failed validating export of `{name} `"))?; | 
|---|
| 1002 | } | 
|---|
| 1003 |  | 
|---|
| 1004 | // Second make sure that this item, if it's an interface, will not alter | 
|---|
| 1005 | // the meaning of the preexisting world by ensuring that it's not in the | 
|---|
| 1006 | // set of "must be imported" items. | 
|---|
| 1007 | if let WorldItem::Interface { id, .. } = item { | 
|---|
| 1008 | if let Some(export) = must_be_imported.get(&id) { | 
|---|
| 1009 | let export_name = self.name_world_key(export); | 
|---|
| 1010 | bail!( | 
|---|
| 1011 | "export `{export_name} ` depends on `{name} ` \ | 
|---|
| 1012 |                      previously as an import which will change meaning \ | 
|---|
| 1013 |                      if `{name} ` is added as an export" | 
|---|
| 1014 | ); | 
|---|
| 1015 | } | 
|---|
| 1016 | } | 
|---|
| 1017 |  | 
|---|
| 1018 | Ok(()) | 
|---|
| 1019 | } | 
|---|
| 1020 |  | 
|---|
| 1021 | fn ensure_not_exported(&self, world: &World, id: InterfaceId) -> Result<()> { | 
|---|
| 1022 | let key = WorldKey::Interface(id); | 
|---|
| 1023 | let name = self.name_world_key(&key); | 
|---|
| 1024 | if world.exports.contains_key(&key) { | 
|---|
| 1025 | bail!( | 
|---|
| 1026 | "world exports `{name} ` but it's also transitively used by an \ | 
|---|
| 1027 |                      import \ | 
|---|
| 1028 |                    which means that this is not valid" | 
|---|
| 1029 | ) | 
|---|
| 1030 | } | 
|---|
| 1031 | for dep in self.interface_direct_deps(id) { | 
|---|
| 1032 | self.ensure_not_exported(world, dep) | 
|---|
| 1033 | .with_context(|| format!( "failed validating transitive import dep `{name} `"))?; | 
|---|
| 1034 | } | 
|---|
| 1035 | Ok(()) | 
|---|
| 1036 | } | 
|---|
| 1037 |  | 
|---|
| 1038 | /// Returns an iterator of all the direct interface dependencies of this | 
|---|
| 1039 | /// `item`. | 
|---|
| 1040 | /// | 
|---|
| 1041 | /// Note that this doesn't include transitive dependencies, that must be | 
|---|
| 1042 | /// followed manually. | 
|---|
| 1043 | fn world_item_direct_deps(&self, item: &WorldItem) -> impl Iterator<Item = InterfaceId> + '_ { | 
|---|
| 1044 | let mut interface = None; | 
|---|
| 1045 | let mut ty = None; | 
|---|
| 1046 | match item { | 
|---|
| 1047 | WorldItem::Function(_) => {} | 
|---|
| 1048 | WorldItem::Type(id) => ty = Some(*id), | 
|---|
| 1049 | WorldItem::Interface { id, .. } => interface = Some(*id), | 
|---|
| 1050 | } | 
|---|
| 1051 |  | 
|---|
| 1052 | interface | 
|---|
| 1053 | .into_iter() | 
|---|
| 1054 | .flat_map(move |id| self.interface_direct_deps(id)) | 
|---|
| 1055 | .chain(ty.and_then(|t| self.type_interface_dep(t))) | 
|---|
| 1056 | } | 
|---|
| 1057 |  | 
|---|
| 1058 | /// Invokes `f` with `id` and all transitive interface dependencies of `id`. | 
|---|
| 1059 | /// | 
|---|
| 1060 | /// Note that `f` may be called with the same id multiple times. | 
|---|
| 1061 | fn foreach_interface_dep(&self, id: InterfaceId, f: &mut dyn FnMut(InterfaceId)) { | 
|---|
| 1062 | f(id); | 
|---|
| 1063 | for dep in self.interface_direct_deps(id) { | 
|---|
| 1064 | self.foreach_interface_dep(dep, f); | 
|---|
| 1065 | } | 
|---|
| 1066 | } | 
|---|
| 1067 |  | 
|---|
| 1068 | /// Returns the ID of the specified `interface`. | 
|---|
| 1069 | /// | 
|---|
| 1070 | /// Returns `None` for unnamed interfaces. | 
|---|
| 1071 | pub fn id_of(&self, interface: InterfaceId) -> Option<String> { | 
|---|
| 1072 | let interface = &self.interfaces[interface]; | 
|---|
| 1073 | Some(self.id_of_name(interface.package.unwrap(), interface.name.as_ref()?)) | 
|---|
| 1074 | } | 
|---|
| 1075 |  | 
|---|
| 1076 | /// Returns the "canonicalized interface name" of `interface`. | 
|---|
| 1077 | /// | 
|---|
| 1078 | /// Returns `None` for unnamed interfaces. See `BuildTargets.md` in the | 
|---|
| 1079 | /// upstream component model repository for more information about this. | 
|---|
| 1080 | pub fn canonicalized_id_of(&self, interface: InterfaceId) -> Option<String> { | 
|---|
| 1081 | let interface = &self.interfaces[interface]; | 
|---|
| 1082 | Some(self.canonicalized_id_of_name(interface.package.unwrap(), interface.name.as_ref()?)) | 
|---|
| 1083 | } | 
|---|
| 1084 |  | 
|---|
| 1085 | /// Convert a world to an "importized" version where the world is updated | 
|---|
| 1086 | /// in-place to reflect what it would look like to be imported. | 
|---|
| 1087 | /// | 
|---|
| 1088 | /// This is a transformation which is used as part of the process of | 
|---|
| 1089 | /// importing a component today. For example when a component depends on | 
|---|
| 1090 | /// another component this is useful for generating WIT which can be use to | 
|---|
| 1091 | /// represent the component being imported. The general idea is that this | 
|---|
| 1092 | /// function will update the `world_id` specified such it imports the | 
|---|
| 1093 | /// functionality that it previously exported. The world will be left with | 
|---|
| 1094 | /// no exports. | 
|---|
| 1095 | /// | 
|---|
| 1096 | /// This world is then suitable for merging into other worlds or generating | 
|---|
| 1097 | /// bindings in a context that is importing the original world. This | 
|---|
| 1098 | /// is intended to be used as part of language tooling when depending on | 
|---|
| 1099 | /// other components. | 
|---|
| 1100 | pub fn importize(&mut self, world_id: WorldId, out_world_name: Option<String>) -> Result<()> { | 
|---|
| 1101 | // Rename the world to avoid having it get confused with the original | 
|---|
| 1102 | // name of the world. Add `-importized` to it for now. Precisely how | 
|---|
| 1103 | // this new world is created may want to be updated over time if this | 
|---|
| 1104 | // becomes problematic. | 
|---|
| 1105 | let world = &mut self.worlds[world_id]; | 
|---|
| 1106 | let pkg = &mut self.packages[world.package.unwrap()]; | 
|---|
| 1107 | pkg.worlds.shift_remove(&world.name); | 
|---|
| 1108 | if let Some(name) = out_world_name { | 
|---|
| 1109 | world.name = name.clone(); | 
|---|
| 1110 | pkg.worlds.insert(name, world_id); | 
|---|
| 1111 | } else { | 
|---|
| 1112 | world.name.push_str( "-importized"); | 
|---|
| 1113 | pkg.worlds.insert(world.name.clone(), world_id); | 
|---|
| 1114 | } | 
|---|
| 1115 |  | 
|---|
| 1116 | // Trim all non-type definitions from imports. Types can be used by | 
|---|
| 1117 | // exported functions, for example, so they're preserved. | 
|---|
| 1118 | world.imports.retain(|_, item| match item { | 
|---|
| 1119 | WorldItem::Type(_) => true, | 
|---|
| 1120 | _ => false, | 
|---|
| 1121 | }); | 
|---|
| 1122 |  | 
|---|
| 1123 | for (name, export) in mem::take(&mut world.exports) { | 
|---|
| 1124 | match (name.clone(), world.imports.insert(name, export)) { | 
|---|
| 1125 | // no previous item? this insertion was ok | 
|---|
| 1126 | (_, None) => {} | 
|---|
| 1127 |  | 
|---|
| 1128 | // cannot overwrite an import with an export | 
|---|
| 1129 | (WorldKey::Name(name), Some(_)) => { | 
|---|
| 1130 | bail!( "world export `{name} ` conflicts with import of same name"); | 
|---|
| 1131 | } | 
|---|
| 1132 |  | 
|---|
| 1133 | // Exports already don't overlap each other and the only imports | 
|---|
| 1134 | // preserved above were types so this shouldn't be reachable. | 
|---|
| 1135 | (WorldKey::Interface(_), _) => unreachable!(), | 
|---|
| 1136 | } | 
|---|
| 1137 | } | 
|---|
| 1138 |  | 
|---|
| 1139 | // Fill out any missing transitive interface imports by elaborating this | 
|---|
| 1140 | // world which does that for us. | 
|---|
| 1141 | self.elaborate_world(world_id)?; | 
|---|
| 1142 |  | 
|---|
| 1143 | #[ cfg(debug_assertions)] | 
|---|
| 1144 | self.assert_valid(); | 
|---|
| 1145 | Ok(()) | 
|---|
| 1146 | } | 
|---|
| 1147 |  | 
|---|
| 1148 | /// Returns the ID of the specified `name` within the `pkg`. | 
|---|
| 1149 | pub fn id_of_name(&self, pkg: PackageId, name: &str) -> String { | 
|---|
| 1150 | let package = &self.packages[pkg]; | 
|---|
| 1151 | let mut base = String::new(); | 
|---|
| 1152 | base.push_str(&package.name.namespace); | 
|---|
| 1153 | base.push_str( ":"); | 
|---|
| 1154 | base.push_str(&package.name.name); | 
|---|
| 1155 | base.push_str( "/"); | 
|---|
| 1156 | base.push_str(name); | 
|---|
| 1157 | if let Some(version) = &package.name.version { | 
|---|
| 1158 | base.push_str(&format!( "@{version} ")); | 
|---|
| 1159 | } | 
|---|
| 1160 | base | 
|---|
| 1161 | } | 
|---|
| 1162 |  | 
|---|
| 1163 | /// Returns the "canonicalized interface name" of the specified `name` | 
|---|
| 1164 | /// within the `pkg`. | 
|---|
| 1165 | /// | 
|---|
| 1166 | /// See `BuildTargets.md` in the upstream component model repository for | 
|---|
| 1167 | /// more information about this. | 
|---|
| 1168 | pub fn canonicalized_id_of_name(&self, pkg: PackageId, name: &str) -> String { | 
|---|
| 1169 | let package = &self.packages[pkg]; | 
|---|
| 1170 | let mut base = String::new(); | 
|---|
| 1171 | base.push_str(&package.name.namespace); | 
|---|
| 1172 | base.push_str( ":"); | 
|---|
| 1173 | base.push_str(&package.name.name); | 
|---|
| 1174 | base.push_str( "/"); | 
|---|
| 1175 | base.push_str(name); | 
|---|
| 1176 | if let Some(version) = &package.name.version { | 
|---|
| 1177 | base.push_str( "@"); | 
|---|
| 1178 | let string = PackageName::version_compat_track_string(version); | 
|---|
| 1179 | base.push_str(&string); | 
|---|
| 1180 | } | 
|---|
| 1181 | base | 
|---|
| 1182 | } | 
|---|
| 1183 |  | 
|---|
| 1184 | /// Attempts to locate a world given the "default" set of `packages` and the | 
|---|
| 1185 | /// optional string specifier `world`. | 
|---|
| 1186 | /// | 
|---|
| 1187 | /// This method is intended to be used by bindings generation tools to | 
|---|
| 1188 | /// select a world from either `packages` or a package in this `Resolve`. | 
|---|
| 1189 | /// The `packages` list is a return value from methods such as | 
|---|
| 1190 | /// [`push_path`](Resolve::push_path), [`push_dir`](Resolve::push_dir), | 
|---|
| 1191 | /// [`push_file`](Resolve::push_file), [`push_group`](Resolve::push_group), | 
|---|
| 1192 | /// or [`push_str`](Resolve::push_str). The return values of those methods | 
|---|
| 1193 | /// are the "main package list" which is specified by the user and is used | 
|---|
| 1194 | /// as a heuristic for world selection. | 
|---|
| 1195 | /// | 
|---|
| 1196 | /// If `world` is `None` then `packages` must have one entry and that | 
|---|
| 1197 | /// package must have exactly one world. If this is the case then that world | 
|---|
| 1198 | /// will be returned, otherwise an error will be returned. | 
|---|
| 1199 | /// | 
|---|
| 1200 | /// If `world` is `Some` then it can either be: | 
|---|
| 1201 | /// | 
|---|
| 1202 | /// * A kebab-name of a world such as `"the-world"`. In this situation | 
|---|
| 1203 | ///   the `packages` list must have only a single entry. If `packages` has | 
|---|
| 1204 | ///   no entries or more than one, or if the kebab-name does not exist in | 
|---|
| 1205 | ///   the one package specified, then an error will be returned. | 
|---|
| 1206 | /// | 
|---|
| 1207 | /// * An ID-based form of a world which is selected within this `Resolve`, | 
|---|
| 1208 | ///   for example `"wasi:http/proxy"`. In this situation the `packages` | 
|---|
| 1209 | ///   array is ignored and the ID specified is use to lookup a package. Note | 
|---|
| 1210 | ///   that a version does not need to be specified in this string if there's | 
|---|
| 1211 | ///   only one package of the same name and it has a version. In this | 
|---|
| 1212 | ///   situation the version can be omitted. | 
|---|
| 1213 | /// | 
|---|
| 1214 | /// If successful the corresponding `WorldId` is returned, otherwise an | 
|---|
| 1215 | /// error is returned. | 
|---|
| 1216 | /// | 
|---|
| 1217 | /// # Examples | 
|---|
| 1218 | /// | 
|---|
| 1219 | /// ``` | 
|---|
| 1220 | /// use anyhow::Result; | 
|---|
| 1221 | /// use wit_parser::Resolve; | 
|---|
| 1222 | /// | 
|---|
| 1223 | /// fn main() -> Result<()> { | 
|---|
| 1224 | ///     let mut resolve = Resolve::default(); | 
|---|
| 1225 | /// | 
|---|
| 1226 | ///     // For inputs which have a single package and only one world `None` | 
|---|
| 1227 | ///     // can be specified. | 
|---|
| 1228 | ///     let id = resolve.push_str( | 
|---|
| 1229 | /// "./my-test.wit", | 
|---|
| 1230 | /// r#" | 
|---|
| 1231 | ///             package example:wit1; | 
|---|
| 1232 | /// | 
|---|
| 1233 | ///             world foo { | 
|---|
| 1234 | ///                 // ... | 
|---|
| 1235 | ///             } | 
|---|
| 1236 | ///         "#, | 
|---|
| 1237 | ///     )?; | 
|---|
| 1238 | ///     assert!(resolve.select_world(id, None).is_ok()); | 
|---|
| 1239 | /// | 
|---|
| 1240 | ///     // For inputs which have a single package and multiple worlds then | 
|---|
| 1241 | ///     // a world must be specified. | 
|---|
| 1242 | ///     let id = resolve.push_str( | 
|---|
| 1243 | /// "./my-test.wit", | 
|---|
| 1244 | /// r#" | 
|---|
| 1245 | ///             package example:wit2; | 
|---|
| 1246 | /// | 
|---|
| 1247 | ///             world foo { /* ... */ } | 
|---|
| 1248 | /// | 
|---|
| 1249 | ///             world bar { /* ... */ } | 
|---|
| 1250 | ///         "#, | 
|---|
| 1251 | ///     )?; | 
|---|
| 1252 | ///     assert!(resolve.select_world(id, None).is_err()); | 
|---|
| 1253 | ///     assert!(resolve.select_world(id, Some( "foo")).is_ok()); | 
|---|
| 1254 | ///     assert!(resolve.select_world(id, Some( "bar")).is_ok()); | 
|---|
| 1255 | /// | 
|---|
| 1256 | ///     // For inputs which have more than one package then a fully | 
|---|
| 1257 | ///     // qualified name must be specified. | 
|---|
| 1258 | /// | 
|---|
| 1259 | ///     // Note that the `ids` or `packages` argument is ignored if a fully | 
|---|
| 1260 | ///     // qualified world specified is provided meaning previous worlds | 
|---|
| 1261 | ///     // can be selected. | 
|---|
| 1262 | ///     assert!(resolve.select_world(id, Some( "example:wit1/foo")).is_ok()); | 
|---|
| 1263 | ///     assert!(resolve.select_world(id, Some( "example:wit2/foo")).is_ok()); | 
|---|
| 1264 | /// | 
|---|
| 1265 | ///     // When selecting with a version it's ok to drop the version when | 
|---|
| 1266 | ///     // there's only a single copy of that package in `Resolve`. | 
|---|
| 1267 | ///     resolve.push_str( | 
|---|
| 1268 | /// "./my-test.wit", | 
|---|
| 1269 | /// r#" | 
|---|
| 1270 | ///             package example:wit5@1.0.0; | 
|---|
| 1271 | /// | 
|---|
| 1272 | ///             world foo { /* ... */ } | 
|---|
| 1273 | ///         "#, | 
|---|
| 1274 | ///     )?; | 
|---|
| 1275 | ///     assert!(resolve.select_world(id, Some( "example:wit5/foo")).is_ok()); | 
|---|
| 1276 | /// | 
|---|
| 1277 | ///     // However when a single package has multiple versions in a resolve | 
|---|
| 1278 | ///     // it's required to specify the version to select which one. | 
|---|
| 1279 | ///     resolve.push_str( | 
|---|
| 1280 | /// "./my-test.wit", | 
|---|
| 1281 | /// r#" | 
|---|
| 1282 | ///             package example:wit5@2.0.0; | 
|---|
| 1283 | /// | 
|---|
| 1284 | ///             world foo { /* ... */ } | 
|---|
| 1285 | ///         "#, | 
|---|
| 1286 | ///     )?; | 
|---|
| 1287 | ///     assert!(resolve.select_world(id, Some( "example:wit5/foo")).is_err()); | 
|---|
| 1288 | ///     assert!(resolve.select_world(id, Some( "example:wit5/foo@1.0.0")).is_ok()); | 
|---|
| 1289 | ///     assert!(resolve.select_world(id, Some( "example:wit5/foo@2.0.0")).is_ok()); | 
|---|
| 1290 | /// | 
|---|
| 1291 | ///     Ok(()) | 
|---|
| 1292 | /// } | 
|---|
| 1293 | /// ``` | 
|---|
| 1294 | pub fn select_world(&self, package: PackageId, world: Option<&str>) -> Result<WorldId> { | 
|---|
| 1295 | let world_path = match world { | 
|---|
| 1296 | Some(world) => Some( | 
|---|
| 1297 | parse_use_path(world) | 
|---|
| 1298 | .with_context(|| format!( "failed to parse world specifier `{world} `"))?, | 
|---|
| 1299 | ), | 
|---|
| 1300 | None => None, | 
|---|
| 1301 | }; | 
|---|
| 1302 |  | 
|---|
| 1303 | let (pkg, world_name) = match world_path { | 
|---|
| 1304 | Some(ParsedUsePath::Name(name)) => (package, name), | 
|---|
| 1305 | Some(ParsedUsePath::Package(pkg, interface)) => { | 
|---|
| 1306 | let pkg = match self.package_names.get(&pkg) { | 
|---|
| 1307 | Some(pkg) => *pkg, | 
|---|
| 1308 | None => { | 
|---|
| 1309 | let mut candidates = self.package_names.iter().filter(|(name, _)| { | 
|---|
| 1310 | pkg.version.is_none() | 
|---|
| 1311 | && pkg.name == name.name | 
|---|
| 1312 | && pkg.namespace == name.namespace | 
|---|
| 1313 | && name.version.is_some() | 
|---|
| 1314 | }); | 
|---|
| 1315 | let candidate = candidates.next(); | 
|---|
| 1316 | if let Some((c2, _)) = candidates.next() { | 
|---|
| 1317 | let (c1, _) = candidate.unwrap(); | 
|---|
| 1318 | bail!( | 
|---|
| 1319 | "package name `{pkg} ` is available at both \ | 
|---|
| 1320 |                                  versions {}  and {}  but which is not specified", | 
|---|
| 1321 | c1.version.as_ref().unwrap(), | 
|---|
| 1322 | c2.version.as_ref().unwrap(), | 
|---|
| 1323 | ); | 
|---|
| 1324 | } | 
|---|
| 1325 | match candidate { | 
|---|
| 1326 | Some((_, id)) => *id, | 
|---|
| 1327 | None => bail!( "unknown package `{pkg} `"), | 
|---|
| 1328 | } | 
|---|
| 1329 | } | 
|---|
| 1330 | }; | 
|---|
| 1331 | (pkg, interface.to_string()) | 
|---|
| 1332 | } | 
|---|
| 1333 | None => { | 
|---|
| 1334 | let pkg = &self.packages[package]; | 
|---|
| 1335 | let worlds = pkg | 
|---|
| 1336 | .worlds | 
|---|
| 1337 | .values() | 
|---|
| 1338 | .map(|world| (package, *world)) | 
|---|
| 1339 | .collect::<Vec<_>>(); | 
|---|
| 1340 |  | 
|---|
| 1341 | match &worlds[..] { | 
|---|
| 1342 | [] => bail!( "The main package `{} ` contains no worlds", pkg.name), | 
|---|
| 1343 | [(_, world)] => return Ok(*world), | 
|---|
| 1344 | _ => bail!( | 
|---|
| 1345 | "multiple worlds found; one must be explicitly chosen:{} ", | 
|---|
| 1346 | worlds | 
|---|
| 1347 | .iter() | 
|---|
| 1348 | .map(|(pkg, world)| format!( | 
|---|
| 1349 | "\n   {} /{} ", | 
|---|
| 1350 | self.packages[*pkg].name, self.worlds[*world].name | 
|---|
| 1351 | )) | 
|---|
| 1352 | .collect::<String>() | 
|---|
| 1353 | ), | 
|---|
| 1354 | } | 
|---|
| 1355 | } | 
|---|
| 1356 | }; | 
|---|
| 1357 | let pkg = &self.packages[pkg]; | 
|---|
| 1358 | pkg.worlds | 
|---|
| 1359 | .get(&world_name) | 
|---|
| 1360 | .copied() | 
|---|
| 1361 | .ok_or_else(|| anyhow!( "no world named `{world_name} ` in package")) | 
|---|
| 1362 | } | 
|---|
| 1363 |  | 
|---|
| 1364 | /// Assigns a human readable name to the `WorldKey` specified. | 
|---|
| 1365 | pub fn name_world_key(&self, key: &WorldKey) -> String { | 
|---|
| 1366 | match key { | 
|---|
| 1367 | WorldKey::Name(s) => s.to_string(), | 
|---|
| 1368 | WorldKey::Interface(i) => self.id_of(*i).expect( "unexpected anonymous interface"), | 
|---|
| 1369 | } | 
|---|
| 1370 | } | 
|---|
| 1371 |  | 
|---|
| 1372 | /// Same as [`Resolve::name_world_key`] except that `WorldKey::Interfaces` | 
|---|
| 1373 | /// uses [`Resolve::canonicalized_id_of`]. | 
|---|
| 1374 | pub fn name_canonicalized_world_key(&self, key: &WorldKey) -> String { | 
|---|
| 1375 | match key { | 
|---|
| 1376 | WorldKey::Name(s) => s.to_string(), | 
|---|
| 1377 | WorldKey::Interface(i) => self | 
|---|
| 1378 | .canonicalized_id_of(*i) | 
|---|
| 1379 | .expect( "unexpected anonymous interface"), | 
|---|
| 1380 | } | 
|---|
| 1381 | } | 
|---|
| 1382 |  | 
|---|
| 1383 | /// Returns the interface that `id` uses a type from, if it uses a type from | 
|---|
| 1384 | /// a different interface than `id` is defined within. | 
|---|
| 1385 | /// | 
|---|
| 1386 | /// If `id` is not a use-of-a-type or it's using a type in the same | 
|---|
| 1387 | /// interface then `None` is returned. | 
|---|
| 1388 | pub fn type_interface_dep(&self, id: TypeId) -> Option<InterfaceId> { | 
|---|
| 1389 | let ty = &self.types[id]; | 
|---|
| 1390 | let dep = match ty.kind { | 
|---|
| 1391 | TypeDefKind::Type(Type::Id(id)) => id, | 
|---|
| 1392 | _ => return None, | 
|---|
| 1393 | }; | 
|---|
| 1394 | let other = &self.types[dep]; | 
|---|
| 1395 | if ty.owner == other.owner { | 
|---|
| 1396 | None | 
|---|
| 1397 | } else { | 
|---|
| 1398 | match other.owner { | 
|---|
| 1399 | TypeOwner::Interface(id) => Some(id), | 
|---|
| 1400 | _ => unreachable!(), | 
|---|
| 1401 | } | 
|---|
| 1402 | } | 
|---|
| 1403 | } | 
|---|
| 1404 |  | 
|---|
| 1405 | /// Returns an iterator of all interfaces that the interface `id` depends | 
|---|
| 1406 | /// on. | 
|---|
| 1407 | /// | 
|---|
| 1408 | /// Interfaces may depend on others for type information to resolve type | 
|---|
| 1409 | /// imports. | 
|---|
| 1410 | /// | 
|---|
| 1411 | /// Note that the returned iterator may yield the same interface as a | 
|---|
| 1412 | /// dependency multiple times. Additionally only direct dependencies of `id` | 
|---|
| 1413 | /// are yielded, not transitive dependencies. | 
|---|
| 1414 | pub fn interface_direct_deps(&self, id: InterfaceId) -> impl Iterator<Item = InterfaceId> + '_ { | 
|---|
| 1415 | self.interfaces[id] | 
|---|
| 1416 | .types | 
|---|
| 1417 | .iter() | 
|---|
| 1418 | .filter_map(move |(_name, ty)| self.type_interface_dep(*ty)) | 
|---|
| 1419 | } | 
|---|
| 1420 |  | 
|---|
| 1421 | /// Returns an iterator of all packages that the package `id` depends | 
|---|
| 1422 | /// on. | 
|---|
| 1423 | /// | 
|---|
| 1424 | /// Packages may depend on others for type information to resolve type | 
|---|
| 1425 | /// imports or interfaces to resolve worlds. | 
|---|
| 1426 | /// | 
|---|
| 1427 | /// Note that the returned iterator may yield the same package as a | 
|---|
| 1428 | /// dependency multiple times. Additionally only direct dependencies of `id` | 
|---|
| 1429 | /// are yielded, not transitive dependencies. | 
|---|
| 1430 | pub fn package_direct_deps(&self, id: PackageId) -> impl Iterator<Item = PackageId> + '_ { | 
|---|
| 1431 | let pkg = &self.packages[id]; | 
|---|
| 1432 |  | 
|---|
| 1433 | pkg.interfaces | 
|---|
| 1434 | .iter() | 
|---|
| 1435 | .flat_map(move |(_name, id)| self.interface_direct_deps(*id)) | 
|---|
| 1436 | .chain(pkg.worlds.iter().flat_map(move |(_name, id)| { | 
|---|
| 1437 | let world = &self.worlds[*id]; | 
|---|
| 1438 | world | 
|---|
| 1439 | .imports | 
|---|
| 1440 | .iter() | 
|---|
| 1441 | .chain(world.exports.iter()) | 
|---|
| 1442 | .filter_map(move |(_name, item)| match item { | 
|---|
| 1443 | WorldItem::Interface { id, .. } => Some(*id), | 
|---|
| 1444 | WorldItem::Function(_) => None, | 
|---|
| 1445 | WorldItem::Type(t) => self.type_interface_dep(*t), | 
|---|
| 1446 | }) | 
|---|
| 1447 | })) | 
|---|
| 1448 | .filter_map(move |iface_id| { | 
|---|
| 1449 | let pkg = self.interfaces[iface_id].package?; | 
|---|
| 1450 | if pkg == id { | 
|---|
| 1451 | None | 
|---|
| 1452 | } else { | 
|---|
| 1453 | Some(pkg) | 
|---|
| 1454 | } | 
|---|
| 1455 | }) | 
|---|
| 1456 | } | 
|---|
| 1457 |  | 
|---|
| 1458 | /// Returns a topological ordering of packages contained in this `Resolve`. | 
|---|
| 1459 | /// | 
|---|
| 1460 | /// This returns a list of `PackageId` such that when visited in order it's | 
|---|
| 1461 | /// guaranteed that all dependencies will have been defined by prior items | 
|---|
| 1462 | /// in the list. | 
|---|
| 1463 | pub fn topological_packages(&self) -> Vec<PackageId> { | 
|---|
| 1464 | let mut pushed = vec![false; self.packages.len()]; | 
|---|
| 1465 | let mut order = Vec::new(); | 
|---|
| 1466 | for (id, _) in self.packages.iter() { | 
|---|
| 1467 | self.build_topological_package_ordering(id, &mut pushed, &mut order); | 
|---|
| 1468 | } | 
|---|
| 1469 | order | 
|---|
| 1470 | } | 
|---|
| 1471 |  | 
|---|
| 1472 | fn build_topological_package_ordering( | 
|---|
| 1473 | &self, | 
|---|
| 1474 | id: PackageId, | 
|---|
| 1475 | pushed: &mut Vec<bool>, | 
|---|
| 1476 | order: &mut Vec<PackageId>, | 
|---|
| 1477 | ) { | 
|---|
| 1478 | if pushed[id.index()] { | 
|---|
| 1479 | return; | 
|---|
| 1480 | } | 
|---|
| 1481 | for dep in self.package_direct_deps(id) { | 
|---|
| 1482 | self.build_topological_package_ordering(dep, pushed, order); | 
|---|
| 1483 | } | 
|---|
| 1484 | order.push(id); | 
|---|
| 1485 | pushed[id.index()] = true; | 
|---|
| 1486 | } | 
|---|
| 1487 |  | 
|---|
| 1488 | #[ doc(hidden)] | 
|---|
| 1489 | pub fn assert_valid(&self) { | 
|---|
| 1490 | let mut package_interfaces = Vec::new(); | 
|---|
| 1491 | let mut package_worlds = Vec::new(); | 
|---|
| 1492 | for (id, pkg) in self.packages.iter() { | 
|---|
| 1493 | let mut interfaces = HashSet::new(); | 
|---|
| 1494 | for (name, iface) in pkg.interfaces.iter() { | 
|---|
| 1495 | assert!(interfaces.insert(*iface)); | 
|---|
| 1496 | let iface = &self.interfaces[*iface]; | 
|---|
| 1497 | assert_eq!(name, iface.name.as_ref().unwrap()); | 
|---|
| 1498 | assert_eq!(iface.package.unwrap(), id); | 
|---|
| 1499 | } | 
|---|
| 1500 | package_interfaces.push(pkg.interfaces.values().copied().collect::<HashSet<_>>()); | 
|---|
| 1501 | let mut worlds = HashSet::new(); | 
|---|
| 1502 | for (name, world) in pkg.worlds.iter() { | 
|---|
| 1503 | assert!(worlds.insert(*world)); | 
|---|
| 1504 | assert_eq!( | 
|---|
| 1505 | pkg.worlds.get_key_value(name), | 
|---|
| 1506 | Some((name, world)), | 
|---|
| 1507 | "`MutableKeys` impl may have been used to change a key's hash or equality" | 
|---|
| 1508 | ); | 
|---|
| 1509 | let world = &self.worlds[*world]; | 
|---|
| 1510 | assert_eq!(*name, world.name); | 
|---|
| 1511 | assert_eq!(world.package.unwrap(), id); | 
|---|
| 1512 | } | 
|---|
| 1513 | package_worlds.push(pkg.worlds.values().copied().collect::<HashSet<_>>()); | 
|---|
| 1514 | } | 
|---|
| 1515 |  | 
|---|
| 1516 | let mut interface_types = Vec::new(); | 
|---|
| 1517 | for (id, iface) in self.interfaces.iter() { | 
|---|
| 1518 | assert!(self.packages.get(iface.package.unwrap()).is_some()); | 
|---|
| 1519 | if iface.name.is_some() { | 
|---|
| 1520 | assert!(package_interfaces[iface.package.unwrap().index()].contains(&id)); | 
|---|
| 1521 | } | 
|---|
| 1522 |  | 
|---|
| 1523 | for (name, ty) in iface.types.iter() { | 
|---|
| 1524 | let ty = &self.types[*ty]; | 
|---|
| 1525 | assert_eq!(ty.name.as_ref(), Some(name)); | 
|---|
| 1526 | assert_eq!(ty.owner, TypeOwner::Interface(id)); | 
|---|
| 1527 | } | 
|---|
| 1528 | interface_types.push(iface.types.values().copied().collect::<HashSet<_>>()); | 
|---|
| 1529 | for (name, f) in iface.functions.iter() { | 
|---|
| 1530 | assert_eq!(*name, f.name); | 
|---|
| 1531 | } | 
|---|
| 1532 | } | 
|---|
| 1533 |  | 
|---|
| 1534 | let mut world_types = Vec::new(); | 
|---|
| 1535 | for (id, world) in self.worlds.iter() { | 
|---|
| 1536 | log::debug!( "validating world {} ", &world.name); | 
|---|
| 1537 | if let Some(package) = world.package { | 
|---|
| 1538 | assert!(self.packages.get(package).is_some()); | 
|---|
| 1539 | assert!(package_worlds[package.index()].contains(&id)); | 
|---|
| 1540 | } | 
|---|
| 1541 | assert!(world.includes.is_empty()); | 
|---|
| 1542 |  | 
|---|
| 1543 | let mut types = HashSet::new(); | 
|---|
| 1544 | for (name, item) in world.imports.iter().chain(world.exports.iter()) { | 
|---|
| 1545 | log::debug!( "validating world item: {} ", self.name_world_key(name)); | 
|---|
| 1546 | match item { | 
|---|
| 1547 | WorldItem::Interface { id, .. } => { | 
|---|
| 1548 | // anonymous interfaces must belong to the same package | 
|---|
| 1549 | // as the world's package. | 
|---|
| 1550 | if matches!(name, WorldKey::Name(_)) { | 
|---|
| 1551 | assert_eq!(self.interfaces[*id].package, world.package); | 
|---|
| 1552 | } | 
|---|
| 1553 | } | 
|---|
| 1554 | WorldItem::Function(f) => { | 
|---|
| 1555 | assert!(!matches!(name, WorldKey::Interface(_))); | 
|---|
| 1556 | assert_eq!(f.name, name.clone().unwrap_name()); | 
|---|
| 1557 | } | 
|---|
| 1558 | WorldItem::Type(ty) => { | 
|---|
| 1559 | assert!(!matches!(name, WorldKey::Interface(_))); | 
|---|
| 1560 | assert!(types.insert(*ty)); | 
|---|
| 1561 | let ty = &self.types[*ty]; | 
|---|
| 1562 | assert_eq!(ty.name, Some(name.clone().unwrap_name())); | 
|---|
| 1563 | assert_eq!(ty.owner, TypeOwner::World(id)); | 
|---|
| 1564 | } | 
|---|
| 1565 | } | 
|---|
| 1566 | } | 
|---|
| 1567 | self.assert_world_elaborated(world); | 
|---|
| 1568 | world_types.push(types); | 
|---|
| 1569 | } | 
|---|
| 1570 |  | 
|---|
| 1571 | for (ty_id, ty) in self.types.iter() { | 
|---|
| 1572 | match ty.owner { | 
|---|
| 1573 | TypeOwner::Interface(id) => { | 
|---|
| 1574 | assert!(self.interfaces.get(id).is_some()); | 
|---|
| 1575 | assert!(interface_types[id.index()].contains(&ty_id)); | 
|---|
| 1576 | } | 
|---|
| 1577 | TypeOwner::World(id) => { | 
|---|
| 1578 | assert!(self.worlds.get(id).is_some()); | 
|---|
| 1579 | assert!(world_types[id.index()].contains(&ty_id)); | 
|---|
| 1580 | } | 
|---|
| 1581 | TypeOwner::None => {} | 
|---|
| 1582 | } | 
|---|
| 1583 | } | 
|---|
| 1584 |  | 
|---|
| 1585 | self.assert_topologically_sorted(); | 
|---|
| 1586 | } | 
|---|
| 1587 |  | 
|---|
| 1588 | fn assert_topologically_sorted(&self) { | 
|---|
| 1589 | let mut positions = IndexMap::new(); | 
|---|
| 1590 | for id in self.topological_packages() { | 
|---|
| 1591 | let pkg = &self.packages[id]; | 
|---|
| 1592 | log::debug!( "pkg {} ", pkg.name); | 
|---|
| 1593 | let prev = positions.insert(Some(id), IndexSet::new()); | 
|---|
| 1594 | assert!(prev.is_none()); | 
|---|
| 1595 | } | 
|---|
| 1596 | positions.insert(None, IndexSet::new()); | 
|---|
| 1597 |  | 
|---|
| 1598 | for (id, iface) in self.interfaces.iter() { | 
|---|
| 1599 | log::debug!( "iface {:?} ", iface.name); | 
|---|
| 1600 | let ok = positions.get_mut(&iface.package).unwrap().insert(id); | 
|---|
| 1601 | assert!(ok); | 
|---|
| 1602 | } | 
|---|
| 1603 |  | 
|---|
| 1604 | for (_, world) in self.worlds.iter() { | 
|---|
| 1605 | log::debug!( "world {:?} ", world.name); | 
|---|
| 1606 |  | 
|---|
| 1607 | let my_package = world.package; | 
|---|
| 1608 | let my_package_pos = positions.get_index_of(&my_package).unwrap(); | 
|---|
| 1609 |  | 
|---|
| 1610 | for (_, item) in world.imports.iter().chain(&world.exports) { | 
|---|
| 1611 | let id = match item { | 
|---|
| 1612 | WorldItem::Interface { id, .. } => *id, | 
|---|
| 1613 | _ => continue, | 
|---|
| 1614 | }; | 
|---|
| 1615 | let other_package = self.interfaces[id].package; | 
|---|
| 1616 | let other_package_pos = positions.get_index_of(&other_package).unwrap(); | 
|---|
| 1617 |  | 
|---|
| 1618 | assert!(other_package_pos <= my_package_pos); | 
|---|
| 1619 | } | 
|---|
| 1620 | } | 
|---|
| 1621 |  | 
|---|
| 1622 | for (_id, ty) in self.types.iter() { | 
|---|
| 1623 | log::debug!( "type {:?}  {:?} ", ty.name, ty.owner); | 
|---|
| 1624 | let other_id = match ty.kind { | 
|---|
| 1625 | TypeDefKind::Type(Type::Id(ty)) => ty, | 
|---|
| 1626 | _ => continue, | 
|---|
| 1627 | }; | 
|---|
| 1628 | let other = &self.types[other_id]; | 
|---|
| 1629 | if ty.kind == other.kind { | 
|---|
| 1630 | continue; | 
|---|
| 1631 | } | 
|---|
| 1632 | let my_interface = match ty.owner { | 
|---|
| 1633 | TypeOwner::Interface(id) => id, | 
|---|
| 1634 | _ => continue, | 
|---|
| 1635 | }; | 
|---|
| 1636 | let other_interface = match other.owner { | 
|---|
| 1637 | TypeOwner::Interface(id) => id, | 
|---|
| 1638 | _ => continue, | 
|---|
| 1639 | }; | 
|---|
| 1640 |  | 
|---|
| 1641 | let my_package = self.interfaces[my_interface].package; | 
|---|
| 1642 | let other_package = self.interfaces[other_interface].package; | 
|---|
| 1643 | let my_package_pos = positions.get_index_of(&my_package).unwrap(); | 
|---|
| 1644 | let other_package_pos = positions.get_index_of(&other_package).unwrap(); | 
|---|
| 1645 |  | 
|---|
| 1646 | if my_package_pos == other_package_pos { | 
|---|
| 1647 | let interfaces = &positions[&my_package]; | 
|---|
| 1648 | let my_interface_pos = interfaces.get_index_of(&my_interface).unwrap(); | 
|---|
| 1649 | let other_interface_pos = interfaces.get_index_of(&other_interface).unwrap(); | 
|---|
| 1650 | assert!(other_interface_pos <= my_interface_pos); | 
|---|
| 1651 | } else { | 
|---|
| 1652 | assert!(other_package_pos < my_package_pos); | 
|---|
| 1653 | } | 
|---|
| 1654 | } | 
|---|
| 1655 | } | 
|---|
| 1656 |  | 
|---|
| 1657 | fn assert_world_elaborated(&self, world: &World) { | 
|---|
| 1658 | for (key, item) in world.imports.iter() { | 
|---|
| 1659 | log::debug!( | 
|---|
| 1660 | "asserting elaborated world import {} ", | 
|---|
| 1661 | self.name_world_key(key) | 
|---|
| 1662 | ); | 
|---|
| 1663 | match item { | 
|---|
| 1664 | WorldItem::Type(t) => self.assert_world_imports_type_deps(world, key, *t), | 
|---|
| 1665 |  | 
|---|
| 1666 | // All types referred to must be imported. | 
|---|
| 1667 | WorldItem::Function(f) => self.assert_world_function_imports_types(world, key, f), | 
|---|
| 1668 |  | 
|---|
| 1669 | // All direct dependencies of this interface must be imported. | 
|---|
| 1670 | WorldItem::Interface { id, .. } => { | 
|---|
| 1671 | for dep in self.interface_direct_deps(*id) { | 
|---|
| 1672 | assert!( | 
|---|
| 1673 | world.imports.contains_key(&WorldKey::Interface(dep)), | 
|---|
| 1674 | "world import of {}  is missing transitive dep of {} ", | 
|---|
| 1675 | self.name_world_key(key), | 
|---|
| 1676 | self.id_of(dep).unwrap(), | 
|---|
| 1677 | ); | 
|---|
| 1678 | } | 
|---|
| 1679 | } | 
|---|
| 1680 | } | 
|---|
| 1681 | } | 
|---|
| 1682 | for (key, item) in world.exports.iter() { | 
|---|
| 1683 | log::debug!( | 
|---|
| 1684 | "asserting elaborated world export {} ", | 
|---|
| 1685 | self.name_world_key(key) | 
|---|
| 1686 | ); | 
|---|
| 1687 | match item { | 
|---|
| 1688 | // Types referred to by this function must be imported. | 
|---|
| 1689 | WorldItem::Function(f) => self.assert_world_function_imports_types(world, key, f), | 
|---|
| 1690 |  | 
|---|
| 1691 | // Dependencies of exported interfaces must also be exported, or | 
|---|
| 1692 | // if imported then that entire chain of imports must be | 
|---|
| 1693 | // imported and not exported. | 
|---|
| 1694 | WorldItem::Interface { id, .. } => { | 
|---|
| 1695 | for dep in self.interface_direct_deps(*id) { | 
|---|
| 1696 | let dep_key = WorldKey::Interface(dep); | 
|---|
| 1697 | if world.exports.contains_key(&dep_key) { | 
|---|
| 1698 | continue; | 
|---|
| 1699 | } | 
|---|
| 1700 | self.foreach_interface_dep(dep, &mut |dep| { | 
|---|
| 1701 | let dep_key = WorldKey::Interface(dep); | 
|---|
| 1702 | assert!( | 
|---|
| 1703 | world.imports.contains_key(&dep_key), | 
|---|
| 1704 | "world should import {}  (required by {} )", | 
|---|
| 1705 | self.name_world_key(&dep_key), | 
|---|
| 1706 | self.name_world_key(key), | 
|---|
| 1707 | ); | 
|---|
| 1708 | assert!( | 
|---|
| 1709 | !world.exports.contains_key(&dep_key), | 
|---|
| 1710 | "world should not export {}  (required by {} )", | 
|---|
| 1711 | self.name_world_key(&dep_key), | 
|---|
| 1712 | self.name_world_key(key), | 
|---|
| 1713 | ); | 
|---|
| 1714 | }); | 
|---|
| 1715 | } | 
|---|
| 1716 | } | 
|---|
| 1717 |  | 
|---|
| 1718 | // exported types not allowed at this time | 
|---|
| 1719 | WorldItem::Type(_) => unreachable!(), | 
|---|
| 1720 | } | 
|---|
| 1721 | } | 
|---|
| 1722 | } | 
|---|
| 1723 |  | 
|---|
| 1724 | fn assert_world_imports_type_deps(&self, world: &World, key: &WorldKey, ty: TypeId) { | 
|---|
| 1725 | // If this is a `use` statement then the referred-to interface must be | 
|---|
| 1726 | // imported into this world. | 
|---|
| 1727 | let ty = &self.types[ty]; | 
|---|
| 1728 | if let TypeDefKind::Type(Type::Id(other)) = ty.kind { | 
|---|
| 1729 | if let TypeOwner::Interface(id) = self.types[other].owner { | 
|---|
| 1730 | let key = WorldKey::Interface(id); | 
|---|
| 1731 | assert!(world.imports.contains_key(&key)); | 
|---|
| 1732 | return; | 
|---|
| 1733 | } | 
|---|
| 1734 | } | 
|---|
| 1735 |  | 
|---|
| 1736 | // ... otherwise any named type that this type refers to, one level | 
|---|
| 1737 | // deep, must be imported into this world under that name. | 
|---|
| 1738 |  | 
|---|
| 1739 | let mut visitor = MyVisit(self, Vec::new()); | 
|---|
| 1740 | visitor.visit_type_def(self, ty); | 
|---|
| 1741 | for ty in visitor.1 { | 
|---|
| 1742 | let ty = &self.types[ty]; | 
|---|
| 1743 | let Some(name) = ty.name.clone() else { | 
|---|
| 1744 | continue; | 
|---|
| 1745 | }; | 
|---|
| 1746 | let dep_key = WorldKey::Name(name); | 
|---|
| 1747 | assert!( | 
|---|
| 1748 | world.imports.contains_key(&dep_key), | 
|---|
| 1749 | "world import `{} ` should also force an import of `{} `", | 
|---|
| 1750 | self.name_world_key(key), | 
|---|
| 1751 | self.name_world_key(&dep_key), | 
|---|
| 1752 | ); | 
|---|
| 1753 | } | 
|---|
| 1754 |  | 
|---|
| 1755 | struct MyVisit<'a>(&'a Resolve, Vec<TypeId>); | 
|---|
| 1756 |  | 
|---|
| 1757 | impl TypeIdVisitor for MyVisit<'_> { | 
|---|
| 1758 | fn before_visit_type_id(&mut self, id: TypeId) -> bool { | 
|---|
| 1759 | self.1.push(id); | 
|---|
| 1760 | // recurse into unnamed types to look at all named types | 
|---|
| 1761 | self.0.types[id].name.is_none() | 
|---|
| 1762 | } | 
|---|
| 1763 | } | 
|---|
| 1764 | } | 
|---|
| 1765 |  | 
|---|
| 1766 | /// This asserts that all types referred to by `func` are imported into | 
|---|
| 1767 | /// `world` under `WorldKey::Name`. Note that this is only applicable to | 
|---|
| 1768 | /// named type | 
|---|
| 1769 | fn assert_world_function_imports_types(&self, world: &World, key: &WorldKey, func: &Function) { | 
|---|
| 1770 | for ty in func | 
|---|
| 1771 | .parameter_and_result_types() | 
|---|
| 1772 | .chain(func.kind.resource().map(Type::Id)) | 
|---|
| 1773 | { | 
|---|
| 1774 | let Type::Id(id) = ty else { | 
|---|
| 1775 | continue; | 
|---|
| 1776 | }; | 
|---|
| 1777 | self.assert_world_imports_type_deps(world, key, id); | 
|---|
| 1778 | } | 
|---|
| 1779 | } | 
|---|
| 1780 |  | 
|---|
| 1781 | fn include_stability(&self, stability: &Stability, pkg_id: &PackageId) -> Result<bool> { | 
|---|
| 1782 | Ok(match stability { | 
|---|
| 1783 | Stability::Unknown => true, | 
|---|
| 1784 | // NOTE: deprecations are intentionally omitted -- an existing `@since` takes precedence over `@deprecated` | 
|---|
| 1785 | Stability::Stable { since, .. } => { | 
|---|
| 1786 | let Some(p) = self.packages.get(*pkg_id) else { | 
|---|
| 1787 | // We can't check much without a package (possibly dealing with an item in an `UnresolvedPackage`), | 
|---|
| 1788 | // @since version & deprecations can't be checked because there's no package version to compare to. | 
|---|
| 1789 | // | 
|---|
| 1790 | // Feature requirements on stabilized features are ignored in resolved packages, so we do the same here. | 
|---|
| 1791 | return Ok(true); | 
|---|
| 1792 | }; | 
|---|
| 1793 |  | 
|---|
| 1794 | // Use of feature gating with version specifiers inside a package that is not versioned is not allowed | 
|---|
| 1795 | let package_version = p.name.version.as_ref().with_context(|| format!( "package [{} ] contains a feature gate with a version specifier, so it must have a version", p.name))?; | 
|---|
| 1796 |  | 
|---|
| 1797 | // If the version on the feature gate is: | 
|---|
| 1798 | // - released, then we can include it | 
|---|
| 1799 | // - unreleased, then we must check the feature (if present) | 
|---|
| 1800 | ensure!( | 
|---|
| 1801 | since <= package_version, | 
|---|
| 1802 | "feature gate cannot reference unreleased version {since}  of package [{} ] (current version {package_version} )", | 
|---|
| 1803 | p.name | 
|---|
| 1804 | ); | 
|---|
| 1805 |  | 
|---|
| 1806 | true | 
|---|
| 1807 | } | 
|---|
| 1808 | Stability::Unstable { feature, .. } => { | 
|---|
| 1809 | self.features.contains(feature) || self.all_features | 
|---|
| 1810 | } | 
|---|
| 1811 | }) | 
|---|
| 1812 | } | 
|---|
| 1813 |  | 
|---|
| 1814 | /// Performs the "elaboration process" necessary for the `world_id` | 
|---|
| 1815 | /// specified to ensure that all of its transitive imports are listed. | 
|---|
| 1816 | /// | 
|---|
| 1817 | /// This function will take the unordered lists of the specified world's | 
|---|
| 1818 | /// imports and exports and "elaborate" them to ensure that they're | 
|---|
| 1819 | /// topographically sorted where all transitively required interfaces by | 
|---|
| 1820 | /// imports, or exports, are listed. This will additionally validate that | 
|---|
| 1821 | /// the exports are all valid and present, specifically with the restriction | 
|---|
| 1822 | /// noted on `elaborate_world_exports`. | 
|---|
| 1823 | /// | 
|---|
| 1824 | /// The world is mutated in-place in this `Resolve`. | 
|---|
| 1825 | fn elaborate_world(&mut self, world_id: WorldId) -> Result<()> { | 
|---|
| 1826 | // First process all imports. This is easier than exports since the only | 
|---|
| 1827 | // requirement here is that all interfaces need to be added with a | 
|---|
| 1828 | // topological order between them. | 
|---|
| 1829 | let mut new_imports = IndexMap::new(); | 
|---|
| 1830 | let world = &self.worlds[world_id]; | 
|---|
| 1831 | for (name, item) in world.imports.iter() { | 
|---|
| 1832 | match item { | 
|---|
| 1833 | // Interfaces get their dependencies added first followed by the | 
|---|
| 1834 | // interface itself. | 
|---|
| 1835 | WorldItem::Interface { id, stability } => { | 
|---|
| 1836 | self.elaborate_world_import(&mut new_imports, name.clone(), *id, &stability); | 
|---|
| 1837 | } | 
|---|
| 1838 |  | 
|---|
| 1839 | // Functions are added as-is since their dependence on types in | 
|---|
| 1840 | // the world should already be satisfied. | 
|---|
| 1841 | WorldItem::Function(_) => { | 
|---|
| 1842 | let prev = new_imports.insert(name.clone(), item.clone()); | 
|---|
| 1843 | assert!(prev.is_none()); | 
|---|
| 1844 | } | 
|---|
| 1845 |  | 
|---|
| 1846 | // Types may depend on an interface, in which case a (possibly) | 
|---|
| 1847 | // recursive addition of that interface happens here. Afterwards | 
|---|
| 1848 | // the type itself can be added safely. | 
|---|
| 1849 | WorldItem::Type(id) => { | 
|---|
| 1850 | if let Some(dep) = self.type_interface_dep(*id) { | 
|---|
| 1851 | self.elaborate_world_import( | 
|---|
| 1852 | &mut new_imports, | 
|---|
| 1853 | WorldKey::Interface(dep), | 
|---|
| 1854 | dep, | 
|---|
| 1855 | &self.types[*id].stability, | 
|---|
| 1856 | ); | 
|---|
| 1857 | } | 
|---|
| 1858 | let prev = new_imports.insert(name.clone(), item.clone()); | 
|---|
| 1859 | assert!(prev.is_none()); | 
|---|
| 1860 | } | 
|---|
| 1861 | } | 
|---|
| 1862 | } | 
|---|
| 1863 |  | 
|---|
| 1864 | // Exports are trickier than imports, notably to uphold the invariant | 
|---|
| 1865 | // required by `elaborate_world_exports`. To do this the exports are | 
|---|
| 1866 | // partitioned into interfaces/functions. All functions are added to | 
|---|
| 1867 | // the new exports list during this loop but interfaces are all deferred | 
|---|
| 1868 | // to be handled in the `elaborate_world_exports` function. | 
|---|
| 1869 | let mut new_exports = IndexMap::new(); | 
|---|
| 1870 | let mut export_interfaces = IndexMap::new(); | 
|---|
| 1871 | for (name, item) in world.exports.iter() { | 
|---|
| 1872 | match item { | 
|---|
| 1873 | WorldItem::Interface { id, stability } => { | 
|---|
| 1874 | let prev = export_interfaces.insert(*id, (name.clone(), stability)); | 
|---|
| 1875 | assert!(prev.is_none()); | 
|---|
| 1876 | } | 
|---|
| 1877 | WorldItem::Function(_) => { | 
|---|
| 1878 | let prev = new_exports.insert(name.clone(), item.clone()); | 
|---|
| 1879 | assert!(prev.is_none()); | 
|---|
| 1880 | } | 
|---|
| 1881 | WorldItem::Type(_) => unreachable!(), | 
|---|
| 1882 | } | 
|---|
| 1883 | } | 
|---|
| 1884 |  | 
|---|
| 1885 | self.elaborate_world_exports(&export_interfaces, &mut new_imports, &mut new_exports)?; | 
|---|
| 1886 |  | 
|---|
| 1887 | // And with all that done the world is updated in-place with | 
|---|
| 1888 | // imports/exports. | 
|---|
| 1889 | log::trace!( "imports = {:?} ", new_imports); | 
|---|
| 1890 | log::trace!( "exports = {:?} ", new_exports); | 
|---|
| 1891 | let world = &mut self.worlds[world_id]; | 
|---|
| 1892 | world.imports = new_imports; | 
|---|
| 1893 | world.exports = new_exports; | 
|---|
| 1894 |  | 
|---|
| 1895 | Ok(()) | 
|---|
| 1896 | } | 
|---|
| 1897 |  | 
|---|
| 1898 | fn elaborate_world_import( | 
|---|
| 1899 | &self, | 
|---|
| 1900 | imports: &mut IndexMap<WorldKey, WorldItem>, | 
|---|
| 1901 | key: WorldKey, | 
|---|
| 1902 | id: InterfaceId, | 
|---|
| 1903 | stability: &Stability, | 
|---|
| 1904 | ) { | 
|---|
| 1905 | if imports.contains_key(&key) { | 
|---|
| 1906 | return; | 
|---|
| 1907 | } | 
|---|
| 1908 | for dep in self.interface_direct_deps(id) { | 
|---|
| 1909 | self.elaborate_world_import(imports, WorldKey::Interface(dep), dep, stability); | 
|---|
| 1910 | } | 
|---|
| 1911 | let prev = imports.insert( | 
|---|
| 1912 | key, | 
|---|
| 1913 | WorldItem::Interface { | 
|---|
| 1914 | id, | 
|---|
| 1915 | stability: stability.clone(), | 
|---|
| 1916 | }, | 
|---|
| 1917 | ); | 
|---|
| 1918 | assert!(prev.is_none()); | 
|---|
| 1919 | } | 
|---|
| 1920 |  | 
|---|
| 1921 | /// This function adds all of the interfaces in `export_interfaces` to the | 
|---|
| 1922 | /// list of exports of the `world` specified. | 
|---|
| 1923 | /// | 
|---|
| 1924 | /// This method is more involved than adding imports because it is fallible. | 
|---|
| 1925 | /// Chiefly what can happen is that the dependencies of all exports must be | 
|---|
| 1926 | /// satisfied by other exports or imports, but not both. For example given a | 
|---|
| 1927 | /// situation such as: | 
|---|
| 1928 | /// | 
|---|
| 1929 | /// ```wit | 
|---|
| 1930 | /// interface a { | 
|---|
| 1931 | ///     type t = u32 | 
|---|
| 1932 | /// } | 
|---|
| 1933 | /// interface b { | 
|---|
| 1934 | ///     use a.{t} | 
|---|
| 1935 | /// } | 
|---|
| 1936 | /// interface c { | 
|---|
| 1937 | ///     use a.{t} | 
|---|
| 1938 | ///     use b.{t as t2} | 
|---|
| 1939 | /// } | 
|---|
| 1940 | /// ``` | 
|---|
| 1941 | /// | 
|---|
| 1942 | /// where `c` depends on `b` and `a` where `b` depends on `a`, then the | 
|---|
| 1943 | /// purpose of this method is to reject this world: | 
|---|
| 1944 | /// | 
|---|
| 1945 | /// ```wit | 
|---|
| 1946 | /// world foo { | 
|---|
| 1947 | ///     export a | 
|---|
| 1948 | ///     export c | 
|---|
| 1949 | /// } | 
|---|
| 1950 | /// ``` | 
|---|
| 1951 | /// | 
|---|
| 1952 | /// The reasoning here is unfortunately subtle and is additionally the | 
|---|
| 1953 | /// subject of WebAssembly/component-model#208. Effectively the `c` | 
|---|
| 1954 | /// interface depends on `b`, but it's not listed explicitly as an import, | 
|---|
| 1955 | /// so it's then implicitly added as an import. This then transitively | 
|---|
| 1956 | /// depends on `a` so it's also added as an import. At this point though `c` | 
|---|
| 1957 | /// also depends on `a`, and it's also exported, so naively it should depend | 
|---|
| 1958 | /// on the export and not implicitly add an import. This means though that | 
|---|
| 1959 | /// `c` has access to two copies of `a`, one imported and one exported. This | 
|---|
| 1960 | /// is not valid, especially in the face of resource types. | 
|---|
| 1961 | /// | 
|---|
| 1962 | /// Overall this method is tasked with rejecting the above world by walking | 
|---|
| 1963 | /// over all the exports and adding their dependencies. Each dependency is | 
|---|
| 1964 | /// recorded with whether it's required to be imported, and then if an | 
|---|
| 1965 | /// export is added for something that's required to be an error then the | 
|---|
| 1966 | /// operation fails. | 
|---|
| 1967 | fn elaborate_world_exports( | 
|---|
| 1968 | &self, | 
|---|
| 1969 | export_interfaces: &IndexMap<InterfaceId, (WorldKey, &Stability)>, | 
|---|
| 1970 | imports: &mut IndexMap<WorldKey, WorldItem>, | 
|---|
| 1971 | exports: &mut IndexMap<WorldKey, WorldItem>, | 
|---|
| 1972 | ) -> Result<()> { | 
|---|
| 1973 | let mut required_imports = HashSet::new(); | 
|---|
| 1974 | for (id, (key, stability)) in export_interfaces.iter() { | 
|---|
| 1975 | let name = self.name_world_key(&key); | 
|---|
| 1976 | let ok = add_world_export( | 
|---|
| 1977 | self, | 
|---|
| 1978 | imports, | 
|---|
| 1979 | exports, | 
|---|
| 1980 | export_interfaces, | 
|---|
| 1981 | &mut required_imports, | 
|---|
| 1982 | *id, | 
|---|
| 1983 | key, | 
|---|
| 1984 | true, | 
|---|
| 1985 | stability, | 
|---|
| 1986 | ); | 
|---|
| 1987 | if !ok { | 
|---|
| 1988 | bail!( | 
|---|
| 1989 | // FIXME: this is not a great error message and basically no | 
|---|
| 1990 | // one will know what to do when it gets printed. Improving | 
|---|
| 1991 | // this error message, however, is a chunk of work that may | 
|---|
| 1992 | // not be best spent doing this at this time, so I'm writing | 
|---|
| 1993 | // this comment instead. | 
|---|
| 1994 | // | 
|---|
| 1995 | // More-or-less what should happen here is that a "path" | 
|---|
| 1996 | // from this interface to the conflicting interface should | 
|---|
| 1997 | // be printed. It should be explained why an import is being | 
|---|
| 1998 | // injected, why that's conflicting with an export, and | 
|---|
| 1999 | // ideally with a suggestion of "add this interface to the | 
|---|
| 2000 | // export list to fix this error". | 
|---|
| 2001 | // | 
|---|
| 2002 | // That's a lot of info that's not easy to get at without | 
|---|
| 2003 | // more refactoring, so it's left to a future date in the | 
|---|
| 2004 | // hopes that most folks won't actually run into this for | 
|---|
| 2005 | // the time being. | 
|---|
| 2006 | InvalidTransitiveDependency(name), | 
|---|
| 2007 | ); | 
|---|
| 2008 | } | 
|---|
| 2009 | } | 
|---|
| 2010 | return Ok(()); | 
|---|
| 2011 |  | 
|---|
| 2012 | fn add_world_export( | 
|---|
| 2013 | resolve: &Resolve, | 
|---|
| 2014 | imports: &mut IndexMap<WorldKey, WorldItem>, | 
|---|
| 2015 | exports: &mut IndexMap<WorldKey, WorldItem>, | 
|---|
| 2016 | export_interfaces: &IndexMap<InterfaceId, (WorldKey, &Stability)>, | 
|---|
| 2017 | required_imports: &mut HashSet<InterfaceId>, | 
|---|
| 2018 | id: InterfaceId, | 
|---|
| 2019 | key: &WorldKey, | 
|---|
| 2020 | add_export: bool, | 
|---|
| 2021 | stability: &Stability, | 
|---|
| 2022 | ) -> bool { | 
|---|
| 2023 | if exports.contains_key(key) { | 
|---|
| 2024 | if add_export { | 
|---|
| 2025 | return true; | 
|---|
| 2026 | } else { | 
|---|
| 2027 | return false; | 
|---|
| 2028 | } | 
|---|
| 2029 | } | 
|---|
| 2030 | // If this is an import and it's already in the `required_imports` | 
|---|
| 2031 | // set then we can skip it as we've already visited this interface. | 
|---|
| 2032 | if !add_export && required_imports.contains(&id) { | 
|---|
| 2033 | return true; | 
|---|
| 2034 | } | 
|---|
| 2035 | let ok = resolve.interface_direct_deps(id).all(|dep| { | 
|---|
| 2036 | let key = WorldKey::Interface(dep); | 
|---|
| 2037 | let add_export = add_export && export_interfaces.contains_key(&dep); | 
|---|
| 2038 | add_world_export( | 
|---|
| 2039 | resolve, | 
|---|
| 2040 | imports, | 
|---|
| 2041 | exports, | 
|---|
| 2042 | export_interfaces, | 
|---|
| 2043 | required_imports, | 
|---|
| 2044 | dep, | 
|---|
| 2045 | &key, | 
|---|
| 2046 | add_export, | 
|---|
| 2047 | stability, | 
|---|
| 2048 | ) | 
|---|
| 2049 | }); | 
|---|
| 2050 | if !ok { | 
|---|
| 2051 | return false; | 
|---|
| 2052 | } | 
|---|
| 2053 | let item = WorldItem::Interface { | 
|---|
| 2054 | id, | 
|---|
| 2055 | stability: stability.clone(), | 
|---|
| 2056 | }; | 
|---|
| 2057 | if add_export { | 
|---|
| 2058 | if required_imports.contains(&id) { | 
|---|
| 2059 | return false; | 
|---|
| 2060 | } | 
|---|
| 2061 | exports.insert(key.clone(), item); | 
|---|
| 2062 | } else { | 
|---|
| 2063 | required_imports.insert(id); | 
|---|
| 2064 | imports.insert(key.clone(), item); | 
|---|
| 2065 | } | 
|---|
| 2066 | true | 
|---|
| 2067 | } | 
|---|
| 2068 | } | 
|---|
| 2069 |  | 
|---|
| 2070 | /// Remove duplicate imports from a world if they import from the same | 
|---|
| 2071 | /// interface with semver-compatible versions. | 
|---|
| 2072 | /// | 
|---|
| 2073 | /// This will merge duplicate interfaces present at multiple versions in | 
|---|
| 2074 | /// both a world by selecting the larger version of the two interfaces. This | 
|---|
| 2075 | /// requires that the interfaces are indeed semver-compatible and it means | 
|---|
| 2076 | /// that some imports might be removed and replaced. Note that this is only | 
|---|
| 2077 | /// done within a single semver track, for example the world imports 0.2.0 | 
|---|
| 2078 | /// and 0.2.1 then the result afterwards will be that it imports | 
|---|
| 2079 | /// 0.2.1. If, however, 0.3.0 where imported then the final result would | 
|---|
| 2080 | /// import both 0.2.0 and 0.3.0. | 
|---|
| 2081 | pub fn merge_world_imports_based_on_semver(&mut self, world_id: WorldId) -> Result<()> { | 
|---|
| 2082 | let world = &self.worlds[world_id]; | 
|---|
| 2083 |  | 
|---|
| 2084 | // The first pass here is to build a map of "semver tracks" where they | 
|---|
| 2085 | // key is per-interface and the value is the maximal version found in | 
|---|
| 2086 | // that semver-compatible-track plus the interface which is the maximal | 
|---|
| 2087 | // version. | 
|---|
| 2088 | // | 
|---|
| 2089 | // At the same time a `to_remove` set is maintained to remember what | 
|---|
| 2090 | // interfaces are being removed from `from` and `into`. All of | 
|---|
| 2091 | // `to_remove` are placed with a known other version. | 
|---|
| 2092 | let mut semver_tracks = HashMap::new(); | 
|---|
| 2093 | let mut to_remove = HashSet::new(); | 
|---|
| 2094 | for (key, _) in world.imports.iter() { | 
|---|
| 2095 | let iface_id = match key { | 
|---|
| 2096 | WorldKey::Interface(id) => *id, | 
|---|
| 2097 | WorldKey::Name(_) => continue, | 
|---|
| 2098 | }; | 
|---|
| 2099 | let (track, version) = match self.semver_track(iface_id) { | 
|---|
| 2100 | Some(track) => track, | 
|---|
| 2101 | None => continue, | 
|---|
| 2102 | }; | 
|---|
| 2103 | log::debug!( | 
|---|
| 2104 | "{}  is on track {} /{} ", | 
|---|
| 2105 | self.id_of(iface_id).unwrap(), | 
|---|
| 2106 | track.0, | 
|---|
| 2107 | track.1, | 
|---|
| 2108 | ); | 
|---|
| 2109 | match semver_tracks.entry(track.clone()) { | 
|---|
| 2110 | hash_map::Entry::Vacant(e) => { | 
|---|
| 2111 | e.insert((version, iface_id)); | 
|---|
| 2112 | } | 
|---|
| 2113 | hash_map::Entry::Occupied(mut e) => match version.cmp(&e.get().0) { | 
|---|
| 2114 | Ordering::Greater => { | 
|---|
| 2115 | to_remove.insert(e.get().1); | 
|---|
| 2116 | e.insert((version, iface_id)); | 
|---|
| 2117 | } | 
|---|
| 2118 | Ordering::Equal => {} | 
|---|
| 2119 | Ordering::Less => { | 
|---|
| 2120 | to_remove.insert(iface_id); | 
|---|
| 2121 | } | 
|---|
| 2122 | }, | 
|---|
| 2123 | } | 
|---|
| 2124 | } | 
|---|
| 2125 |  | 
|---|
| 2126 | // Build a map of "this interface is replaced with this interface" using | 
|---|
| 2127 | // the results of the loop above. | 
|---|
| 2128 | let mut replacements = HashMap::new(); | 
|---|
| 2129 | for id in to_remove { | 
|---|
| 2130 | let (track, _) = self.semver_track(id).unwrap(); | 
|---|
| 2131 | let (_, latest) = semver_tracks[&track]; | 
|---|
| 2132 | let prev = replacements.insert(id, latest); | 
|---|
| 2133 | assert!(prev.is_none()); | 
|---|
| 2134 | } | 
|---|
| 2135 |  | 
|---|
| 2136 | // Validate that `merge_world_item` succeeds for merging all removed | 
|---|
| 2137 | // interfaces with their replacement. This is a double-check that the | 
|---|
| 2138 | // semver version is actually correct and all items present in the old | 
|---|
| 2139 | // interface are in the new. | 
|---|
| 2140 | for (to_replace, replace_with) in replacements.iter() { | 
|---|
| 2141 | self.merge_world_item( | 
|---|
| 2142 | &WorldItem::Interface { | 
|---|
| 2143 | id: *to_replace, | 
|---|
| 2144 | stability: Default::default(), | 
|---|
| 2145 | }, | 
|---|
| 2146 | &WorldItem::Interface { | 
|---|
| 2147 | id: *replace_with, | 
|---|
| 2148 | stability: Default::default(), | 
|---|
| 2149 | }, | 
|---|
| 2150 | ) | 
|---|
| 2151 | .with_context(|| { | 
|---|
| 2152 | let old_name = self.id_of(*to_replace).unwrap(); | 
|---|
| 2153 | let new_name = self.id_of(*replace_with).unwrap(); | 
|---|
| 2154 | format!( | 
|---|
| 2155 | "failed to upgrade `{old_name} ` to `{new_name} `, was \ | 
|---|
| 2156 |                      this semver-compatible update not semver compatible?" | 
|---|
| 2157 | ) | 
|---|
| 2158 | })?; | 
|---|
| 2159 | } | 
|---|
| 2160 |  | 
|---|
| 2161 | for (to_replace, replace_with) in replacements.iter() { | 
|---|
| 2162 | log::debug!( | 
|---|
| 2163 | "REPLACE {}  => {} ", | 
|---|
| 2164 | self.id_of(*to_replace).unwrap(), | 
|---|
| 2165 | self.id_of(*replace_with).unwrap(), | 
|---|
| 2166 | ); | 
|---|
| 2167 | } | 
|---|
| 2168 |  | 
|---|
| 2169 | // Finally perform the actual transformation of the imports/exports. | 
|---|
| 2170 | // Here all imports are removed if they're replaced and otherwise all | 
|---|
| 2171 | // imports have their dependencies updated, possibly transitively, to | 
|---|
| 2172 | // point to the new interfaces in `replacements`. | 
|---|
| 2173 | // | 
|---|
| 2174 | // Afterwards exports are additionally updated, but only their | 
|---|
| 2175 | // dependencies on imports which were remapped. Exports themselves are | 
|---|
| 2176 | // not deduplicated and/or removed. | 
|---|
| 2177 | for (key, item) in mem::take(&mut self.worlds[world_id].imports) { | 
|---|
| 2178 | if let WorldItem::Interface { id, .. } = item { | 
|---|
| 2179 | if replacements.contains_key(&id) { | 
|---|
| 2180 | continue; | 
|---|
| 2181 | } | 
|---|
| 2182 | } | 
|---|
| 2183 |  | 
|---|
| 2184 | self.update_interface_deps_of_world_item(&item, &replacements); | 
|---|
| 2185 |  | 
|---|
| 2186 | let prev = self.worlds[world_id].imports.insert(key, item); | 
|---|
| 2187 | assert!(prev.is_none()); | 
|---|
| 2188 | } | 
|---|
| 2189 | for (key, item) in mem::take(&mut self.worlds[world_id].exports) { | 
|---|
| 2190 | self.update_interface_deps_of_world_item(&item, &replacements); | 
|---|
| 2191 | let prev = self.worlds[world_id].exports.insert(key, item); | 
|---|
| 2192 | assert!(prev.is_none()); | 
|---|
| 2193 | } | 
|---|
| 2194 |  | 
|---|
| 2195 | // Run through `elaborate_world` to reorder imports as appropriate and | 
|---|
| 2196 | // fill anything back in if it's actually required by exports. For now | 
|---|
| 2197 | // this doesn't tamper with exports at all. Also note that this is | 
|---|
| 2198 | // applied to all worlds in this `Resolve` because interfaces were | 
|---|
| 2199 | // modified directly. | 
|---|
| 2200 | let ids = self.worlds.iter().map(|(id, _)| id).collect::<Vec<_>>(); | 
|---|
| 2201 | for world_id in ids { | 
|---|
| 2202 | self.elaborate_world(world_id).with_context(|| { | 
|---|
| 2203 | let name = &self.worlds[world_id].name; | 
|---|
| 2204 | format!( | 
|---|
| 2205 | "failed to elaborate world `{name} ` after deduplicating imports \ | 
|---|
| 2206 |                      based on semver" | 
|---|
| 2207 | ) | 
|---|
| 2208 | })?; | 
|---|
| 2209 | } | 
|---|
| 2210 |  | 
|---|
| 2211 | #[ cfg(debug_assertions)] | 
|---|
| 2212 | self.assert_valid(); | 
|---|
| 2213 |  | 
|---|
| 2214 | Ok(()) | 
|---|
| 2215 | } | 
|---|
| 2216 |  | 
|---|
| 2217 | fn update_interface_deps_of_world_item( | 
|---|
| 2218 | &mut self, | 
|---|
| 2219 | item: &WorldItem, | 
|---|
| 2220 | replacements: &HashMap<InterfaceId, InterfaceId>, | 
|---|
| 2221 | ) { | 
|---|
| 2222 | match *item { | 
|---|
| 2223 | WorldItem::Type(t) => self.update_interface_dep_of_type(t, &replacements), | 
|---|
| 2224 | WorldItem::Interface { id, .. } => { | 
|---|
| 2225 | let types = self.interfaces[id] | 
|---|
| 2226 | .types | 
|---|
| 2227 | .values() | 
|---|
| 2228 | .copied() | 
|---|
| 2229 | .collect::<Vec<_>>(); | 
|---|
| 2230 | for ty in types { | 
|---|
| 2231 | self.update_interface_dep_of_type(ty, &replacements); | 
|---|
| 2232 | } | 
|---|
| 2233 | } | 
|---|
| 2234 | WorldItem::Function(_) => {} | 
|---|
| 2235 | } | 
|---|
| 2236 | } | 
|---|
| 2237 |  | 
|---|
| 2238 | /// Returns the "semver track" of an interface plus the interface's version. | 
|---|
| 2239 | /// | 
|---|
| 2240 | /// This function returns `None` if the interface `id` has a package without | 
|---|
| 2241 | /// a version. If the version is present, however, the first element of the | 
|---|
| 2242 | /// tuple returned is a "semver track" for the specific interface. The | 
|---|
| 2243 | /// version listed in `PackageName` will be modified so all | 
|---|
| 2244 | /// semver-compatible versions are listed the same way. | 
|---|
| 2245 | /// | 
|---|
| 2246 | /// The second element in the returned tuple is this interface's package's | 
|---|
| 2247 | /// version. | 
|---|
| 2248 | fn semver_track(&self, id: InterfaceId) -> Option<((PackageName, String), &Version)> { | 
|---|
| 2249 | let iface = &self.interfaces[id]; | 
|---|
| 2250 | let pkg = &self.packages[iface.package?]; | 
|---|
| 2251 | let version = pkg.name.version.as_ref()?; | 
|---|
| 2252 | let mut name = pkg.name.clone(); | 
|---|
| 2253 | name.version = Some(PackageName::version_compat_track(version)); | 
|---|
| 2254 | Some(((name, iface.name.clone()?), version)) | 
|---|
| 2255 | } | 
|---|
| 2256 |  | 
|---|
| 2257 | /// If `ty` is a definition where it's a `use` from another interface, then | 
|---|
| 2258 | /// change what interface it's using from according to the pairs in the | 
|---|
| 2259 | /// `replacements` map. | 
|---|
| 2260 | fn update_interface_dep_of_type( | 
|---|
| 2261 | &mut self, | 
|---|
| 2262 | ty: TypeId, | 
|---|
| 2263 | replacements: &HashMap<InterfaceId, InterfaceId>, | 
|---|
| 2264 | ) { | 
|---|
| 2265 | let to_replace = match self.type_interface_dep(ty) { | 
|---|
| 2266 | Some(id) => id, | 
|---|
| 2267 | None => return, | 
|---|
| 2268 | }; | 
|---|
| 2269 | let replace_with = match replacements.get(&to_replace) { | 
|---|
| 2270 | Some(id) => id, | 
|---|
| 2271 | None => return, | 
|---|
| 2272 | }; | 
|---|
| 2273 | let dep = match self.types[ty].kind { | 
|---|
| 2274 | TypeDefKind::Type(Type::Id(id)) => id, | 
|---|
| 2275 | _ => return, | 
|---|
| 2276 | }; | 
|---|
| 2277 | let name = self.types[dep].name.as_ref().unwrap(); | 
|---|
| 2278 | // Note the infallible name indexing happening here. This should be | 
|---|
| 2279 | // previously validated with `merge_world_item` to succeed. | 
|---|
| 2280 | let replacement_id = self.interfaces[*replace_with].types[name]; | 
|---|
| 2281 | self.types[ty].kind = TypeDefKind::Type(Type::Id(replacement_id)); | 
|---|
| 2282 | } | 
|---|
| 2283 |  | 
|---|
| 2284 | /// Returns the core wasm module/field names for the specified `import`. | 
|---|
| 2285 | /// | 
|---|
| 2286 | /// This function will return the core wasm module/field that can be used to | 
|---|
| 2287 | /// use `import` with the name `mangling` scheme specified as well. This can | 
|---|
| 2288 | /// be useful for bindings generators, for example, and these names are | 
|---|
| 2289 | /// recognized by `wit-component` and `wasm-tools component new`. | 
|---|
| 2290 | pub fn wasm_import_name( | 
|---|
| 2291 | &self, | 
|---|
| 2292 | mangling: ManglingAndAbi, | 
|---|
| 2293 | import: WasmImport<'_>, | 
|---|
| 2294 | ) -> (String, String) { | 
|---|
| 2295 | match mangling { | 
|---|
| 2296 | ManglingAndAbi::Standard32 => match import { | 
|---|
| 2297 | WasmImport::Func { interface, func } => { | 
|---|
| 2298 | let module = match interface { | 
|---|
| 2299 | Some(key) => format!( "cm32p2|{} ", self.name_canonicalized_world_key(key)), | 
|---|
| 2300 | None => format!( "cm32p2"), | 
|---|
| 2301 | }; | 
|---|
| 2302 | (module, func.name.clone()) | 
|---|
| 2303 | } | 
|---|
| 2304 | WasmImport::ResourceIntrinsic { | 
|---|
| 2305 | interface, | 
|---|
| 2306 | resource, | 
|---|
| 2307 | intrinsic, | 
|---|
| 2308 | } => { | 
|---|
| 2309 | let name = self.types[resource].name.as_ref().unwrap(); | 
|---|
| 2310 | let (prefix, name) = match intrinsic { | 
|---|
| 2311 | ResourceIntrinsic::ImportedDrop => ( "", format!( "{name} _drop")), | 
|---|
| 2312 | ResourceIntrinsic::ExportedDrop => ( "_ex_", format!( "{name} _drop")), | 
|---|
| 2313 | ResourceIntrinsic::ExportedNew => ( "_ex_", format!( "{name} _new")), | 
|---|
| 2314 | ResourceIntrinsic::ExportedRep => ( "_ex_", format!( "{name} _rep")), | 
|---|
| 2315 | }; | 
|---|
| 2316 | let module = match interface { | 
|---|
| 2317 | Some(key) => { | 
|---|
| 2318 | format!( "cm32p2|{prefix}{} ", self.name_canonicalized_world_key(key)) | 
|---|
| 2319 | } | 
|---|
| 2320 | None => { | 
|---|
| 2321 | assert_eq!(prefix, ""); | 
|---|
| 2322 | format!( "cm32p2") | 
|---|
| 2323 | } | 
|---|
| 2324 | }; | 
|---|
| 2325 | (module, name) | 
|---|
| 2326 | } | 
|---|
| 2327 | }, | 
|---|
| 2328 | ManglingAndAbi::Legacy(abi) => match import { | 
|---|
| 2329 | WasmImport::Func { interface, func } => { | 
|---|
| 2330 | let module = match interface { | 
|---|
| 2331 | Some(key) => self.name_world_key(key), | 
|---|
| 2332 | None => format!( "$root"), | 
|---|
| 2333 | }; | 
|---|
| 2334 | (module, format!( "{}{} ", abi.import_prefix(), func.name)) | 
|---|
| 2335 | } | 
|---|
| 2336 | WasmImport::ResourceIntrinsic { | 
|---|
| 2337 | interface, | 
|---|
| 2338 | resource, | 
|---|
| 2339 | intrinsic, | 
|---|
| 2340 | } => { | 
|---|
| 2341 | let name = self.types[resource].name.as_ref().unwrap(); | 
|---|
| 2342 | let (prefix, name) = match intrinsic { | 
|---|
| 2343 | ResourceIntrinsic::ImportedDrop => ( "", format!( "[resource-drop]{name} ")), | 
|---|
| 2344 | ResourceIntrinsic::ExportedDrop => { | 
|---|
| 2345 | ( "[export]", format!( "[resource-drop]{name} ")) | 
|---|
| 2346 | } | 
|---|
| 2347 | ResourceIntrinsic::ExportedNew => { | 
|---|
| 2348 | ( "[export]", format!( "[resource-new]{name} ")) | 
|---|
| 2349 | } | 
|---|
| 2350 | ResourceIntrinsic::ExportedRep => { | 
|---|
| 2351 | ( "[export]", format!( "[resource-rep]{name} ")) | 
|---|
| 2352 | } | 
|---|
| 2353 | }; | 
|---|
| 2354 | let module = match interface { | 
|---|
| 2355 | Some(key) => format!( "{prefix}{} ", self.name_world_key(key)), | 
|---|
| 2356 | None => { | 
|---|
| 2357 | assert_eq!(prefix, ""); | 
|---|
| 2358 | format!( "$root") | 
|---|
| 2359 | } | 
|---|
| 2360 | }; | 
|---|
| 2361 | (module, format!( "{}{name} ", abi.import_prefix())) | 
|---|
| 2362 | } | 
|---|
| 2363 | }, | 
|---|
| 2364 | } | 
|---|
| 2365 | } | 
|---|
| 2366 |  | 
|---|
| 2367 | /// Returns the core wasm export name for the specified `export`. | 
|---|
| 2368 | /// | 
|---|
| 2369 | /// This is the same as [`Resolve::wasm_import_name`], except for exports. | 
|---|
| 2370 | pub fn wasm_export_name(&self, mangling: ManglingAndAbi, export: WasmExport<'_>) -> String { | 
|---|
| 2371 | match mangling { | 
|---|
| 2372 | ManglingAndAbi::Standard32 => match export { | 
|---|
| 2373 | WasmExport::Func { | 
|---|
| 2374 | interface, | 
|---|
| 2375 | func, | 
|---|
| 2376 | kind, | 
|---|
| 2377 | } => { | 
|---|
| 2378 | let mut name = String::from( "cm32p2|"); | 
|---|
| 2379 | if let Some(interface) = interface { | 
|---|
| 2380 | let s = self.name_canonicalized_world_key(interface); | 
|---|
| 2381 | name.push_str(&s); | 
|---|
| 2382 | } | 
|---|
| 2383 | name.push_str( "|"); | 
|---|
| 2384 | name.push_str(&func.name); | 
|---|
| 2385 | match kind { | 
|---|
| 2386 | WasmExportKind::Normal => {} | 
|---|
| 2387 | WasmExportKind::PostReturn => name.push_str( "_post"), | 
|---|
| 2388 | WasmExportKind::Callback => todo!( | 
|---|
| 2389 | "not yet supported: \ | 
|---|
| 2390 |                              async callback functions using standard name mangling" | 
|---|
| 2391 | ), | 
|---|
| 2392 | } | 
|---|
| 2393 | name | 
|---|
| 2394 | } | 
|---|
| 2395 | WasmExport::ResourceDtor { | 
|---|
| 2396 | interface, | 
|---|
| 2397 | resource, | 
|---|
| 2398 | } => { | 
|---|
| 2399 | let name = self.types[resource].name.as_ref().unwrap(); | 
|---|
| 2400 | let interface = self.name_canonicalized_world_key(interface); | 
|---|
| 2401 | format!( "cm32p2|{interface} |{name} _dtor") | 
|---|
| 2402 | } | 
|---|
| 2403 | WasmExport::Memory => "cm32p2_memory".to_string(), | 
|---|
| 2404 | WasmExport::Initialize => "cm32p2_initialize".to_string(), | 
|---|
| 2405 | WasmExport::Realloc => "cm32p2_realloc".to_string(), | 
|---|
| 2406 | }, | 
|---|
| 2407 | ManglingAndAbi::Legacy(abi) => match export { | 
|---|
| 2408 | WasmExport::Func { | 
|---|
| 2409 | interface, | 
|---|
| 2410 | func, | 
|---|
| 2411 | kind, | 
|---|
| 2412 | } => { | 
|---|
| 2413 | let mut name = abi.export_prefix().to_string(); | 
|---|
| 2414 | match kind { | 
|---|
| 2415 | WasmExportKind::Normal => {} | 
|---|
| 2416 | WasmExportKind::PostReturn => name.push_str( "cabi_post_"), | 
|---|
| 2417 | WasmExportKind::Callback => { | 
|---|
| 2418 | assert!(matches!(abi, LiftLowerAbi::AsyncCallback)); | 
|---|
| 2419 | name = format!( "[callback]{name} ") | 
|---|
| 2420 | } | 
|---|
| 2421 | } | 
|---|
| 2422 | if let Some(interface) = interface { | 
|---|
| 2423 | let s = self.name_world_key(interface); | 
|---|
| 2424 | name.push_str(&s); | 
|---|
| 2425 | name.push_str( "#"); | 
|---|
| 2426 | } | 
|---|
| 2427 | name.push_str(&func.name); | 
|---|
| 2428 | name | 
|---|
| 2429 | } | 
|---|
| 2430 | WasmExport::ResourceDtor { | 
|---|
| 2431 | interface, | 
|---|
| 2432 | resource, | 
|---|
| 2433 | } => { | 
|---|
| 2434 | let name = self.types[resource].name.as_ref().unwrap(); | 
|---|
| 2435 | let interface = self.name_world_key(interface); | 
|---|
| 2436 | format!( "{}{interface} #[dtor]{name} ", abi.export_prefix()) | 
|---|
| 2437 | } | 
|---|
| 2438 | WasmExport::Memory => "memory".to_string(), | 
|---|
| 2439 | WasmExport::Initialize => "_initialize".to_string(), | 
|---|
| 2440 | WasmExport::Realloc => "cabi_realloc".to_string(), | 
|---|
| 2441 | }, | 
|---|
| 2442 | } | 
|---|
| 2443 | } | 
|---|
| 2444 | } | 
|---|
| 2445 |  | 
|---|
| 2446 | /// Possible imports that can be passed to [`Resolve::wasm_import_name`]. | 
|---|
| 2447 | #[ derive(Debug)] | 
|---|
| 2448 | pub enum WasmImport<'a> { | 
|---|
| 2449 | /// A WIT function is being imported. Optionally from an interface. | 
|---|
| 2450 | Func { | 
|---|
| 2451 | /// The name of the interface that the function is being imported from. | 
|---|
| 2452 | /// | 
|---|
| 2453 | /// If the function is imported directly from the world then this is | 
|---|
| 2454 | /// `Noen`. | 
|---|
| 2455 | interface: Option<&'a WorldKey>, | 
|---|
| 2456 |  | 
|---|
| 2457 | /// The function being imported. | 
|---|
| 2458 | func: &'a Function, | 
|---|
| 2459 | }, | 
|---|
| 2460 |  | 
|---|
| 2461 | /// A resource-related intrinsic is being imported. | 
|---|
| 2462 | ResourceIntrinsic { | 
|---|
| 2463 | /// The optional interface to import from, same as `WasmImport::Func`. | 
|---|
| 2464 | interface: Option<&'a WorldKey>, | 
|---|
| 2465 |  | 
|---|
| 2466 | /// The resource that's being operated on. | 
|---|
| 2467 | resource: TypeId, | 
|---|
| 2468 |  | 
|---|
| 2469 | /// The intrinsic that's being imported. | 
|---|
| 2470 | intrinsic: ResourceIntrinsic, | 
|---|
| 2471 | }, | 
|---|
| 2472 | } | 
|---|
| 2473 |  | 
|---|
| 2474 | /// Intrinsic definitions to go with [`WasmImport::ResourceIntrinsic`] which | 
|---|
| 2475 | /// also goes with [`Resolve::wasm_import_name`]. | 
|---|
| 2476 | #[ derive(Debug)] | 
|---|
| 2477 | pub enum ResourceIntrinsic { | 
|---|
| 2478 | ImportedDrop, | 
|---|
| 2479 | ExportedDrop, | 
|---|
| 2480 | ExportedNew, | 
|---|
| 2481 | ExportedRep, | 
|---|
| 2482 | } | 
|---|
| 2483 |  | 
|---|
| 2484 | /// Indicates whether a function export is a normal export, a post-return | 
|---|
| 2485 | /// function, or a callback function. | 
|---|
| 2486 | #[ derive(Debug)] | 
|---|
| 2487 | pub enum WasmExportKind { | 
|---|
| 2488 | /// Normal function export. | 
|---|
| 2489 | Normal, | 
|---|
| 2490 |  | 
|---|
| 2491 | /// Post-return function. | 
|---|
| 2492 | PostReturn, | 
|---|
| 2493 |  | 
|---|
| 2494 | /// Async callback function. | 
|---|
| 2495 | Callback, | 
|---|
| 2496 | } | 
|---|
| 2497 |  | 
|---|
| 2498 | /// Different kinds of exports that can be passed to | 
|---|
| 2499 | /// [`Resolve::wasm_export_name`] to export from core wasm modules. | 
|---|
| 2500 | #[ derive(Debug)] | 
|---|
| 2501 | pub enum WasmExport<'a> { | 
|---|
| 2502 | /// A WIT function is being exported, optionally from an interface. | 
|---|
| 2503 | Func { | 
|---|
| 2504 | /// An optional interface which owns `func`. Use `None` for top-level | 
|---|
| 2505 | /// world function. | 
|---|
| 2506 | interface: Option<&'a WorldKey>, | 
|---|
| 2507 |  | 
|---|
| 2508 | /// The function being exported. | 
|---|
| 2509 | func: &'a Function, | 
|---|
| 2510 |  | 
|---|
| 2511 | /// Kind of function (normal, post-return, or callback) being exported. | 
|---|
| 2512 | kind: WasmExportKind, | 
|---|
| 2513 | }, | 
|---|
| 2514 |  | 
|---|
| 2515 | /// A destructor for a resource exported from this module. | 
|---|
| 2516 | ResourceDtor { | 
|---|
| 2517 | /// The interface that owns the resource. | 
|---|
| 2518 | interface: &'a WorldKey, | 
|---|
| 2519 | /// The resource itself that the destructor is for. | 
|---|
| 2520 | resource: TypeId, | 
|---|
| 2521 | }, | 
|---|
| 2522 |  | 
|---|
| 2523 | /// Linear memory, the one that the canonical ABI uses. | 
|---|
| 2524 | Memory, | 
|---|
| 2525 |  | 
|---|
| 2526 | /// An initialization function (not the core wasm `start`). | 
|---|
| 2527 | Initialize, | 
|---|
| 2528 |  | 
|---|
| 2529 | /// The general-purpose realloc hook. | 
|---|
| 2530 | Realloc, | 
|---|
| 2531 | } | 
|---|
| 2532 |  | 
|---|
| 2533 | /// Structure returned by [`Resolve::merge`] which contains mappings from | 
|---|
| 2534 | /// old-ids to new-ids after the merge. | 
|---|
| 2535 | #[ derive(Default)] | 
|---|
| 2536 | pub struct Remap { | 
|---|
| 2537 | pub types: Vec<Option<TypeId>>, | 
|---|
| 2538 | pub interfaces: Vec<Option<InterfaceId>>, | 
|---|
| 2539 | pub worlds: Vec<Option<WorldId>>, | 
|---|
| 2540 | pub packages: Vec<PackageId>, | 
|---|
| 2541 |  | 
|---|
| 2542 | /// A cache of anonymous `own<T>` handles for resource types. | 
|---|
| 2543 | /// | 
|---|
| 2544 | /// The appending operation of `Remap` is the one responsible for | 
|---|
| 2545 | /// translating references to `T` where `T` is a resource into `own<T>` | 
|---|
| 2546 | /// instead. This map is used to deduplicate the `own<T>` types generated | 
|---|
| 2547 | /// to generate as few as possible. | 
|---|
| 2548 | /// | 
|---|
| 2549 | /// The key of this map is the resource id `T` in the new resolve, and | 
|---|
| 2550 | /// the value is the `own<T>` type pointing to `T`. | 
|---|
| 2551 | own_handles: HashMap<TypeId, TypeId>, | 
|---|
| 2552 |  | 
|---|
| 2553 | type_has_borrow: Vec<Option<bool>>, | 
|---|
| 2554 | } | 
|---|
| 2555 |  | 
|---|
| 2556 | fn apply_map<T>(map: &[Option<Id<T>>], id: Id<T>, desc: &str, span: Option<Span>) -> Result<Id<T>> { | 
|---|
| 2557 | match map.get(id.index()) { | 
|---|
| 2558 | Some(Some(id: &Id)) => Ok(*id), | 
|---|
| 2559 | Some(None) => { | 
|---|
| 2560 | let msg: String = format!( | 
|---|
| 2561 | "found a reference to a {desc}  which is excluded \ | 
|---|
| 2562 |                  due to its feature not being activated" | 
|---|
| 2563 | ); | 
|---|
| 2564 | match span { | 
|---|
| 2565 | Some(span: Span) => Err(Error::new(span, msg).into()), | 
|---|
| 2566 | None => bail!( "{msg} "), | 
|---|
| 2567 | } | 
|---|
| 2568 | } | 
|---|
| 2569 | None => panic!( "request to remap a {desc}  that has not yet been registered"), | 
|---|
| 2570 | } | 
|---|
| 2571 | } | 
|---|
| 2572 |  | 
|---|
| 2573 | impl Remap { | 
|---|
| 2574 | pub fn map_type(&self, id: TypeId, span: Option<Span>) -> Result<TypeId> { | 
|---|
| 2575 | apply_map(&self.types, id, "type", span) | 
|---|
| 2576 | } | 
|---|
| 2577 |  | 
|---|
| 2578 | pub fn map_interface(&self, id: InterfaceId, span: Option<Span>) -> Result<InterfaceId> { | 
|---|
| 2579 | apply_map(&self.interfaces, id, "interface", span) | 
|---|
| 2580 | } | 
|---|
| 2581 |  | 
|---|
| 2582 | pub fn map_world(&self, id: WorldId, span: Option<Span>) -> Result<WorldId> { | 
|---|
| 2583 | apply_map(&self.worlds, id, "world", span) | 
|---|
| 2584 | } | 
|---|
| 2585 |  | 
|---|
| 2586 | fn append( | 
|---|
| 2587 | &mut self, | 
|---|
| 2588 | resolve: &mut Resolve, | 
|---|
| 2589 | unresolved: UnresolvedPackage, | 
|---|
| 2590 | ) -> Result<PackageId> { | 
|---|
| 2591 | self.process_foreign_deps(resolve, &unresolved)?; | 
|---|
| 2592 |  | 
|---|
| 2593 | let foreign_types = self.types.len(); | 
|---|
| 2594 | let foreign_interfaces = self.interfaces.len(); | 
|---|
| 2595 | let foreign_worlds = self.worlds.len(); | 
|---|
| 2596 |  | 
|---|
| 2597 | let pkgid = resolve.packages.alloc(Package { | 
|---|
| 2598 | name: unresolved.name.clone(), | 
|---|
| 2599 | docs: unresolved.docs.clone(), | 
|---|
| 2600 | interfaces: Default::default(), | 
|---|
| 2601 | worlds: Default::default(), | 
|---|
| 2602 | }); | 
|---|
| 2603 | let prev = resolve.package_names.insert(unresolved.name.clone(), pkgid); | 
|---|
| 2604 | assert!(prev.is_none()); | 
|---|
| 2605 |  | 
|---|
| 2606 | // Copy over all types first, updating any intra-type references. Note | 
|---|
| 2607 | // that types are sorted topologically which means this iteration | 
|---|
| 2608 | // order should be sufficient. Also note though that the interface | 
|---|
| 2609 | // owner of a type isn't updated here due to interfaces not being known | 
|---|
| 2610 | // yet. | 
|---|
| 2611 | assert_eq!(unresolved.types.len(), unresolved.type_spans.len()); | 
|---|
| 2612 | for ((id, mut ty), span) in unresolved | 
|---|
| 2613 | .types | 
|---|
| 2614 | .into_iter() | 
|---|
| 2615 | .zip(&unresolved.type_spans) | 
|---|
| 2616 | .skip(foreign_types) | 
|---|
| 2617 | { | 
|---|
| 2618 | if !resolve | 
|---|
| 2619 | .include_stability(&ty.stability, &pkgid) | 
|---|
| 2620 | .with_context(|| { | 
|---|
| 2621 | format!( | 
|---|
| 2622 | "failed to process feature gate for type [{} ] in package [{} ]", | 
|---|
| 2623 | ty.name.as_ref().map(String::as_str).unwrap_or( "<unknown>"), | 
|---|
| 2624 | resolve.packages[pkgid].name, | 
|---|
| 2625 | ) | 
|---|
| 2626 | })? | 
|---|
| 2627 | { | 
|---|
| 2628 | self.types.push(None); | 
|---|
| 2629 | continue; | 
|---|
| 2630 | } | 
|---|
| 2631 |  | 
|---|
| 2632 | self.update_typedef(resolve, &mut ty, Some(*span))?; | 
|---|
| 2633 | let new_id = resolve.types.alloc(ty); | 
|---|
| 2634 | assert_eq!(self.types.len(), id.index()); | 
|---|
| 2635 |  | 
|---|
| 2636 | let new_id = match resolve.types[new_id] { | 
|---|
| 2637 | // If this is an `own<T>` handle then either replace it with a | 
|---|
| 2638 | // preexisting `own<T>` handle which may have been generated in | 
|---|
| 2639 | // `update_ty`. If that doesn't exist though then insert it into | 
|---|
| 2640 | // the `own_handles` cache. | 
|---|
| 2641 | TypeDef { | 
|---|
| 2642 | name: None, | 
|---|
| 2643 | owner: TypeOwner::None, | 
|---|
| 2644 | kind: TypeDefKind::Handle(Handle::Own(id)), | 
|---|
| 2645 | docs: _, | 
|---|
| 2646 | stability: _, | 
|---|
| 2647 | } => *self.own_handles.entry(id).or_insert(new_id), | 
|---|
| 2648 |  | 
|---|
| 2649 | // Everything not-related to `own<T>` doesn't get its ID | 
|---|
| 2650 | // modified. | 
|---|
| 2651 | _ => new_id, | 
|---|
| 2652 | }; | 
|---|
| 2653 | self.types.push(Some(new_id)); | 
|---|
| 2654 | } | 
|---|
| 2655 |  | 
|---|
| 2656 | // Next transfer all interfaces into `Resolve`, updating type ids | 
|---|
| 2657 | // referenced along the way. | 
|---|
| 2658 | assert_eq!( | 
|---|
| 2659 | unresolved.interfaces.len(), | 
|---|
| 2660 | unresolved.interface_spans.len() | 
|---|
| 2661 | ); | 
|---|
| 2662 | for ((id, mut iface), span) in unresolved | 
|---|
| 2663 | .interfaces | 
|---|
| 2664 | .into_iter() | 
|---|
| 2665 | .zip(&unresolved.interface_spans) | 
|---|
| 2666 | .skip(foreign_interfaces) | 
|---|
| 2667 | { | 
|---|
| 2668 | if !resolve | 
|---|
| 2669 | .include_stability(&iface.stability, &pkgid) | 
|---|
| 2670 | .with_context(|| { | 
|---|
| 2671 | format!( | 
|---|
| 2672 | "failed to process feature gate for interface [{} ] in package [{} ]", | 
|---|
| 2673 | iface | 
|---|
| 2674 | .name | 
|---|
| 2675 | .as_ref() | 
|---|
| 2676 | .map(String::as_str) | 
|---|
| 2677 | .unwrap_or( "<unknown>"), | 
|---|
| 2678 | resolve.packages[pkgid].name, | 
|---|
| 2679 | ) | 
|---|
| 2680 | })? | 
|---|
| 2681 | { | 
|---|
| 2682 | self.interfaces.push(None); | 
|---|
| 2683 | continue; | 
|---|
| 2684 | } | 
|---|
| 2685 | assert!(iface.package.is_none()); | 
|---|
| 2686 | iface.package = Some(pkgid); | 
|---|
| 2687 | self.update_interface(resolve, &mut iface, Some(span))?; | 
|---|
| 2688 | let new_id = resolve.interfaces.alloc(iface); | 
|---|
| 2689 | assert_eq!(self.interfaces.len(), id.index()); | 
|---|
| 2690 | self.interfaces.push(Some(new_id)); | 
|---|
| 2691 | } | 
|---|
| 2692 |  | 
|---|
| 2693 | // Now that interfaces are identified go back through the types and | 
|---|
| 2694 | // update their interface owners. | 
|---|
| 2695 | for (i, id) in self.types.iter().enumerate().skip(foreign_types) { | 
|---|
| 2696 | let id = match id { | 
|---|
| 2697 | Some(id) => *id, | 
|---|
| 2698 | None => continue, | 
|---|
| 2699 | }; | 
|---|
| 2700 | match &mut resolve.types[id].owner { | 
|---|
| 2701 | TypeOwner::Interface(id) => { | 
|---|
| 2702 | let span = unresolved.type_spans[i]; | 
|---|
| 2703 | *id = self.map_interface(*id, Some(span)) | 
|---|
| 2704 | .with_context(|| { | 
|---|
| 2705 | "this type is not gated by a feature but its interface is gated by a feature" | 
|---|
| 2706 | })?; | 
|---|
| 2707 | } | 
|---|
| 2708 | TypeOwner::World(_) | TypeOwner::None => {} | 
|---|
| 2709 | } | 
|---|
| 2710 | } | 
|---|
| 2711 |  | 
|---|
| 2712 | // Perform a weighty step of full resolution of worlds. This will fully | 
|---|
| 2713 | // expand imports/exports for a world and create the topological | 
|---|
| 2714 | // ordering necessary for this. | 
|---|
| 2715 | // | 
|---|
| 2716 | // This is done after types/interfaces are fully settled so the | 
|---|
| 2717 | // transitive relation between interfaces, through types, is understood | 
|---|
| 2718 | // here. | 
|---|
| 2719 | assert_eq!(unresolved.worlds.len(), unresolved.world_spans.len()); | 
|---|
| 2720 | for ((id, mut world), span) in unresolved | 
|---|
| 2721 | .worlds | 
|---|
| 2722 | .into_iter() | 
|---|
| 2723 | .zip(&unresolved.world_spans) | 
|---|
| 2724 | .skip(foreign_worlds) | 
|---|
| 2725 | { | 
|---|
| 2726 | if !resolve | 
|---|
| 2727 | .include_stability(&world.stability, &pkgid) | 
|---|
| 2728 | .with_context(|| { | 
|---|
| 2729 | format!( | 
|---|
| 2730 | "failed to process feature gate for world [{} ] in package [{} ]", | 
|---|
| 2731 | world.name, resolve.packages[pkgid].name, | 
|---|
| 2732 | ) | 
|---|
| 2733 | })? | 
|---|
| 2734 | { | 
|---|
| 2735 | self.worlds.push(None); | 
|---|
| 2736 | continue; | 
|---|
| 2737 | } | 
|---|
| 2738 | self.update_world(&mut world, resolve, &pkgid, &span)?; | 
|---|
| 2739 |  | 
|---|
| 2740 | let new_id = resolve.worlds.alloc(world); | 
|---|
| 2741 | assert_eq!(self.worlds.len(), id.index()); | 
|---|
| 2742 | self.worlds.push(Some(new_id)); | 
|---|
| 2743 |  | 
|---|
| 2744 | resolve.elaborate_world(new_id).with_context(|| { | 
|---|
| 2745 | Error::new( | 
|---|
| 2746 | span.span, | 
|---|
| 2747 | format!( | 
|---|
| 2748 | "failed to elaborate world imports/exports of `{} `", | 
|---|
| 2749 | resolve.worlds[new_id].name | 
|---|
| 2750 | ), | 
|---|
| 2751 | ) | 
|---|
| 2752 | })?; | 
|---|
| 2753 | } | 
|---|
| 2754 |  | 
|---|
| 2755 | // As with interfaces, now update the ids of world-owned types. | 
|---|
| 2756 | for (i, id) in self.types.iter().enumerate().skip(foreign_types) { | 
|---|
| 2757 | let id = match id { | 
|---|
| 2758 | Some(id) => *id, | 
|---|
| 2759 | None => continue, | 
|---|
| 2760 | }; | 
|---|
| 2761 | match &mut resolve.types[id].owner { | 
|---|
| 2762 | TypeOwner::World(id) => { | 
|---|
| 2763 | let span = unresolved.type_spans[i]; | 
|---|
| 2764 | *id = self.map_world(*id, Some(span)) | 
|---|
| 2765 | .with_context(|| { | 
|---|
| 2766 | "this type is not gated by a feature but its interface is gated by a feature" | 
|---|
| 2767 | })?; | 
|---|
| 2768 | } | 
|---|
| 2769 | TypeOwner::Interface(_) | TypeOwner::None => {} | 
|---|
| 2770 | } | 
|---|
| 2771 | } | 
|---|
| 2772 |  | 
|---|
| 2773 | // Fixup "parent" ids now that everything has been identified | 
|---|
| 2774 | for id in self.interfaces.iter().skip(foreign_interfaces) { | 
|---|
| 2775 | let id = match id { | 
|---|
| 2776 | Some(id) => *id, | 
|---|
| 2777 | None => continue, | 
|---|
| 2778 | }; | 
|---|
| 2779 | let iface = &mut resolve.interfaces[id]; | 
|---|
| 2780 | iface.package = Some(pkgid); | 
|---|
| 2781 | if let Some(name) = &iface.name { | 
|---|
| 2782 | let prev = resolve.packages[pkgid].interfaces.insert(name.clone(), id); | 
|---|
| 2783 | assert!(prev.is_none()); | 
|---|
| 2784 | } | 
|---|
| 2785 | } | 
|---|
| 2786 | for id in self.worlds.iter().skip(foreign_worlds) { | 
|---|
| 2787 | let id = match id { | 
|---|
| 2788 | Some(id) => *id, | 
|---|
| 2789 | None => continue, | 
|---|
| 2790 | }; | 
|---|
| 2791 | let world = &mut resolve.worlds[id]; | 
|---|
| 2792 | world.package = Some(pkgid); | 
|---|
| 2793 | let prev = resolve.packages[pkgid] | 
|---|
| 2794 | .worlds | 
|---|
| 2795 | .insert(world.name.clone(), id); | 
|---|
| 2796 | assert!(prev.is_none()); | 
|---|
| 2797 | } | 
|---|
| 2798 | Ok(pkgid) | 
|---|
| 2799 | } | 
|---|
| 2800 |  | 
|---|
| 2801 | fn process_foreign_deps( | 
|---|
| 2802 | &mut self, | 
|---|
| 2803 | resolve: &mut Resolve, | 
|---|
| 2804 | unresolved: &UnresolvedPackage, | 
|---|
| 2805 | ) -> Result<()> { | 
|---|
| 2806 | // Invert the `foreign_deps` map to be keyed by world id to get | 
|---|
| 2807 | // used in the loops below. | 
|---|
| 2808 | let mut world_to_package = HashMap::new(); | 
|---|
| 2809 | let mut interface_to_package = HashMap::new(); | 
|---|
| 2810 | for (i, (pkg_name, worlds_or_ifaces)) in unresolved.foreign_deps.iter().enumerate() { | 
|---|
| 2811 | for (name, item) in worlds_or_ifaces { | 
|---|
| 2812 | match item { | 
|---|
| 2813 | AstItem::Interface(unresolved_interface_id) => { | 
|---|
| 2814 | let prev = interface_to_package.insert( | 
|---|
| 2815 | *unresolved_interface_id, | 
|---|
| 2816 | (pkg_name, name, unresolved.foreign_dep_spans[i]), | 
|---|
| 2817 | ); | 
|---|
| 2818 | assert!(prev.is_none()); | 
|---|
| 2819 | } | 
|---|
| 2820 | AstItem::World(unresolved_world_id) => { | 
|---|
| 2821 | let prev = world_to_package.insert( | 
|---|
| 2822 | *unresolved_world_id, | 
|---|
| 2823 | (pkg_name, name, unresolved.foreign_dep_spans[i]), | 
|---|
| 2824 | ); | 
|---|
| 2825 | assert!(prev.is_none()); | 
|---|
| 2826 | } | 
|---|
| 2827 | } | 
|---|
| 2828 | } | 
|---|
| 2829 | } | 
|---|
| 2830 |  | 
|---|
| 2831 | // Connect all interfaces referred to in `interface_to_package`, which | 
|---|
| 2832 | // are at the front of `unresolved.interfaces`, to interfaces already | 
|---|
| 2833 | // contained within `resolve`. | 
|---|
| 2834 | self.process_foreign_interfaces(unresolved, &interface_to_package, resolve)?; | 
|---|
| 2835 |  | 
|---|
| 2836 | // Connect all worlds referred to in `world_to_package`, which | 
|---|
| 2837 | // are at the front of `unresolved.worlds`, to worlds already | 
|---|
| 2838 | // contained within `resolve`. | 
|---|
| 2839 | self.process_foreign_worlds(unresolved, &world_to_package, resolve)?; | 
|---|
| 2840 |  | 
|---|
| 2841 | // Finally, iterate over all foreign-defined types and determine | 
|---|
| 2842 | // what they map to. | 
|---|
| 2843 | self.process_foreign_types(unresolved, resolve)?; | 
|---|
| 2844 |  | 
|---|
| 2845 | for (id, span) in unresolved.required_resource_types.iter() { | 
|---|
| 2846 | let mut id = self.map_type(*id, Some(*span))?; | 
|---|
| 2847 | loop { | 
|---|
| 2848 | match resolve.types[id].kind { | 
|---|
| 2849 | TypeDefKind::Type(Type::Id(i)) => id = i, | 
|---|
| 2850 | TypeDefKind::Resource => break, | 
|---|
| 2851 | _ => bail!(Error::new( | 
|---|
| 2852 | *span, | 
|---|
| 2853 | format!( "type used in a handle must be a resource"), | 
|---|
| 2854 | )), | 
|---|
| 2855 | } | 
|---|
| 2856 | } | 
|---|
| 2857 | } | 
|---|
| 2858 |  | 
|---|
| 2859 | #[ cfg(debug_assertions)] | 
|---|
| 2860 | resolve.assert_valid(); | 
|---|
| 2861 |  | 
|---|
| 2862 | Ok(()) | 
|---|
| 2863 | } | 
|---|
| 2864 |  | 
|---|
| 2865 | fn process_foreign_interfaces( | 
|---|
| 2866 | &mut self, | 
|---|
| 2867 | unresolved: &UnresolvedPackage, | 
|---|
| 2868 | interface_to_package: &HashMap<InterfaceId, (&PackageName, &String, Span)>, | 
|---|
| 2869 | resolve: &mut Resolve, | 
|---|
| 2870 | ) -> Result<(), anyhow::Error> { | 
|---|
| 2871 | for (unresolved_iface_id, unresolved_iface) in unresolved.interfaces.iter() { | 
|---|
| 2872 | let (pkg_name, interface, span) = match interface_to_package.get(&unresolved_iface_id) { | 
|---|
| 2873 | Some(items) => *items, | 
|---|
| 2874 | // All foreign interfaces are defined first, so the first one | 
|---|
| 2875 | // which is defined in a non-foreign document means that all | 
|---|
| 2876 | // further interfaces will be non-foreign as well. | 
|---|
| 2877 | None => break, | 
|---|
| 2878 | }; | 
|---|
| 2879 | let pkgid = resolve | 
|---|
| 2880 | .package_names | 
|---|
| 2881 | .get(pkg_name) | 
|---|
| 2882 | .copied() | 
|---|
| 2883 | .ok_or_else(|| { | 
|---|
| 2884 | PackageNotFoundError::new( | 
|---|
| 2885 | span, | 
|---|
| 2886 | pkg_name.clone(), | 
|---|
| 2887 | resolve.package_names.keys().cloned().collect(), | 
|---|
| 2888 | ) | 
|---|
| 2889 | })?; | 
|---|
| 2890 |  | 
|---|
| 2891 | // Functions can't be imported so this should be empty. | 
|---|
| 2892 | assert!(unresolved_iface.functions.is_empty()); | 
|---|
| 2893 |  | 
|---|
| 2894 | let pkg = &resolve.packages[pkgid]; | 
|---|
| 2895 | let span = &unresolved.interface_spans[unresolved_iface_id.index()]; | 
|---|
| 2896 | let iface_id = pkg | 
|---|
| 2897 | .interfaces | 
|---|
| 2898 | .get(interface) | 
|---|
| 2899 | .copied() | 
|---|
| 2900 | .ok_or_else(|| Error::new(span.span, "interface not found in package"))?; | 
|---|
| 2901 | assert_eq!(self.interfaces.len(), unresolved_iface_id.index()); | 
|---|
| 2902 | self.interfaces.push(Some(iface_id)); | 
|---|
| 2903 | } | 
|---|
| 2904 | for (id, _) in unresolved.interfaces.iter().skip(self.interfaces.len()) { | 
|---|
| 2905 | assert!( | 
|---|
| 2906 | interface_to_package.get(&id).is_none(), | 
|---|
| 2907 | "found foreign interface after local interface" | 
|---|
| 2908 | ); | 
|---|
| 2909 | } | 
|---|
| 2910 | Ok(()) | 
|---|
| 2911 | } | 
|---|
| 2912 |  | 
|---|
| 2913 | fn process_foreign_worlds( | 
|---|
| 2914 | &mut self, | 
|---|
| 2915 | unresolved: &UnresolvedPackage, | 
|---|
| 2916 | world_to_package: &HashMap<WorldId, (&PackageName, &String, Span)>, | 
|---|
| 2917 | resolve: &mut Resolve, | 
|---|
| 2918 | ) -> Result<(), anyhow::Error> { | 
|---|
| 2919 | for (unresolved_world_id, _) in unresolved.worlds.iter() { | 
|---|
| 2920 | let (pkg_name, world, span) = match world_to_package.get(&unresolved_world_id) { | 
|---|
| 2921 | Some(items) => *items, | 
|---|
| 2922 | // Same as above, all worlds are foreign until we find a | 
|---|
| 2923 | // non-foreign one. | 
|---|
| 2924 | None => break, | 
|---|
| 2925 | }; | 
|---|
| 2926 |  | 
|---|
| 2927 | let pkgid = resolve | 
|---|
| 2928 | .package_names | 
|---|
| 2929 | .get(pkg_name) | 
|---|
| 2930 | .copied() | 
|---|
| 2931 | .ok_or_else(|| Error::new(span, "package not found"))?; | 
|---|
| 2932 | let pkg = &resolve.packages[pkgid]; | 
|---|
| 2933 | let span = &unresolved.world_spans[unresolved_world_id.index()]; | 
|---|
| 2934 | let world_id = pkg | 
|---|
| 2935 | .worlds | 
|---|
| 2936 | .get(world) | 
|---|
| 2937 | .copied() | 
|---|
| 2938 | .ok_or_else(|| Error::new(span.span, "world not found in package"))?; | 
|---|
| 2939 | assert_eq!(self.worlds.len(), unresolved_world_id.index()); | 
|---|
| 2940 | self.worlds.push(Some(world_id)); | 
|---|
| 2941 | } | 
|---|
| 2942 | for (id, _) in unresolved.worlds.iter().skip(self.worlds.len()) { | 
|---|
| 2943 | assert!( | 
|---|
| 2944 | world_to_package.get(&id).is_none(), | 
|---|
| 2945 | "found foreign world after local world" | 
|---|
| 2946 | ); | 
|---|
| 2947 | } | 
|---|
| 2948 | Ok(()) | 
|---|
| 2949 | } | 
|---|
| 2950 |  | 
|---|
| 2951 | fn process_foreign_types( | 
|---|
| 2952 | &mut self, | 
|---|
| 2953 | unresolved: &UnresolvedPackage, | 
|---|
| 2954 | resolve: &mut Resolve, | 
|---|
| 2955 | ) -> Result<(), anyhow::Error> { | 
|---|
| 2956 | for (unresolved_type_id, unresolved_ty) in unresolved.types.iter() { | 
|---|
| 2957 | // All "Unknown" types should appear first so once we're no longer | 
|---|
| 2958 | // in unknown territory it's package-defined types so break out of | 
|---|
| 2959 | // this loop. | 
|---|
| 2960 | match unresolved_ty.kind { | 
|---|
| 2961 | TypeDefKind::Unknown => {} | 
|---|
| 2962 | _ => break, | 
|---|
| 2963 | } | 
|---|
| 2964 | let unresolved_iface_id = match unresolved_ty.owner { | 
|---|
| 2965 | TypeOwner::Interface(id) => id, | 
|---|
| 2966 | _ => unreachable!(), | 
|---|
| 2967 | }; | 
|---|
| 2968 | let iface_id = self.map_interface(unresolved_iface_id, None)?; | 
|---|
| 2969 | let name = unresolved_ty.name.as_ref().unwrap(); | 
|---|
| 2970 | let span = unresolved.unknown_type_spans[unresolved_type_id.index()]; | 
|---|
| 2971 | let type_id = *resolve.interfaces[iface_id] | 
|---|
| 2972 | .types | 
|---|
| 2973 | .get(name) | 
|---|
| 2974 | .ok_or_else(|| { | 
|---|
| 2975 | Error::new(span, format!( "type `{name} ` not defined in interface")) | 
|---|
| 2976 | })?; | 
|---|
| 2977 | assert_eq!(self.types.len(), unresolved_type_id.index()); | 
|---|
| 2978 | self.types.push(Some(type_id)); | 
|---|
| 2979 | } | 
|---|
| 2980 | for (_, ty) in unresolved.types.iter().skip(self.types.len()) { | 
|---|
| 2981 | if let TypeDefKind::Unknown = ty.kind { | 
|---|
| 2982 | panic!( "unknown type after defined type"); | 
|---|
| 2983 | } | 
|---|
| 2984 | } | 
|---|
| 2985 | Ok(()) | 
|---|
| 2986 | } | 
|---|
| 2987 |  | 
|---|
| 2988 | fn update_typedef( | 
|---|
| 2989 | &mut self, | 
|---|
| 2990 | resolve: &mut Resolve, | 
|---|
| 2991 | ty: &mut TypeDef, | 
|---|
| 2992 | span: Option<Span>, | 
|---|
| 2993 | ) -> Result<()> { | 
|---|
| 2994 | // NB: note that `ty.owner` is not updated here since interfaces | 
|---|
| 2995 | // haven't been mapped yet and that's done in a separate step. | 
|---|
| 2996 | use crate::TypeDefKind::*; | 
|---|
| 2997 | match &mut ty.kind { | 
|---|
| 2998 | Handle(handle) => match handle { | 
|---|
| 2999 | crate::Handle::Own(ty) | crate::Handle::Borrow(ty) => { | 
|---|
| 3000 | self.update_type_id(ty, span)? | 
|---|
| 3001 | } | 
|---|
| 3002 | }, | 
|---|
| 3003 | Resource => {} | 
|---|
| 3004 | Record(r) => { | 
|---|
| 3005 | for field in r.fields.iter_mut() { | 
|---|
| 3006 | self.update_ty(resolve, &mut field.ty, span) | 
|---|
| 3007 | .with_context(|| format!( "failed to update field `{} `", field.name))?; | 
|---|
| 3008 | } | 
|---|
| 3009 | } | 
|---|
| 3010 | Tuple(t) => { | 
|---|
| 3011 | for ty in t.types.iter_mut() { | 
|---|
| 3012 | self.update_ty(resolve, ty, span)?; | 
|---|
| 3013 | } | 
|---|
| 3014 | } | 
|---|
| 3015 | Variant(v) => { | 
|---|
| 3016 | for case in v.cases.iter_mut() { | 
|---|
| 3017 | if let Some(t) = &mut case.ty { | 
|---|
| 3018 | self.update_ty(resolve, t, span)?; | 
|---|
| 3019 | } | 
|---|
| 3020 | } | 
|---|
| 3021 | } | 
|---|
| 3022 | Option(t) | List(t) | Stream(t) => self.update_ty(resolve, t, span)?, | 
|---|
| 3023 | Result(r) => { | 
|---|
| 3024 | if let Some(ty) = &mut r.ok { | 
|---|
| 3025 | self.update_ty(resolve, ty, span)?; | 
|---|
| 3026 | } | 
|---|
| 3027 | if let Some(ty) = &mut r.err { | 
|---|
| 3028 | self.update_ty(resolve, ty, span)?; | 
|---|
| 3029 | } | 
|---|
| 3030 | } | 
|---|
| 3031 | Future(Some(t)) => self.update_ty(resolve, t, span)?, | 
|---|
| 3032 | ErrorContext => {} | 
|---|
| 3033 |  | 
|---|
| 3034 | // Note that `update_ty` is specifically not used here as typedefs | 
|---|
| 3035 | // because for the `type a = b` form that doesn't force `a` to be a | 
|---|
| 3036 | // handle type if `b` is a resource type, instead `a` is | 
|---|
| 3037 | // simultaneously usable as a resource and a handle type | 
|---|
| 3038 | Type(crate::Type::Id(id)) => self.update_type_id(id, span)?, | 
|---|
| 3039 | Type(_) => {} | 
|---|
| 3040 |  | 
|---|
| 3041 | // nothing to do for these as they're just names or empty | 
|---|
| 3042 | Flags(_) | Enum(_) | Future(None) => {} | 
|---|
| 3043 |  | 
|---|
| 3044 | Unknown => unreachable!(), | 
|---|
| 3045 | } | 
|---|
| 3046 |  | 
|---|
| 3047 | Ok(()) | 
|---|
| 3048 | } | 
|---|
| 3049 |  | 
|---|
| 3050 | fn update_ty( | 
|---|
| 3051 | &mut self, | 
|---|
| 3052 | resolve: &mut Resolve, | 
|---|
| 3053 | ty: &mut Type, | 
|---|
| 3054 | span: Option<Span>, | 
|---|
| 3055 | ) -> Result<()> { | 
|---|
| 3056 | let id = match ty { | 
|---|
| 3057 | Type::Id(id) => id, | 
|---|
| 3058 | _ => return Ok(()), | 
|---|
| 3059 | }; | 
|---|
| 3060 | self.update_type_id(id, span)?; | 
|---|
| 3061 |  | 
|---|
| 3062 | // If `id` points to a `Resource` type then this means that what was | 
|---|
| 3063 | // just discovered was a reference to what will implicitly become an | 
|---|
| 3064 | // `own<T>` handle. This `own` handle is implicitly allocated here | 
|---|
| 3065 | // and handled during the merging process. | 
|---|
| 3066 | let mut cur = *id; | 
|---|
| 3067 | let points_to_resource = loop { | 
|---|
| 3068 | match resolve.types[cur].kind { | 
|---|
| 3069 | TypeDefKind::Type(Type::Id(id)) => cur = id, | 
|---|
| 3070 | TypeDefKind::Resource => break true, | 
|---|
| 3071 | _ => break false, | 
|---|
| 3072 | } | 
|---|
| 3073 | }; | 
|---|
| 3074 |  | 
|---|
| 3075 | if points_to_resource { | 
|---|
| 3076 | *id = *self.own_handles.entry(*id).or_insert_with(|| { | 
|---|
| 3077 | resolve.types.alloc(TypeDef { | 
|---|
| 3078 | name: None, | 
|---|
| 3079 | owner: TypeOwner::None, | 
|---|
| 3080 | kind: TypeDefKind::Handle(Handle::Own(*id)), | 
|---|
| 3081 | docs: Default::default(), | 
|---|
| 3082 | stability: Default::default(), | 
|---|
| 3083 | }) | 
|---|
| 3084 | }); | 
|---|
| 3085 | } | 
|---|
| 3086 | Ok(()) | 
|---|
| 3087 | } | 
|---|
| 3088 |  | 
|---|
| 3089 | fn update_type_id(&self, id: &mut TypeId, span: Option<Span>) -> Result<()> { | 
|---|
| 3090 | *id = self.map_type(*id, span)?; | 
|---|
| 3091 | Ok(()) | 
|---|
| 3092 | } | 
|---|
| 3093 |  | 
|---|
| 3094 | fn update_interface( | 
|---|
| 3095 | &mut self, | 
|---|
| 3096 | resolve: &mut Resolve, | 
|---|
| 3097 | iface: &mut Interface, | 
|---|
| 3098 | spans: Option<&InterfaceSpan>, | 
|---|
| 3099 | ) -> Result<()> { | 
|---|
| 3100 | iface.types.retain(|_, ty| self.types[ty.index()].is_some()); | 
|---|
| 3101 | let iface_pkg_id = iface.package.as_ref().unwrap_or_else(|| { | 
|---|
| 3102 | panic!( | 
|---|
| 3103 | "unexpectedly missing package on interface [{} ]", | 
|---|
| 3104 | iface | 
|---|
| 3105 | .name | 
|---|
| 3106 | .as_ref() | 
|---|
| 3107 | .map(String::as_str) | 
|---|
| 3108 | .unwrap_or( "<unknown>"), | 
|---|
| 3109 | ) | 
|---|
| 3110 | }); | 
|---|
| 3111 |  | 
|---|
| 3112 | // NB: note that `iface.doc` is not updated here since interfaces | 
|---|
| 3113 | // haven't been mapped yet and that's done in a separate step. | 
|---|
| 3114 | for (_name, ty) in iface.types.iter_mut() { | 
|---|
| 3115 | self.update_type_id(ty, spans.map(|s| s.span))?; | 
|---|
| 3116 | } | 
|---|
| 3117 | if let Some(spans) = spans { | 
|---|
| 3118 | assert_eq!(iface.functions.len(), spans.funcs.len()); | 
|---|
| 3119 | } | 
|---|
| 3120 | for (i, (func_name, func)) in iface.functions.iter_mut().enumerate() { | 
|---|
| 3121 | if !resolve | 
|---|
| 3122 | .include_stability(&func.stability, iface_pkg_id) | 
|---|
| 3123 | .with_context(|| { | 
|---|
| 3124 | format!( | 
|---|
| 3125 | "failed to process feature gate for function [{func_name} ] in package [{} ]", | 
|---|
| 3126 | resolve.packages[*iface_pkg_id].name, | 
|---|
| 3127 | ) | 
|---|
| 3128 | })? | 
|---|
| 3129 | { | 
|---|
| 3130 | continue; | 
|---|
| 3131 | } | 
|---|
| 3132 | let span = spans.map(|s| s.funcs[i]); | 
|---|
| 3133 | self.update_function(resolve, func, span) | 
|---|
| 3134 | .with_context(|| format!( "failed to update function `{} `", func.name))?; | 
|---|
| 3135 | } | 
|---|
| 3136 |  | 
|---|
| 3137 | // Filter out all of the existing functions in interface which fail the | 
|---|
| 3138 | // `include_stability()` check, as they shouldn't be available. | 
|---|
| 3139 | for (name, func) in mem::take(&mut iface.functions) { | 
|---|
| 3140 | if resolve.include_stability(&func.stability, iface_pkg_id)? { | 
|---|
| 3141 | iface.functions.insert(name, func); | 
|---|
| 3142 | } | 
|---|
| 3143 | } | 
|---|
| 3144 |  | 
|---|
| 3145 | Ok(()) | 
|---|
| 3146 | } | 
|---|
| 3147 |  | 
|---|
| 3148 | fn update_function( | 
|---|
| 3149 | &mut self, | 
|---|
| 3150 | resolve: &mut Resolve, | 
|---|
| 3151 | func: &mut Function, | 
|---|
| 3152 | span: Option<Span>, | 
|---|
| 3153 | ) -> Result<()> { | 
|---|
| 3154 | match &mut func.kind { | 
|---|
| 3155 | FunctionKind::Freestanding => {} | 
|---|
| 3156 | FunctionKind::Method(id) | FunctionKind::Constructor(id) | FunctionKind::Static(id) => { | 
|---|
| 3157 | self.update_type_id(id, span)?; | 
|---|
| 3158 | } | 
|---|
| 3159 | } | 
|---|
| 3160 | for (_, ty) in func.params.iter_mut() { | 
|---|
| 3161 | self.update_ty(resolve, ty, span)?; | 
|---|
| 3162 | } | 
|---|
| 3163 | match &mut func.results { | 
|---|
| 3164 | Results::Named(named) => { | 
|---|
| 3165 | for (_, ty) in named.iter_mut() { | 
|---|
| 3166 | self.update_ty(resolve, ty, span)?; | 
|---|
| 3167 | } | 
|---|
| 3168 | } | 
|---|
| 3169 | Results::Anon(ty) => self.update_ty(resolve, ty, span)?, | 
|---|
| 3170 | } | 
|---|
| 3171 |  | 
|---|
| 3172 | for ty in func.results.iter_types() { | 
|---|
| 3173 | if !self.type_has_borrow(resolve, ty) { | 
|---|
| 3174 | continue; | 
|---|
| 3175 | } | 
|---|
| 3176 | match span { | 
|---|
| 3177 | Some(span) => { | 
|---|
| 3178 | bail!(Error::new( | 
|---|
| 3179 | span, | 
|---|
| 3180 | format!( | 
|---|
| 3181 | "function returns a type which contains \ | 
|---|
| 3182 |                              a `borrow<T>` which is not supported" | 
|---|
| 3183 | ) | 
|---|
| 3184 | )) | 
|---|
| 3185 | } | 
|---|
| 3186 | None => unreachable!(), | 
|---|
| 3187 | } | 
|---|
| 3188 | } | 
|---|
| 3189 |  | 
|---|
| 3190 | Ok(()) | 
|---|
| 3191 | } | 
|---|
| 3192 |  | 
|---|
| 3193 | fn update_world( | 
|---|
| 3194 | &mut self, | 
|---|
| 3195 | world: &mut World, | 
|---|
| 3196 | resolve: &mut Resolve, | 
|---|
| 3197 | pkg_id: &PackageId, | 
|---|
| 3198 | spans: &WorldSpan, | 
|---|
| 3199 | ) -> Result<()> { | 
|---|
| 3200 | assert_eq!(world.imports.len(), spans.imports.len()); | 
|---|
| 3201 | assert_eq!(world.exports.len(), spans.exports.len()); | 
|---|
| 3202 |  | 
|---|
| 3203 | // Rewrite imports/exports with their updated versions. Note that this | 
|---|
| 3204 | // may involve updating the key of the imports/exports maps so this | 
|---|
| 3205 | // starts by emptying them out and then everything is re-inserted. | 
|---|
| 3206 | let imports = mem::take(&mut world.imports).into_iter(); | 
|---|
| 3207 | let imports = imports.zip(&spans.imports).map(|p| (p, true)); | 
|---|
| 3208 | let exports = mem::take(&mut world.exports).into_iter(); | 
|---|
| 3209 | let exports = exports.zip(&spans.exports).map(|p| (p, false)); | 
|---|
| 3210 | for (((mut name, mut item), span), import) in imports.chain(exports) { | 
|---|
| 3211 | // Update the `id` eagerly here so `item.stability(..)` below | 
|---|
| 3212 | // works. | 
|---|
| 3213 | if let WorldItem::Type(id) = &mut item { | 
|---|
| 3214 | *id = self.map_type(*id, Some(*span))?; | 
|---|
| 3215 | } | 
|---|
| 3216 | let stability = item.stability(resolve); | 
|---|
| 3217 | if !resolve | 
|---|
| 3218 | .include_stability(stability, pkg_id) | 
|---|
| 3219 | .with_context(|| { | 
|---|
| 3220 | format!( | 
|---|
| 3221 | "failed to process imported world item type [{} ] in package [{} ]", | 
|---|
| 3222 | resolve.name_world_key(&name), | 
|---|
| 3223 | resolve.packages[*pkg_id].name, | 
|---|
| 3224 | ) | 
|---|
| 3225 | })? | 
|---|
| 3226 | { | 
|---|
| 3227 | continue; | 
|---|
| 3228 | } | 
|---|
| 3229 | self.update_world_key(&mut name, Some(*span))?; | 
|---|
| 3230 | match &mut item { | 
|---|
| 3231 | WorldItem::Interface { id, .. } => { | 
|---|
| 3232 | *id = self.map_interface(*id, Some(*span))?; | 
|---|
| 3233 | } | 
|---|
| 3234 | WorldItem::Function(f) => { | 
|---|
| 3235 | self.update_function(resolve, f, Some(*span))?; | 
|---|
| 3236 | } | 
|---|
| 3237 | WorldItem::Type(_) => { | 
|---|
| 3238 | // already mapped above | 
|---|
| 3239 | } | 
|---|
| 3240 | } | 
|---|
| 3241 |  | 
|---|
| 3242 | let dst = if import { | 
|---|
| 3243 | &mut world.imports | 
|---|
| 3244 | } else { | 
|---|
| 3245 | &mut world.exports | 
|---|
| 3246 | }; | 
|---|
| 3247 | let prev = dst.insert(name, item); | 
|---|
| 3248 | assert!(prev.is_none()); | 
|---|
| 3249 | } | 
|---|
| 3250 |  | 
|---|
| 3251 | // Resolve all `include` statements of the world which will add more | 
|---|
| 3252 | // entries to the imports/exports list for this world. | 
|---|
| 3253 | assert_eq!(world.includes.len(), spans.includes.len()); | 
|---|
| 3254 | let includes = mem::take(&mut world.includes); | 
|---|
| 3255 | let include_names = mem::take(&mut world.include_names); | 
|---|
| 3256 | for (((stability, include_world), span), names) in includes | 
|---|
| 3257 | .into_iter() | 
|---|
| 3258 | .zip(&spans.includes) | 
|---|
| 3259 | .zip(&include_names) | 
|---|
| 3260 | { | 
|---|
| 3261 | if !resolve | 
|---|
| 3262 | .include_stability(&stability, pkg_id) | 
|---|
| 3263 | .with_context(|| { | 
|---|
| 3264 | format!( | 
|---|
| 3265 | "failed to process feature gate for included world [{} ] in package [{} ]", | 
|---|
| 3266 | resolve.worlds[include_world].name.as_str(), | 
|---|
| 3267 | resolve.packages[*pkg_id].name | 
|---|
| 3268 | ) | 
|---|
| 3269 | })? | 
|---|
| 3270 | { | 
|---|
| 3271 | continue; | 
|---|
| 3272 | } | 
|---|
| 3273 | self.resolve_include(world, include_world, names, *span, resolve)?; | 
|---|
| 3274 | } | 
|---|
| 3275 |  | 
|---|
| 3276 | Ok(()) | 
|---|
| 3277 | } | 
|---|
| 3278 |  | 
|---|
| 3279 | fn update_world_key(&self, key: &mut WorldKey, span: Option<Span>) -> Result<()> { | 
|---|
| 3280 | match key { | 
|---|
| 3281 | WorldKey::Name(_) => {} | 
|---|
| 3282 | WorldKey::Interface(id) => { | 
|---|
| 3283 | *id = self.map_interface(*id, span)?; | 
|---|
| 3284 | } | 
|---|
| 3285 | } | 
|---|
| 3286 | Ok(()) | 
|---|
| 3287 | } | 
|---|
| 3288 |  | 
|---|
| 3289 | fn resolve_include( | 
|---|
| 3290 | &self, | 
|---|
| 3291 | world: &mut World, | 
|---|
| 3292 | include_world: WorldId, | 
|---|
| 3293 | names: &[IncludeName], | 
|---|
| 3294 | span: Span, | 
|---|
| 3295 | resolve: &Resolve, | 
|---|
| 3296 | ) -> Result<()> { | 
|---|
| 3297 | let include_world_id = self.map_world(include_world, Some(span))?; | 
|---|
| 3298 | let include_world = &resolve.worlds[include_world_id]; | 
|---|
| 3299 | let mut names_ = names.to_owned(); | 
|---|
| 3300 |  | 
|---|
| 3301 | // remove all imports and exports that match the names we're including | 
|---|
| 3302 | for import in include_world.imports.iter() { | 
|---|
| 3303 | self.remove_matching_name(import, &mut names_); | 
|---|
| 3304 | } | 
|---|
| 3305 | for export in include_world.exports.iter() { | 
|---|
| 3306 | self.remove_matching_name(export, &mut names_); | 
|---|
| 3307 | } | 
|---|
| 3308 | if !names_.is_empty() { | 
|---|
| 3309 | bail!(Error::new( | 
|---|
| 3310 | span, | 
|---|
| 3311 | format!( "no import or export kebab-name `{} `. Note that an ID does not support renaming", names_[0].name), | 
|---|
| 3312 | )); | 
|---|
| 3313 | } | 
|---|
| 3314 |  | 
|---|
| 3315 | // copy the imports and exports from the included world into the current world | 
|---|
| 3316 | for import in include_world.imports.iter() { | 
|---|
| 3317 | self.resolve_include_item(names, &mut world.imports, import, span, "import")?; | 
|---|
| 3318 | } | 
|---|
| 3319 |  | 
|---|
| 3320 | for export in include_world.exports.iter() { | 
|---|
| 3321 | self.resolve_include_item(names, &mut world.exports, export, span, "export")?; | 
|---|
| 3322 | } | 
|---|
| 3323 | Ok(()) | 
|---|
| 3324 | } | 
|---|
| 3325 |  | 
|---|
| 3326 | fn resolve_include_item( | 
|---|
| 3327 | &self, | 
|---|
| 3328 | names: &[IncludeName], | 
|---|
| 3329 | items: &mut IndexMap<WorldKey, WorldItem>, | 
|---|
| 3330 | item: (&WorldKey, &WorldItem), | 
|---|
| 3331 | span: Span, | 
|---|
| 3332 | item_type: &str, | 
|---|
| 3333 | ) -> Result<()> { | 
|---|
| 3334 | match item.0 { | 
|---|
| 3335 | WorldKey::Name(n) => { | 
|---|
| 3336 | let n = if let Some(found) = names | 
|---|
| 3337 | .into_iter() | 
|---|
| 3338 | .find(|include_name| include_name.name == n.clone()) | 
|---|
| 3339 | { | 
|---|
| 3340 | found.as_.clone() | 
|---|
| 3341 | } else { | 
|---|
| 3342 | n.clone() | 
|---|
| 3343 | }; | 
|---|
| 3344 |  | 
|---|
| 3345 | let prev = items.insert(WorldKey::Name(n.clone()), item.1.clone()); | 
|---|
| 3346 | if prev.is_some() { | 
|---|
| 3347 | bail!(Error::new( | 
|---|
| 3348 | span, | 
|---|
| 3349 | format!( "{item_type}  of `{n} ` shadows previously {item_type} ed items"), | 
|---|
| 3350 | )) | 
|---|
| 3351 | } | 
|---|
| 3352 | } | 
|---|
| 3353 | key @ WorldKey::Interface(_) => { | 
|---|
| 3354 | let prev = items.entry(key.clone()).or_insert(item.1.clone()); | 
|---|
| 3355 | match (&item.1, prev) { | 
|---|
| 3356 | ( | 
|---|
| 3357 | WorldItem::Interface { | 
|---|
| 3358 | id: aid, | 
|---|
| 3359 | stability: astability, | 
|---|
| 3360 | }, | 
|---|
| 3361 | WorldItem::Interface { | 
|---|
| 3362 | id: bid, | 
|---|
| 3363 | stability: bstability, | 
|---|
| 3364 | }, | 
|---|
| 3365 | ) => { | 
|---|
| 3366 | assert_eq!(*aid, *bid); | 
|---|
| 3367 | update_stability(astability, bstability)?; | 
|---|
| 3368 | } | 
|---|
| 3369 | (WorldItem::Interface { .. }, _) => unreachable!(), | 
|---|
| 3370 | (WorldItem::Function(_), _) => unreachable!(), | 
|---|
| 3371 | (WorldItem::Type(_), _) => unreachable!(), | 
|---|
| 3372 | } | 
|---|
| 3373 | } | 
|---|
| 3374 | }; | 
|---|
| 3375 | Ok(()) | 
|---|
| 3376 | } | 
|---|
| 3377 |  | 
|---|
| 3378 | fn remove_matching_name(&self, item: (&WorldKey, &WorldItem), names: &mut Vec<IncludeName>) { | 
|---|
| 3379 | match item.0 { | 
|---|
| 3380 | WorldKey::Name(n) => { | 
|---|
| 3381 | names.retain(|name| name.name != n.clone()); | 
|---|
| 3382 | } | 
|---|
| 3383 | _ => {} | 
|---|
| 3384 | } | 
|---|
| 3385 | } | 
|---|
| 3386 |  | 
|---|
| 3387 | fn type_has_borrow(&mut self, resolve: &Resolve, ty: &Type) -> bool { | 
|---|
| 3388 | let id = match ty { | 
|---|
| 3389 | Type::Id(id) => *id, | 
|---|
| 3390 | _ => return false, | 
|---|
| 3391 | }; | 
|---|
| 3392 |  | 
|---|
| 3393 | if let Some(Some(has_borrow)) = self.type_has_borrow.get(id.index()) { | 
|---|
| 3394 | return *has_borrow; | 
|---|
| 3395 | } | 
|---|
| 3396 |  | 
|---|
| 3397 | let result = self.typedef_has_borrow(resolve, &resolve.types[id]); | 
|---|
| 3398 | if self.type_has_borrow.len() <= id.index() { | 
|---|
| 3399 | self.type_has_borrow.resize(id.index() + 1, None); | 
|---|
| 3400 | } | 
|---|
| 3401 | self.type_has_borrow[id.index()] = Some(result); | 
|---|
| 3402 | result | 
|---|
| 3403 | } | 
|---|
| 3404 |  | 
|---|
| 3405 | fn typedef_has_borrow(&mut self, resolve: &Resolve, ty: &TypeDef) -> bool { | 
|---|
| 3406 | match &ty.kind { | 
|---|
| 3407 | TypeDefKind::Type(t) => self.type_has_borrow(resolve, t), | 
|---|
| 3408 | TypeDefKind::Variant(v) => v | 
|---|
| 3409 | .cases | 
|---|
| 3410 | .iter() | 
|---|
| 3411 | .filter_map(|case| case.ty.as_ref()) | 
|---|
| 3412 | .any(|ty| self.type_has_borrow(resolve, ty)), | 
|---|
| 3413 | TypeDefKind::Handle(Handle::Borrow(_)) => true, | 
|---|
| 3414 | TypeDefKind::Handle(Handle::Own(_)) => false, | 
|---|
| 3415 | TypeDefKind::Resource => false, | 
|---|
| 3416 | TypeDefKind::Record(r) => r | 
|---|
| 3417 | .fields | 
|---|
| 3418 | .iter() | 
|---|
| 3419 | .any(|case| self.type_has_borrow(resolve, &case.ty)), | 
|---|
| 3420 | TypeDefKind::Flags(_) => false, | 
|---|
| 3421 | TypeDefKind::Tuple(t) => t.types.iter().any(|t| self.type_has_borrow(resolve, t)), | 
|---|
| 3422 | TypeDefKind::Enum(_) => false, | 
|---|
| 3423 | TypeDefKind::List(ty) | 
|---|
| 3424 | | TypeDefKind::Future(Some(ty)) | 
|---|
| 3425 | | TypeDefKind::Stream(ty) | 
|---|
| 3426 | | TypeDefKind::Option(ty) => self.type_has_borrow(resolve, ty), | 
|---|
| 3427 | TypeDefKind::Result(r) => [&r.ok, &r.err] | 
|---|
| 3428 | .iter() | 
|---|
| 3429 | .filter_map(|t| t.as_ref()) | 
|---|
| 3430 | .any(|t| self.type_has_borrow(resolve, t)), | 
|---|
| 3431 | TypeDefKind::Future(None) | TypeDefKind::ErrorContext => false, | 
|---|
| 3432 | TypeDefKind::Unknown => unreachable!(), | 
|---|
| 3433 | } | 
|---|
| 3434 | } | 
|---|
| 3435 | } | 
|---|
| 3436 |  | 
|---|
| 3437 | struct MergeMap<'a> { | 
|---|
| 3438 | /// A map of package ids in `from` to those in `into` for those that are | 
|---|
| 3439 | /// found to be equivalent. | 
|---|
| 3440 | package_map: HashMap<PackageId, PackageId>, | 
|---|
| 3441 |  | 
|---|
| 3442 | /// A map of interface ids in `from` to those in `into` for those that are | 
|---|
| 3443 | /// found to be equivalent. | 
|---|
| 3444 | interface_map: HashMap<InterfaceId, InterfaceId>, | 
|---|
| 3445 |  | 
|---|
| 3446 | /// A map of type ids in `from` to those in `into` for those that are | 
|---|
| 3447 | /// found to be equivalent. | 
|---|
| 3448 | type_map: HashMap<TypeId, TypeId>, | 
|---|
| 3449 |  | 
|---|
| 3450 | /// A map of world ids in `from` to those in `into` for those that are | 
|---|
| 3451 | /// found to be equivalent. | 
|---|
| 3452 | world_map: HashMap<WorldId, WorldId>, | 
|---|
| 3453 |  | 
|---|
| 3454 | /// A list of documents that need to be added to packages in `into`. | 
|---|
| 3455 | /// | 
|---|
| 3456 | /// The elements here are: | 
|---|
| 3457 | /// | 
|---|
| 3458 | /// * The name of the interface/world | 
|---|
| 3459 | /// * The ID within `into` of the package being added to | 
|---|
| 3460 | /// * The ID within `from` of the item being added. | 
|---|
| 3461 | interfaces_to_add: Vec<(String, PackageId, InterfaceId)>, | 
|---|
| 3462 | worlds_to_add: Vec<(String, PackageId, WorldId)>, | 
|---|
| 3463 |  | 
|---|
| 3464 | /// Which `Resolve` is being merged from. | 
|---|
| 3465 | from: &'a Resolve, | 
|---|
| 3466 |  | 
|---|
| 3467 | /// Which `Resolve` is being merged into. | 
|---|
| 3468 | into: &'a Resolve, | 
|---|
| 3469 | } | 
|---|
| 3470 |  | 
|---|
| 3471 | impl<'a> MergeMap<'a> { | 
|---|
| 3472 | fn new(from: &'a Resolve, into: &'a Resolve) -> MergeMap<'a> { | 
|---|
| 3473 | MergeMap { | 
|---|
| 3474 | package_map: Default::default(), | 
|---|
| 3475 | interface_map: Default::default(), | 
|---|
| 3476 | type_map: Default::default(), | 
|---|
| 3477 | world_map: Default::default(), | 
|---|
| 3478 | interfaces_to_add: Default::default(), | 
|---|
| 3479 | worlds_to_add: Default::default(), | 
|---|
| 3480 | from, | 
|---|
| 3481 | into, | 
|---|
| 3482 | } | 
|---|
| 3483 | } | 
|---|
| 3484 |  | 
|---|
| 3485 | fn build(&mut self) -> Result<()> { | 
|---|
| 3486 | for from_id in self.from.topological_packages() { | 
|---|
| 3487 | let from = &self.from.packages[from_id]; | 
|---|
| 3488 | let into_id = match self.into.package_names.get(&from.name) { | 
|---|
| 3489 | Some(id) => *id, | 
|---|
| 3490 |  | 
|---|
| 3491 | // This package, according to its name and url, is not present | 
|---|
| 3492 | // in `self` so it needs to get added below. | 
|---|
| 3493 | None => { | 
|---|
| 3494 | log::trace!( "adding unique package {} ", from.name); | 
|---|
| 3495 | continue; | 
|---|
| 3496 | } | 
|---|
| 3497 | }; | 
|---|
| 3498 | log::trace!( "merging duplicate package {} ", from.name); | 
|---|
| 3499 |  | 
|---|
| 3500 | self.build_package(from_id, into_id).with_context(|| { | 
|---|
| 3501 | format!( "failed to merge package `{} ` into existing copy", from.name) | 
|---|
| 3502 | })?; | 
|---|
| 3503 | } | 
|---|
| 3504 |  | 
|---|
| 3505 | Ok(()) | 
|---|
| 3506 | } | 
|---|
| 3507 |  | 
|---|
| 3508 | fn build_package(&mut self, from_id: PackageId, into_id: PackageId) -> Result<()> { | 
|---|
| 3509 | let prev = self.package_map.insert(from_id, into_id); | 
|---|
| 3510 | assert!(prev.is_none()); | 
|---|
| 3511 |  | 
|---|
| 3512 | let from = &self.from.packages[from_id]; | 
|---|
| 3513 | let into = &self.into.packages[into_id]; | 
|---|
| 3514 |  | 
|---|
| 3515 | // If an interface is present in `from_id` but not present in `into_id` | 
|---|
| 3516 | // then it can be copied over wholesale. That copy is scheduled to | 
|---|
| 3517 | // happen within the `self.interfaces_to_add` list. | 
|---|
| 3518 | for (name, from_interface_id) in from.interfaces.iter() { | 
|---|
| 3519 | let into_interface_id = match into.interfaces.get(name) { | 
|---|
| 3520 | Some(id) => *id, | 
|---|
| 3521 | None => { | 
|---|
| 3522 | log::trace!( "adding unique interface {} ", name); | 
|---|
| 3523 | self.interfaces_to_add | 
|---|
| 3524 | .push((name.clone(), into_id, *from_interface_id)); | 
|---|
| 3525 | continue; | 
|---|
| 3526 | } | 
|---|
| 3527 | }; | 
|---|
| 3528 |  | 
|---|
| 3529 | log::trace!( "merging duplicate interfaces {} ", name); | 
|---|
| 3530 | self.build_interface(*from_interface_id, into_interface_id) | 
|---|
| 3531 | .with_context(|| format!( "failed to merge interface `{name} `"))?; | 
|---|
| 3532 | } | 
|---|
| 3533 |  | 
|---|
| 3534 | for (name, from_world_id) in from.worlds.iter() { | 
|---|
| 3535 | let into_world_id = match into.worlds.get(name) { | 
|---|
| 3536 | Some(id) => *id, | 
|---|
| 3537 | None => { | 
|---|
| 3538 | log::trace!( "adding unique world {} ", name); | 
|---|
| 3539 | self.worlds_to_add | 
|---|
| 3540 | .push((name.clone(), into_id, *from_world_id)); | 
|---|
| 3541 | continue; | 
|---|
| 3542 | } | 
|---|
| 3543 | }; | 
|---|
| 3544 |  | 
|---|
| 3545 | log::trace!( "merging duplicate worlds {} ", name); | 
|---|
| 3546 | self.build_world(*from_world_id, into_world_id) | 
|---|
| 3547 | .with_context(|| format!( "failed to merge world `{name} `"))?; | 
|---|
| 3548 | } | 
|---|
| 3549 |  | 
|---|
| 3550 | Ok(()) | 
|---|
| 3551 | } | 
|---|
| 3552 |  | 
|---|
| 3553 | fn build_interface(&mut self, from_id: InterfaceId, into_id: InterfaceId) -> Result<()> { | 
|---|
| 3554 | let prev = self.interface_map.insert(from_id, into_id); | 
|---|
| 3555 | assert!(prev.is_none()); | 
|---|
| 3556 |  | 
|---|
| 3557 | let from_interface = &self.from.interfaces[from_id]; | 
|---|
| 3558 | let into_interface = &self.into.interfaces[into_id]; | 
|---|
| 3559 |  | 
|---|
| 3560 | // Unlike documents/interfaces above if an interface in `from` | 
|---|
| 3561 | // differs from the interface in `into` then that's considered an | 
|---|
| 3562 | // error. Changing interfaces can reflect changes in imports/exports | 
|---|
| 3563 | // which may not be expected so it's currently required that all | 
|---|
| 3564 | // interfaces, when merged, exactly match. | 
|---|
| 3565 | // | 
|---|
| 3566 | // One case to consider here, for example, is that if a world in | 
|---|
| 3567 | // `into` exports the interface `into_id` then if `from_id` were to | 
|---|
| 3568 | // add more items into `into` then it would unexpectedly require more | 
|---|
| 3569 | // items to be exported which may not work. In an import context this | 
|---|
| 3570 | // might work since it's "just more items available for import", but | 
|---|
| 3571 | // for now a conservative route of "interfaces must match" is taken. | 
|---|
| 3572 |  | 
|---|
| 3573 | for (name, from_type_id) in from_interface.types.iter() { | 
|---|
| 3574 | let into_type_id = *into_interface | 
|---|
| 3575 | .types | 
|---|
| 3576 | .get(name) | 
|---|
| 3577 | .ok_or_else(|| anyhow!( "expected type `{name} ` to be present"))?; | 
|---|
| 3578 | let prev = self.type_map.insert(*from_type_id, into_type_id); | 
|---|
| 3579 | assert!(prev.is_none()); | 
|---|
| 3580 |  | 
|---|
| 3581 | self.build_type_id(*from_type_id, into_type_id) | 
|---|
| 3582 | .with_context(|| format!( "mismatch in type `{name} `"))?; | 
|---|
| 3583 | } | 
|---|
| 3584 |  | 
|---|
| 3585 | for (name, from_func) in from_interface.functions.iter() { | 
|---|
| 3586 | let into_func = match into_interface.functions.get(name) { | 
|---|
| 3587 | Some(func) => func, | 
|---|
| 3588 | None => bail!( "expected function `{name} ` to be present"), | 
|---|
| 3589 | }; | 
|---|
| 3590 | self.build_function(from_func, into_func) | 
|---|
| 3591 | .with_context(|| format!( "mismatch in function `{name} `"))?; | 
|---|
| 3592 | } | 
|---|
| 3593 |  | 
|---|
| 3594 | Ok(()) | 
|---|
| 3595 | } | 
|---|
| 3596 |  | 
|---|
| 3597 | fn build_type_id(&mut self, from_id: TypeId, into_id: TypeId) -> Result<()> { | 
|---|
| 3598 | // FIXME: ideally the types should be "structurally | 
|---|
| 3599 | // equal" but that's not trivial to do in the face of | 
|---|
| 3600 | // resources. | 
|---|
| 3601 | let _ = from_id; | 
|---|
| 3602 | let _ = into_id; | 
|---|
| 3603 | Ok(()) | 
|---|
| 3604 | } | 
|---|
| 3605 |  | 
|---|
| 3606 | fn build_type(&mut self, from_ty: &Type, into_ty: &Type) -> Result<()> { | 
|---|
| 3607 | match (from_ty, into_ty) { | 
|---|
| 3608 | (Type::Id(from), Type::Id(into)) => { | 
|---|
| 3609 | self.build_type_id(*from, *into)?; | 
|---|
| 3610 | } | 
|---|
| 3611 | (from, into) if from != into => bail!( "different kinds of types"), | 
|---|
| 3612 | _ => {} | 
|---|
| 3613 | } | 
|---|
| 3614 | Ok(()) | 
|---|
| 3615 | } | 
|---|
| 3616 |  | 
|---|
| 3617 | fn build_function(&mut self, from_func: &Function, into_func: &Function) -> Result<()> { | 
|---|
| 3618 | if from_func.name != into_func.name { | 
|---|
| 3619 | bail!( | 
|---|
| 3620 | "different function names `{} ` and `{} `", | 
|---|
| 3621 | from_func.name, | 
|---|
| 3622 | into_func.name | 
|---|
| 3623 | ); | 
|---|
| 3624 | } | 
|---|
| 3625 | match (&from_func.kind, &into_func.kind) { | 
|---|
| 3626 | (FunctionKind::Freestanding, FunctionKind::Freestanding) => {} | 
|---|
| 3627 |  | 
|---|
| 3628 | (FunctionKind::Method(from), FunctionKind::Method(into)) | 
|---|
| 3629 | | (FunctionKind::Constructor(from), FunctionKind::Constructor(into)) | 
|---|
| 3630 | | (FunctionKind::Static(from), FunctionKind::Static(into)) => self | 
|---|
| 3631 | .build_type_id(*from, *into) | 
|---|
| 3632 | .context( "different function kind types")?, | 
|---|
| 3633 |  | 
|---|
| 3634 | (FunctionKind::Method(_), _) | 
|---|
| 3635 | | (FunctionKind::Constructor(_), _) | 
|---|
| 3636 | | (FunctionKind::Static(_), _) | 
|---|
| 3637 | | (FunctionKind::Freestanding, _) => { | 
|---|
| 3638 | bail!( "different function kind types") | 
|---|
| 3639 | } | 
|---|
| 3640 | } | 
|---|
| 3641 |  | 
|---|
| 3642 | if from_func.params.len() != into_func.params.len() { | 
|---|
| 3643 | bail!( "different number of function parameters"); | 
|---|
| 3644 | } | 
|---|
| 3645 | for ((from_name, from_ty), (into_name, into_ty)) in | 
|---|
| 3646 | from_func.params.iter().zip(&into_func.params) | 
|---|
| 3647 | { | 
|---|
| 3648 | if from_name != into_name { | 
|---|
| 3649 | bail!( "different function parameter names: {from_name}  != {into_name} "); | 
|---|
| 3650 | } | 
|---|
| 3651 | self.build_type(from_ty, into_ty) | 
|---|
| 3652 | .with_context(|| format!( "different function parameter types for `{from_name} `"))?; | 
|---|
| 3653 | } | 
|---|
| 3654 | if from_func.results.len() != into_func.results.len() { | 
|---|
| 3655 | bail!( "different number of function results"); | 
|---|
| 3656 | } | 
|---|
| 3657 | for (from_ty, into_ty) in from_func | 
|---|
| 3658 | .results | 
|---|
| 3659 | .iter_types() | 
|---|
| 3660 | .zip(into_func.results.iter_types()) | 
|---|
| 3661 | { | 
|---|
| 3662 | self.build_type(from_ty, into_ty) | 
|---|
| 3663 | .context( "different function result types")?; | 
|---|
| 3664 | } | 
|---|
| 3665 | Ok(()) | 
|---|
| 3666 | } | 
|---|
| 3667 |  | 
|---|
| 3668 | fn build_world(&mut self, from_id: WorldId, into_id: WorldId) -> Result<()> { | 
|---|
| 3669 | let prev = self.world_map.insert(from_id, into_id); | 
|---|
| 3670 | assert!(prev.is_none()); | 
|---|
| 3671 |  | 
|---|
| 3672 | let from_world = &self.from.worlds[from_id]; | 
|---|
| 3673 | let into_world = &self.into.worlds[into_id]; | 
|---|
| 3674 |  | 
|---|
| 3675 | // Same as interfaces worlds are expected to exactly match to avoid | 
|---|
| 3676 | // unexpectedly changing a particular component's view of imports and | 
|---|
| 3677 | // exports. | 
|---|
| 3678 | // | 
|---|
| 3679 | // FIXME: this should probably share functionality with | 
|---|
| 3680 | // `Resolve::merge_worlds` to support adding imports but not changing | 
|---|
| 3681 | // exports. | 
|---|
| 3682 |  | 
|---|
| 3683 | if from_world.imports.len() != into_world.imports.len() { | 
|---|
| 3684 | bail!( "world contains different number of imports than expected"); | 
|---|
| 3685 | } | 
|---|
| 3686 | if from_world.exports.len() != into_world.exports.len() { | 
|---|
| 3687 | bail!( "world contains different number of exports than expected"); | 
|---|
| 3688 | } | 
|---|
| 3689 |  | 
|---|
| 3690 | for (from_name, from) in from_world.imports.iter() { | 
|---|
| 3691 | let into_name = self.map_name(from_name); | 
|---|
| 3692 | let name_str = self.from.name_world_key(from_name); | 
|---|
| 3693 | let into = into_world | 
|---|
| 3694 | .imports | 
|---|
| 3695 | .get(&into_name) | 
|---|
| 3696 | .ok_or_else(|| anyhow!( "import `{name_str} ` not found in target world"))?; | 
|---|
| 3697 | self.match_world_item(from, into) | 
|---|
| 3698 | .with_context(|| format!( "import `{name_str} ` didn't match target world"))?; | 
|---|
| 3699 | } | 
|---|
| 3700 |  | 
|---|
| 3701 | for (from_name, from) in from_world.exports.iter() { | 
|---|
| 3702 | let into_name = self.map_name(from_name); | 
|---|
| 3703 | let name_str = self.from.name_world_key(from_name); | 
|---|
| 3704 | let into = into_world | 
|---|
| 3705 | .exports | 
|---|
| 3706 | .get(&into_name) | 
|---|
| 3707 | .ok_or_else(|| anyhow!( "export `{name_str} ` not found in target world"))?; | 
|---|
| 3708 | self.match_world_item(from, into) | 
|---|
| 3709 | .with_context(|| format!( "export `{name_str} ` didn't match target world"))?; | 
|---|
| 3710 | } | 
|---|
| 3711 |  | 
|---|
| 3712 | Ok(()) | 
|---|
| 3713 | } | 
|---|
| 3714 |  | 
|---|
| 3715 | fn map_name(&self, from_name: &WorldKey) -> WorldKey { | 
|---|
| 3716 | match from_name { | 
|---|
| 3717 | WorldKey::Name(s) => WorldKey::Name(s.clone()), | 
|---|
| 3718 | WorldKey::Interface(id) => { | 
|---|
| 3719 | WorldKey::Interface(self.interface_map.get(id).copied().unwrap_or(*id)) | 
|---|
| 3720 | } | 
|---|
| 3721 | } | 
|---|
| 3722 | } | 
|---|
| 3723 |  | 
|---|
| 3724 | fn match_world_item(&mut self, from: &WorldItem, into: &WorldItem) -> Result<()> { | 
|---|
| 3725 | match (from, into) { | 
|---|
| 3726 | (WorldItem::Interface { id: from, .. }, WorldItem::Interface { id: into, .. }) => { | 
|---|
| 3727 | match ( | 
|---|
| 3728 | &self.from.interfaces[*from].name, | 
|---|
| 3729 | &self.into.interfaces[*into].name, | 
|---|
| 3730 | ) { | 
|---|
| 3731 | // If one interface is unnamed then they must both be | 
|---|
| 3732 | // unnamed and they must both have the same structure for | 
|---|
| 3733 | // now. | 
|---|
| 3734 | (None, None) => self.build_interface(*from, *into)?, | 
|---|
| 3735 |  | 
|---|
| 3736 | // Otherwise both interfaces must be named and they must | 
|---|
| 3737 | // have been previously found to be equivalent. Note that | 
|---|
| 3738 | // if either is unnamed it won't be present in | 
|---|
| 3739 | // `interface_map` so this'll return an error. | 
|---|
| 3740 | _ => { | 
|---|
| 3741 | if self.interface_map.get(&from) != Some(&into) { | 
|---|
| 3742 | bail!( "interfaces are not the same"); | 
|---|
| 3743 | } | 
|---|
| 3744 | } | 
|---|
| 3745 | } | 
|---|
| 3746 | } | 
|---|
| 3747 | (WorldItem::Function(from), WorldItem::Function(into)) => { | 
|---|
| 3748 | let _ = (from, into); | 
|---|
| 3749 | // FIXME: should assert an check that `from` structurally | 
|---|
| 3750 | // matches `into` | 
|---|
| 3751 | } | 
|---|
| 3752 | (WorldItem::Type(from), WorldItem::Type(into)) => { | 
|---|
| 3753 | // FIXME: should assert an check that `from` structurally | 
|---|
| 3754 | // matches `into` | 
|---|
| 3755 | let prev = self.type_map.insert(*from, *into); | 
|---|
| 3756 | assert!(prev.is_none()); | 
|---|
| 3757 | } | 
|---|
| 3758 |  | 
|---|
| 3759 | (WorldItem::Interface { .. }, _) | 
|---|
| 3760 | | (WorldItem::Function(_), _) | 
|---|
| 3761 | | (WorldItem::Type(_), _) => { | 
|---|
| 3762 | bail!( "world items do not have the same type") | 
|---|
| 3763 | } | 
|---|
| 3764 | } | 
|---|
| 3765 | Ok(()) | 
|---|
| 3766 | } | 
|---|
| 3767 | } | 
|---|
| 3768 |  | 
|---|
| 3769 | /// Updates stability annotations when merging `from` into `into`. | 
|---|
| 3770 | /// | 
|---|
| 3771 | /// This is done to keep up-to-date stability information if possible. | 
|---|
| 3772 | /// Components for example don't carry stability information but WIT does so | 
|---|
| 3773 | /// this tries to move from "unknown" to stable/unstable if possible. | 
|---|
| 3774 | fn update_stability(from: &Stability, into: &mut Stability) -> Result<()> { | 
|---|
| 3775 | // If `from` is unknown or the two stability annotations are equal then | 
|---|
| 3776 | // there's nothing to do here. | 
|---|
| 3777 | if from == into || from.is_unknown() { | 
|---|
| 3778 | return Ok(()); | 
|---|
| 3779 | } | 
|---|
| 3780 | // Otherwise if `into` is unknown then inherit the stability listed in | 
|---|
| 3781 | // `from`. | 
|---|
| 3782 | if into.is_unknown() { | 
|---|
| 3783 | *into = from.clone(); | 
|---|
| 3784 | return Ok(()); | 
|---|
| 3785 | } | 
|---|
| 3786 |  | 
|---|
| 3787 | // Failing all that this means that the two attributes are different so | 
|---|
| 3788 | // generate an error. | 
|---|
| 3789 | bail!( "mismatch in stability attributes") | 
|---|
| 3790 | } | 
|---|
| 3791 |  | 
|---|
| 3792 | /// An error that can be returned during "world elaboration" during various | 
|---|
| 3793 | /// [`Resolve`] operations. | 
|---|
| 3794 | /// | 
|---|
| 3795 | /// Methods on [`Resolve`] which mutate its internals, such as | 
|---|
| 3796 | /// [`Resolve::push_dir`] or [`Resolve::importize`] can fail if `world` imports | 
|---|
| 3797 | /// in WIT packages are invalid. This error indicates one of these situations | 
|---|
| 3798 | /// where an invalid dependency graph between imports and exports are detected. | 
|---|
| 3799 | /// | 
|---|
| 3800 | /// Note that at this time this error is subtle and not easy to understand, and | 
|---|
| 3801 | /// work needs to be done to explain this better and additionally provide a | 
|---|
| 3802 | /// better error message. For now though this type enables callers to test for | 
|---|
| 3803 | /// the exact kind of error emitted. | 
|---|
| 3804 | #[ derive(Debug, Clone)] | 
|---|
| 3805 | pub struct InvalidTransitiveDependency(String); | 
|---|
| 3806 |  | 
|---|
| 3807 | impl fmt::Display for InvalidTransitiveDependency { | 
|---|
| 3808 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 
|---|
| 3809 | write!( | 
|---|
| 3810 | f, | 
|---|
| 3811 | "interface `{} ` transitively depends on an interface in \ | 
|---|
| 3812 |              incompatible ways", | 
|---|
| 3813 | self.0 | 
|---|
| 3814 | ) | 
|---|
| 3815 | } | 
|---|
| 3816 | } | 
|---|
| 3817 |  | 
|---|
| 3818 | impl std::error::Error for InvalidTransitiveDependency {} | 
|---|
| 3819 |  | 
|---|
| 3820 | #[ cfg(test)] | 
|---|
| 3821 | mod tests { | 
|---|
| 3822 | use crate::Resolve; | 
|---|
| 3823 | use anyhow::Result; | 
|---|
| 3824 |  | 
|---|
| 3825 | #[ test] | 
|---|
| 3826 | fn select_world() -> Result<()> { | 
|---|
| 3827 | let mut resolve = Resolve::default(); | 
|---|
| 3828 | resolve.push_str( | 
|---|
| 3829 | "test.wit", | 
|---|
| 3830 | r#" | 
|---|
| 3831 |                 package foo:bar@0.1.0; | 
|---|
| 3832 |  | 
|---|
| 3833 |                 world foo {} | 
|---|
| 3834 |             "#, | 
|---|
| 3835 | )?; | 
|---|
| 3836 | resolve.push_str( | 
|---|
| 3837 | "test.wit", | 
|---|
| 3838 | r#" | 
|---|
| 3839 |                 package foo:baz@0.1.0; | 
|---|
| 3840 |  | 
|---|
| 3841 |                 world foo {} | 
|---|
| 3842 |             "#, | 
|---|
| 3843 | )?; | 
|---|
| 3844 | resolve.push_str( | 
|---|
| 3845 | "test.wit", | 
|---|
| 3846 | r#" | 
|---|
| 3847 |                 package foo:baz@0.2.0; | 
|---|
| 3848 |  | 
|---|
| 3849 |                 world foo {} | 
|---|
| 3850 |             "#, | 
|---|
| 3851 | )?; | 
|---|
| 3852 |  | 
|---|
| 3853 | let dummy = resolve.push_str( | 
|---|
| 3854 | "test.wit", | 
|---|
| 3855 | r#" | 
|---|
| 3856 |                 package foo:dummy; | 
|---|
| 3857 |  | 
|---|
| 3858 |                 world foo {} | 
|---|
| 3859 |             "#, | 
|---|
| 3860 | )?; | 
|---|
| 3861 |  | 
|---|
| 3862 | assert!(resolve.select_world(dummy, None).is_ok()); | 
|---|
| 3863 | assert!(resolve.select_world(dummy, Some( "xx")).is_err()); | 
|---|
| 3864 | assert!(resolve.select_world(dummy, Some( "")).is_err()); | 
|---|
| 3865 | assert!(resolve.select_world(dummy, Some( "foo:bar/foo")).is_ok()); | 
|---|
| 3866 | assert!(resolve | 
|---|
| 3867 | .select_world(dummy, Some( "foo:bar/foo@0.1.0")) | 
|---|
| 3868 | .is_ok()); | 
|---|
| 3869 | assert!(resolve.select_world(dummy, Some( "foo:baz/foo")).is_err()); | 
|---|
| 3870 | assert!(resolve | 
|---|
| 3871 | .select_world(dummy, Some( "foo:baz/foo@0.1.0")) | 
|---|
| 3872 | .is_ok()); | 
|---|
| 3873 | assert!(resolve | 
|---|
| 3874 | .select_world(dummy, Some( "foo:baz/foo@0.2.0")) | 
|---|
| 3875 | .is_ok()); | 
|---|
| 3876 | Ok(()) | 
|---|
| 3877 | } | 
|---|
| 3878 | } | 
|---|
| 3879 |  | 
|---|