wit_parser/
live.rs

1use crate::{
2    Function, FunctionKind, InterfaceId, Resolve, Type, TypeDef, TypeDefKind, TypeId, WorldId,
3    WorldItem,
4};
5use indexmap::IndexSet;
6
7#[derive(Default)]
8pub struct LiveTypes {
9    set: IndexSet<TypeId>,
10}
11
12impl LiveTypes {
13    pub fn iter(&self) -> impl Iterator<Item = TypeId> + '_ {
14        self.set.iter().copied()
15    }
16
17    pub fn len(&self) -> usize {
18        self.set.len()
19    }
20
21    pub fn contains(&self, id: TypeId) -> bool {
22        self.set.contains(&id)
23    }
24
25    pub fn add_interface(&mut self, resolve: &Resolve, iface: InterfaceId) {
26        self.visit_interface(resolve, iface);
27    }
28
29    pub fn add_world(&mut self, resolve: &Resolve, world: WorldId) {
30        self.visit_world(resolve, world);
31    }
32
33    pub fn add_world_item(&mut self, resolve: &Resolve, item: &WorldItem) {
34        self.visit_world_item(resolve, item);
35    }
36
37    pub fn add_func(&mut self, resolve: &Resolve, func: &Function) {
38        self.visit_func(resolve, func);
39    }
40
41    pub fn add_type_id(&mut self, resolve: &Resolve, ty: TypeId) {
42        self.visit_type_id(resolve, ty);
43    }
44
45    pub fn add_type(&mut self, resolve: &Resolve, ty: &Type) {
46        self.visit_type(resolve, ty);
47    }
48}
49
50impl TypeIdVisitor for LiveTypes {
51    fn before_visit_type_id(&mut self, id: TypeId) -> bool {
52        !self.set.contains(&id)
53    }
54
55    fn after_visit_type_id(&mut self, id: TypeId) {
56        assert!(self.set.insert(id));
57    }
58}
59
60/// Helper trait to walk the structure of a type and visit all `TypeId`s that
61/// it refers to, possibly transitively.
62pub trait TypeIdVisitor {
63    /// Callback invoked just before a type is visited.
64    ///
65    /// If this function returns `false` the type is not visited, otherwise it's
66    /// recursed into.
67    fn before_visit_type_id(&mut self, id: TypeId) -> bool {
68        let _ = id;
69        true
70    }
71
72    /// Callback invoked once a type is finished being visited.
73    fn after_visit_type_id(&mut self, id: TypeId) {
74        let _ = id;
75    }
76
77    fn visit_interface(&mut self, resolve: &Resolve, iface: InterfaceId) {
78        let iface = &resolve.interfaces[iface];
79        for (_, id) in iface.types.iter() {
80            self.visit_type_id(resolve, *id);
81        }
82        for (_, func) in iface.functions.iter() {
83            self.visit_func(resolve, func);
84        }
85    }
86
87    fn visit_world(&mut self, resolve: &Resolve, world: WorldId) {
88        let world = &resolve.worlds[world];
89        for (_, item) in world.imports.iter().chain(world.exports.iter()) {
90            self.visit_world_item(resolve, item);
91        }
92    }
93
94    fn visit_world_item(&mut self, resolve: &Resolve, item: &WorldItem) {
95        match item {
96            WorldItem::Interface { id, .. } => self.visit_interface(resolve, *id),
97            WorldItem::Function(f) => self.visit_func(resolve, f),
98            WorldItem::Type(t) => self.visit_type_id(resolve, *t),
99        }
100    }
101
102    fn visit_func(&mut self, resolve: &Resolve, func: &Function) {
103        match func.kind {
104            // This resource is live as it's attached to a static method but
105            // it's not guaranteed to be present in either params or results, so
106            // be sure to attach it here.
107            FunctionKind::Static(id) | FunctionKind::AsyncStatic(id) => {
108                self.visit_type_id(resolve, id)
109            }
110
111            // The resource these are attached to is in the params/results, so
112            // no need to re-add it here.
113            FunctionKind::Method(_)
114            | FunctionKind::AsyncMethod(_)
115            | FunctionKind::Constructor(_) => {}
116
117            FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {}
118        }
119
120        for (_, ty) in func.params.iter() {
121            self.visit_type(resolve, ty);
122        }
123        if let Some(ty) = &func.result {
124            self.visit_type(resolve, ty);
125        }
126    }
127
128    fn visit_type_id(&mut self, resolve: &Resolve, ty: TypeId) {
129        if self.before_visit_type_id(ty) {
130            self.visit_type_def(resolve, &resolve.types[ty]);
131            self.after_visit_type_id(ty);
132        }
133    }
134
135    fn visit_type_def(&mut self, resolve: &Resolve, ty: &TypeDef) {
136        match &ty.kind {
137            TypeDefKind::Type(t)
138            | TypeDefKind::List(t)
139            | TypeDefKind::FixedSizeList(t, ..)
140            | TypeDefKind::Option(t)
141            | TypeDefKind::Future(Some(t))
142            | TypeDefKind::Stream(Some(t)) => self.visit_type(resolve, t),
143            TypeDefKind::Handle(handle) => match handle {
144                crate::Handle::Own(ty) => self.visit_type_id(resolve, *ty),
145                crate::Handle::Borrow(ty) => self.visit_type_id(resolve, *ty),
146            },
147            TypeDefKind::Resource => {}
148            TypeDefKind::Record(r) => {
149                for field in r.fields.iter() {
150                    self.visit_type(resolve, &field.ty);
151                }
152            }
153            TypeDefKind::Tuple(r) => {
154                for ty in r.types.iter() {
155                    self.visit_type(resolve, ty);
156                }
157            }
158            TypeDefKind::Variant(v) => {
159                for case in v.cases.iter() {
160                    if let Some(ty) = &case.ty {
161                        self.visit_type(resolve, ty);
162                    }
163                }
164            }
165            TypeDefKind::Result(r) => {
166                if let Some(ty) = &r.ok {
167                    self.visit_type(resolve, ty);
168                }
169                if let Some(ty) = &r.err {
170                    self.visit_type(resolve, ty);
171                }
172            }
173            TypeDefKind::Flags(_)
174            | TypeDefKind::Enum(_)
175            | TypeDefKind::Future(None)
176            | TypeDefKind::Stream(None) => {}
177            TypeDefKind::Unknown => unreachable!(),
178        }
179    }
180
181    fn visit_type(&mut self, resolve: &Resolve, ty: &Type) {
182        match ty {
183            Type::Id(id) => self.visit_type_id(resolve, *id),
184            _ => {}
185        }
186    }
187}
188
189#[cfg(test)]
190mod tests {
191    use super::{LiveTypes, Resolve};
192
193    fn live(wit: &str, ty: &str) -> Vec<String> {
194        let mut resolve = Resolve::default();
195        resolve.push_str("test.wit", wit).unwrap();
196        let (_, interface) = resolve.interfaces.iter().next_back().unwrap();
197        let ty = interface.types[ty];
198        let mut live = LiveTypes::default();
199        live.add_type_id(&resolve, ty);
200
201        live.iter()
202            .filter_map(|ty| resolve.types[ty].name.clone())
203            .collect()
204    }
205
206    #[test]
207    fn no_deps() {
208        let types = live(
209            "
210                package foo:bar;
211
212                interface foo {
213                    type t = u32;
214                }
215            ",
216            "t",
217        );
218        assert_eq!(types, ["t"]);
219    }
220
221    #[test]
222    fn one_dep() {
223        let types = live(
224            "
225                package foo:bar;
226
227                interface foo {
228                    type t = u32;
229                    type u = t;
230                }
231            ",
232            "u",
233        );
234        assert_eq!(types, ["t", "u"]);
235    }
236
237    #[test]
238    fn chain() {
239        let types = live(
240            "
241                package foo:bar;
242
243                interface foo {
244                    resource t1;
245                    record t2 {
246                        x: t1,
247                    }
248                    variant t3 {
249                        x(t2),
250                    }
251                    flags t4 { a }
252                    enum t5 { a }
253                    type t6 = tuple<t5, t4, t3>;
254                }
255            ",
256            "t6",
257        );
258        assert_eq!(types, ["t5", "t4", "t1", "t2", "t3", "t6"]);
259    }
260}