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