1 | use super::{ParamList, ResultList, 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 | Option(Type), |
96 | Result(Option<Type>, Option<Type>), |
97 | Future(Option<Type>), |
98 | Stream(Type), |
99 | ErrorContext, |
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 | 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 | if let Some(cur) = &file.package_id { |
118 | let cur_name = cur.package_name(); |
119 | if let Some((prev, _)) = &self.package_name { |
120 | if cur_name != *prev { |
121 | bail!(Error::new( |
122 | cur.span, |
123 | format!( |
124 | "package identifier ` {cur_name}` does not match \ |
125 | previous package name of ` {prev}`" |
126 | ), |
127 | )) |
128 | } |
129 | } |
130 | self.package_name = Some((cur_name, cur.span)); |
131 | |
132 | // At most one 'package' item can have doc comments. |
133 | let docs = self.docs(&cur.docs); |
134 | if docs.contents.is_some() { |
135 | if self.package_docs.contents.is_some() { |
136 | bail!(Error::new( |
137 | cur.docs.span, |
138 | "found doc comments on multiple 'package' items" |
139 | )) |
140 | } |
141 | self.package_docs = docs; |
142 | } |
143 | } |
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 | for item in file.decl_list.items.iter() { |
149 | let span = match item { |
150 | ast::AstItem::Package(pkg) => pkg.package_id.as_ref().unwrap().span, |
151 | _ => continue, |
152 | }; |
153 | bail!(Error::new( |
154 | span, |
155 | "nested packages must be placed at the top-level" |
156 | )) |
157 | } |
158 | |
159 | self.decl_lists.push(file.decl_list); |
160 | Ok(()) |
161 | } |
162 | |
163 | pub(crate) fn resolve(&mut self) -> Result<UnresolvedPackage> { |
164 | // At least one of the WIT files must have a `package` annotation. |
165 | let (name, package_name_span) = match &self.package_name { |
166 | Some(name) => name.clone(), |
167 | None => { |
168 | 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 | let decl_lists = mem::take(&mut self.decl_lists); |
177 | self.populate_foreign_deps(&decl_lists); |
178 | let (iface_order, world_order) = self.populate_ast_items(&decl_lists)?; |
179 | 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 | let mut iface_id_to_ast = IndexMap::new(); |
185 | let mut world_id_to_ast = IndexMap::new(); |
186 | for (i, decl_list) in decl_lists.iter().enumerate() { |
187 | for item in decl_list.items.iter() { |
188 | match item { |
189 | ast::AstItem::Interface(iface) => { |
190 | let id = match self.ast_items[i][iface.name.name] { |
191 | AstItem::Interface(id) => id, |
192 | AstItem::World(_) => unreachable!(), |
193 | }; |
194 | iface_id_to_ast.insert(id, (iface, i)); |
195 | } |
196 | ast::AstItem::World(world) => { |
197 | let id = match self.ast_items[i][world.name.name] { |
198 | AstItem::World(id) => id, |
199 | AstItem::Interface(_) => unreachable!(), |
200 | }; |
201 | world_id_to_ast.insert(id, (world, i)); |
202 | } |
203 | ast::AstItem::Use(_) => {} |
204 | ast::AstItem::Package(_) => unreachable!(), |
205 | } |
206 | } |
207 | } |
208 | |
209 | for id in iface_order { |
210 | let (interface, i) = &iface_id_to_ast[&id]; |
211 | self.cur_ast_index = *i; |
212 | self.resolve_interface(id, &interface.items, &interface.docs, &interface.attributes)?; |
213 | } |
214 | |
215 | for id in world_order { |
216 | let (world, i) = &world_id_to_ast[&id]; |
217 | self.cur_ast_index = *i; |
218 | self.resolve_world(id, world)?; |
219 | } |
220 | |
221 | self.decl_lists = decl_lists; |
222 | Ok(UnresolvedPackage { |
223 | package_name_span, |
224 | name, |
225 | docs: mem::take(&mut self.package_docs), |
226 | worlds: mem::take(&mut self.worlds), |
227 | types: mem::take(&mut self.types), |
228 | interfaces: mem::take(&mut self.interfaces), |
229 | foreign_deps: self |
230 | .foreign_deps |
231 | .iter() |
232 | .map(|(name, deps)| { |
233 | ( |
234 | name.clone(), |
235 | deps.iter() |
236 | .map(|(name, id)| (name.to_string(), *id)) |
237 | .collect(), |
238 | ) |
239 | }) |
240 | .collect(), |
241 | unknown_type_spans: mem::take(&mut self.unknown_type_spans), |
242 | interface_spans: mem::take(&mut self.interface_spans), |
243 | world_spans: mem::take(&mut self.world_spans), |
244 | type_spans: mem::take(&mut self.type_spans), |
245 | foreign_dep_spans: mem::take(&mut self.foreign_dep_spans), |
246 | required_resource_types: mem::take(&mut self.required_resource_types), |
247 | }) |
248 | } |
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 | fn populate_foreign_deps(&mut self, decl_lists: &[ast::DeclList<'a>]) { |
255 | let mut foreign_deps = mem::take(&mut self.foreign_deps); |
256 | let mut foreign_interfaces = mem::take(&mut self.foreign_interfaces); |
257 | let mut foreign_worlds = mem::take(&mut self.foreign_worlds); |
258 | for decl_list in decl_lists { |
259 | decl_list |
260 | .for_each_path(&mut |_, path, _names, world_or_iface| { |
261 | let (id, name) = match path { |
262 | ast::UsePath::Package { id, name } => (id, name), |
263 | _ => return Ok(()), |
264 | }; |
265 | |
266 | let deps = foreign_deps.entry(id.package_name()).or_insert_with(|| { |
267 | self.foreign_dep_spans.push(id.span); |
268 | IndexMap::new() |
269 | }); |
270 | let id = *deps.entry(name.name).or_insert_with(|| { |
271 | match world_or_iface { |
272 | WorldOrInterface::World => { |
273 | log::trace!( |
274 | "creating a world for foreign dep: {}/ {}" , |
275 | id.package_name(), |
276 | name.name |
277 | ); |
278 | 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 | log::trace!( |
284 | "creating an interface for foreign dep: {}/ {}" , |
285 | id.package_name(), |
286 | name.name |
287 | ); |
288 | AstItem::Interface(self.alloc_interface(name.span)) |
289 | } |
290 | } |
291 | }); |
292 | |
293 | let _ = match id { |
294 | AstItem::Interface(id) => foreign_interfaces.insert(id), |
295 | AstItem::World(id) => foreign_worlds.insert(id), |
296 | }; |
297 | |
298 | Ok(()) |
299 | }) |
300 | .unwrap(); |
301 | } |
302 | self.foreign_deps = foreign_deps; |
303 | self.foreign_interfaces = foreign_interfaces; |
304 | self.foreign_worlds = foreign_worlds; |
305 | } |
306 | |
307 | fn alloc_interface(&mut self, span: Span) -> InterfaceId { |
308 | self.interface_types.push(IndexMap::new()); |
309 | self.interface_spans.push(InterfaceSpan { |
310 | span, |
311 | funcs: Vec::new(), |
312 | }); |
313 | self.interfaces.alloc(Interface { |
314 | name: None, |
315 | types: IndexMap::new(), |
316 | docs: Docs::default(), |
317 | stability: Default::default(), |
318 | functions: IndexMap::new(), |
319 | package: None, |
320 | }) |
321 | } |
322 | |
323 | fn alloc_world(&mut self, span: Span) -> WorldId { |
324 | self.world_spans.push(WorldSpan { |
325 | span, |
326 | imports: Vec::new(), |
327 | exports: Vec::new(), |
328 | includes: Vec::new(), |
329 | }); |
330 | self.worlds.alloc(World { |
331 | name: String::new(), |
332 | docs: Docs::default(), |
333 | exports: IndexMap::new(), |
334 | imports: IndexMap::new(), |
335 | package: None, |
336 | includes: Default::default(), |
337 | include_names: Default::default(), |
338 | stability: Default::default(), |
339 | }) |
340 | } |
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 | fn populate_ast_items( |
346 | &mut self, |
347 | decl_lists: &[ast::DeclList<'a>], |
348 | ) -> Result<(Vec<InterfaceId>, Vec<WorldId>)> { |
349 | 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 | let mut names = HashMap::new(); |
354 | let mut decl_list_namespaces = Vec::new(); |
355 | let mut order = IndexMap::new(); |
356 | for decl_list in decl_lists { |
357 | let mut decl_list_ns = IndexMap::new(); |
358 | for item in decl_list.items.iter() { |
359 | match item { |
360 | ast::AstItem::Interface(i) => { |
361 | if package_items.insert(i.name.name, i.name.span).is_some() { |
362 | bail!(Error::new( |
363 | i.name.span, |
364 | format!("duplicate item named ` {}`" , i.name.name), |
365 | )) |
366 | } |
367 | let prev = decl_list_ns.insert(i.name.name, ()); |
368 | assert!(prev.is_none()); |
369 | let prev = order.insert(i.name.name, Vec::new()); |
370 | assert!(prev.is_none()); |
371 | let prev = names.insert(i.name.name, item); |
372 | assert!(prev.is_none()); |
373 | } |
374 | ast::AstItem::World(w) => { |
375 | if package_items.insert(w.name.name, w.name.span).is_some() { |
376 | bail!(Error::new( |
377 | w.name.span, |
378 | format!("duplicate item named ` {}`" , w.name.name), |
379 | )) |
380 | } |
381 | let prev = decl_list_ns.insert(w.name.name, ()); |
382 | assert!(prev.is_none()); |
383 | let prev = order.insert(w.name.name, Vec::new()); |
384 | assert!(prev.is_none()); |
385 | let prev = names.insert(w.name.name, item); |
386 | assert!(prev.is_none()); |
387 | } |
388 | // These are processed down below. |
389 | ast::AstItem::Use(_) => {} |
390 | |
391 | ast::AstItem::Package(_) => unreachable!(), |
392 | } |
393 | } |
394 | 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 | 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 | let mut decl_list_ns = IndexMap::new(); |
412 | for item in decl_list.items.iter() { |
413 | let (name, src) = match item { |
414 | ast::AstItem::Use(u) => { |
415 | let name = u.as_.as_ref().unwrap_or(u.item.name()); |
416 | let src = match &u.item { |
417 | ast::UsePath::Id(id) => ItemSource::Local(id.clone()), |
418 | ast::UsePath::Package { .. } => ItemSource::Foreign, |
419 | }; |
420 | (name, src) |
421 | } |
422 | ast::AstItem::Interface(i) => (&i.name, ItemSource::Local(i.name.clone())), |
423 | ast::AstItem::World(w) => (&w.name, ItemSource::Local(w.name.clone())), |
424 | ast::AstItem::Package(_) => unreachable!(), |
425 | }; |
426 | if decl_list_ns.insert(name.name, (name.span, src)).is_some() { |
427 | bail!(Error::new( |
428 | name.span, |
429 | format!("duplicate name ` {}` in this file" , name.name), |
430 | )); |
431 | } |
432 | } |
433 | |
434 | // With this file's namespace information look at all `use` paths |
435 | // and record dependencies between interfaces. |
436 | decl_list.for_each_path(&mut |iface, 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 | let iface = match iface { |
441 | Some(name) => name, |
442 | None => return Ok(()), |
443 | }; |
444 | let used_name = match path { |
445 | ast::UsePath::Id(id) => id, |
446 | ast::UsePath::Package { .. } => return Ok(()), |
447 | }; |
448 | match decl_list_ns.get(used_name.name) { |
449 | Some((_, ItemSource::Foreign)) => return Ok(()), |
450 | Some((_, ItemSource::Local(id))) => { |
451 | order[iface.name].push(id.clone()); |
452 | } |
453 | None => match package_items.get(used_name.name) { |
454 | Some(_) => { |
455 | order[iface.name].push(used_name.clone()); |
456 | } |
457 | None => { |
458 | bail!(Error::new( |
459 | used_name.span, |
460 | format!( |
461 | "interface or world ` {name}` not found in package" , |
462 | name = used_name.name |
463 | ), |
464 | )) |
465 | } |
466 | }, |
467 | } |
468 | Ok(()) |
469 | })?; |
470 | } |
471 | |
472 | let order = toposort("interface or world" , &order)?; |
473 | 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 | let mut ids = IndexMap::new(); |
479 | let mut iface_id_order = Vec::new(); |
480 | let mut world_id_order = Vec::new(); |
481 | for name in order { |
482 | match names.get(name).unwrap() { |
483 | ast::AstItem::Interface(_) => { |
484 | let id = self.alloc_interface(package_items[name]); |
485 | self.interfaces[id].name = Some(name.to_string()); |
486 | let prev = ids.insert(name, AstItem::Interface(id)); |
487 | assert!(prev.is_none()); |
488 | iface_id_order.push(id); |
489 | } |
490 | ast::AstItem::World(_) => { |
491 | let id = self.alloc_world(package_items[name]); |
492 | self.worlds[id].name = name.to_string(); |
493 | let prev = ids.insert(name, AstItem::World(id)); |
494 | assert!(prev.is_none()); |
495 | world_id_order.push(id); |
496 | } |
497 | ast::AstItem::Use(_) | ast::AstItem::Package(_) => unreachable!(), |
498 | }; |
499 | } |
500 | for decl_list in decl_lists { |
501 | let mut items = IndexMap::new(); |
502 | for item in decl_list.items.iter() { |
503 | let (name, ast_item) = match item { |
504 | ast::AstItem::Use(u) => { |
505 | if !u.attributes.is_empty() { |
506 | bail!(Error::new( |
507 | u.span, |
508 | format!("attributes not allowed on top-level use" ), |
509 | )) |
510 | } |
511 | let name = u.as_.as_ref().unwrap_or(u.item.name()); |
512 | let item = match &u.item { |
513 | ast::UsePath::Id(name) => *ids.get(name.name).ok_or_else(|| { |
514 | Error::new( |
515 | name.span, |
516 | format!( |
517 | "interface or world ` {name}` does not exist" , |
518 | name = name.name |
519 | ), |
520 | ) |
521 | })?, |
522 | ast::UsePath::Package { id, name } => { |
523 | self.foreign_deps[&id.package_name()][name.name] |
524 | } |
525 | }; |
526 | (name.name, item) |
527 | } |
528 | ast::AstItem::Interface(i) => { |
529 | let iface_item = ids[i.name.name]; |
530 | assert!(matches!(iface_item, AstItem::Interface(_))); |
531 | (i.name.name, iface_item) |
532 | } |
533 | ast::AstItem::World(w) => { |
534 | let world_item = ids[w.name.name]; |
535 | assert!(matches!(world_item, AstItem::World(_))); |
536 | (w.name.name, world_item) |
537 | } |
538 | ast::AstItem::Package(_) => unreachable!(), |
539 | }; |
540 | let prev = items.insert(name, ast_item); |
541 | assert!(prev.is_none()); |
542 | |
543 | // Items defined via `use` don't go into the package namespace, |
544 | // only the file namespace. |
545 | if !matches!(item, ast::AstItem::Use(_)) { |
546 | let prev = self.package_items.insert(name, ast_item); |
547 | assert!(prev.is_none()); |
548 | } |
549 | } |
550 | self.ast_items.push(items); |
551 | } |
552 | Ok((iface_id_order, world_id_order)) |
553 | } |
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 | fn populate_foreign_types(&mut self, decl_lists: &[ast::DeclList<'a>]) -> Result<()> { |
562 | for (i, decl_list) in decl_lists.iter().enumerate() { |
563 | self.cur_ast_index = i; |
564 | decl_list.for_each_path(&mut |_, path, names, _| { |
565 | let names = match names { |
566 | Some(names) => names, |
567 | None => return Ok(()), |
568 | }; |
569 | let (item, name, span) = self.resolve_ast_item_path(path)?; |
570 | let iface = self.extract_iface_from_item(&item, &name, span)?; |
571 | if !self.foreign_interfaces.contains(&iface) { |
572 | return Ok(()); |
573 | } |
574 | |
575 | let lookup = &mut self.interface_types[iface.index()]; |
576 | for name in names { |
577 | // If this name has already been defined then use that prior |
578 | // definition, otherwise create a new type with an unknown |
579 | // representation and insert it into the various maps. |
580 | if lookup.contains_key(name.name.name) { |
581 | continue; |
582 | } |
583 | let id = self.types.alloc(TypeDef { |
584 | docs: Docs::default(), |
585 | stability: Default::default(), |
586 | kind: TypeDefKind::Unknown, |
587 | name: Some(name.name.name.to_string()), |
588 | owner: TypeOwner::Interface(iface), |
589 | }); |
590 | self.unknown_type_spans.push(name.name.span); |
591 | self.type_spans.push(name.name.span); |
592 | lookup.insert(name.name.name, (TypeOrItem::Type(id), name.name.span)); |
593 | self.interfaces[iface] |
594 | .types |
595 | .insert(name.name.name.to_string(), id); |
596 | } |
597 | |
598 | Ok(()) |
599 | })?; |
600 | } |
601 | Ok(()) |
602 | } |
603 | |
604 | fn resolve_world(&mut self, world_id: WorldId, world: &ast::World<'a>) -> Result<WorldId> { |
605 | let docs = self.docs(&world.docs); |
606 | self.worlds[world_id].docs = docs; |
607 | let stability = self.stability(&world.attributes)?; |
608 | self.worlds[world_id].stability = stability; |
609 | |
610 | self.resolve_types( |
611 | TypeOwner::World(world_id), |
612 | world.items.iter().filter_map(|i| match i { |
613 | ast::WorldItem::Use(u) => Some(TypeItem::Use(u)), |
614 | ast::WorldItem::Type(t) => Some(TypeItem::Def(t)), |
615 | ast::WorldItem::Import(_) | ast::WorldItem::Export(_) => None, |
616 | // should be handled in `wit-parser::resolve` |
617 | ast::WorldItem::Include(_) => None, |
618 | }), |
619 | )?; |
620 | |
621 | // resolve include items |
622 | let items = world.items.iter().filter_map(|i| match i { |
623 | ast::WorldItem::Include(i) => Some(i), |
624 | _ => None, |
625 | }); |
626 | for include in items { |
627 | self.resolve_include(world_id, include)?; |
628 | } |
629 | |
630 | let mut export_spans = Vec::new(); |
631 | let mut import_spans = Vec::new(); |
632 | let mut import_names = HashMap::new(); |
633 | let mut export_names = HashMap::new(); |
634 | for (name, (item, span)) in self.type_lookup.iter() { |
635 | match *item { |
636 | TypeOrItem::Type(id) => { |
637 | let prev = import_names.insert(*name, "import" ); |
638 | if let Some(prev) = prev { |
639 | bail!(Error::new( |
640 | *span, |
641 | format!("import ` {name}` conflicts with prior {prev} of same name" ,), |
642 | )) |
643 | } |
644 | self.worlds[world_id] |
645 | .imports |
646 | .insert(WorldKey::Name(name.to_string()), WorldItem::Type(id)); |
647 | import_spans.push(*span); |
648 | } |
649 | TypeOrItem::Item(_) => unreachable!(), |
650 | } |
651 | } |
652 | |
653 | let mut imported_interfaces = HashSet::new(); |
654 | let mut exported_interfaces = HashSet::new(); |
655 | for item in world.items.iter() { |
656 | let (docs, attrs, kind, desc, spans, interfaces, names) = match item { |
657 | ast::WorldItem::Import(import) => ( |
658 | &import.docs, |
659 | &import.attributes, |
660 | &import.kind, |
661 | "import" , |
662 | &mut import_spans, |
663 | &mut imported_interfaces, |
664 | &mut import_names, |
665 | ), |
666 | ast::WorldItem::Export(export) => ( |
667 | &export.docs, |
668 | &export.attributes, |
669 | &export.kind, |
670 | "export" , |
671 | &mut export_spans, |
672 | &mut exported_interfaces, |
673 | &mut export_names, |
674 | ), |
675 | |
676 | ast::WorldItem::Type(ast::TypeDef { |
677 | name, |
678 | ty: ast::Type::Resource(r), |
679 | .. |
680 | }) => { |
681 | for func in r.funcs.iter() { |
682 | import_spans.push(func.named_func().name.span); |
683 | let func = self.resolve_resource_func(func, name)?; |
684 | let prev = self.worlds[world_id] |
685 | .imports |
686 | .insert(WorldKey::Name(func.name.clone()), WorldItem::Function(func)); |
687 | // Resource names themselves are unique, and methods are |
688 | // uniquely named, so this should be possible to assert |
689 | // at this point and never trip. |
690 | assert!(prev.is_none()); |
691 | } |
692 | continue; |
693 | } |
694 | |
695 | // handled in `resolve_types` |
696 | ast::WorldItem::Use(_) | ast::WorldItem::Type(_) | ast::WorldItem::Include(_) => { |
697 | continue |
698 | } |
699 | }; |
700 | let key = match kind { |
701 | ast::ExternKind::Interface(name, _) | ast::ExternKind::Func(name, _) => { |
702 | let prev = names.insert(name.name, desc); |
703 | if let Some(prev) = prev { |
704 | bail!(Error::new( |
705 | kind.span(), |
706 | format!( |
707 | " {desc} ` {name}` conflicts with prior {prev} of same name" , |
708 | name = name.name |
709 | ), |
710 | )) |
711 | } |
712 | WorldKey::Name(name.name.to_string()) |
713 | } |
714 | ast::ExternKind::Path(path) => { |
715 | let (item, name, span) = self.resolve_ast_item_path(path)?; |
716 | let id = self.extract_iface_from_item(&item, &name, span)?; |
717 | WorldKey::Interface(id) |
718 | } |
719 | }; |
720 | let world_item = self.resolve_world_item(docs, attrs, kind)?; |
721 | if let WorldItem::Interface { id, .. } = world_item { |
722 | if !interfaces.insert(id) { |
723 | bail!(Error::new( |
724 | kind.span(), |
725 | format!("interface cannot be {desc}ed more than once" ), |
726 | )) |
727 | } |
728 | } |
729 | let dst = if desc == "import" { |
730 | &mut self.worlds[world_id].imports |
731 | } else { |
732 | &mut self.worlds[world_id].exports |
733 | }; |
734 | let prev = dst.insert(key, world_item); |
735 | assert!(prev.is_none()); |
736 | spans.push(kind.span()); |
737 | } |
738 | self.world_spans[world_id.index()].imports = import_spans; |
739 | self.world_spans[world_id.index()].exports = export_spans; |
740 | self.type_lookup.clear(); |
741 | |
742 | Ok(world_id) |
743 | } |
744 | |
745 | fn resolve_world_item( |
746 | &mut self, |
747 | docs: &ast::Docs<'a>, |
748 | attrs: &[ast::Attribute<'a>], |
749 | kind: &ast::ExternKind<'a>, |
750 | ) -> Result<WorldItem> { |
751 | match kind { |
752 | ast::ExternKind::Interface(name, items) => { |
753 | let prev = mem::take(&mut self.type_lookup); |
754 | let id = self.alloc_interface(name.span); |
755 | self.resolve_interface(id, items, docs, attrs)?; |
756 | self.type_lookup = prev; |
757 | let stability = self.interfaces[id].stability.clone(); |
758 | Ok(WorldItem::Interface { id, stability }) |
759 | } |
760 | ast::ExternKind::Path(path) => { |
761 | let stability = self.stability(attrs)?; |
762 | let (item, name, span) = self.resolve_ast_item_path(path)?; |
763 | let id = self.extract_iface_from_item(&item, &name, span)?; |
764 | Ok(WorldItem::Interface { id, stability }) |
765 | } |
766 | ast::ExternKind::Func(name, func) => { |
767 | let func = self.resolve_function( |
768 | docs, |
769 | attrs, |
770 | name.name, |
771 | func, |
772 | FunctionKind::Freestanding, |
773 | )?; |
774 | Ok(WorldItem::Function(func)) |
775 | } |
776 | } |
777 | } |
778 | |
779 | fn resolve_interface( |
780 | &mut self, |
781 | interface_id: InterfaceId, |
782 | fields: &[ast::InterfaceItem<'a>], |
783 | docs: &ast::Docs<'a>, |
784 | attrs: &[ast::Attribute<'a>], |
785 | ) -> Result<()> { |
786 | let docs = self.docs(docs); |
787 | self.interfaces[interface_id].docs = docs; |
788 | let stability = self.stability(attrs)?; |
789 | self.interfaces[interface_id].stability = stability; |
790 | |
791 | self.resolve_types( |
792 | TypeOwner::Interface(interface_id), |
793 | fields.iter().filter_map(|i| match i { |
794 | ast::InterfaceItem::Use(u) => Some(TypeItem::Use(u)), |
795 | ast::InterfaceItem::TypeDef(t) => Some(TypeItem::Def(t)), |
796 | ast::InterfaceItem::Func(_) => None, |
797 | }), |
798 | )?; |
799 | |
800 | for (name, (ty, _)) in self.type_lookup.iter() { |
801 | match *ty { |
802 | TypeOrItem::Type(id) => { |
803 | self.interfaces[interface_id] |
804 | .types |
805 | .insert(name.to_string(), id); |
806 | } |
807 | TypeOrItem::Item(_) => unreachable!(), |
808 | } |
809 | } |
810 | |
811 | // Finally process all function definitions now that all types are |
812 | // defined. |
813 | let mut funcs = Vec::new(); |
814 | for field in fields { |
815 | match field { |
816 | ast::InterfaceItem::Func(f) => { |
817 | self.define_interface_name(&f.name, TypeOrItem::Item("function" ))?; |
818 | funcs.push(self.resolve_function( |
819 | &f.docs, |
820 | &f.attributes, |
821 | &f.name.name, |
822 | &f.func, |
823 | FunctionKind::Freestanding, |
824 | )?); |
825 | self.interface_spans[interface_id.index()] |
826 | .funcs |
827 | .push(f.name.span); |
828 | } |
829 | ast::InterfaceItem::Use(_) => {} |
830 | ast::InterfaceItem::TypeDef(ast::TypeDef { |
831 | name, |
832 | ty: ast::Type::Resource(r), |
833 | .. |
834 | }) => { |
835 | for func in r.funcs.iter() { |
836 | funcs.push(self.resolve_resource_func(func, name)?); |
837 | self.interface_spans[interface_id.index()] |
838 | .funcs |
839 | .push(func.named_func().name.span); |
840 | } |
841 | } |
842 | ast::InterfaceItem::TypeDef(_) => {} |
843 | } |
844 | } |
845 | for func in funcs { |
846 | let prev = self.interfaces[interface_id] |
847 | .functions |
848 | .insert(func.name.clone(), func); |
849 | assert!(prev.is_none()); |
850 | } |
851 | |
852 | let lookup = mem::take(&mut self.type_lookup); |
853 | self.interface_types[interface_id.index()] = lookup; |
854 | |
855 | Ok(()) |
856 | } |
857 | |
858 | fn resolve_types<'b>( |
859 | &mut self, |
860 | owner: TypeOwner, |
861 | fields: impl Iterator<Item = TypeItem<'a, 'b>> + Clone, |
862 | ) -> Result<()> |
863 | where |
864 | 'a: 'b, |
865 | { |
866 | assert!(self.type_lookup.is_empty()); |
867 | |
868 | // First, populate our namespace with `use` statements |
869 | for field in fields.clone() { |
870 | match field { |
871 | TypeItem::Use(u) => { |
872 | self.resolve_use(owner, u)?; |
873 | } |
874 | TypeItem::Def(_) => {} |
875 | } |
876 | } |
877 | |
878 | // Next determine dependencies between types, perform a topological |
879 | // sort, and then define all types. This will define types in a |
880 | // topological fashion, forbid cycles, and weed out references to |
881 | // undefined types all in one go. |
882 | let mut type_deps = IndexMap::new(); |
883 | let mut type_defs = IndexMap::new(); |
884 | for field in fields { |
885 | match field { |
886 | TypeItem::Def(t) => { |
887 | let prev = type_defs.insert(t.name.name, Some(t)); |
888 | if prev.is_some() { |
889 | bail!(Error::new( |
890 | t.name.span, |
891 | format!("name ` {}` is defined more than once" , t.name.name), |
892 | )) |
893 | } |
894 | let mut deps = Vec::new(); |
895 | collect_deps(&t.ty, &mut deps); |
896 | type_deps.insert(t.name.name, deps); |
897 | } |
898 | TypeItem::Use(u) => { |
899 | for name in u.names.iter() { |
900 | let name = name.as_.as_ref().unwrap_or(&name.name); |
901 | type_deps.insert(name.name, Vec::new()); |
902 | type_defs.insert(name.name, None); |
903 | } |
904 | } |
905 | } |
906 | } |
907 | let order = toposort("type" , &type_deps).map_err(attach_old_float_type_context)?; |
908 | for ty in order { |
909 | let def = match type_defs.swap_remove(&ty).unwrap() { |
910 | Some(def) => def, |
911 | None => continue, |
912 | }; |
913 | let docs = self.docs(&def.docs); |
914 | let stability = self.stability(&def.attributes)?; |
915 | let kind = self.resolve_type_def(&def.ty, &stability)?; |
916 | let id = self.types.alloc(TypeDef { |
917 | docs, |
918 | stability, |
919 | kind, |
920 | name: Some(def.name.name.to_string()), |
921 | owner, |
922 | }); |
923 | self.type_spans.push(def.name.span); |
924 | self.define_interface_name(&def.name, TypeOrItem::Type(id))?; |
925 | } |
926 | return Ok(()); |
927 | |
928 | fn attach_old_float_type_context(err: ast::toposort::Error) -> anyhow::Error { |
929 | let name = match &err { |
930 | ast::toposort::Error::NonexistentDep { name, .. } => name, |
931 | _ => return err.into(), |
932 | }; |
933 | let new = match name.as_str() { |
934 | "float32" => "f32" , |
935 | "float64" => "f64" , |
936 | _ => return err.into(), |
937 | }; |
938 | |
939 | let context = format!( |
940 | "the ` {name}` type has been renamed to ` {new}` and is \ |
941 | no longer accepted, but the `WIT_REQUIRE_F32_F64=0` \ |
942 | environment variable can be used to temporarily \ |
943 | disable this error" |
944 | ); |
945 | anyhow::Error::from(err).context(context) |
946 | } |
947 | } |
948 | |
949 | fn resolve_use(&mut self, owner: TypeOwner, u: &ast::Use<'a>) -> Result<()> { |
950 | let (item, name, span) = self.resolve_ast_item_path(&u.from)?; |
951 | let use_from = self.extract_iface_from_item(&item, &name, span)?; |
952 | let stability = self.stability(&u.attributes)?; |
953 | |
954 | for name in u.names.iter() { |
955 | let lookup = &self.interface_types[use_from.index()]; |
956 | let id = match lookup.get(name.name.name) { |
957 | Some((TypeOrItem::Type(id), _)) => *id, |
958 | Some((TypeOrItem::Item(s), _)) => { |
959 | bail!(Error::new( |
960 | name.name.span, |
961 | format!("cannot import {s} ` {}`" , name.name.name), |
962 | )) |
963 | } |
964 | None => bail!(Error::new( |
965 | name.name.span, |
966 | format!("name ` {}` is not defined" , name.name.name), |
967 | )), |
968 | }; |
969 | self.type_spans.push(name.name.span); |
970 | let name = name.as_.as_ref().unwrap_or(&name.name); |
971 | let id = self.types.alloc(TypeDef { |
972 | docs: Docs::default(), |
973 | stability: stability.clone(), |
974 | kind: TypeDefKind::Type(Type::Id(id)), |
975 | name: Some(name.name.to_string()), |
976 | owner, |
977 | }); |
978 | self.define_interface_name(name, TypeOrItem::Type(id))?; |
979 | } |
980 | Ok(()) |
981 | } |
982 | |
983 | /// For each name in the `include`, resolve the path of the include, add it to the self.includes |
984 | fn resolve_include(&mut self, world_id: WorldId, i: &ast::Include<'a>) -> Result<()> { |
985 | let stability = self.stability(&i.attributes)?; |
986 | let (item, name, span) = self.resolve_ast_item_path(&i.from)?; |
987 | let include_from = self.extract_world_from_item(&item, &name, span)?; |
988 | self.worlds[world_id] |
989 | .includes |
990 | .push((stability, include_from)); |
991 | self.worlds[world_id].include_names.push( |
992 | i.names |
993 | .iter() |
994 | .map(|n| IncludeName { |
995 | name: n.name.name.to_string(), |
996 | as_: n.as_.name.to_string(), |
997 | }) |
998 | .collect(), |
999 | ); |
1000 | self.world_spans[world_id.index()].includes.push(span); |
1001 | Ok(()) |
1002 | } |
1003 | |
1004 | fn resolve_resource_func( |
1005 | &mut self, |
1006 | func: &ast::ResourceFunc<'_>, |
1007 | resource: &ast::Id<'_>, |
1008 | ) -> Result<Function> { |
1009 | let resource_id = match self.type_lookup.get(resource.name) { |
1010 | Some((TypeOrItem::Type(id), _)) => *id, |
1011 | _ => panic!("type lookup for resource failed" ), |
1012 | }; |
1013 | let (name, kind); |
1014 | match func { |
1015 | ast::ResourceFunc::Method(f) => { |
1016 | name = format!("[method] {}. {}" , resource.name, f.name.name); |
1017 | kind = FunctionKind::Method(resource_id); |
1018 | } |
1019 | ast::ResourceFunc::Static(f) => { |
1020 | name = format!("[static] {}. {}" , resource.name, f.name.name); |
1021 | kind = FunctionKind::Static(resource_id); |
1022 | } |
1023 | ast::ResourceFunc::Constructor(_) => { |
1024 | name = format!("[constructor] {}" , resource.name); |
1025 | kind = FunctionKind::Constructor(resource_id); |
1026 | } |
1027 | } |
1028 | let named_func = func.named_func(); |
1029 | self.resolve_function( |
1030 | &named_func.docs, |
1031 | &named_func.attributes, |
1032 | &name, |
1033 | &named_func.func, |
1034 | kind, |
1035 | ) |
1036 | } |
1037 | |
1038 | fn resolve_function( |
1039 | &mut self, |
1040 | docs: &ast::Docs<'_>, |
1041 | attrs: &[ast::Attribute<'_>], |
1042 | name: &str, |
1043 | func: &ast::Func, |
1044 | kind: FunctionKind, |
1045 | ) -> Result<Function> { |
1046 | let docs = self.docs(docs); |
1047 | let stability = self.stability(attrs)?; |
1048 | let params = self.resolve_params(&func.params, &kind, func.span)?; |
1049 | let results = self.resolve_results(&func.results, &kind, func.span)?; |
1050 | Ok(Function { |
1051 | docs, |
1052 | stability, |
1053 | name: name.to_string(), |
1054 | kind, |
1055 | params, |
1056 | results, |
1057 | }) |
1058 | } |
1059 | |
1060 | fn resolve_ast_item_path(&self, path: &ast::UsePath<'a>) -> Result<(AstItem, String, Span)> { |
1061 | match path { |
1062 | ast::UsePath::Id(id) => { |
1063 | let item = self.ast_items[self.cur_ast_index] |
1064 | .get(id.name) |
1065 | .or_else(|| self.package_items.get(id.name)); |
1066 | match item { |
1067 | Some(item) => Ok((*item, id.name.into(), id.span)), |
1068 | None => { |
1069 | bail!(Error::new( |
1070 | id.span, |
1071 | format!("interface or world ` {}` does not exist" , id.name), |
1072 | )) |
1073 | } |
1074 | } |
1075 | } |
1076 | ast::UsePath::Package { id, name } => Ok(( |
1077 | self.foreign_deps[&id.package_name()][name.name], |
1078 | name.name.into(), |
1079 | name.span, |
1080 | )), |
1081 | } |
1082 | } |
1083 | |
1084 | fn extract_iface_from_item( |
1085 | &self, |
1086 | item: &AstItem, |
1087 | name: &str, |
1088 | span: Span, |
1089 | ) -> Result<InterfaceId> { |
1090 | match item { |
1091 | AstItem::Interface(id) => Ok(*id), |
1092 | AstItem::World(_) => { |
1093 | bail!(Error::new( |
1094 | span, |
1095 | format!("name ` {}` is defined as a world, not an interface" , name), |
1096 | )) |
1097 | } |
1098 | } |
1099 | } |
1100 | |
1101 | fn extract_world_from_item(&self, item: &AstItem, name: &str, span: Span) -> Result<WorldId> { |
1102 | match item { |
1103 | AstItem::World(id) => Ok(*id), |
1104 | AstItem::Interface(_) => { |
1105 | bail!(Error::new( |
1106 | span, |
1107 | format!("name ` {}` is defined as an interface, not a world" , name), |
1108 | )) |
1109 | } |
1110 | } |
1111 | } |
1112 | |
1113 | fn define_interface_name(&mut self, name: &ast::Id<'a>, item: TypeOrItem) -> Result<()> { |
1114 | let prev = self.type_lookup.insert(name.name, (item, name.span)); |
1115 | if prev.is_some() { |
1116 | bail!(Error::new( |
1117 | name.span, |
1118 | format!("name ` {}` is defined more than once" , name.name), |
1119 | )) |
1120 | } else { |
1121 | Ok(()) |
1122 | } |
1123 | } |
1124 | |
1125 | fn resolve_type_def( |
1126 | &mut self, |
1127 | ty: &ast::Type<'_>, |
1128 | stability: &Stability, |
1129 | ) -> Result<TypeDefKind> { |
1130 | Ok(match ty { |
1131 | ast::Type::Bool(_) => TypeDefKind::Type(Type::Bool), |
1132 | ast::Type::U8(_) => TypeDefKind::Type(Type::U8), |
1133 | ast::Type::U16(_) => TypeDefKind::Type(Type::U16), |
1134 | ast::Type::U32(_) => TypeDefKind::Type(Type::U32), |
1135 | ast::Type::U64(_) => TypeDefKind::Type(Type::U64), |
1136 | ast::Type::S8(_) => TypeDefKind::Type(Type::S8), |
1137 | ast::Type::S16(_) => TypeDefKind::Type(Type::S16), |
1138 | ast::Type::S32(_) => TypeDefKind::Type(Type::S32), |
1139 | ast::Type::S64(_) => TypeDefKind::Type(Type::S64), |
1140 | ast::Type::F32(_) => TypeDefKind::Type(Type::F32), |
1141 | ast::Type::F64(_) => TypeDefKind::Type(Type::F64), |
1142 | ast::Type::Char(_) => TypeDefKind::Type(Type::Char), |
1143 | ast::Type::String(_) => TypeDefKind::Type(Type::String), |
1144 | ast::Type::Name(name) => { |
1145 | let id = self.resolve_type_name(name)?; |
1146 | TypeDefKind::Type(Type::Id(id)) |
1147 | } |
1148 | ast::Type::List(list) => { |
1149 | let ty = self.resolve_type(&list.ty, stability)?; |
1150 | TypeDefKind::List(ty) |
1151 | } |
1152 | ast::Type::Handle(handle) => TypeDefKind::Handle(match handle { |
1153 | ast::Handle::Own { resource } => Handle::Own(self.validate_resource(resource)?), |
1154 | ast::Handle::Borrow { resource } => { |
1155 | Handle::Borrow(self.validate_resource(resource)?) |
1156 | } |
1157 | }), |
1158 | ast::Type::Resource(resource) => { |
1159 | // Validate here that the resource doesn't have any duplicate-ly |
1160 | // named methods and that there's at most one constructor. |
1161 | let mut ctors = 0; |
1162 | let mut names = HashSet::new(); |
1163 | for func in resource.funcs.iter() { |
1164 | match func { |
1165 | ast::ResourceFunc::Method(f) | ast::ResourceFunc::Static(f) => { |
1166 | if !names.insert(&f.name.name) { |
1167 | bail!(Error::new( |
1168 | f.name.span, |
1169 | format!("duplicate function name ` {}`" , f.name.name), |
1170 | )) |
1171 | } |
1172 | } |
1173 | ast::ResourceFunc::Constructor(f) => { |
1174 | ctors += 1; |
1175 | if ctors > 1 { |
1176 | bail!(Error::new(f.name.span, "duplicate constructors" )) |
1177 | } |
1178 | } |
1179 | } |
1180 | } |
1181 | |
1182 | TypeDefKind::Resource |
1183 | } |
1184 | ast::Type::Record(record) => { |
1185 | let fields = record |
1186 | .fields |
1187 | .iter() |
1188 | .map(|field| { |
1189 | Ok(Field { |
1190 | docs: self.docs(&field.docs), |
1191 | name: field.name.name.to_string(), |
1192 | ty: self.resolve_type(&field.ty, stability)?, |
1193 | }) |
1194 | }) |
1195 | .collect::<Result<Vec<_>>>()?; |
1196 | TypeDefKind::Record(Record { fields }) |
1197 | } |
1198 | ast::Type::Flags(flags) => { |
1199 | let flags = flags |
1200 | .flags |
1201 | .iter() |
1202 | .map(|flag| Flag { |
1203 | docs: self.docs(&flag.docs), |
1204 | name: flag.name.name.to_string(), |
1205 | }) |
1206 | .collect::<Vec<_>>(); |
1207 | TypeDefKind::Flags(Flags { flags }) |
1208 | } |
1209 | ast::Type::Tuple(t) => { |
1210 | let types = t |
1211 | .types |
1212 | .iter() |
1213 | .map(|ty| self.resolve_type(ty, stability)) |
1214 | .collect::<Result<Vec<_>>>()?; |
1215 | TypeDefKind::Tuple(Tuple { types }) |
1216 | } |
1217 | ast::Type::Variant(variant) => { |
1218 | if variant.cases.is_empty() { |
1219 | bail!(Error::new(variant.span, "empty variant" )) |
1220 | } |
1221 | let cases = variant |
1222 | .cases |
1223 | .iter() |
1224 | .map(|case| { |
1225 | Ok(Case { |
1226 | docs: self.docs(&case.docs), |
1227 | name: case.name.name.to_string(), |
1228 | ty: self.resolve_optional_type(case.ty.as_ref(), stability)?, |
1229 | }) |
1230 | }) |
1231 | .collect::<Result<Vec<_>>>()?; |
1232 | TypeDefKind::Variant(Variant { cases }) |
1233 | } |
1234 | ast::Type::Enum(e) => { |
1235 | if e.cases.is_empty() { |
1236 | bail!(Error::new(e.span, "empty enum" )) |
1237 | } |
1238 | let cases = e |
1239 | .cases |
1240 | .iter() |
1241 | .map(|case| { |
1242 | Ok(EnumCase { |
1243 | docs: self.docs(&case.docs), |
1244 | name: case.name.name.to_string(), |
1245 | }) |
1246 | }) |
1247 | .collect::<Result<Vec<_>>>()?; |
1248 | TypeDefKind::Enum(Enum { cases }) |
1249 | } |
1250 | ast::Type::Option(ty) => TypeDefKind::Option(self.resolve_type(&ty.ty, stability)?), |
1251 | ast::Type::Result(r) => TypeDefKind::Result(Result_ { |
1252 | ok: self.resolve_optional_type(r.ok.as_deref(), stability)?, |
1253 | err: self.resolve_optional_type(r.err.as_deref(), stability)?, |
1254 | }), |
1255 | ast::Type::Future(t) => { |
1256 | TypeDefKind::Future(self.resolve_optional_type(t.ty.as_deref(), stability)?) |
1257 | } |
1258 | ast::Type::Stream(s) => TypeDefKind::Stream(self.resolve_type(&s.ty, stability)?), |
1259 | ast::Type::ErrorContext(_) => TypeDefKind::ErrorContext, |
1260 | }) |
1261 | } |
1262 | |
1263 | fn resolve_type_name(&mut self, name: &ast::Id<'_>) -> Result<TypeId> { |
1264 | match self.type_lookup.get(name.name) { |
1265 | Some((TypeOrItem::Type(id), _)) => Ok(*id), |
1266 | Some((TypeOrItem::Item(s), _)) => bail!(Error::new( |
1267 | name.span, |
1268 | format!("cannot use {s} ` {name}` as a type" , name = name.name), |
1269 | )), |
1270 | None => bail!(Error::new( |
1271 | name.span, |
1272 | format!("name ` {name}` is not defined" , name = name.name), |
1273 | )), |
1274 | } |
1275 | } |
1276 | |
1277 | fn validate_resource(&mut self, name: &ast::Id<'_>) -> Result<TypeId> { |
1278 | let id = self.resolve_type_name(name)?; |
1279 | let mut cur = id; |
1280 | loop { |
1281 | match self.types[cur].kind { |
1282 | TypeDefKind::Resource => break Ok(id), |
1283 | TypeDefKind::Type(Type::Id(ty)) => cur = ty, |
1284 | TypeDefKind::Unknown => { |
1285 | self.required_resource_types.push((cur, name.span)); |
1286 | break Ok(id); |
1287 | } |
1288 | _ => bail!(Error::new( |
1289 | name.span, |
1290 | format!("type ` {}` used in a handle must be a resource" , name.name), |
1291 | )), |
1292 | } |
1293 | } |
1294 | } |
1295 | |
1296 | /// If `stability` is `Stability::Unknown`, recursively inspect the |
1297 | /// specified `kind` until we either bottom out or find a type which has a |
1298 | /// stability that's _not_ unknown. If we find such a type, return a clone |
1299 | /// of its stability; otherwise return `Stability::Unknown`. |
1300 | /// |
1301 | /// The idea here is that e.g. `option<T>` should inherit `T`'s stability. |
1302 | /// This gets a little ambiguous in the case of e.g. `tuple<T, U, V>`; for |
1303 | /// now, we just pick the first one has a known stability, if any. |
1304 | fn find_stability(&self, kind: &TypeDefKind, stability: &Stability) -> Stability { |
1305 | fn find_in_type(types: &Arena<TypeDef>, ty: Type) -> Option<&Stability> { |
1306 | if let Type::Id(id) = ty { |
1307 | let ty = &types[id]; |
1308 | if !matches!(&ty.stability, Stability::Unknown) { |
1309 | Some(&ty.stability) |
1310 | } else { |
1311 | find_in_kind(types, &ty.kind) |
1312 | } |
1313 | } else { |
1314 | None |
1315 | } |
1316 | } |
1317 | |
1318 | fn find_in_kind<'a>( |
1319 | types: &'a Arena<TypeDef>, |
1320 | kind: &TypeDefKind, |
1321 | ) -> Option<&'a Stability> { |
1322 | match kind { |
1323 | TypeDefKind::Type(ty) => find_in_type(types, *ty), |
1324 | TypeDefKind::Handle(Handle::Borrow(id) | Handle::Own(id)) => { |
1325 | find_in_type(types, Type::Id(*id)) |
1326 | } |
1327 | TypeDefKind::Tuple(t) => t.types.iter().find_map(|ty| find_in_type(types, *ty)), |
1328 | TypeDefKind::List(ty) | TypeDefKind::Stream(ty) | TypeDefKind::Option(ty) => { |
1329 | find_in_type(types, *ty) |
1330 | } |
1331 | TypeDefKind::Future(ty) => ty.as_ref().and_then(|ty| find_in_type(types, *ty)), |
1332 | TypeDefKind::Result(r) => { |
1333 | r.ok.as_ref() |
1334 | .and_then(|ty| find_in_type(types, *ty)) |
1335 | .or_else(|| r.err.as_ref().and_then(|ty| find_in_type(types, *ty))) |
1336 | } |
1337 | // Assume these are named types which will be annotated with an |
1338 | // explicit stability if applicable: |
1339 | TypeDefKind::ErrorContext |
1340 | | TypeDefKind::Resource |
1341 | | TypeDefKind::Variant(_) |
1342 | | TypeDefKind::Record(_) |
1343 | | TypeDefKind::Flags(_) |
1344 | | TypeDefKind::Enum(_) |
1345 | | TypeDefKind::Unknown => None, |
1346 | } |
1347 | } |
1348 | |
1349 | if let Stability::Unknown = stability { |
1350 | find_in_kind(&self.types, kind) |
1351 | .cloned() |
1352 | .unwrap_or(Stability::Unknown) |
1353 | } else { |
1354 | stability.clone() |
1355 | } |
1356 | } |
1357 | |
1358 | fn resolve_type(&mut self, ty: &super::Type<'_>, stability: &Stability) -> Result<Type> { |
1359 | // Resources must be declared at the top level to have their methods |
1360 | // processed appropriately, but resources also shouldn't show up |
1361 | // recursively so assert that's not happening here. |
1362 | match ty { |
1363 | ast::Type::Resource(_) => unreachable!(), |
1364 | _ => {} |
1365 | } |
1366 | let kind = self.resolve_type_def(ty, stability)?; |
1367 | let stability = self.find_stability(&kind, stability); |
1368 | Ok(self.anon_type_def( |
1369 | TypeDef { |
1370 | kind, |
1371 | name: None, |
1372 | docs: Docs::default(), |
1373 | stability, |
1374 | owner: TypeOwner::None, |
1375 | }, |
1376 | ty.span(), |
1377 | )) |
1378 | } |
1379 | |
1380 | fn resolve_optional_type( |
1381 | &mut self, |
1382 | ty: Option<&super::Type<'_>>, |
1383 | stability: &Stability, |
1384 | ) -> Result<Option<Type>> { |
1385 | match ty { |
1386 | Some(ty) => Ok(Some(self.resolve_type(ty, stability)?)), |
1387 | None => Ok(None), |
1388 | } |
1389 | } |
1390 | |
1391 | fn anon_type_def(&mut self, ty: TypeDef, span: Span) -> Type { |
1392 | let key = match &ty.kind { |
1393 | TypeDefKind::Type(t) => return *t, |
1394 | TypeDefKind::Variant(v) => Key::Variant( |
1395 | v.cases |
1396 | .iter() |
1397 | .map(|case| (case.name.clone(), case.ty)) |
1398 | .collect::<Vec<_>>(), |
1399 | ), |
1400 | TypeDefKind::Handle(Handle::Borrow(h)) => Key::BorrowHandle(*h), |
1401 | // An anonymous `own<T>` type is the same as a reference to the type |
1402 | // `T`, so avoid creating anonymous type and return that here |
1403 | // directly. Note that this additionally avoids creating distinct |
1404 | // anonymous types for `list<T>` and `list<own<T>>` for example. |
1405 | TypeDefKind::Handle(Handle::Own(id)) => return Type::Id(*id), |
1406 | TypeDefKind::Resource => unreachable!("anonymous resources aren't supported" ), |
1407 | TypeDefKind::Record(r) => Key::Record( |
1408 | r.fields |
1409 | .iter() |
1410 | .map(|case| (case.name.clone(), case.ty)) |
1411 | .collect::<Vec<_>>(), |
1412 | ), |
1413 | TypeDefKind::Flags(r) => { |
1414 | Key::Flags(r.flags.iter().map(|f| f.name.clone()).collect::<Vec<_>>()) |
1415 | } |
1416 | TypeDefKind::Tuple(t) => Key::Tuple(t.types.clone()), |
1417 | TypeDefKind::Enum(r) => { |
1418 | Key::Enum(r.cases.iter().map(|f| f.name.clone()).collect::<Vec<_>>()) |
1419 | } |
1420 | TypeDefKind::List(ty) => Key::List(*ty), |
1421 | TypeDefKind::Option(t) => Key::Option(*t), |
1422 | TypeDefKind::Result(r) => Key::Result(r.ok, r.err), |
1423 | TypeDefKind::Future(ty) => Key::Future(*ty), |
1424 | TypeDefKind::Stream(ty) => Key::Stream(*ty), |
1425 | TypeDefKind::ErrorContext => Key::ErrorContext, |
1426 | TypeDefKind::Unknown => unreachable!(), |
1427 | }; |
1428 | let id = self.anon_types.entry(key).or_insert_with(|| { |
1429 | self.type_spans.push(span); |
1430 | self.types.alloc(ty) |
1431 | }); |
1432 | Type::Id(*id) |
1433 | } |
1434 | |
1435 | fn docs(&mut self, doc: &super::Docs<'_>) -> Docs { |
1436 | let mut docs = vec![]; |
1437 | |
1438 | for doc in doc.docs.iter() { |
1439 | let contents = match doc.strip_prefix("/**" ) { |
1440 | Some(doc) => doc.strip_suffix("*/" ).unwrap(), |
1441 | None => doc.trim_start_matches('/' ), |
1442 | }; |
1443 | |
1444 | docs.push(contents.trim_end()); |
1445 | } |
1446 | |
1447 | // Scan the (non-empty) doc lines to find the minimum amount of leading whitespace. |
1448 | // This amount of whitespace will be removed from the start of all doc lines, |
1449 | // normalizing the output while retaining intentional spacing added by the original authors. |
1450 | let min_leading_ws = docs |
1451 | .iter() |
1452 | .filter(|doc| !doc.is_empty()) |
1453 | .map(|doc| doc.bytes().take_while(|c| c.is_ascii_whitespace()).count()) |
1454 | .min() |
1455 | .unwrap_or(0); |
1456 | |
1457 | if min_leading_ws > 0 { |
1458 | let leading_ws_pattern = " " .repeat(min_leading_ws); |
1459 | docs = docs |
1460 | .iter() |
1461 | .map(|doc| doc.strip_prefix(&leading_ws_pattern).unwrap_or(doc)) |
1462 | .collect(); |
1463 | } |
1464 | |
1465 | let contents = if docs.is_empty() { |
1466 | None |
1467 | } else { |
1468 | // NB: this notably, through the use of `lines`, normalizes `\r\n` |
1469 | // to `\n`. |
1470 | let mut contents = String::new(); |
1471 | for doc in docs { |
1472 | if doc.is_empty() { |
1473 | contents.push_str(" \n" ); |
1474 | } else { |
1475 | for line in doc.lines() { |
1476 | contents.push_str(line); |
1477 | contents.push_str(" \n" ); |
1478 | } |
1479 | } |
1480 | } |
1481 | while contents.ends_with(" \n" ) { |
1482 | contents.pop(); |
1483 | } |
1484 | Some(contents) |
1485 | }; |
1486 | Docs { contents } |
1487 | } |
1488 | |
1489 | fn stability(&mut self, attrs: &[ast::Attribute<'_>]) -> Result<Stability> { |
1490 | match attrs { |
1491 | [] => Ok(Stability::Unknown), |
1492 | |
1493 | [ast::Attribute::Since { version, .. }] => Ok(Stability::Stable { |
1494 | since: version.clone(), |
1495 | deprecated: None, |
1496 | }), |
1497 | |
1498 | [ast::Attribute::Since { version, .. }, ast::Attribute::Deprecated { |
1499 | version: deprecated, |
1500 | .. |
1501 | }] |
1502 | | [ast::Attribute::Deprecated { |
1503 | version: deprecated, |
1504 | .. |
1505 | }, ast::Attribute::Since { version, .. }] => Ok(Stability::Stable { |
1506 | since: version.clone(), |
1507 | deprecated: Some(deprecated.clone()), |
1508 | }), |
1509 | |
1510 | [ast::Attribute::Unstable { feature, .. }] => Ok(Stability::Unstable { |
1511 | feature: feature.name.to_string(), |
1512 | deprecated: None, |
1513 | }), |
1514 | |
1515 | [ast::Attribute::Unstable { feature, .. }, ast::Attribute::Deprecated { version, .. }] |
1516 | | [ast::Attribute::Deprecated { version, .. }, ast::Attribute::Unstable { feature, .. }] => { |
1517 | Ok(Stability::Unstable { |
1518 | feature: feature.name.to_string(), |
1519 | deprecated: Some(version.clone()), |
1520 | }) |
1521 | } |
1522 | [ast::Attribute::Deprecated { span, .. }] => { |
1523 | bail!(Error::new( |
1524 | *span, |
1525 | "must pair @deprecated with either @since or @unstable" , |
1526 | )) |
1527 | } |
1528 | [_, b, ..] => { |
1529 | bail!(Error::new( |
1530 | b.span(), |
1531 | "unsupported combination of attributes" , |
1532 | )) |
1533 | } |
1534 | } |
1535 | } |
1536 | |
1537 | fn resolve_params( |
1538 | &mut self, |
1539 | params: &ParamList<'_>, |
1540 | kind: &FunctionKind, |
1541 | span: Span, |
1542 | ) -> Result<Params> { |
1543 | let mut ret = IndexMap::new(); |
1544 | match *kind { |
1545 | // These kinds of methods don't have any adjustments to the |
1546 | // parameters, so do nothing here. |
1547 | FunctionKind::Freestanding | FunctionKind::Constructor(_) | FunctionKind::Static(_) => { |
1548 | } |
1549 | |
1550 | // Methods automatically get a `self` initial argument so insert |
1551 | // that here before processing the normal parameters. |
1552 | FunctionKind::Method(id) => { |
1553 | let kind = TypeDefKind::Handle(Handle::Borrow(id)); |
1554 | let stability = self.find_stability(&kind, &Stability::Unknown); |
1555 | let shared = self.anon_type_def( |
1556 | TypeDef { |
1557 | docs: Docs::default(), |
1558 | stability, |
1559 | kind, |
1560 | name: None, |
1561 | owner: TypeOwner::None, |
1562 | }, |
1563 | span, |
1564 | ); |
1565 | ret.insert("self" .to_string(), shared); |
1566 | } |
1567 | } |
1568 | for (name, ty) in params { |
1569 | let prev = ret.insert( |
1570 | name.name.to_string(), |
1571 | self.resolve_type(ty, &Stability::Unknown)?, |
1572 | ); |
1573 | if prev.is_some() { |
1574 | bail!(Error::new( |
1575 | name.span, |
1576 | format!("param ` {}` is defined more than once" , name.name), |
1577 | )) |
1578 | } |
1579 | } |
1580 | Ok(ret.into_iter().collect()) |
1581 | } |
1582 | |
1583 | fn resolve_results( |
1584 | &mut self, |
1585 | results: &ResultList<'_>, |
1586 | kind: &FunctionKind, |
1587 | span: Span, |
1588 | ) -> Result<Results> { |
1589 | match *kind { |
1590 | // These kinds of methods don't have any adjustments to the return |
1591 | // values, so plumb them through as-is. |
1592 | FunctionKind::Freestanding | FunctionKind::Method(_) | FunctionKind::Static(_) => { |
1593 | match results { |
1594 | ResultList::Named(rs) => Ok(Results::Named(self.resolve_params( |
1595 | rs, |
1596 | &FunctionKind::Freestanding, |
1597 | span, |
1598 | )?)), |
1599 | ResultList::Anon(ty) => { |
1600 | Ok(Results::Anon(self.resolve_type(ty, &Stability::Unknown)?)) |
1601 | } |
1602 | } |
1603 | } |
1604 | |
1605 | // Constructors are alwys parsed as 0 returned types but they're |
1606 | // automatically translated as a single return type of the type that |
1607 | // it's a constructor for. |
1608 | FunctionKind::Constructor(id) => { |
1609 | match results { |
1610 | ResultList::Named(rs) => assert!(rs.is_empty()), |
1611 | ResultList::Anon(_) => unreachable!(), |
1612 | } |
1613 | Ok(Results::Anon(Type::Id(id))) |
1614 | } |
1615 | } |
1616 | } |
1617 | } |
1618 | |
1619 | fn collect_deps<'a>(ty: &ast::Type<'a>, deps: &mut Vec<ast::Id<'a>>) { |
1620 | match ty { |
1621 | ast::Type::Bool(_) |
1622 | | ast::Type::U8(_) |
1623 | | ast::Type::U16(_) |
1624 | | ast::Type::U32(_) |
1625 | | ast::Type::U64(_) |
1626 | | ast::Type::S8(_) |
1627 | | ast::Type::S16(_) |
1628 | | ast::Type::S32(_) |
1629 | | ast::Type::S64(_) |
1630 | | ast::Type::F32(_) |
1631 | | ast::Type::F64(_) |
1632 | | ast::Type::Char(_) |
1633 | | ast::Type::String(_) |
1634 | | ast::Type::Flags(_) |
1635 | | ast::Type::Enum(_) |
1636 | | ast::Type::ErrorContext(_) => {} |
1637 | ast::Type::Name(name) => deps.push(name.clone()), |
1638 | ast::Type::Handle(handle) => match handle { |
1639 | ast::Handle::Own { resource } => deps.push(resource.clone()), |
1640 | ast::Handle::Borrow { resource } => deps.push(resource.clone()), |
1641 | }, |
1642 | ast::Type::Resource(_) => {} |
1643 | ast::Type::Record(record) => { |
1644 | for field in record.fields.iter() { |
1645 | collect_deps(&field.ty, deps); |
1646 | } |
1647 | } |
1648 | ast::Type::Tuple(t) => { |
1649 | for ty in t.types.iter() { |
1650 | collect_deps(ty, deps); |
1651 | } |
1652 | } |
1653 | ast::Type::Variant(variant) => { |
1654 | for case in variant.cases.iter() { |
1655 | if let Some(ty) = &case.ty { |
1656 | collect_deps(ty, deps); |
1657 | } |
1658 | } |
1659 | } |
1660 | ast::Type::Option(ast::Option_ { ty, .. }) |
1661 | | ast::Type::List(ast::List { ty, .. }) |
1662 | | ast::Type::Stream(ast::Stream { ty, .. }) => collect_deps(ty, deps), |
1663 | ast::Type::Result(r) => { |
1664 | if let Some(ty) = &r.ok { |
1665 | collect_deps(ty, deps); |
1666 | } |
1667 | if let Some(ty) = &r.err { |
1668 | collect_deps(ty, deps); |
1669 | } |
1670 | } |
1671 | ast::Type::Future(t) => { |
1672 | if let Some(t) = &t.ty { |
1673 | collect_deps(t, deps) |
1674 | } |
1675 | } |
1676 | } |
1677 | } |
1678 | |