/src/wasm-tools/crates/wit-parser/src/ast/resolve.rs
Line | Count | Source |
1 | | use super::{ParamList, WorldOrInterface}; |
2 | | use crate::ast::toposort::toposort; |
3 | | use crate::*; |
4 | | use anyhow::bail; |
5 | | use std::collections::{HashMap, HashSet}; |
6 | | use std::mem; |
7 | | |
8 | | #[derive(Default)] |
9 | | pub struct Resolver<'a> { |
10 | | /// Current package name learned through the ASTs pushed onto this resolver. |
11 | | package_name: Option<(PackageName, Span)>, |
12 | | |
13 | | /// Package docs. |
14 | | package_docs: Docs, |
15 | | |
16 | | /// All non-`package` WIT decls are going to be resolved together. |
17 | | decl_lists: Vec<ast::DeclList<'a>>, |
18 | | |
19 | | // Arenas that get plumbed to the final `UnresolvedPackage` |
20 | | types: Arena<TypeDef>, |
21 | | interfaces: Arena<Interface>, |
22 | | worlds: Arena<World>, |
23 | | |
24 | | // Interning structure for types which-need-not-be-named such as |
25 | | // `list<string>` and such. |
26 | | anon_types: HashMap<Key, TypeId>, |
27 | | |
28 | | /// The index within `self.ast_items` that lookups should go through. This |
29 | | /// is updated as the ASTs are walked. |
30 | | cur_ast_index: usize, |
31 | | |
32 | | /// A map per `ast::DeclList` which keeps track of the file's top level |
33 | | /// names in scope. This maps each name onto either a world or an interface, |
34 | | /// handling things like `use` at the top level. |
35 | | ast_items: Vec<IndexMap<&'a str, AstItem>>, |
36 | | |
37 | | /// A map for the entire package being created of all names defined within, |
38 | | /// along with the ID they're mapping to. |
39 | | package_items: IndexMap<&'a str, AstItem>, |
40 | | |
41 | | /// A per-interface map of name to item-in-the-interface. This is the same |
42 | | /// length as `self.types` and is pushed to whenever `self.types` is pushed |
43 | | /// to. |
44 | | interface_types: Vec<IndexMap<&'a str, (TypeOrItem, Span)>>, |
45 | | |
46 | | /// Metadata about foreign dependencies which are not defined in this |
47 | | /// package. This map is keyed by the name of the package being imported |
48 | | /// from. The next level of key is the name of the interface being imported |
49 | | /// from, and the final value is the assigned ID of the interface. |
50 | | foreign_deps: IndexMap<PackageName, IndexMap<&'a str, AstItem>>, |
51 | | |
52 | | /// All interfaces that are present within `self.foreign_deps`. |
53 | | foreign_interfaces: HashSet<InterfaceId>, |
54 | | |
55 | | foreign_worlds: HashSet<WorldId>, |
56 | | |
57 | | /// The current type lookup scope which will eventually make its way into |
58 | | /// `self.interface_types`. |
59 | | type_lookup: IndexMap<&'a str, (TypeOrItem, Span)>, |
60 | | |
61 | | /// An assigned span for where all types inserted into `self.types` as |
62 | | /// imported from foreign interfaces. These types all show up first in the |
63 | | /// `self.types` arena and this span is used to generate an error message |
64 | | /// pointing to it if the item isn't actually defined. |
65 | | unknown_type_spans: Vec<Span>, |
66 | | |
67 | | /// Spans for each world in `self.worlds` |
68 | | world_spans: Vec<WorldSpan>, |
69 | | |
70 | | /// Spans for each type in `self.types` |
71 | | type_spans: Vec<Span>, |
72 | | |
73 | | /// The span of each interface's definition which is used for error |
74 | | /// reporting during the final `Resolve` phase. |
75 | | interface_spans: Vec<InterfaceSpan>, |
76 | | |
77 | | /// Spans per entry in `self.foreign_deps` for where the dependency was |
78 | | /// introduced to print an error message if necessary. |
79 | | foreign_dep_spans: Vec<Span>, |
80 | | |
81 | | /// A list of `TypeDefKind::Unknown` types which are required to be |
82 | | /// resources when this package is resolved against its dependencies. |
83 | | required_resource_types: Vec<(TypeId, Span)>, |
84 | | } |
85 | | |
86 | | #[derive(PartialEq, Eq, Hash)] |
87 | | enum Key { |
88 | | Variant(Vec<(String, Option<Type>)>), |
89 | | BorrowHandle(TypeId), |
90 | | Record(Vec<(String, Type)>), |
91 | | Flags(Vec<String>), |
92 | | Tuple(Vec<Type>), |
93 | | Enum(Vec<String>), |
94 | | List(Type), |
95 | | FixedSizeList(Type, u32), |
96 | | Option(Type), |
97 | | Result(Option<Type>, Option<Type>), |
98 | | Future(Option<Type>), |
99 | | Stream(Option<Type>), |
100 | | } |
101 | | |
102 | | enum TypeItem<'a, 'b> { |
103 | | Use(&'b ast::Use<'a>), |
104 | | Def(&'b ast::TypeDef<'a>), |
105 | | } |
106 | | |
107 | | enum TypeOrItem { |
108 | | Type(TypeId), |
109 | | Item(&'static str), |
110 | | } |
111 | | |
112 | | impl<'a> Resolver<'a> { |
113 | 22.2k | pub(super) fn push(&mut self, file: ast::PackageFile<'a>) -> Result<()> { |
114 | | // As each WIT file is pushed into this resolver keep track of the |
115 | | // current package name assigned. Only one file needs to mention it, but |
116 | | // if multiple mention it then they must all match. |
117 | 22.2k | if let Some(cur) = &file.package_id { |
118 | 16.5k | let cur_name = cur.package_name(); |
119 | 16.5k | if let Some((prev, _)) = &self.package_name { |
120 | 3.45k | if cur_name != *prev { |
121 | 0 | bail!(Error::new( |
122 | 0 | cur.span, |
123 | 0 | format!( |
124 | 0 | "package identifier `{cur_name}` does not match \ |
125 | 0 | previous package name of `{prev}`" |
126 | 0 | ), |
127 | 0 | )) |
128 | 3.45k | } |
129 | 13.1k | } |
130 | 16.5k | self.package_name = Some((cur_name, cur.span)); |
131 | | |
132 | | // At most one 'package' item can have doc comments. |
133 | 16.5k | let docs = self.docs(&cur.docs); |
134 | 16.5k | if docs.contents.is_some() { |
135 | 0 | if self.package_docs.contents.is_some() { |
136 | 0 | bail!(Error::new( |
137 | 0 | cur.docs.span, |
138 | 0 | "found doc comments on multiple 'package' items" |
139 | 0 | )) |
140 | 0 | } |
141 | 0 | self.package_docs = docs; |
142 | 16.5k | } |
143 | 5.69k | } |
144 | | |
145 | | // Ensure that there are no nested packages in `file`. Note that for |
146 | | // top level files nested packages are handled separately in `ast.rs` |
147 | | // with their own resolver. |
148 | 71.5k | for item in file.decl_list.items.iter() { |
149 | 71.5k | let span = match item { |
150 | 0 | ast::AstItem::Package(pkg) => pkg.package_id.as_ref().unwrap().span, |
151 | 71.5k | _ => continue, |
152 | | }; |
153 | 0 | bail!(Error::new( |
154 | 0 | span, |
155 | 0 | "nested packages must be placed at the top-level" |
156 | 0 | )) |
157 | | } |
158 | | |
159 | 22.2k | self.decl_lists.push(file.decl_list); |
160 | 22.2k | Ok(()) |
161 | 22.2k | } |
162 | | |
163 | 13.1k | pub(crate) fn resolve(&mut self) -> Result<UnresolvedPackage> { |
164 | | // At least one of the WIT files must have a `package` annotation. |
165 | 13.1k | let (name, package_name_span) = match &self.package_name { |
166 | 13.1k | Some(name) => name.clone(), |
167 | | None => { |
168 | 0 | bail!("no `package` header was found in any WIT file for this package") |
169 | | } |
170 | | }; |
171 | | |
172 | | // First populate information about foreign dependencies and the general |
173 | | // structure of the package. This should resolve the "base" of many |
174 | | // `use` statements and additionally generate a topological ordering of |
175 | | // all interfaces in the package to visit. |
176 | 13.1k | let decl_lists = mem::take(&mut self.decl_lists); |
177 | 13.1k | self.populate_foreign_deps(&decl_lists); |
178 | 13.1k | let (iface_order, world_order) = self.populate_ast_items(&decl_lists)?; |
179 | 13.1k | self.populate_foreign_types(&decl_lists)?; |
180 | | |
181 | | // Use the topological ordering of all interfaces to resolve all |
182 | | // interfaces in-order. Note that a reverse-mapping from ID to AST is |
183 | | // generated here to assist with this. |
184 | 13.1k | let mut iface_id_to_ast = IndexMap::new(); |
185 | 13.1k | let mut world_id_to_ast = IndexMap::new(); |
186 | 22.2k | for (i, decl_list) in decl_lists.iter().enumerate() { |
187 | 71.5k | for item in decl_list.items.iter() { |
188 | 71.5k | match item { |
189 | 51.7k | ast::AstItem::Interface(iface) => { |
190 | 51.7k | let id = match self.ast_items[i][iface.name.name] { |
191 | 51.7k | AstItem::Interface(id) => id, |
192 | 0 | AstItem::World(_) => unreachable!(), |
193 | | }; |
194 | 51.7k | iface_id_to_ast.insert(id, (iface, i)); |
195 | | } |
196 | 17.4k | ast::AstItem::World(world) => { |
197 | 17.4k | let id = match self.ast_items[i][world.name.name] { |
198 | 17.4k | AstItem::World(id) => id, |
199 | 0 | AstItem::Interface(_) => unreachable!(), |
200 | | }; |
201 | 17.4k | world_id_to_ast.insert(id, (world, i)); |
202 | | } |
203 | 2.37k | ast::AstItem::Use(_) => {} |
204 | 0 | ast::AstItem::Package(_) => unreachable!(), |
205 | | } |
206 | | } |
207 | | } |
208 | | |
209 | 64.8k | for id in iface_order { |
210 | 51.7k | let (interface, i) = &iface_id_to_ast[&id]; |
211 | 51.7k | self.cur_ast_index = *i; |
212 | 51.7k | self.resolve_interface(id, &interface.items, &interface.docs, &interface.attributes)?; |
213 | | } |
214 | | |
215 | 30.6k | for id in world_order { |
216 | 17.4k | let (world, i) = &world_id_to_ast[&id]; |
217 | 17.4k | self.cur_ast_index = *i; |
218 | 17.4k | self.resolve_world(id, world)?; |
219 | | } |
220 | | |
221 | 13.1k | self.decl_lists = decl_lists; |
222 | | Ok(UnresolvedPackage { |
223 | 13.1k | package_name_span, |
224 | 13.1k | name, |
225 | 13.1k | docs: mem::take(&mut self.package_docs), |
226 | 13.1k | worlds: mem::take(&mut self.worlds), |
227 | 13.1k | types: mem::take(&mut self.types), |
228 | 13.1k | interfaces: mem::take(&mut self.interfaces), |
229 | 13.1k | foreign_deps: self |
230 | 13.1k | .foreign_deps |
231 | 13.1k | .iter() |
232 | 13.1k | .map(|(name, deps)| { |
233 | | ( |
234 | 1.87k | name.clone(), |
235 | 1.87k | deps.iter() |
236 | 2.17k | .map(|(name, id)| (name.to_string(), *id)) |
237 | 1.87k | .collect(), |
238 | | ) |
239 | 1.87k | }) |
240 | 13.1k | .collect(), |
241 | 13.1k | unknown_type_spans: mem::take(&mut self.unknown_type_spans), |
242 | 13.1k | interface_spans: mem::take(&mut self.interface_spans), |
243 | 13.1k | world_spans: mem::take(&mut self.world_spans), |
244 | 13.1k | type_spans: mem::take(&mut self.type_spans), |
245 | 13.1k | foreign_dep_spans: mem::take(&mut self.foreign_dep_spans), |
246 | 13.1k | required_resource_types: mem::take(&mut self.required_resource_types), |
247 | | }) |
248 | 13.1k | } |
249 | | |
250 | | /// Registers all foreign dependencies made within the ASTs provided. |
251 | | /// |
252 | | /// This will populate the `self.foreign_{deps,interfaces,worlds}` maps with all |
253 | | /// `UsePath::Package` entries. |
254 | 13.1k | fn populate_foreign_deps(&mut self, decl_lists: &[ast::DeclList<'a>]) { |
255 | 13.1k | let mut foreign_deps = mem::take(&mut self.foreign_deps); |
256 | 13.1k | let mut foreign_interfaces = mem::take(&mut self.foreign_interfaces); |
257 | 13.1k | let mut foreign_worlds = mem::take(&mut self.foreign_worlds); |
258 | 35.4k | for decl_list in decl_lists { |
259 | 22.2k | decl_list |
260 | 22.2k | .for_each_path(&mut |_, _attrs, path, _names, world_or_iface| { |
261 | 15.2k | let (id, name) = match path { |
262 | 9.22k | ast::UsePath::Package { id, name } => (id, name), |
263 | 6.00k | _ => return Ok(()), |
264 | | }; |
265 | | |
266 | 9.22k | let deps = foreign_deps.entry(id.package_name()).or_insert_with(|| { |
267 | 1.87k | self.foreign_dep_spans.push(id.span); |
268 | 1.87k | IndexMap::new() |
269 | 1.87k | }); |
270 | 9.22k | let id = *deps.entry(name.name).or_insert_with(|| { |
271 | 2.17k | match world_or_iface { |
272 | | WorldOrInterface::World => { |
273 | 0 | log::trace!( |
274 | 0 | "creating a world for foreign dep: {}/{}", |
275 | 0 | id.package_name(), |
276 | | name.name |
277 | | ); |
278 | 0 | AstItem::World(self.alloc_world(name.span)) |
279 | | } |
280 | | WorldOrInterface::Interface | WorldOrInterface::Unknown => { |
281 | | // Currently top-level `use` always assumes an interface, so the |
282 | | // `Unknown` case is the same as `Interface`. |
283 | 2.17k | log::trace!( |
284 | 0 | "creating an interface for foreign dep: {}/{}", |
285 | 0 | id.package_name(), |
286 | | name.name |
287 | | ); |
288 | 2.17k | AstItem::Interface(self.alloc_interface(name.span)) |
289 | | } |
290 | | } |
291 | 2.17k | }); |
292 | | |
293 | 9.22k | let _ = match id { |
294 | 9.22k | AstItem::Interface(id) => foreign_interfaces.insert(id), |
295 | 0 | AstItem::World(id) => foreign_worlds.insert(id), |
296 | | }; |
297 | | |
298 | 9.22k | Ok(()) |
299 | 15.2k | }) |
300 | 22.2k | .unwrap(); |
301 | | } |
302 | 13.1k | self.foreign_deps = foreign_deps; |
303 | 13.1k | self.foreign_interfaces = foreign_interfaces; |
304 | 13.1k | self.foreign_worlds = foreign_worlds; |
305 | 13.1k | } |
306 | | |
307 | 56.8k | fn alloc_interface(&mut self, span: Span) -> InterfaceId { |
308 | 56.8k | self.interface_types.push(IndexMap::new()); |
309 | 56.8k | self.interface_spans.push(InterfaceSpan { |
310 | 56.8k | span, |
311 | 56.8k | funcs: Vec::new(), |
312 | 56.8k | }); |
313 | 56.8k | self.interfaces.alloc(Interface { |
314 | 56.8k | name: None, |
315 | 56.8k | types: IndexMap::new(), |
316 | 56.8k | docs: Docs::default(), |
317 | 56.8k | stability: Default::default(), |
318 | 56.8k | functions: IndexMap::new(), |
319 | 56.8k | package: None, |
320 | 56.8k | }) |
321 | 56.8k | } |
322 | | |
323 | 17.4k | fn alloc_world(&mut self, span: Span) -> WorldId { |
324 | 17.4k | self.world_spans.push(WorldSpan { |
325 | 17.4k | span, |
326 | 17.4k | imports: Vec::new(), |
327 | 17.4k | exports: Vec::new(), |
328 | 17.4k | includes: Vec::new(), |
329 | 17.4k | }); |
330 | 17.4k | self.worlds.alloc(World { |
331 | 17.4k | name: String::new(), |
332 | 17.4k | docs: Docs::default(), |
333 | 17.4k | exports: IndexMap::new(), |
334 | 17.4k | imports: IndexMap::new(), |
335 | 17.4k | package: None, |
336 | 17.4k | includes: Default::default(), |
337 | 17.4k | include_names: Default::default(), |
338 | 17.4k | stability: Default::default(), |
339 | 17.4k | }) |
340 | 17.4k | } |
341 | | |
342 | | /// This method will create a `World` and an `Interface` for all items |
343 | | /// present in the specified set of ASTs. Additionally maps for each AST are |
344 | | /// generated for resolving use-paths later on. |
345 | 13.1k | fn populate_ast_items( |
346 | 13.1k | &mut self, |
347 | 13.1k | decl_lists: &[ast::DeclList<'a>], |
348 | 13.1k | ) -> Result<(Vec<InterfaceId>, Vec<WorldId>)> { |
349 | 13.1k | let mut package_items = IndexMap::new(); |
350 | | |
351 | | // Validate that all worlds and interfaces have unique names within this |
352 | | // package across all ASTs which make up the package. |
353 | 13.1k | let mut names = HashMap::new(); |
354 | 13.1k | let mut decl_list_namespaces = Vec::new(); |
355 | 13.1k | let mut order = IndexMap::new(); |
356 | 35.4k | for decl_list in decl_lists { |
357 | 22.2k | let mut decl_list_ns = IndexMap::new(); |
358 | 71.5k | for item in decl_list.items.iter() { |
359 | 71.5k | match item { |
360 | 51.7k | ast::AstItem::Interface(i) => { |
361 | 51.7k | if package_items.insert(i.name.name, i.name.span).is_some() { |
362 | 0 | bail!(Error::new( |
363 | 0 | i.name.span, |
364 | 0 | format!("duplicate item named `{}`", i.name.name), |
365 | 0 | )) |
366 | 51.7k | } |
367 | 51.7k | let prev = decl_list_ns.insert(i.name.name, ()); |
368 | 51.7k | assert!(prev.is_none()); |
369 | 51.7k | let prev = order.insert(i.name.name, Vec::new()); |
370 | 51.7k | assert!(prev.is_none()); |
371 | 51.7k | let prev = names.insert(i.name.name, item); |
372 | 51.7k | assert!(prev.is_none()); |
373 | | } |
374 | 17.4k | ast::AstItem::World(w) => { |
375 | 17.4k | if package_items.insert(w.name.name, w.name.span).is_some() { |
376 | 0 | bail!(Error::new( |
377 | 0 | w.name.span, |
378 | 0 | format!("duplicate item named `{}`", w.name.name), |
379 | 0 | )) |
380 | 17.4k | } |
381 | 17.4k | let prev = decl_list_ns.insert(w.name.name, ()); |
382 | 17.4k | assert!(prev.is_none()); |
383 | 17.4k | let prev = order.insert(w.name.name, Vec::new()); |
384 | 17.4k | assert!(prev.is_none()); |
385 | 17.4k | let prev = names.insert(w.name.name, item); |
386 | 17.4k | assert!(prev.is_none()); |
387 | | } |
388 | | // These are processed down below. |
389 | 2.37k | ast::AstItem::Use(_) => {} |
390 | | |
391 | 0 | ast::AstItem::Package(_) => unreachable!(), |
392 | | } |
393 | | } |
394 | 22.2k | decl_list_namespaces.push(decl_list_ns); |
395 | | } |
396 | | |
397 | | // Next record dependencies between interfaces as induced via `use` |
398 | | // paths. This step is used to perform a topological sort of all |
399 | | // interfaces to ensure there are no cycles and to generate an ordering |
400 | | // which we can resolve in. |
401 | | enum ItemSource<'a> { |
402 | | Foreign, |
403 | | Local(ast::Id<'a>), |
404 | | } |
405 | | |
406 | 35.4k | for decl_list in decl_lists { |
407 | | // Record, in the context of this file, what all names are defined |
408 | | // at the top level and whether they point to other items in this |
409 | | // package or foreign items. Foreign deps are ignored for |
410 | | // topological ordering. |
411 | 22.2k | let mut decl_list_ns = IndexMap::new(); |
412 | 71.5k | for item in decl_list.items.iter() { |
413 | 71.5k | let (name, src) = match item { |
414 | 2.37k | ast::AstItem::Use(u) => { |
415 | 2.37k | let name = u.as_.as_ref().unwrap_or(u.item.name()); |
416 | 2.37k | let src = match &u.item { |
417 | 1.12k | ast::UsePath::Id(id) => ItemSource::Local(id.clone()), |
418 | 1.25k | ast::UsePath::Package { .. } => ItemSource::Foreign, |
419 | | }; |
420 | 2.37k | (name, src) |
421 | | } |
422 | 51.7k | ast::AstItem::Interface(i) => (&i.name, ItemSource::Local(i.name.clone())), |
423 | 17.4k | ast::AstItem::World(w) => (&w.name, ItemSource::Local(w.name.clone())), |
424 | 0 | ast::AstItem::Package(_) => unreachable!(), |
425 | | }; |
426 | 71.5k | if decl_list_ns.insert(name.name, (name.span, src)).is_some() { |
427 | 0 | bail!(Error::new( |
428 | 0 | name.span, |
429 | 0 | format!("duplicate name `{}` in this file", name.name), |
430 | 0 | )); |
431 | 71.5k | } |
432 | | } |
433 | | |
434 | | // With this file's namespace information look at all `use` paths |
435 | | // and record dependencies between interfaces. |
436 | 22.2k | decl_list.for_each_path(&mut |iface, _attrs, path, _names, _| { |
437 | | // If this import isn't contained within an interface then it's |
438 | | // in a world and it doesn't need to participate in our |
439 | | // topo-sort. |
440 | 15.2k | let iface = match iface { |
441 | 9.73k | Some(name) => name, |
442 | 5.49k | None => return Ok(()), |
443 | | }; |
444 | 9.73k | let used_name = match path { |
445 | 2.90k | ast::UsePath::Id(id) => id, |
446 | 6.83k | ast::UsePath::Package { .. } => return Ok(()), |
447 | | }; |
448 | 2.90k | match decl_list_ns.get(used_name.name) { |
449 | 30 | Some((_, ItemSource::Foreign)) => return Ok(()), |
450 | 1.39k | Some((_, ItemSource::Local(id))) => { |
451 | 1.39k | order[iface.name].push(id.clone()); |
452 | 1.39k | } |
453 | 1.47k | None => match package_items.get(used_name.name) { |
454 | 1.47k | Some(_) => { |
455 | 1.47k | order[iface.name].push(used_name.clone()); |
456 | 1.47k | } |
457 | | None => { |
458 | 0 | bail!(Error::new( |
459 | 0 | used_name.span, |
460 | 0 | format!( |
461 | 0 | "interface or world `{name}` not found in package", |
462 | 0 | name = used_name.name |
463 | 0 | ), |
464 | 0 | )) |
465 | | } |
466 | | }, |
467 | | } |
468 | 2.87k | Ok(()) |
469 | 15.2k | })?; |
470 | | } |
471 | | |
472 | 13.1k | let order = toposort("interface or world", &order)?; |
473 | 13.1k | log::debug!("toposort for interfaces and worlds in order: {order:?}"); |
474 | | |
475 | | // Allocate interfaces in-order now that the ordering is defined. This |
476 | | // is then used to build up internal maps for each AST which are stored |
477 | | // in `self.ast_items`. |
478 | 13.1k | let mut ids = IndexMap::new(); |
479 | 13.1k | let mut iface_id_order = Vec::new(); |
480 | 13.1k | let mut world_id_order = Vec::new(); |
481 | 82.3k | for name in order { |
482 | 69.2k | match names.get(name).unwrap() { |
483 | | ast::AstItem::Interface(_) => { |
484 | 51.7k | let id = self.alloc_interface(package_items[name]); |
485 | 51.7k | self.interfaces[id].name = Some(name.to_string()); |
486 | 51.7k | let prev = ids.insert(name, AstItem::Interface(id)); |
487 | 51.7k | assert!(prev.is_none()); |
488 | 51.7k | iface_id_order.push(id); |
489 | | } |
490 | | ast::AstItem::World(_) => { |
491 | 17.4k | let id = self.alloc_world(package_items[name]); |
492 | 17.4k | self.worlds[id].name = name.to_string(); |
493 | 17.4k | let prev = ids.insert(name, AstItem::World(id)); |
494 | 17.4k | assert!(prev.is_none()); |
495 | 17.4k | world_id_order.push(id); |
496 | | } |
497 | 0 | ast::AstItem::Use(_) | ast::AstItem::Package(_) => unreachable!(), |
498 | | }; |
499 | | } |
500 | 35.4k | for decl_list in decl_lists { |
501 | 22.2k | let mut items = IndexMap::new(); |
502 | 71.5k | for item in decl_list.items.iter() { |
503 | 71.5k | let (name, ast_item) = match item { |
504 | 2.37k | ast::AstItem::Use(u) => { |
505 | 2.37k | if !u.attributes.is_empty() { |
506 | 0 | bail!(Error::new( |
507 | 0 | u.span, |
508 | 0 | format!("attributes not allowed on top-level use"), |
509 | 0 | )) |
510 | 2.37k | } |
511 | 2.37k | let name = u.as_.as_ref().unwrap_or(u.item.name()); |
512 | 2.37k | let item = match &u.item { |
513 | 1.12k | ast::UsePath::Id(name) => *ids.get(name.name).ok_or_else(|| { |
514 | 0 | Error::new( |
515 | 0 | name.span, |
516 | 0 | format!( |
517 | 0 | "interface or world `{name}` does not exist", |
518 | | name = name.name |
519 | | ), |
520 | | ) |
521 | 0 | })?, |
522 | 1.25k | ast::UsePath::Package { id, name } => { |
523 | 1.25k | self.foreign_deps[&id.package_name()][name.name] |
524 | | } |
525 | | }; |
526 | 2.37k | (name.name, item) |
527 | | } |
528 | 51.7k | ast::AstItem::Interface(i) => { |
529 | 51.7k | let iface_item = ids[i.name.name]; |
530 | 51.7k | assert!(matches!(iface_item, AstItem::Interface(_))); |
531 | 51.7k | (i.name.name, iface_item) |
532 | | } |
533 | 17.4k | ast::AstItem::World(w) => { |
534 | 17.4k | let world_item = ids[w.name.name]; |
535 | 17.4k | assert!(matches!(world_item, AstItem::World(_))); |
536 | 17.4k | (w.name.name, world_item) |
537 | | } |
538 | 0 | ast::AstItem::Package(_) => unreachable!(), |
539 | | }; |
540 | 71.5k | let prev = items.insert(name, ast_item); |
541 | 71.5k | assert!(prev.is_none()); |
542 | | |
543 | | // Items defined via `use` don't go into the package namespace, |
544 | | // only the file namespace. |
545 | 71.5k | if !matches!(item, ast::AstItem::Use(_)) { |
546 | 69.2k | let prev = self.package_items.insert(name, ast_item); |
547 | 69.2k | assert!(prev.is_none()); |
548 | 2.37k | } |
549 | | } |
550 | 22.2k | self.ast_items.push(items); |
551 | | } |
552 | 13.1k | Ok((iface_id_order, world_id_order)) |
553 | 13.1k | } |
554 | | |
555 | | /// Generate a `Type::Unknown` entry for all types imported from foreign |
556 | | /// packages. |
557 | | /// |
558 | | /// This is done after all interfaces are generated so `self.resolve_path` |
559 | | /// can be used to determine if what's being imported from is a foreign |
560 | | /// interface or not. |
561 | 13.1k | fn populate_foreign_types(&mut self, decl_lists: &[ast::DeclList<'a>]) -> Result<()> { |
562 | 22.2k | for (i, decl_list) in decl_lists.iter().enumerate() { |
563 | 22.2k | self.cur_ast_index = i; |
564 | 22.2k | decl_list.for_each_path(&mut |_, attrs, path, names, _| { |
565 | 15.2k | let names = match names { |
566 | 11.7k | Some(names) => names, |
567 | 3.49k | None => return Ok(()), |
568 | | }; |
569 | 11.7k | let stability = self.stability(attrs)?; |
570 | 11.7k | let (item, name, span) = self.resolve_ast_item_path(path)?; |
571 | 11.7k | let iface = self.extract_iface_from_item(&item, &name, span)?; |
572 | 11.7k | if !self.foreign_interfaces.contains(&iface) { |
573 | 4.16k | return Ok(()); |
574 | 7.57k | } |
575 | | |
576 | 7.57k | let lookup = &mut self.interface_types[iface.index()]; |
577 | 15.9k | for name in names { |
578 | | // If this name has already been defined then use that prior |
579 | | // definition, otherwise create a new type with an unknown |
580 | | // representation and insert it into the various maps. |
581 | 8.40k | if lookup.contains_key(name.name.name) { |
582 | 6.34k | continue; |
583 | 2.05k | } |
584 | 2.05k | let id = self.types.alloc(TypeDef { |
585 | 2.05k | docs: Docs::default(), |
586 | 2.05k | stability: stability.clone(), |
587 | 2.05k | kind: TypeDefKind::Unknown, |
588 | 2.05k | name: Some(name.name.name.to_string()), |
589 | 2.05k | owner: TypeOwner::Interface(iface), |
590 | 2.05k | }); |
591 | 2.05k | self.unknown_type_spans.push(name.name.span); |
592 | 2.05k | self.type_spans.push(name.name.span); |
593 | 2.05k | lookup.insert(name.name.name, (TypeOrItem::Type(id), name.name.span)); |
594 | 2.05k | self.interfaces[iface] |
595 | 2.05k | .types |
596 | 2.05k | .insert(name.name.name.to_string(), id); |
597 | | } |
598 | | |
599 | 7.57k | Ok(()) |
600 | 15.2k | })?; |
601 | | } |
602 | 13.1k | Ok(()) |
603 | 13.1k | } |
604 | | |
605 | 17.4k | fn resolve_world(&mut self, world_id: WorldId, world: &ast::World<'a>) -> Result<WorldId> { |
606 | 17.4k | let docs = self.docs(&world.docs); |
607 | 17.4k | self.worlds[world_id].docs = docs; |
608 | 17.4k | let stability = self.stability(&world.attributes)?; |
609 | 17.4k | self.worlds[world_id].stability = stability; |
610 | | |
611 | 17.4k | self.resolve_types( |
612 | 17.4k | TypeOwner::World(world_id), |
613 | 53.8k | world.items.iter().filter_map(|i| match i { |
614 | 3.01k | ast::WorldItem::Use(u) => Some(TypeItem::Use(u)), |
615 | 35.4k | ast::WorldItem::Type(t) => Some(TypeItem::Def(t)), |
616 | 15.3k | ast::WorldItem::Import(_) | ast::WorldItem::Export(_) => None, |
617 | | // should be handled in `wit-parser::resolve` |
618 | 0 | ast::WorldItem::Include(_) => None, |
619 | 53.8k | }), |
620 | 0 | )?; |
621 | | |
622 | | // resolve include items |
623 | 26.9k | let items = world.items.iter().filter_map(|i| match i { |
624 | 0 | ast::WorldItem::Include(i) => Some(i), |
625 | 26.9k | _ => None, |
626 | 26.9k | }); |
627 | 17.4k | for include in items { |
628 | 0 | self.resolve_include(world_id, include)?; |
629 | | } |
630 | | |
631 | 17.4k | let mut export_spans = Vec::new(); |
632 | 17.4k | let mut import_spans = Vec::new(); |
633 | 19.6k | for (name, (item, span)) in self.type_lookup.iter() { |
634 | 19.6k | match *item { |
635 | 19.6k | TypeOrItem::Type(id) => { |
636 | 19.6k | let prev = self.worlds[world_id] |
637 | 19.6k | .imports |
638 | 19.6k | .insert(WorldKey::Name(name.to_string()), WorldItem::Type(id)); |
639 | 19.6k | if prev.is_some() { |
640 | 0 | bail!(Error::new( |
641 | 0 | *span, |
642 | 0 | format!("import `{name}` conflicts with prior import of same name"), |
643 | 0 | )) |
644 | 19.6k | } |
645 | 19.6k | import_spans.push(*span); |
646 | | } |
647 | 0 | TypeOrItem::Item(_) => unreachable!(), |
648 | | } |
649 | | } |
650 | | |
651 | 17.4k | let mut imported_interfaces = HashSet::new(); |
652 | 17.4k | let mut exported_interfaces = HashSet::new(); |
653 | 26.9k | for item in world.items.iter() { |
654 | 17.7k | let (docs, attrs, kind, desc, spans, interfaces) = match item { |
655 | 4.85k | ast::WorldItem::Import(import) => ( |
656 | 4.85k | &import.docs, |
657 | 4.85k | &import.attributes, |
658 | 4.85k | &import.kind, |
659 | 4.85k | "import", |
660 | 4.85k | &mut import_spans, |
661 | 4.85k | &mut imported_interfaces, |
662 | 4.85k | ), |
663 | 2.83k | ast::WorldItem::Export(export) => ( |
664 | 2.83k | &export.docs, |
665 | 2.83k | &export.attributes, |
666 | 2.83k | &export.kind, |
667 | 2.83k | "export", |
668 | 2.83k | &mut export_spans, |
669 | 2.83k | &mut exported_interfaces, |
670 | 2.83k | ), |
671 | | |
672 | | ast::WorldItem::Type(ast::TypeDef { |
673 | 791 | name, |
674 | 791 | ty: ast::Type::Resource(r), |
675 | | .. |
676 | | }) => { |
677 | 1.37k | for func in r.funcs.iter() { |
678 | 1.37k | import_spans.push(func.named_func().name.span); |
679 | 1.37k | let func = self.resolve_resource_func(func, name)?; |
680 | 1.37k | let prev = self.worlds[world_id] |
681 | 1.37k | .imports |
682 | 1.37k | .insert(WorldKey::Name(func.name.clone()), WorldItem::Function(func)); |
683 | | // Resource names themselves are unique, and methods are |
684 | | // uniquely named, so this should be possible to assert |
685 | | // at this point and never trip. |
686 | 1.37k | assert!(prev.is_none()); |
687 | | } |
688 | 791 | continue; |
689 | | } |
690 | | |
691 | | // handled in `resolve_types` |
692 | | ast::WorldItem::Use(_) | ast::WorldItem::Type(_) | ast::WorldItem::Include(_) => { |
693 | 18.4k | continue; |
694 | | } |
695 | | }; |
696 | | |
697 | 7.68k | let world_item = self.resolve_world_item(docs, attrs, kind)?; |
698 | 7.68k | let key = match kind { |
699 | | // Interfaces are always named exactly as they are in the WIT. |
700 | 2.94k | ast::ExternKind::Interface(name, _) => WorldKey::Name(name.name.to_string()), |
701 | | |
702 | | // Functions, however, might get mangled (e.g. with async) |
703 | | // meaning that the item's name comes from the function, not |
704 | | // from the in-WIT name. |
705 | | ast::ExternKind::Func(..) => { |
706 | 3.61k | let func = match &world_item { |
707 | 3.61k | WorldItem::Function(f) => f, |
708 | 0 | _ => unreachable!(), |
709 | | }; |
710 | 3.61k | WorldKey::Name(func.name.clone()) |
711 | | } |
712 | | |
713 | 1.12k | ast::ExternKind::Path(path) => { |
714 | 1.12k | let (item, name, span) = self.resolve_ast_item_path(path)?; |
715 | 1.12k | let id = self.extract_iface_from_item(&item, &name, span)?; |
716 | 1.12k | WorldKey::Interface(id) |
717 | | } |
718 | | }; |
719 | 7.68k | if let WorldItem::Interface { id, .. } = world_item { |
720 | 4.06k | if !interfaces.insert(id) { |
721 | 0 | bail!(Error::new( |
722 | 0 | kind.span(), |
723 | 0 | format!("interface cannot be {desc}ed more than once"), |
724 | 0 | )) |
725 | 4.06k | } |
726 | 3.61k | } |
727 | 7.68k | let dst = if desc == "import" { |
728 | 4.85k | &mut self.worlds[world_id].imports |
729 | | } else { |
730 | 2.83k | &mut self.worlds[world_id].exports |
731 | | }; |
732 | 7.68k | let prev = dst.insert(key.clone(), world_item); |
733 | 7.68k | if let Some(prev) = prev { |
734 | 0 | let prev = match prev { |
735 | 0 | WorldItem::Interface { .. } => "interface", |
736 | 0 | WorldItem::Function(..) => "func", |
737 | 0 | WorldItem::Type(..) => "type", |
738 | | }; |
739 | 0 | let name = match key { |
740 | 0 | WorldKey::Name(name) => name, |
741 | 0 | WorldKey::Interface(..) => unreachable!(), |
742 | | }; |
743 | 0 | bail!(Error::new( |
744 | 0 | kind.span(), |
745 | 0 | format!("{desc} `{name}` conflicts with prior {prev} of same name",), |
746 | 0 | )) |
747 | 7.68k | } |
748 | 7.68k | spans.push(kind.span()); |
749 | | } |
750 | 17.4k | self.world_spans[world_id.index()].imports = import_spans; |
751 | 17.4k | self.world_spans[world_id.index()].exports = export_spans; |
752 | 17.4k | self.type_lookup.clear(); |
753 | | |
754 | 17.4k | Ok(world_id) |
755 | 17.4k | } |
756 | | |
757 | 7.68k | fn resolve_world_item( |
758 | 7.68k | &mut self, |
759 | 7.68k | docs: &ast::Docs<'a>, |
760 | 7.68k | attrs: &[ast::Attribute<'a>], |
761 | 7.68k | kind: &ast::ExternKind<'a>, |
762 | 7.68k | ) -> Result<WorldItem> { |
763 | 7.68k | match kind { |
764 | 2.94k | ast::ExternKind::Interface(name, items) => { |
765 | 2.94k | let prev = mem::take(&mut self.type_lookup); |
766 | 2.94k | let id = self.alloc_interface(name.span); |
767 | 2.94k | self.resolve_interface(id, items, docs, attrs)?; |
768 | 2.94k | self.type_lookup = prev; |
769 | 2.94k | let stability = self.interfaces[id].stability.clone(); |
770 | 2.94k | Ok(WorldItem::Interface { id, stability }) |
771 | | } |
772 | 1.12k | ast::ExternKind::Path(path) => { |
773 | 1.12k | let stability = self.stability(attrs)?; |
774 | 1.12k | let (item, name, span) = self.resolve_ast_item_path(path)?; |
775 | 1.12k | let id = self.extract_iface_from_item(&item, &name, span)?; |
776 | 1.12k | Ok(WorldItem::Interface { id, stability }) |
777 | | } |
778 | 3.61k | ast::ExternKind::Func(name, func) => { |
779 | 3.61k | let func = self.resolve_function( |
780 | 3.61k | docs, |
781 | 3.61k | attrs, |
782 | 3.61k | &name.name, |
783 | 3.61k | func, |
784 | 3.61k | if func.async_ { |
785 | 1.25k | FunctionKind::AsyncFreestanding |
786 | | } else { |
787 | 2.35k | FunctionKind::Freestanding |
788 | | }, |
789 | 0 | )?; |
790 | 3.61k | Ok(WorldItem::Function(func)) |
791 | | } |
792 | | } |
793 | 7.68k | } |
794 | | |
795 | 54.6k | fn resolve_interface( |
796 | 54.6k | &mut self, |
797 | 54.6k | interface_id: InterfaceId, |
798 | 54.6k | fields: &[ast::InterfaceItem<'a>], |
799 | 54.6k | docs: &ast::Docs<'a>, |
800 | 54.6k | attrs: &[ast::Attribute<'a>], |
801 | 54.6k | ) -> Result<()> { |
802 | 54.6k | let docs = self.docs(docs); |
803 | 54.6k | self.interfaces[interface_id].docs = docs; |
804 | 54.6k | let stability = self.stability(attrs)?; |
805 | 54.6k | self.interfaces[interface_id].stability = stability; |
806 | | |
807 | 54.6k | self.resolve_types( |
808 | 54.6k | TypeOwner::Interface(interface_id), |
809 | 91.3k | fields.iter().filter_map(|i| match i { |
810 | 20.4k | ast::InterfaceItem::Use(u) => Some(TypeItem::Use(u)), |
811 | 39.4k | ast::InterfaceItem::TypeDef(t) => Some(TypeItem::Def(t)), |
812 | 31.4k | ast::InterfaceItem::Func(_) => None, |
813 | 91.3k | }), |
814 | 0 | )?; |
815 | | |
816 | 54.6k | for (name, (ty, _)) in self.type_lookup.iter() { |
817 | 31.5k | match *ty { |
818 | 31.5k | TypeOrItem::Type(id) => { |
819 | 31.5k | self.interfaces[interface_id] |
820 | 31.5k | .types |
821 | 31.5k | .insert(name.to_string(), id); |
822 | 31.5k | } |
823 | 0 | TypeOrItem::Item(_) => unreachable!(), |
824 | | } |
825 | | } |
826 | | |
827 | | // Finally process all function definitions now that all types are |
828 | | // defined. |
829 | 54.6k | let mut funcs = Vec::new(); |
830 | 100k | for field in fields { |
831 | 19.7k | match field { |
832 | 15.7k | ast::InterfaceItem::Func(f) => { |
833 | 15.7k | self.define_interface_name(&f.name, TypeOrItem::Item("function"))?; |
834 | 15.7k | funcs.push(self.resolve_function( |
835 | 15.7k | &f.docs, |
836 | 15.7k | &f.attributes, |
837 | 15.7k | &f.name.name, |
838 | 15.7k | &f.func, |
839 | 15.7k | if f.func.async_ { |
840 | 9.59k | FunctionKind::AsyncFreestanding |
841 | | } else { |
842 | 6.14k | FunctionKind::Freestanding |
843 | | }, |
844 | 0 | )?); |
845 | 15.7k | self.interface_spans[interface_id.index()] |
846 | 15.7k | .funcs |
847 | 15.7k | .push(f.name.span); |
848 | | } |
849 | 10.2k | ast::InterfaceItem::Use(_) => {} |
850 | | ast::InterfaceItem::TypeDef(ast::TypeDef { |
851 | 1.68k | name, |
852 | 1.68k | ty: ast::Type::Resource(r), |
853 | | .. |
854 | | }) => { |
855 | 2.79k | for func in r.funcs.iter() { |
856 | 2.79k | funcs.push(self.resolve_resource_func(func, name)?); |
857 | 2.79k | self.interface_spans[interface_id.index()] |
858 | 2.79k | .funcs |
859 | 2.79k | .push(func.named_func().name.span); |
860 | | } |
861 | | } |
862 | 18.0k | ast::InterfaceItem::TypeDef(_) => {} |
863 | | } |
864 | | } |
865 | 73.2k | for func in funcs { |
866 | 18.5k | let prev = self.interfaces[interface_id] |
867 | 18.5k | .functions |
868 | 18.5k | .insert(func.name.clone(), func); |
869 | 18.5k | assert!(prev.is_none()); |
870 | | } |
871 | | |
872 | 54.6k | let lookup = mem::take(&mut self.type_lookup); |
873 | 54.6k | self.interface_types[interface_id.index()] = lookup; |
874 | | |
875 | 54.6k | Ok(()) |
876 | 54.6k | } |
877 | | |
878 | 72.1k | fn resolve_types<'b>( |
879 | 72.1k | &mut self, |
880 | 72.1k | owner: TypeOwner, |
881 | 72.1k | fields: impl Iterator<Item = TypeItem<'a, 'b>> + Clone, |
882 | 72.1k | ) -> Result<()> |
883 | 72.1k | where |
884 | 72.1k | 'a: 'b, |
885 | | { |
886 | 72.1k | assert!(self.type_lookup.is_empty()); |
887 | | |
888 | | // First, populate our namespace with `use` statements |
889 | 72.1k | for field in fields.clone() { |
890 | 49.1k | match field { |
891 | 11.7k | TypeItem::Use(u) => { |
892 | 11.7k | self.resolve_use(owner, u)?; |
893 | | } |
894 | 37.4k | TypeItem::Def(_) => {} |
895 | | } |
896 | | } |
897 | | |
898 | | // Next determine dependencies between types, perform a topological |
899 | | // sort, and then define all types. This will define types in a |
900 | | // topological fashion, forbid cycles, and weed out references to |
901 | | // undefined types all in one go. |
902 | 72.1k | let mut type_deps = IndexMap::new(); |
903 | 72.1k | let mut type_defs = IndexMap::new(); |
904 | 121k | for field in fields { |
905 | 49.1k | match field { |
906 | 37.4k | TypeItem::Def(t) => { |
907 | 37.4k | let prev = type_defs.insert(t.name.name, Some(t)); |
908 | 37.4k | if prev.is_some() { |
909 | 0 | bail!(Error::new( |
910 | 0 | t.name.span, |
911 | 0 | format!("name `{}` is defined more than once", t.name.name), |
912 | 0 | )) |
913 | 37.4k | } |
914 | 37.4k | let mut deps = Vec::new(); |
915 | 37.4k | collect_deps(&t.ty, &mut deps); |
916 | 37.4k | type_deps.insert(t.name.name, deps); |
917 | | } |
918 | 11.7k | TypeItem::Use(u) => { |
919 | 13.7k | for name in u.names.iter() { |
920 | 13.7k | let name = name.as_.as_ref().unwrap_or(&name.name); |
921 | 13.7k | type_deps.insert(name.name, Vec::new()); |
922 | 13.7k | type_defs.insert(name.name, None); |
923 | 13.7k | } |
924 | | } |
925 | | } |
926 | | } |
927 | 72.1k | let order = toposort("type", &type_deps).map_err(attach_old_float_type_context)?; |
928 | 123k | for ty in order { |
929 | 51.2k | let def = match type_defs.swap_remove(&ty).unwrap() { |
930 | 37.4k | Some(def) => def, |
931 | 13.7k | None => continue, |
932 | | }; |
933 | 37.4k | let docs = self.docs(&def.docs); |
934 | 37.4k | let stability = self.stability(&def.attributes)?; |
935 | 37.4k | let kind = self.resolve_type_def(&def.ty, &stability)?; |
936 | 37.4k | let id = self.types.alloc(TypeDef { |
937 | 37.4k | docs, |
938 | 37.4k | stability, |
939 | 37.4k | kind, |
940 | 37.4k | name: Some(def.name.name.to_string()), |
941 | 37.4k | owner, |
942 | 37.4k | }); |
943 | 37.4k | self.type_spans.push(def.name.span); |
944 | 37.4k | self.define_interface_name(&def.name, TypeOrItem::Type(id))?; |
945 | | } |
946 | 72.1k | return Ok(()); |
947 | | |
948 | 0 | fn attach_old_float_type_context(err: ast::toposort::Error) -> anyhow::Error { |
949 | 0 | let name = match &err { |
950 | 0 | ast::toposort::Error::NonexistentDep { name, .. } => name, |
951 | 0 | _ => return err.into(), |
952 | | }; |
953 | 0 | let new = match name.as_str() { |
954 | 0 | "float32" => "f32", |
955 | 0 | "float64" => "f64", |
956 | 0 | _ => return err.into(), |
957 | | }; |
958 | | |
959 | 0 | let context = format!( |
960 | 0 | "the `{name}` type has been renamed to `{new}` and is \ |
961 | 0 | no longer accepted, but the `WIT_REQUIRE_F32_F64=0` \ |
962 | 0 | environment variable can be used to temporarily \ |
963 | 0 | disable this error" |
964 | | ); |
965 | 0 | anyhow::Error::from(err).context(context) |
966 | 0 | } |
967 | 72.1k | } <wit_parser::ast::resolve::Resolver>::resolve_types::<core::iter::adapters::filter_map::FilterMap<core::slice::iter::Iter<wit_parser::ast::InterfaceItem>, <wit_parser::ast::resolve::Resolver>::resolve_interface::{closure#0}>>Line | Count | Source | 878 | 54.6k | fn resolve_types<'b>( | 879 | 54.6k | &mut self, | 880 | 54.6k | owner: TypeOwner, | 881 | 54.6k | fields: impl Iterator<Item = TypeItem<'a, 'b>> + Clone, | 882 | 54.6k | ) -> Result<()> | 883 | 54.6k | where | 884 | 54.6k | 'a: 'b, | 885 | | { | 886 | 54.6k | assert!(self.type_lookup.is_empty()); | 887 | | | 888 | | // First, populate our namespace with `use` statements | 889 | 54.6k | for field in fields.clone() { | 890 | 29.9k | match field { | 891 | 10.2k | TypeItem::Use(u) => { | 892 | 10.2k | self.resolve_use(owner, u)?; | 893 | | } | 894 | 19.7k | TypeItem::Def(_) => {} | 895 | | } | 896 | | } | 897 | | | 898 | | // Next determine dependencies between types, perform a topological | 899 | | // sort, and then define all types. This will define types in a | 900 | | // topological fashion, forbid cycles, and weed out references to | 901 | | // undefined types all in one go. | 902 | 54.6k | let mut type_deps = IndexMap::new(); | 903 | 54.6k | let mut type_defs = IndexMap::new(); | 904 | 84.6k | for field in fields { | 905 | 29.9k | match field { | 906 | 19.7k | TypeItem::Def(t) => { | 907 | 19.7k | let prev = type_defs.insert(t.name.name, Some(t)); | 908 | 19.7k | if prev.is_some() { | 909 | 0 | bail!(Error::new( | 910 | 0 | t.name.span, | 911 | 0 | format!("name `{}` is defined more than once", t.name.name), | 912 | 0 | )) | 913 | 19.7k | } | 914 | 19.7k | let mut deps = Vec::new(); | 915 | 19.7k | collect_deps(&t.ty, &mut deps); | 916 | 19.7k | type_deps.insert(t.name.name, deps); | 917 | | } | 918 | 10.2k | TypeItem::Use(u) => { | 919 | 11.8k | for name in u.names.iter() { | 920 | 11.8k | let name = name.as_.as_ref().unwrap_or(&name.name); | 921 | 11.8k | type_deps.insert(name.name, Vec::new()); | 922 | 11.8k | type_defs.insert(name.name, None); | 923 | 11.8k | } | 924 | | } | 925 | | } | 926 | | } | 927 | 54.6k | let order = toposort("type", &type_deps).map_err(attach_old_float_type_context)?; | 928 | 86.2k | for ty in order { | 929 | 31.5k | let def = match type_defs.swap_remove(&ty).unwrap() { | 930 | 19.7k | Some(def) => def, | 931 | 11.8k | None => continue, | 932 | | }; | 933 | 19.7k | let docs = self.docs(&def.docs); | 934 | 19.7k | let stability = self.stability(&def.attributes)?; | 935 | 19.7k | let kind = self.resolve_type_def(&def.ty, &stability)?; | 936 | 19.7k | let id = self.types.alloc(TypeDef { | 937 | 19.7k | docs, | 938 | 19.7k | stability, | 939 | 19.7k | kind, | 940 | 19.7k | name: Some(def.name.name.to_string()), | 941 | 19.7k | owner, | 942 | 19.7k | }); | 943 | 19.7k | self.type_spans.push(def.name.span); | 944 | 19.7k | self.define_interface_name(&def.name, TypeOrItem::Type(id))?; | 945 | | } | 946 | 54.6k | return Ok(()); | 947 | | | 948 | | fn attach_old_float_type_context(err: ast::toposort::Error) -> anyhow::Error { | 949 | | let name = match &err { | 950 | | ast::toposort::Error::NonexistentDep { name, .. } => name, | 951 | | _ => return err.into(), | 952 | | }; | 953 | | let new = match name.as_str() { | 954 | | "float32" => "f32", | 955 | | "float64" => "f64", | 956 | | _ => return err.into(), | 957 | | }; | 958 | | | 959 | | let context = format!( | 960 | | "the `{name}` type has been renamed to `{new}` and is \ | 961 | | no longer accepted, but the `WIT_REQUIRE_F32_F64=0` \ | 962 | | environment variable can be used to temporarily \ | 963 | | disable this error" | 964 | | ); | 965 | | anyhow::Error::from(err).context(context) | 966 | | } | 967 | 54.6k | } |
<wit_parser::ast::resolve::Resolver>::resolve_types::<core::iter::adapters::filter_map::FilterMap<core::slice::iter::Iter<wit_parser::ast::WorldItem>, <wit_parser::ast::resolve::Resolver>::resolve_world::{closure#0}>>Line | Count | Source | 878 | 17.4k | fn resolve_types<'b>( | 879 | 17.4k | &mut self, | 880 | 17.4k | owner: TypeOwner, | 881 | 17.4k | fields: impl Iterator<Item = TypeItem<'a, 'b>> + Clone, | 882 | 17.4k | ) -> Result<()> | 883 | 17.4k | where | 884 | 17.4k | 'a: 'b, | 885 | | { | 886 | 17.4k | assert!(self.type_lookup.is_empty()); | 887 | | | 888 | | // First, populate our namespace with `use` statements | 889 | 19.2k | for field in fields.clone() { | 890 | 19.2k | match field { | 891 | 1.50k | TypeItem::Use(u) => { | 892 | 1.50k | self.resolve_use(owner, u)?; | 893 | | } | 894 | 17.7k | TypeItem::Def(_) => {} | 895 | | } | 896 | | } | 897 | | | 898 | | // Next determine dependencies between types, perform a topological | 899 | | // sort, and then define all types. This will define types in a | 900 | | // topological fashion, forbid cycles, and weed out references to | 901 | | // undefined types all in one go. | 902 | 17.4k | let mut type_deps = IndexMap::new(); | 903 | 17.4k | let mut type_defs = IndexMap::new(); | 904 | 36.6k | for field in fields { | 905 | 19.2k | match field { | 906 | 17.7k | TypeItem::Def(t) => { | 907 | 17.7k | let prev = type_defs.insert(t.name.name, Some(t)); | 908 | 17.7k | if prev.is_some() { | 909 | 0 | bail!(Error::new( | 910 | 0 | t.name.span, | 911 | 0 | format!("name `{}` is defined more than once", t.name.name), | 912 | 0 | )) | 913 | 17.7k | } | 914 | 17.7k | let mut deps = Vec::new(); | 915 | 17.7k | collect_deps(&t.ty, &mut deps); | 916 | 17.7k | type_deps.insert(t.name.name, deps); | 917 | | } | 918 | 1.50k | TypeItem::Use(u) => { | 919 | 1.92k | for name in u.names.iter() { | 920 | 1.92k | let name = name.as_.as_ref().unwrap_or(&name.name); | 921 | 1.92k | type_deps.insert(name.name, Vec::new()); | 922 | 1.92k | type_defs.insert(name.name, None); | 923 | 1.92k | } | 924 | | } | 925 | | } | 926 | | } | 927 | 17.4k | let order = toposort("type", &type_deps).map_err(attach_old_float_type_context)?; | 928 | 37.1k | for ty in order { | 929 | 19.6k | let def = match type_defs.swap_remove(&ty).unwrap() { | 930 | 17.7k | Some(def) => def, | 931 | 1.92k | None => continue, | 932 | | }; | 933 | 17.7k | let docs = self.docs(&def.docs); | 934 | 17.7k | let stability = self.stability(&def.attributes)?; | 935 | 17.7k | let kind = self.resolve_type_def(&def.ty, &stability)?; | 936 | 17.7k | let id = self.types.alloc(TypeDef { | 937 | 17.7k | docs, | 938 | 17.7k | stability, | 939 | 17.7k | kind, | 940 | 17.7k | name: Some(def.name.name.to_string()), | 941 | 17.7k | owner, | 942 | 17.7k | }); | 943 | 17.7k | self.type_spans.push(def.name.span); | 944 | 17.7k | self.define_interface_name(&def.name, TypeOrItem::Type(id))?; | 945 | | } | 946 | 17.4k | return Ok(()); | 947 | | | 948 | | fn attach_old_float_type_context(err: ast::toposort::Error) -> anyhow::Error { | 949 | | let name = match &err { | 950 | | ast::toposort::Error::NonexistentDep { name, .. } => name, | 951 | | _ => return err.into(), | 952 | | }; | 953 | | let new = match name.as_str() { | 954 | | "float32" => "f32", | 955 | | "float64" => "f64", | 956 | | _ => return err.into(), | 957 | | }; | 958 | | | 959 | | let context = format!( | 960 | | "the `{name}` type has been renamed to `{new}` and is \ | 961 | | no longer accepted, but the `WIT_REQUIRE_F32_F64=0` \ | 962 | | environment variable can be used to temporarily \ | 963 | | disable this error" | 964 | | ); | 965 | | anyhow::Error::from(err).context(context) | 966 | | } | 967 | 17.4k | } |
|
968 | | |
969 | 11.7k | fn resolve_use(&mut self, owner: TypeOwner, u: &ast::Use<'a>) -> Result<()> { |
970 | 11.7k | let (item, name, span) = self.resolve_ast_item_path(&u.from)?; |
971 | 11.7k | let use_from = self.extract_iface_from_item(&item, &name, span)?; |
972 | 11.7k | let stability = self.stability(&u.attributes)?; |
973 | | |
974 | 13.7k | for name in u.names.iter() { |
975 | 13.7k | let lookup = &self.interface_types[use_from.index()]; |
976 | 13.7k | let id = match lookup.get(name.name.name) { |
977 | 13.7k | Some((TypeOrItem::Type(id), _)) => *id, |
978 | 0 | Some((TypeOrItem::Item(s), _)) => { |
979 | 0 | bail!(Error::new( |
980 | 0 | name.name.span, |
981 | 0 | format!("cannot import {s} `{}`", name.name.name), |
982 | 0 | )) |
983 | | } |
984 | 0 | None => bail!(Error::new( |
985 | 0 | name.name.span, |
986 | 0 | format!("name `{}` is not defined", name.name.name), |
987 | 0 | )), |
988 | | }; |
989 | 13.7k | self.type_spans.push(name.name.span); |
990 | 13.7k | let name = name.as_.as_ref().unwrap_or(&name.name); |
991 | 13.7k | let id = self.types.alloc(TypeDef { |
992 | 13.7k | docs: Docs::default(), |
993 | 13.7k | stability: stability.clone(), |
994 | 13.7k | kind: TypeDefKind::Type(Type::Id(id)), |
995 | 13.7k | name: Some(name.name.to_string()), |
996 | 13.7k | owner, |
997 | 13.7k | }); |
998 | 13.7k | self.define_interface_name(name, TypeOrItem::Type(id))?; |
999 | | } |
1000 | 11.7k | Ok(()) |
1001 | 11.7k | } |
1002 | | |
1003 | | /// For each name in the `include`, resolve the path of the include, add it to the self.includes |
1004 | 0 | fn resolve_include(&mut self, world_id: WorldId, i: &ast::Include<'a>) -> Result<()> { |
1005 | 0 | let stability = self.stability(&i.attributes)?; |
1006 | 0 | let (item, name, span) = self.resolve_ast_item_path(&i.from)?; |
1007 | 0 | let include_from = self.extract_world_from_item(&item, &name, span)?; |
1008 | 0 | self.worlds[world_id] |
1009 | 0 | .includes |
1010 | 0 | .push((stability, include_from)); |
1011 | 0 | self.worlds[world_id].include_names.push( |
1012 | 0 | i.names |
1013 | 0 | .iter() |
1014 | 0 | .map(|n| IncludeName { |
1015 | 0 | name: n.name.name.to_string(), |
1016 | 0 | as_: n.as_.name.to_string(), |
1017 | 0 | }) |
1018 | 0 | .collect(), |
1019 | | ); |
1020 | 0 | self.world_spans[world_id.index()].includes.push(span); |
1021 | 0 | Ok(()) |
1022 | 0 | } |
1023 | | |
1024 | 4.16k | fn resolve_resource_func( |
1025 | 4.16k | &mut self, |
1026 | 4.16k | func: &ast::ResourceFunc<'_>, |
1027 | 4.16k | resource: &ast::Id<'_>, |
1028 | 4.16k | ) -> Result<Function> { |
1029 | 4.16k | let resource_id = match self.type_lookup.get(resource.name) { |
1030 | 4.16k | Some((TypeOrItem::Type(id), _)) => *id, |
1031 | 0 | _ => panic!("type lookup for resource failed"), |
1032 | | }; |
1033 | | let (name, kind); |
1034 | 4.16k | let named_func = func.named_func(); |
1035 | 4.16k | let async_ = named_func.func.async_; |
1036 | 4.16k | match func { |
1037 | 2.20k | ast::ResourceFunc::Method(f) => { |
1038 | 2.20k | name = format!("[method]{}.{}", resource.name, f.name.name); |
1039 | 2.20k | kind = if async_ { |
1040 | 1.57k | FunctionKind::AsyncMethod(resource_id) |
1041 | | } else { |
1042 | 625 | FunctionKind::Method(resource_id) |
1043 | | }; |
1044 | | } |
1045 | 1.43k | ast::ResourceFunc::Static(f) => { |
1046 | 1.43k | name = format!("[static]{}.{}", resource.name, f.name.name); |
1047 | 1.43k | kind = if async_ { |
1048 | 887 | FunctionKind::AsyncStatic(resource_id) |
1049 | | } else { |
1050 | 543 | FunctionKind::Static(resource_id) |
1051 | | }; |
1052 | | } |
1053 | | ast::ResourceFunc::Constructor(_) => { |
1054 | 530 | assert!(!async_); // should not be possible to parse |
1055 | 530 | name = format!("[constructor]{}", resource.name); |
1056 | 530 | kind = FunctionKind::Constructor(resource_id); |
1057 | | } |
1058 | | } |
1059 | 4.16k | self.resolve_function( |
1060 | 4.16k | &named_func.docs, |
1061 | 4.16k | &named_func.attributes, |
1062 | 4.16k | &name, |
1063 | 4.16k | &named_func.func, |
1064 | 4.16k | kind, |
1065 | | ) |
1066 | 4.16k | } |
1067 | | |
1068 | 23.5k | fn resolve_function( |
1069 | 23.5k | &mut self, |
1070 | 23.5k | docs: &ast::Docs<'_>, |
1071 | 23.5k | attrs: &[ast::Attribute<'_>], |
1072 | 23.5k | name: &str, |
1073 | 23.5k | func: &ast::Func, |
1074 | 23.5k | kind: FunctionKind, |
1075 | 23.5k | ) -> Result<Function> { |
1076 | 23.5k | let docs = self.docs(docs); |
1077 | 23.5k | let stability = self.stability(attrs)?; |
1078 | 23.5k | let params = self.resolve_params(&func.params, &kind, func.span)?; |
1079 | 23.5k | let result = self.resolve_result(&func.result, &kind, func.span)?; |
1080 | 23.5k | Ok(Function { |
1081 | 23.5k | docs, |
1082 | 23.5k | stability, |
1083 | 23.5k | name: name.to_string(), |
1084 | 23.5k | kind, |
1085 | 23.5k | params, |
1086 | 23.5k | result, |
1087 | 23.5k | }) |
1088 | 23.5k | } |
1089 | | |
1090 | 25.7k | fn resolve_ast_item_path(&self, path: &ast::UsePath<'a>) -> Result<(AstItem, String, Span)> { |
1091 | 25.7k | match path { |
1092 | 9.77k | ast::UsePath::Id(id) => { |
1093 | 9.77k | let item = self.ast_items[self.cur_ast_index] |
1094 | 9.77k | .get(id.name) |
1095 | 9.77k | .or_else(|| self.package_items.get(id.name)); |
1096 | 9.77k | match item { |
1097 | 9.77k | Some(item) => Ok((*item, id.name.into(), id.span)), |
1098 | | None => { |
1099 | 0 | bail!(Error::new( |
1100 | 0 | id.span, |
1101 | 0 | format!("interface or world `{}` does not exist", id.name), |
1102 | 0 | )) |
1103 | | } |
1104 | | } |
1105 | | } |
1106 | 15.9k | ast::UsePath::Package { id, name } => Ok(( |
1107 | 15.9k | self.foreign_deps[&id.package_name()][name.name], |
1108 | 15.9k | name.name.into(), |
1109 | 15.9k | name.span, |
1110 | 15.9k | )), |
1111 | | } |
1112 | 25.7k | } |
1113 | | |
1114 | 25.7k | fn extract_iface_from_item( |
1115 | 25.7k | &self, |
1116 | 25.7k | item: &AstItem, |
1117 | 25.7k | name: &str, |
1118 | 25.7k | span: Span, |
1119 | 25.7k | ) -> Result<InterfaceId> { |
1120 | 25.7k | match item { |
1121 | 25.7k | AstItem::Interface(id) => Ok(*id), |
1122 | | AstItem::World(_) => { |
1123 | 0 | bail!(Error::new( |
1124 | 0 | span, |
1125 | 0 | format!("name `{name}` is defined as a world, not an interface"), |
1126 | 0 | )) |
1127 | | } |
1128 | | } |
1129 | 25.7k | } |
1130 | | |
1131 | 0 | fn extract_world_from_item(&self, item: &AstItem, name: &str, span: Span) -> Result<WorldId> { |
1132 | 0 | match item { |
1133 | 0 | AstItem::World(id) => Ok(*id), |
1134 | | AstItem::Interface(_) => { |
1135 | 0 | bail!(Error::new( |
1136 | 0 | span, |
1137 | 0 | format!("name `{name}` is defined as an interface, not a world"), |
1138 | 0 | )) |
1139 | | } |
1140 | | } |
1141 | 0 | } |
1142 | | |
1143 | 66.9k | fn define_interface_name(&mut self, name: &ast::Id<'a>, item: TypeOrItem) -> Result<()> { |
1144 | 66.9k | let prev = self.type_lookup.insert(name.name, (item, name.span)); |
1145 | 66.9k | if prev.is_some() { |
1146 | 0 | bail!(Error::new( |
1147 | 0 | name.span, |
1148 | 0 | format!("name `{}` is defined more than once", name.name), |
1149 | 0 | )) |
1150 | | } else { |
1151 | 66.9k | Ok(()) |
1152 | | } |
1153 | 66.9k | } |
1154 | | |
1155 | 419k | fn resolve_type_def( |
1156 | 419k | &mut self, |
1157 | 419k | ty: &ast::Type<'_>, |
1158 | 419k | stability: &Stability, |
1159 | 419k | ) -> Result<TypeDefKind> { |
1160 | 419k | Ok(match ty { |
1161 | 96.9k | ast::Type::Bool(_) => TypeDefKind::Type(Type::Bool), |
1162 | 6.39k | ast::Type::U8(_) => TypeDefKind::Type(Type::U8), |
1163 | 1.94k | ast::Type::U16(_) => TypeDefKind::Type(Type::U16), |
1164 | 3.44k | ast::Type::U32(_) => TypeDefKind::Type(Type::U32), |
1165 | 2.88k | ast::Type::U64(_) => TypeDefKind::Type(Type::U64), |
1166 | 3.07k | ast::Type::S8(_) => TypeDefKind::Type(Type::S8), |
1167 | 1.54k | ast::Type::S16(_) => TypeDefKind::Type(Type::S16), |
1168 | 2.47k | ast::Type::S32(_) => TypeDefKind::Type(Type::S32), |
1169 | 11.4k | ast::Type::S64(_) => TypeDefKind::Type(Type::S64), |
1170 | 5.17k | ast::Type::F32(_) => TypeDefKind::Type(Type::F32), |
1171 | 8.18k | ast::Type::F64(_) => TypeDefKind::Type(Type::F64), |
1172 | 9.99k | ast::Type::Char(_) => TypeDefKind::Type(Type::Char), |
1173 | 2.32k | ast::Type::String(_) => TypeDefKind::Type(Type::String), |
1174 | 18.4k | ast::Type::ErrorContext(_) => TypeDefKind::Type(Type::ErrorContext), |
1175 | 2.36k | ast::Type::Name(name) => { |
1176 | 2.36k | let id = self.resolve_type_name(name)?; |
1177 | 2.36k | TypeDefKind::Type(Type::Id(id)) |
1178 | | } |
1179 | 6.24k | ast::Type::List(list) => { |
1180 | 6.24k | let ty = self.resolve_type(&list.ty, stability)?; |
1181 | 6.24k | TypeDefKind::List(ty) |
1182 | | } |
1183 | 106k | ast::Type::FixedSizeList(list) => { |
1184 | 106k | let ty = self.resolve_type(&list.ty, stability)?; |
1185 | 106k | TypeDefKind::FixedSizeList(ty, list.size) |
1186 | | } |
1187 | 354 | ast::Type::Handle(handle) => TypeDefKind::Handle(match handle { |
1188 | 354 | ast::Handle::Own { resource } => Handle::Own(self.validate_resource(resource)?), |
1189 | 0 | ast::Handle::Borrow { resource } => { |
1190 | 0 | Handle::Borrow(self.validate_resource(resource)?) |
1191 | | } |
1192 | | }), |
1193 | 2.48k | ast::Type::Resource(resource) => { |
1194 | | // Validate here that the resource doesn't have any duplicate-ly |
1195 | | // named methods and that there's at most one constructor. |
1196 | 2.48k | let mut ctors = 0; |
1197 | 2.48k | let mut names = HashSet::new(); |
1198 | 4.16k | for func in resource.funcs.iter() { |
1199 | 4.16k | match func { |
1200 | 2.20k | ast::ResourceFunc::Method(f) | ast::ResourceFunc::Static(f) => { |
1201 | 3.63k | if !names.insert(&f.name.name) { |
1202 | 0 | bail!(Error::new( |
1203 | 0 | f.name.span, |
1204 | 0 | format!("duplicate function name `{}`", f.name.name), |
1205 | 0 | )) |
1206 | 3.63k | } |
1207 | | } |
1208 | 530 | ast::ResourceFunc::Constructor(f) => { |
1209 | 530 | ctors += 1; |
1210 | 530 | if ctors > 1 { |
1211 | 0 | bail!(Error::new(f.name.span, "duplicate constructors")) |
1212 | 530 | } |
1213 | | } |
1214 | | } |
1215 | | } |
1216 | | |
1217 | 2.48k | TypeDefKind::Resource |
1218 | | } |
1219 | 4.13k | ast::Type::Record(record) => { |
1220 | 4.13k | let fields = record |
1221 | 4.13k | .fields |
1222 | 4.13k | .iter() |
1223 | 11.3k | .map(|field| { |
1224 | | Ok(Field { |
1225 | 11.3k | docs: self.docs(&field.docs), |
1226 | 11.3k | name: field.name.name.to_string(), |
1227 | 11.3k | ty: self.resolve_type(&field.ty, stability)?, |
1228 | | }) |
1229 | 11.3k | }) |
1230 | 4.13k | .collect::<Result<Vec<_>>>()?; |
1231 | 4.13k | TypeDefKind::Record(Record { fields }) |
1232 | | } |
1233 | 1.25k | ast::Type::Flags(flags) => { |
1234 | 1.25k | let flags = flags |
1235 | 1.25k | .flags |
1236 | 1.25k | .iter() |
1237 | 1.25k | .map(|flag| Flag { |
1238 | 3.86k | docs: self.docs(&flag.docs), |
1239 | 3.86k | name: flag.name.name.to_string(), |
1240 | 3.86k | }) |
1241 | 1.25k | .collect::<Vec<_>>(); |
1242 | 1.25k | TypeDefKind::Flags(Flags { flags }) |
1243 | | } |
1244 | 22.3k | ast::Type::Tuple(t) => { |
1245 | 22.3k | let types = t |
1246 | 22.3k | .types |
1247 | 22.3k | .iter() |
1248 | 80.1k | .map(|ty| self.resolve_type(ty, stability)) |
1249 | 22.3k | .collect::<Result<Vec<_>>>()?; |
1250 | 22.3k | TypeDefKind::Tuple(Tuple { types }) |
1251 | | } |
1252 | 5.84k | ast::Type::Variant(variant) => { |
1253 | 5.84k | if variant.cases.is_empty() { |
1254 | 0 | bail!(Error::new(variant.span, "empty variant")) |
1255 | 5.84k | } |
1256 | 5.84k | let cases = variant |
1257 | 5.84k | .cases |
1258 | 5.84k | .iter() |
1259 | 20.2k | .map(|case| { |
1260 | | Ok(Case { |
1261 | 20.2k | docs: self.docs(&case.docs), |
1262 | 20.2k | name: case.name.name.to_string(), |
1263 | 20.2k | ty: self.resolve_optional_type(case.ty.as_ref(), stability)?, |
1264 | | }) |
1265 | 20.2k | }) |
1266 | 5.84k | .collect::<Result<Vec<_>>>()?; |
1267 | 5.84k | TypeDefKind::Variant(Variant { cases }) |
1268 | | } |
1269 | 21.8k | ast::Type::Enum(e) => { |
1270 | 21.8k | if e.cases.is_empty() { |
1271 | 0 | bail!(Error::new(e.span, "empty enum")) |
1272 | 21.8k | } |
1273 | 21.8k | let cases = e |
1274 | 21.8k | .cases |
1275 | 21.8k | .iter() |
1276 | 100k | .map(|case| { |
1277 | 100k | Ok(EnumCase { |
1278 | 100k | docs: self.docs(&case.docs), |
1279 | 100k | name: case.name.name.to_string(), |
1280 | 100k | }) |
1281 | 100k | }) |
1282 | 21.8k | .collect::<Result<Vec<_>>>()?; |
1283 | 21.8k | TypeDefKind::Enum(Enum { cases }) |
1284 | | } |
1285 | 28.5k | ast::Type::Option(ty) => TypeDefKind::Option(self.resolve_type(&ty.ty, stability)?), |
1286 | 30.0k | ast::Type::Result(r) => TypeDefKind::Result(Result_ { |
1287 | 30.0k | ok: self.resolve_optional_type(r.ok.as_deref(), stability)?, |
1288 | 30.0k | err: self.resolve_optional_type(r.err.as_deref(), stability)?, |
1289 | | }), |
1290 | 7.83k | ast::Type::Future(t) => { |
1291 | 7.83k | TypeDefKind::Future(self.resolve_optional_type(t.ty.as_deref(), stability)?) |
1292 | | } |
1293 | 5.00k | ast::Type::Stream(s) => { |
1294 | 5.00k | TypeDefKind::Stream(self.resolve_optional_type(s.ty.as_deref(), stability)?) |
1295 | | } |
1296 | | }) |
1297 | 419k | } |
1298 | | |
1299 | 2.71k | fn resolve_type_name(&mut self, name: &ast::Id<'_>) -> Result<TypeId> { |
1300 | 2.71k | match self.type_lookup.get(name.name) { |
1301 | 2.71k | Some((TypeOrItem::Type(id), _)) => Ok(*id), |
1302 | 0 | Some((TypeOrItem::Item(s), _)) => bail!(Error::new( |
1303 | 0 | name.span, |
1304 | 0 | format!("cannot use {s} `{name}` as a type", name = name.name), |
1305 | 0 | )), |
1306 | 0 | None => bail!(Error::new( |
1307 | 0 | name.span, |
1308 | 0 | format!("name `{name}` is not defined", name = name.name), |
1309 | 0 | )), |
1310 | | } |
1311 | 2.71k | } |
1312 | | |
1313 | 354 | fn validate_resource(&mut self, name: &ast::Id<'_>) -> Result<TypeId> { |
1314 | 354 | let id = self.resolve_type_name(name)?; |
1315 | 354 | let mut cur = id; |
1316 | | loop { |
1317 | 378 | match self.types[cur].kind { |
1318 | 338 | TypeDefKind::Resource => break Ok(id), |
1319 | 24 | TypeDefKind::Type(Type::Id(ty)) => cur = ty, |
1320 | | TypeDefKind::Unknown => { |
1321 | 16 | self.required_resource_types.push((cur, name.span)); |
1322 | 16 | break Ok(id); |
1323 | | } |
1324 | 0 | _ => bail!(Error::new( |
1325 | 0 | name.span, |
1326 | 0 | format!("type `{}` used in a handle must be a resource", name.name), |
1327 | 0 | )), |
1328 | | } |
1329 | | } |
1330 | 354 | } |
1331 | | |
1332 | | /// If `stability` is `Stability::Unknown`, recursively inspect the |
1333 | | /// specified `kind` until we either bottom out or find a type which has a |
1334 | | /// stability that's _not_ unknown. If we find such a type, return a clone |
1335 | | /// of its stability; otherwise return `Stability::Unknown`. |
1336 | | /// |
1337 | | /// The idea here is that e.g. `option<T>` should inherit `T`'s stability. |
1338 | | /// This gets a little ambiguous in the case of e.g. `tuple<T, U, V>`; for |
1339 | | /// now, we just pick the first one has a known stability, if any. |
1340 | 384k | fn find_stability(&self, kind: &TypeDefKind, stability: &Stability) -> Stability { |
1341 | 458k | fn find_in_type(types: &Arena<TypeDef>, ty: Type) -> Option<&Stability> { |
1342 | 458k | if let Type::Id(id) = ty { |
1343 | 200k | let ty = &types[id]; |
1344 | 200k | if !matches!(&ty.stability, Stability::Unknown) { |
1345 | 372 | Some(&ty.stability) |
1346 | | } else { |
1347 | | // Note that this type isn't searched recursively since the |
1348 | | // creation of `id` should already have searched its |
1349 | | // recursive edges, so there's no need to search again. |
1350 | 199k | None |
1351 | | } |
1352 | | } else { |
1353 | 258k | None |
1354 | | } |
1355 | 458k | } |
1356 | | |
1357 | 382k | fn find_in_kind<'a>( |
1358 | 382k | types: &'a Arena<TypeDef>, |
1359 | 382k | kind: &TypeDefKind, |
1360 | 382k | ) -> Option<&'a Stability> { |
1361 | 2.54k | match kind { |
1362 | 174k | TypeDefKind::Type(ty) => find_in_type(types, *ty), |
1363 | 2.20k | TypeDefKind::Handle(Handle::Borrow(id) | Handle::Own(id)) => { |
1364 | 2.54k | find_in_type(types, Type::Id(*id)) |
1365 | | } |
1366 | 79.1k | TypeDefKind::Tuple(t) => t.types.iter().find_map(|ty| find_in_type(types, *ty)), |
1367 | 6.18k | TypeDefKind::List(ty) |
1368 | 106k | | TypeDefKind::FixedSizeList(ty, _) |
1369 | 141k | | TypeDefKind::Option(ty) => find_in_type(types, *ty), |
1370 | 7.79k | TypeDefKind::Future(ty) | TypeDefKind::Stream(ty) => { |
1371 | 12.7k | ty.as_ref().and_then(|ty| find_in_type(types, *ty)) |
1372 | | } |
1373 | 29.5k | TypeDefKind::Result(r) => { |
1374 | 29.5k | r.ok.as_ref() |
1375 | 29.5k | .and_then(|ty| find_in_type(types, *ty)) |
1376 | 29.5k | .or_else(|| r.err.as_ref().and_then(|ty| find_in_type(types, *ty))) |
1377 | | } |
1378 | | // Assume these are named types which will be annotated with an |
1379 | | // explicit stability if applicable: |
1380 | | TypeDefKind::Resource |
1381 | | | TypeDefKind::Variant(_) |
1382 | | | TypeDefKind::Record(_) |
1383 | | | TypeDefKind::Flags(_) |
1384 | | | TypeDefKind::Enum(_) |
1385 | 0 | | TypeDefKind::Unknown => None, |
1386 | | } |
1387 | 382k | } |
1388 | | |
1389 | 384k | if let Stability::Unknown = stability { |
1390 | 382k | find_in_kind(&self.types, kind) |
1391 | 382k | .cloned() |
1392 | 382k | .unwrap_or(Stability::Unknown) |
1393 | | } else { |
1394 | 1.76k | stability.clone() |
1395 | | } |
1396 | 384k | } |
1397 | | |
1398 | 382k | fn resolve_type(&mut self, ty: &super::Type<'_>, stability: &Stability) -> Result<Type> { |
1399 | | // Resources must be declared at the top level to have their methods |
1400 | | // processed appropriately, but resources also shouldn't show up |
1401 | | // recursively so assert that's not happening here. |
1402 | 382k | match ty { |
1403 | 0 | ast::Type::Resource(_) => unreachable!(), |
1404 | 382k | _ => {} |
1405 | | } |
1406 | 382k | let kind = self.resolve_type_def(ty, stability)?; |
1407 | 382k | let stability = self.find_stability(&kind, stability); |
1408 | 382k | Ok(self.anon_type_def( |
1409 | 382k | TypeDef { |
1410 | 382k | kind, |
1411 | 382k | name: None, |
1412 | 382k | docs: Docs::default(), |
1413 | 382k | stability, |
1414 | 382k | owner: TypeOwner::None, |
1415 | 382k | }, |
1416 | 382k | ty.span(), |
1417 | 382k | )) |
1418 | 382k | } |
1419 | | |
1420 | 93.2k | fn resolve_optional_type( |
1421 | 93.2k | &mut self, |
1422 | 93.2k | ty: Option<&super::Type<'_>>, |
1423 | 93.2k | stability: &Stability, |
1424 | 93.2k | ) -> Result<Option<Type>> { |
1425 | 93.2k | match ty { |
1426 | 79.6k | Some(ty) => Ok(Some(self.resolve_type(ty, stability)?)), |
1427 | 13.6k | None => Ok(None), |
1428 | | } |
1429 | 93.2k | } |
1430 | | |
1431 | 384k | fn anon_type_def(&mut self, ty: TypeDef, span: Span) -> Type { |
1432 | 208k | let key = match &ty.kind { |
1433 | 175k | TypeDefKind::Type(t) => return *t, |
1434 | 0 | TypeDefKind::Variant(v) => Key::Variant( |
1435 | 0 | v.cases |
1436 | 0 | .iter() |
1437 | 0 | .map(|case| (case.name.clone(), case.ty)) |
1438 | 0 | .collect::<Vec<_>>(), |
1439 | | ), |
1440 | 2.20k | TypeDefKind::Handle(Handle::Borrow(h)) => Key::BorrowHandle(*h), |
1441 | | // An anonymous `own<T>` type is the same as a reference to the type |
1442 | | // `T`, so avoid creating anonymous type and return that here |
1443 | | // directly. Note that this additionally avoids creating distinct |
1444 | | // anonymous types for `list<T>` and `list<own<T>>` for example. |
1445 | 346 | TypeDefKind::Handle(Handle::Own(id)) => return Type::Id(*id), |
1446 | 0 | TypeDefKind::Resource => unreachable!("anonymous resources aren't supported"), |
1447 | 0 | TypeDefKind::Record(r) => Key::Record( |
1448 | 0 | r.fields |
1449 | 0 | .iter() |
1450 | 0 | .map(|case| (case.name.clone(), case.ty)) |
1451 | 0 | .collect::<Vec<_>>(), |
1452 | | ), |
1453 | 0 | TypeDefKind::Flags(r) => { |
1454 | 0 | Key::Flags(r.flags.iter().map(|f| f.name.clone()).collect::<Vec<_>>()) |
1455 | | } |
1456 | 22.2k | TypeDefKind::Tuple(t) => Key::Tuple(t.types.clone()), |
1457 | 0 | TypeDefKind::Enum(r) => { |
1458 | 0 | Key::Enum(r.cases.iter().map(|f| f.name.clone()).collect::<Vec<_>>()) |
1459 | | } |
1460 | 6.19k | TypeDefKind::List(ty) => Key::List(*ty), |
1461 | 106k | TypeDefKind::FixedSizeList(ty, size) => Key::FixedSizeList(*ty, *size), |
1462 | 28.4k | TypeDefKind::Option(t) => Key::Option(*t), |
1463 | 29.7k | TypeDefKind::Result(r) => Key::Result(r.ok, r.err), |
1464 | 7.81k | TypeDefKind::Future(ty) => Key::Future(*ty), |
1465 | 4.99k | TypeDefKind::Stream(ty) => Key::Stream(*ty), |
1466 | 0 | TypeDefKind::Unknown => unreachable!(), |
1467 | | }; |
1468 | 208k | let id = self.anon_types.entry(key).or_insert_with(|| { |
1469 | 89.9k | self.type_spans.push(span); |
1470 | 89.9k | self.types.alloc(ty) |
1471 | 89.9k | }); |
1472 | 208k | Type::Id(*id) |
1473 | 384k | } |
1474 | | |
1475 | 285k | fn docs(&mut self, doc: &super::Docs<'_>) -> Docs { |
1476 | 285k | let mut docs = vec![]; |
1477 | | |
1478 | 285k | for doc in doc.docs.iter() { |
1479 | 0 | let contents = match doc.strip_prefix("/**") { |
1480 | 0 | Some(doc) => doc.strip_suffix("*/").unwrap(), |
1481 | 0 | None => doc.trim_start_matches('/'), |
1482 | | }; |
1483 | | |
1484 | 0 | docs.push(contents.trim_end()); |
1485 | | } |
1486 | | |
1487 | | // Scan the (non-empty) doc lines to find the minimum amount of leading whitespace. |
1488 | | // This amount of whitespace will be removed from the start of all doc lines, |
1489 | | // normalizing the output while retaining intentional spacing added by the original authors. |
1490 | 285k | let min_leading_ws = docs |
1491 | 285k | .iter() |
1492 | 285k | .filter(|doc| !doc.is_empty()) |
1493 | 285k | .map(|doc| doc.bytes().take_while(|c| c.is_ascii_whitespace()).count()) |
1494 | 285k | .min() |
1495 | 285k | .unwrap_or(0); |
1496 | | |
1497 | 285k | if min_leading_ws > 0 { |
1498 | 0 | let leading_ws_pattern = " ".repeat(min_leading_ws); |
1499 | 0 | docs = docs |
1500 | 0 | .iter() |
1501 | 0 | .map(|doc| doc.strip_prefix(&leading_ws_pattern).unwrap_or(doc)) |
1502 | 0 | .collect(); |
1503 | 285k | } |
1504 | | |
1505 | 285k | let contents = if docs.is_empty() { |
1506 | 285k | None |
1507 | | } else { |
1508 | | // NB: this notably, through the use of `lines`, normalizes `\r\n` |
1509 | | // to `\n`. |
1510 | 0 | let mut contents = String::new(); |
1511 | 0 | for doc in docs { |
1512 | 0 | if doc.is_empty() { |
1513 | 0 | contents.push_str("\n"); |
1514 | 0 | } else { |
1515 | 0 | for line in doc.lines() { |
1516 | 0 | contents.push_str(line); |
1517 | 0 | contents.push_str("\n"); |
1518 | 0 | } |
1519 | | } |
1520 | | } |
1521 | 0 | while contents.ends_with("\n") { |
1522 | 0 | contents.pop(); |
1523 | 0 | } |
1524 | 0 | Some(contents) |
1525 | | }; |
1526 | 285k | Docs { contents } |
1527 | 285k | } |
1528 | | |
1529 | 157k | fn stability(&mut self, attrs: &[ast::Attribute<'_>]) -> Result<Stability> { |
1530 | 540 | match attrs { |
1531 | 157k | [] => Ok(Stability::Unknown), |
1532 | | |
1533 | 2.36k | [ast::Attribute::Since { version, .. }] => Ok(Stability::Stable { |
1534 | 2.36k | since: version.clone(), |
1535 | 2.36k | deprecated: None, |
1536 | 2.36k | }), |
1537 | | |
1538 | | [ |
1539 | 540 | ast::Attribute::Since { version, .. }, |
1540 | | ast::Attribute::Deprecated { |
1541 | 540 | version: deprecated, |
1542 | | .. |
1543 | | }, |
1544 | | ] |
1545 | | | [ |
1546 | | ast::Attribute::Deprecated { |
1547 | 515 | version: deprecated, |
1548 | | .. |
1549 | | }, |
1550 | 515 | ast::Attribute::Since { version, .. }, |
1551 | 1.05k | ] => Ok(Stability::Stable { |
1552 | 1.05k | since: version.clone(), |
1553 | 1.05k | deprecated: Some(deprecated.clone()), |
1554 | 1.05k | }), |
1555 | | |
1556 | 1.06k | [ast::Attribute::Unstable { feature, .. }] => Ok(Stability::Unstable { |
1557 | 1.06k | feature: feature.name.to_string(), |
1558 | 1.06k | deprecated: None, |
1559 | 1.06k | }), |
1560 | | |
1561 | | [ |
1562 | 0 | ast::Attribute::Unstable { feature, .. }, |
1563 | 0 | ast::Attribute::Deprecated { version, .. }, |
1564 | | ] |
1565 | | | [ |
1566 | 0 | ast::Attribute::Deprecated { version, .. }, |
1567 | 0 | ast::Attribute::Unstable { feature, .. }, |
1568 | 0 | ] => Ok(Stability::Unstable { |
1569 | 0 | feature: feature.name.to_string(), |
1570 | 0 | deprecated: Some(version.clone()), |
1571 | 0 | }), |
1572 | 0 | [ast::Attribute::Deprecated { span, .. }] => { |
1573 | 0 | bail!(Error::new( |
1574 | 0 | *span, |
1575 | 0 | "must pair @deprecated with either @since or @unstable", |
1576 | 0 | )) |
1577 | | } |
1578 | 0 | [_, b, ..] => { |
1579 | 0 | bail!(Error::new( |
1580 | 0 | b.span(), |
1581 | 0 | "unsupported combination of attributes", |
1582 | 0 | )) |
1583 | | } |
1584 | | } |
1585 | 157k | } |
1586 | | |
1587 | 23.5k | fn resolve_params( |
1588 | 23.5k | &mut self, |
1589 | 23.5k | params: &ParamList<'_>, |
1590 | 23.5k | kind: &FunctionKind, |
1591 | 23.5k | span: Span, |
1592 | 23.5k | ) -> Result<Vec<(String, Type)>> { |
1593 | 23.5k | let mut ret = IndexMap::new(); |
1594 | 23.5k | match *kind { |
1595 | | // These kinds of methods don't have any adjustments to the |
1596 | | // parameters, so do nothing here. |
1597 | | FunctionKind::Freestanding |
1598 | | | FunctionKind::AsyncFreestanding |
1599 | | | FunctionKind::Constructor(_) |
1600 | | | FunctionKind::Static(_) |
1601 | 21.3k | | FunctionKind::AsyncStatic(_) => {} |
1602 | | |
1603 | | // Methods automatically get a `self` initial argument so insert |
1604 | | // that here before processing the normal parameters. |
1605 | 2.20k | FunctionKind::Method(id) | FunctionKind::AsyncMethod(id) => { |
1606 | 2.20k | let kind = TypeDefKind::Handle(Handle::Borrow(id)); |
1607 | 2.20k | let stability = self.find_stability(&kind, &Stability::Unknown); |
1608 | 2.20k | let shared = self.anon_type_def( |
1609 | 2.20k | TypeDef { |
1610 | 2.20k | docs: Docs::default(), |
1611 | 2.20k | stability, |
1612 | 2.20k | kind, |
1613 | 2.20k | name: None, |
1614 | 2.20k | owner: TypeOwner::None, |
1615 | 2.20k | }, |
1616 | 2.20k | span, |
1617 | 2.20k | ); |
1618 | 2.20k | ret.insert("self".to_string(), shared); |
1619 | 2.20k | } |
1620 | | } |
1621 | 76.1k | for (name, ty) in params { |
1622 | 52.6k | let prev = ret.insert( |
1623 | 52.6k | name.name.to_string(), |
1624 | 52.6k | self.resolve_type(ty, &Stability::Unknown)?, |
1625 | | ); |
1626 | 52.6k | if prev.is_some() { |
1627 | 0 | bail!(Error::new( |
1628 | 0 | name.span, |
1629 | 0 | format!("param `{}` is defined more than once", name.name), |
1630 | 0 | )) |
1631 | 52.6k | } |
1632 | | } |
1633 | 23.5k | Ok(ret.into_iter().collect()) |
1634 | 23.5k | } |
1635 | | |
1636 | 23.5k | fn resolve_result( |
1637 | 23.5k | &mut self, |
1638 | 23.5k | result: &Option<ast::Type<'_>>, |
1639 | 23.5k | kind: &FunctionKind, |
1640 | 23.5k | _span: Span, |
1641 | 23.5k | ) -> Result<Option<Type>> { |
1642 | 23.5k | match *kind { |
1643 | | // These kinds of methods don't have any adjustments to the return |
1644 | | // values, so plumb them through as-is. |
1645 | | FunctionKind::Freestanding |
1646 | | | FunctionKind::AsyncFreestanding |
1647 | | | FunctionKind::Method(_) |
1648 | | | FunctionKind::AsyncMethod(_) |
1649 | | | FunctionKind::Static(_) |
1650 | 22.9k | | FunctionKind::AsyncStatic(_) => match result { |
1651 | 16.7k | Some(ty) => Ok(Some(self.resolve_type(ty, &Stability::Unknown)?)), |
1652 | 6.25k | None => Ok(None), |
1653 | | }, |
1654 | | |
1655 | 530 | FunctionKind::Constructor(id) => match result { |
1656 | | // When constructors don't define a return type, they're |
1657 | | // implicitly assumed to return an owned handle to the type |
1658 | | // they construct. |
1659 | 530 | None => Ok(Some(Type::Id(id))), |
1660 | | |
1661 | | // If a constructor does define a return type, it must be in the |
1662 | | // form of `-> result<R, E?>` where `R` is the resource being |
1663 | | // constructed and `E` is an optional error type. |
1664 | 0 | Some(ty) => Ok(Some(self.resolve_constructor_result(id, ty)?)), |
1665 | | }, |
1666 | | } |
1667 | 23.5k | } |
1668 | | |
1669 | 0 | fn resolve_constructor_result( |
1670 | 0 | &mut self, |
1671 | 0 | resource_id: TypeId, |
1672 | 0 | result_ast: &ast::Type<'_>, |
1673 | 0 | ) -> Result<Type> { |
1674 | 0 | let result = self.resolve_type(result_ast, &Stability::Unknown)?; |
1675 | 0 | let ok_type = match result { |
1676 | 0 | Type::Id(id) => match &self.types[id].kind { |
1677 | 0 | TypeDefKind::Result(r) => Some(r.ok), |
1678 | 0 | _ => None, |
1679 | | }, |
1680 | 0 | _ => None, |
1681 | | }; |
1682 | 0 | let Some(ok_type) = ok_type else { |
1683 | 0 | bail!(Error::new( |
1684 | 0 | result_ast.span(), |
1685 | 0 | "if a constructor return type is declared it must be a `result`", |
1686 | 0 | )); |
1687 | | }; |
1688 | 0 | match ok_type { |
1689 | 0 | Some(Type::Id(ok_id)) if resource_id == ok_id => Ok(result), |
1690 | | _ => { |
1691 | 0 | let ok_span = |
1692 | 0 | if let ast::Type::Result(ast::Result_ { ok: Some(ok), .. }) = result_ast { |
1693 | 0 | ok.span() |
1694 | | } else { |
1695 | 0 | result_ast.span() |
1696 | | }; |
1697 | 0 | bail!(Error::new( |
1698 | 0 | ok_span, |
1699 | 0 | "the `ok` type must be the resource being constructed", |
1700 | 0 | )); |
1701 | | } |
1702 | | } |
1703 | 0 | } |
1704 | | } |
1705 | | |
1706 | 103k | fn collect_deps<'a>(ty: &ast::Type<'a>, deps: &mut Vec<ast::Id<'a>>) { |
1707 | 103k | match ty { |
1708 | | ast::Type::Bool(_) |
1709 | | | ast::Type::U8(_) |
1710 | | | ast::Type::U16(_) |
1711 | | | ast::Type::U32(_) |
1712 | | | ast::Type::U64(_) |
1713 | | | ast::Type::S8(_) |
1714 | | | ast::Type::S16(_) |
1715 | | | ast::Type::S32(_) |
1716 | | | ast::Type::S64(_) |
1717 | | | ast::Type::F32(_) |
1718 | | | ast::Type::F64(_) |
1719 | | | ast::Type::Char(_) |
1720 | | | ast::Type::String(_) |
1721 | | | ast::Type::Flags(_) |
1722 | | | ast::Type::Enum(_) |
1723 | 73.1k | | ast::Type::ErrorContext(_) => {} |
1724 | 1.22k | ast::Type::Name(name) => deps.push(name.clone()), |
1725 | 20 | ast::Type::Handle(handle) => match handle { |
1726 | 20 | ast::Handle::Own { resource } => deps.push(resource.clone()), |
1727 | 0 | ast::Handle::Borrow { resource } => deps.push(resource.clone()), |
1728 | | }, |
1729 | 2.48k | ast::Type::Resource(_) => {} |
1730 | 4.13k | ast::Type::Record(record) => { |
1731 | 11.3k | for field in record.fields.iter() { |
1732 | 11.3k | collect_deps(&field.ty, deps); |
1733 | 11.3k | } |
1734 | | } |
1735 | 5.75k | ast::Type::Tuple(t) => { |
1736 | 24.2k | for ty in t.types.iter() { |
1737 | 24.2k | collect_deps(ty, deps); |
1738 | 24.2k | } |
1739 | | } |
1740 | 5.84k | ast::Type::Variant(variant) => { |
1741 | 20.2k | for case in variant.cases.iter() { |
1742 | 20.2k | if let Some(ty) = &case.ty { |
1743 | 17.2k | collect_deps(ty, deps); |
1744 | 17.2k | } |
1745 | | } |
1746 | | } |
1747 | 5.13k | ast::Type::Option(ast::Option_ { ty, .. }) |
1748 | 532 | | ast::Type::List(ast::List { ty, .. }) |
1749 | 5.86k | | ast::Type::FixedSizeList(ast::FixedSizeList { ty, .. }) => collect_deps(ty, deps), |
1750 | 4.45k | ast::Type::Result(r) => { |
1751 | 4.45k | if let Some(ty) = &r.ok { |
1752 | 3.49k | collect_deps(ty, deps); |
1753 | 3.49k | } |
1754 | 4.45k | if let Some(ty) = &r.err { |
1755 | 3.53k | collect_deps(ty, deps); |
1756 | 3.53k | } |
1757 | | } |
1758 | 548 | ast::Type::Future(t) => { |
1759 | 548 | if let Some(t) = &t.ty { |
1760 | 229 | collect_deps(t, deps) |
1761 | 319 | } |
1762 | | } |
1763 | 345 | ast::Type::Stream(s) => { |
1764 | 345 | if let Some(t) = &s.ty { |
1765 | 345 | collect_deps(t, deps) |
1766 | 0 | } |
1767 | | } |
1768 | | } |
1769 | 103k | } |