Coverage Report

Created: 2026-08-08 08:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wasm-tools/crates/wit-parser/src/live.rs
Line
Count
Source
1
use crate::{
2
    Function, FunctionKind, IndexSet, InterfaceId, Resolve, Type, TypeDef, TypeDefKind, TypeId,
3
    WorldId, WorldItem,
4
};
5
6
#[derive(Default)]
7
pub struct LiveTypes {
8
    set: IndexSet<TypeId>,
9
}
10
11
impl LiveTypes {
12
6.22k
    pub fn iter(&self) -> impl Iterator<Item = TypeId> + '_ {
13
6.22k
        self.set.iter().copied()
14
6.22k
    }
15
16
0
    pub fn len(&self) -> usize {
17
0
        self.set.len()
18
0
    }
19
20
0
    pub fn contains(&self, id: TypeId) -> bool {
21
0
        self.set.contains(&id)
22
0
    }
23
24
1.65k
    pub fn add_interface(&mut self, resolve: &Resolve, iface: InterfaceId) {
25
1.65k
        self.visit_interface(resolve, iface);
26
1.65k
    }
27
28
0
    pub fn add_world(&mut self, resolve: &Resolve, world: WorldId) {
29
0
        self.visit_world(resolve, world);
30
0
    }
31
32
2.54k
    pub fn add_world_item(&mut self, resolve: &Resolve, item: &WorldItem) {
33
2.54k
        self.visit_world_item(resolve, item);
34
2.54k
    }
35
36
934
    pub fn add_func(&mut self, resolve: &Resolve, func: &Function) {
37
934
        self.visit_func(resolve, func);
38
934
    }
39
40
3.24k
    pub fn add_type_id(&mut self, resolve: &Resolve, ty: TypeId) {
41
3.24k
        self.visit_type_id(resolve, ty);
42
3.24k
    }
43
44
742
    pub fn add_type(&mut self, resolve: &Resolve, ty: &Type) {
45
742
        self.visit_type(resolve, ty);
46
742
    }
47
}
48
49
impl TypeIdVisitor for LiveTypes {
50
36.4k
    fn before_visit_type_id(&mut self, id: TypeId) -> bool {
51
36.4k
        !self.set.contains(&id)
52
36.4k
    }
53
54
29.7k
    fn after_visit_type_id(&mut self, id: TypeId) {
55
29.7k
        assert!(self.set.insert(id));
56
29.7k
    }
57
}
58
59
/// Helper trait to walk the structure of a type and visit all `TypeId`s that
60
/// it refers to, possibly transitively.
61
pub 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
0
    fn before_visit_type_id(&mut self, id: TypeId) -> bool {
67
0
        let _ = id;
68
0
        true
69
0
    }
70
71
    /// Callback invoked once a type is finished being visited.
72
8.35k
    fn after_visit_type_id(&mut self, id: TypeId) {
73
8.35k
        let _ = id;
74
8.35k
    }
75
76
3.30k
    fn visit_interface(&mut self, resolve: &Resolve, iface: InterfaceId) {
77
3.30k
        let iface = &resolve.interfaces[iface];
78
14.8k
        for (_, id) in iface.types.iter() {
79
14.8k
            self.visit_type_id(resolve, *id);
80
14.8k
        }
81
5.21k
        for (_, func) in iface.functions.iter() {
82
5.21k
            self.visit_func(resolve, func);
83
5.21k
        }
84
3.30k
    }
85
86
0
    fn visit_world(&mut self, resolve: &Resolve, world: WorldId) {
87
0
        let world = &resolve.worlds[world];
88
0
        for (_, item) in world.imports.iter().chain(world.exports.iter()) {
89
0
            self.visit_world_item(resolve, item);
90
0
        }
91
0
    }
92
93
2.54k
    fn visit_world_item(&mut self, resolve: &Resolve, item: &WorldItem) {
94
2.54k
        match item {
95
1.65k
            WorldItem::Interface { id, .. } => self.visit_interface(resolve, *id),
96
898
            WorldItem::Function(f) => self.visit_func(resolve, f),
97
0
            WorldItem::Type { id, .. } => self.visit_type_id(resolve, *id),
98
        }
99
2.54k
    }
100
101
7.04k
    fn visit_func(&mut self, resolve: &Resolve, func: &Function) {
102
7.04k
        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
1.30k
            FunctionKind::Static(id) | FunctionKind::AsyncStatic(id) => {
107
1.37k
                self.visit_type_id(resolve, id)
108
            }
109
110
            // The resource these are attached to is in the params/results, so
111
            // no need to re-add it here.
112
            FunctionKind::Method(_)
113
            | FunctionKind::AsyncMethod(_)
114
735
            | FunctionKind::Constructor(_) => {}
115
116
4.93k
            FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => {}
117
        }
118
119
14.1k
        for param in func.params.iter() {
120
14.1k
            self.visit_type(resolve, &param.ty);
121
14.1k
        }
122
7.04k
        if let Some(ty) = &func.result {
123
6.31k
            self.visit_type(resolve, ty);
124
6.31k
        }
125
7.04k
    }
126
127
45.4k
    fn visit_type_id(&mut self, resolve: &Resolve, ty: TypeId) {
128
45.4k
        if self.before_visit_type_id(ty) {
129
38.0k
            self.visit_type_def(resolve, &resolve.types[ty]);
130
38.0k
            self.after_visit_type_id(ty);
131
38.0k
        }
132
45.4k
    }
<<wit_parser::resolve::Resolve>::assert_world_imports_type_deps::MyVisit as wit_parser::live::TypeIdVisitor>::visit_type_id
Line
Count
Source
127
8.97k
    fn visit_type_id(&mut self, resolve: &Resolve, ty: TypeId) {
128
8.97k
        if self.before_visit_type_id(ty) {
129
8.35k
            self.visit_type_def(resolve, &resolve.types[ty]);
130
8.35k
            self.after_visit_type_id(ty);
131
8.35k
        }
132
8.97k
    }
<wit_parser::live::LiveTypes as wit_parser::live::TypeIdVisitor>::visit_type_id
Line
Count
Source
127
36.4k
    fn visit_type_id(&mut self, resolve: &Resolve, ty: TypeId) {
128
36.4k
        if self.before_visit_type_id(ty) {
129
29.7k
            self.visit_type_def(resolve, &resolve.types[ty]);
130
29.7k
            self.after_visit_type_id(ty);
131
29.7k
        }
132
36.4k
    }
133
134
42.2k
    fn visit_type_def(&mut self, resolve: &Resolve, ty: &TypeDef) {
135
983
        match &ty.kind {
136
952
            TypeDefKind::Type(t)
137
1.16k
            | TypeDefKind::List(t)
138
491
            | TypeDefKind::FixedLengthList(t, ..)
139
5.46k
            | TypeDefKind::Option(t)
140
881
            | TypeDefKind::Future(Some(t))
141
9.52k
            | TypeDefKind::Stream(Some(t)) => self.visit_type(resolve, t),
142
0
            TypeDefKind::Map(k, v) => {
143
0
                self.visit_type(resolve, k);
144
0
                self.visit_type(resolve, v);
145
0
            }
146
830
            TypeDefKind::Handle(handle) => match handle {
147
264
                crate::Handle::Own(ty) => self.visit_type_id(resolve, *ty),
148
566
                crate::Handle::Borrow(ty) => self.visit_type_id(resolve, *ty),
149
            },
150
1.44k
            TypeDefKind::Resource => {}
151
916
            TypeDefKind::Record(r) => {
152
2.58k
                for field in r.fields.iter() {
153
2.58k
                    self.visit_type(resolve, &field.ty);
154
2.58k
                }
155
            }
156
8.75k
            TypeDefKind::Tuple(r) => {
157
32.0k
                for ty in r.types.iter() {
158
32.0k
                    self.visit_type(resolve, ty);
159
32.0k
                }
160
            }
161
668
            TypeDefKind::Variant(v) => {
162
3.68k
                for case in v.cases.iter() {
163
3.68k
                    if let Some(ty) = &case.ty {
164
3.48k
                        self.visit_type(resolve, ty);
165
3.48k
                    }
166
                }
167
            }
168
4.13k
            TypeDefKind::Result(r) => {
169
4.13k
                if let Some(ty) = &r.ok {
170
3.84k
                    self.visit_type(resolve, ty);
171
3.84k
                }
172
4.13k
                if let Some(ty) = &r.err {
173
3.65k
                    self.visit_type(resolve, ty);
174
3.65k
                }
175
            }
176
            TypeDefKind::Flags(_)
177
            | TypeDefKind::Enum(_)
178
            | TypeDefKind::Future(None)
179
16.0k
            | TypeDefKind::Stream(None) => {}
180
0
            TypeDefKind::Unknown => unreachable!(),
181
        }
182
42.2k
    }
<<wit_parser::resolve::Resolve>::assert_world_imports_type_deps::MyVisit as wit_parser::live::TypeIdVisitor>::visit_type_def
Line
Count
Source
134
12.5k
    fn visit_type_def(&mut self, resolve: &Resolve, ty: &TypeDef) {
135
190
        match &ty.kind {
136
302
            TypeDefKind::Type(t)
137
596
            | TypeDefKind::List(t)
138
188
            | TypeDefKind::FixedLengthList(t, ..)
139
3.54k
            | TypeDefKind::Option(t)
140
162
            | TypeDefKind::Future(Some(t))
141
5.15k
            | TypeDefKind::Stream(Some(t)) => self.visit_type(resolve, t),
142
0
            TypeDefKind::Map(k, v) => {
143
0
                self.visit_type(resolve, k);
144
0
                self.visit_type(resolve, v);
145
0
            }
146
330
            TypeDefKind::Handle(handle) => match handle {
147
94
                crate::Handle::Own(ty) => self.visit_type_id(resolve, *ty),
148
236
                crate::Handle::Borrow(ty) => self.visit_type_id(resolve, *ty),
149
            },
150
604
            TypeDefKind::Resource => {}
151
250
            TypeDefKind::Record(r) => {
152
524
                for field in r.fields.iter() {
153
524
                    self.visit_type(resolve, &field.ty);
154
524
                }
155
            }
156
3.72k
            TypeDefKind::Tuple(r) => {
157
15.0k
                for ty in r.types.iter() {
158
15.0k
                    self.visit_type(resolve, ty);
159
15.0k
                }
160
            }
161
156
            TypeDefKind::Variant(v) => {
162
412
                for case in v.cases.iter() {
163
412
                    if let Some(ty) = &case.ty {
164
310
                        self.visit_type(resolve, ty);
165
310
                    }
166
                }
167
            }
168
628
            TypeDefKind::Result(r) => {
169
628
                if let Some(ty) = &r.ok {
170
502
                    self.visit_type(resolve, ty);
171
502
                }
172
628
                if let Some(ty) = &r.err {
173
452
                    self.visit_type(resolve, ty);
174
452
                }
175
            }
176
            TypeDefKind::Flags(_)
177
            | TypeDefKind::Enum(_)
178
            | TypeDefKind::Future(None)
179
1.74k
            | TypeDefKind::Stream(None) => {}
180
0
            TypeDefKind::Unknown => unreachable!(),
181
        }
182
12.5k
    }
<wit_parser::live::LiveTypes as wit_parser::live::TypeIdVisitor>::visit_type_def
Line
Count
Source
134
29.7k
    fn visit_type_def(&mut self, resolve: &Resolve, ty: &TypeDef) {
135
793
        match &ty.kind {
136
650
            TypeDefKind::Type(t)
137
569
            | TypeDefKind::List(t)
138
303
            | TypeDefKind::FixedLengthList(t, ..)
139
1.91k
            | TypeDefKind::Option(t)
140
719
            | TypeDefKind::Future(Some(t))
141
4.37k
            | TypeDefKind::Stream(Some(t)) => self.visit_type(resolve, t),
142
0
            TypeDefKind::Map(k, v) => {
143
0
                self.visit_type(resolve, k);
144
0
                self.visit_type(resolve, v);
145
0
            }
146
500
            TypeDefKind::Handle(handle) => match handle {
147
170
                crate::Handle::Own(ty) => self.visit_type_id(resolve, *ty),
148
330
                crate::Handle::Borrow(ty) => self.visit_type_id(resolve, *ty),
149
            },
150
839
            TypeDefKind::Resource => {}
151
666
            TypeDefKind::Record(r) => {
152
2.06k
                for field in r.fields.iter() {
153
2.06k
                    self.visit_type(resolve, &field.ty);
154
2.06k
                }
155
            }
156
5.03k
            TypeDefKind::Tuple(r) => {
157
17.0k
                for ty in r.types.iter() {
158
17.0k
                    self.visit_type(resolve, ty);
159
17.0k
                }
160
            }
161
512
            TypeDefKind::Variant(v) => {
162
3.27k
                for case in v.cases.iter() {
163
3.27k
                    if let Some(ty) = &case.ty {
164
3.17k
                        self.visit_type(resolve, ty);
165
3.17k
                    }
166
                }
167
            }
168
3.50k
            TypeDefKind::Result(r) => {
169
3.50k
                if let Some(ty) = &r.ok {
170
3.34k
                    self.visit_type(resolve, ty);
171
3.34k
                }
172
3.50k
                if let Some(ty) = &r.err {
173
3.19k
                    self.visit_type(resolve, ty);
174
3.19k
                }
175
            }
176
            TypeDefKind::Flags(_)
177
            | TypeDefKind::Enum(_)
178
            | TypeDefKind::Future(None)
179
14.2k
            | TypeDefKind::Stream(None) => {}
180
0
            TypeDefKind::Unknown => unreachable!(),
181
        }
182
29.7k
    }
183
184
76.4k
    fn visit_type(&mut self, resolve: &Resolve, ty: &Type) {
185
76.4k
        match ty {
186
25.1k
            Type::Id(id) => self.visit_type_id(resolve, *id),
187
51.2k
            _ => {}
188
        }
189
76.4k
    }
<<wit_parser::resolve::Resolve>::assert_world_imports_type_deps::MyVisit as wit_parser::live::TypeIdVisitor>::visit_type
Line
Count
Source
184
22.0k
    fn visit_type(&mut self, resolve: &Resolve, ty: &Type) {
185
22.0k
        match ty {
186
8.64k
            Type::Id(id) => self.visit_type_id(resolve, *id),
187
13.3k
            _ => {}
188
        }
189
22.0k
    }
<wit_parser::live::LiveTypes as wit_parser::live::TypeIdVisitor>::visit_type
Line
Count
Source
184
54.4k
    fn visit_type(&mut self, resolve: &Resolve, ty: &Type) {
185
54.4k
        match ty {
186
16.5k
            Type::Id(id) => self.visit_type_id(resolve, *id),
187
37.9k
            _ => {}
188
        }
189
54.4k
    }
190
}
191
192
#[cfg(test)]
193
mod tests {
194
    use super::{LiveTypes, Resolve};
195
    use alloc::string::String;
196
    use alloc::vec::Vec;
197
198
    fn live(wit: &str, ty: &str) -> Vec<String> {
199
        let mut resolve = Resolve::default();
200
        resolve.push_str("test.wit", wit).unwrap();
201
        let (_, interface) = resolve.interfaces.iter().next_back().unwrap();
202
        let ty = interface.types[ty];
203
        let mut live = LiveTypes::default();
204
        live.add_type_id(&resolve, ty);
205
206
        live.iter()
207
            .filter_map(|ty| resolve.types[ty].name.clone())
208
            .collect()
209
    }
210
211
    #[test]
212
    fn no_deps() {
213
        let types = live(
214
            "
215
                package foo:bar;
216
217
                interface foo {
218
                    type t = u32;
219
                }
220
            ",
221
            "t",
222
        );
223
        assert_eq!(types, ["t"]);
224
    }
225
226
    #[test]
227
    fn one_dep() {
228
        let types = live(
229
            "
230
                package foo:bar;
231
232
                interface foo {
233
                    type t = u32;
234
                    type u = t;
235
                }
236
            ",
237
            "u",
238
        );
239
        assert_eq!(types, ["t", "u"]);
240
    }
241
242
    #[test]
243
    fn chain() {
244
        let types = live(
245
            "
246
                package foo:bar;
247
248
                interface foo {
249
                    resource t1;
250
                    record t2 {
251
                        x: t1,
252
                    }
253
                    variant t3 {
254
                        x(t2),
255
                    }
256
                    flags t4 { a }
257
                    enum t5 { a }
258
                    type t6 = tuple<t5, t4, t3>;
259
                }
260
            ",
261
            "t6",
262
        );
263
        assert_eq!(types, ["t5", "t4", "t1", "t2", "t3", "t6"]);
264
    }
265
}