Skip to main content

wit_parser/
live.rs

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