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
59pub trait TypeIdVisitor {
62 fn before_visit_type_id(&mut self, id: TypeId) -> bool {
67 let _ = id;
68 true
69 }
70
71 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 FunctionKind::Static(id)
107 | FunctionKind::AsyncStatic(id)
108 | FunctionKind::StaticGetter(id)
109 | FunctionKind::StaticSetter(id) => self.visit_type_id(resolve, id),
110
111 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, ¶m.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}