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