11use crate :: {
2- Function , FunctionKind , InterfaceId , Resolve , Type , TypeDefKind , TypeId , WorldId , WorldItem ,
2+ Function , FunctionKind , InterfaceId , Resolve , Type , TypeDef , TypeDefKind , TypeId , WorldId ,
3+ WorldItem ,
34} ;
45use indexmap:: IndexSet ;
56
@@ -18,36 +19,88 @@ impl LiveTypes {
1819 }
1920
2021 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+
46+ impl 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.
58+ pub 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 ) {
2174 let iface = & resolve. interfaces [ iface] ;
2275 for ( _, id) in iface. types . iter ( ) {
23- self . add_type_id ( resolve, * id) ;
76+ self . visit_type_id ( resolve, * id) ;
2477 }
2578 for ( _, func) in iface. functions . iter ( ) {
26- self . add_func ( resolve, func) ;
79+ self . visit_func ( resolve, func) ;
2780 }
2881 }
2982
30- pub fn add_world ( & mut self , resolve : & Resolve , world : WorldId ) {
83+ fn visit_world ( & mut self , resolve : & Resolve , world : WorldId ) {
3184 let world = & resolve. worlds [ world] ;
3285 for ( _, item) in world. imports . iter ( ) . chain ( world. exports . iter ( ) ) {
33- self . add_world_item ( resolve, item) ;
86+ self . visit_world_item ( resolve, item) ;
3487 }
3588 }
3689
37- pub fn add_world_item ( & mut self , resolve : & Resolve , item : & WorldItem ) {
90+ fn visit_world_item ( & mut self , resolve : & Resolve , item : & WorldItem ) {
3891 match item {
39- WorldItem :: Interface { id, .. } => self . add_interface ( resolve, * id) ,
40- WorldItem :: Function ( f) => self . add_func ( resolve, f) ,
41- WorldItem :: Type ( t) => self . add_type_id ( resolve, * t) ,
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) ,
4295 }
4396 }
4497
45- pub fn add_func ( & mut self , resolve : & Resolve , func : & Function ) {
98+ fn visit_func ( & mut self , resolve : & Resolve , func : & Function ) {
4699 match func. kind {
47100 // This resource is live as it's attached to a static method but
48101 // it's not guaranteed to be present in either params or results, so
49102 // be sure to attach it here.
50- FunctionKind :: Static ( id) => self . add_type_id ( resolve, id) ,
103+ FunctionKind :: Static ( id) => self . visit_type_id ( resolve, id) ,
51104
52105 // The resource these are attached to is in the params/results, so
53106 // no need to re-add it here.
@@ -57,70 +110,146 @@ impl LiveTypes {
57110 }
58111
59112 for ( _, ty) in func. params . iter ( ) {
60- self . add_type ( resolve, ty) ;
113+ self . visit_type ( resolve, ty) ;
61114 }
62115 for ty in func. results . iter_types ( ) {
63- self . add_type ( resolve, ty) ;
116+ self . visit_type ( resolve, ty) ;
64117 }
65118 }
66119
67- pub fn add_type_id ( & mut self , resolve : & Resolve , ty : TypeId ) {
68- if self . set . contains ( & ty) {
69- return ;
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) ;
70124 }
71- match & resolve. types [ ty] . kind {
125+ }
126+
127+ fn visit_type_def ( & mut self , resolve : & Resolve , ty : & TypeDef ) {
128+ match & ty. kind {
72129 TypeDefKind :: Type ( t)
73130 | TypeDefKind :: List ( t)
74131 | TypeDefKind :: Option ( t)
75- | TypeDefKind :: Future ( Some ( t) ) => self . add_type ( resolve, t) ,
132+ | TypeDefKind :: Future ( Some ( t) ) => self . visit_type ( resolve, t) ,
76133 TypeDefKind :: Handle ( handle) => match handle {
77- crate :: Handle :: Own ( ty) => self . add_type_id ( resolve, * ty) ,
78- crate :: Handle :: Borrow ( ty) => self . add_type_id ( resolve, * ty) ,
134+ crate :: Handle :: Own ( ty) => self . visit_type_id ( resolve, * ty) ,
135+ crate :: Handle :: Borrow ( ty) => self . visit_type_id ( resolve, * ty) ,
79136 } ,
80137 TypeDefKind :: Resource => { }
81138 TypeDefKind :: Record ( r) => {
82139 for field in r. fields . iter ( ) {
83- self . add_type ( resolve, & field. ty ) ;
140+ self . visit_type ( resolve, & field. ty ) ;
84141 }
85142 }
86143 TypeDefKind :: Tuple ( r) => {
87144 for ty in r. types . iter ( ) {
88- self . add_type ( resolve, ty) ;
145+ self . visit_type ( resolve, ty) ;
89146 }
90147 }
91148 TypeDefKind :: Variant ( v) => {
92149 for case in v. cases . iter ( ) {
93150 if let Some ( ty) = & case. ty {
94- self . add_type ( resolve, ty) ;
151+ self . visit_type ( resolve, ty) ;
95152 }
96153 }
97154 }
98155 TypeDefKind :: Result ( r) => {
99156 if let Some ( ty) = & r. ok {
100- self . add_type ( resolve, ty) ;
157+ self . visit_type ( resolve, ty) ;
101158 }
102159 if let Some ( ty) = & r. err {
103- self . add_type ( resolve, ty) ;
160+ self . visit_type ( resolve, ty) ;
104161 }
105162 }
106163 TypeDefKind :: Stream ( s) => {
107164 if let Some ( ty) = & s. element {
108- self . add_type ( resolve, ty) ;
165+ self . visit_type ( resolve, ty) ;
109166 }
110167 if let Some ( ty) = & s. end {
111- self . add_type ( resolve, ty) ;
168+ self . visit_type ( resolve, ty) ;
112169 }
113170 }
114171 TypeDefKind :: Flags ( _) | TypeDefKind :: Enum ( _) | TypeDefKind :: Future ( None ) => { }
115172 TypeDefKind :: Unknown => unreachable ! ( ) ,
116173 }
117- assert ! ( self . set. insert( ty) ) ;
118174 }
119175
120- pub fn add_type ( & mut self , resolve : & Resolve , ty : & Type ) {
176+ fn visit_type ( & mut self , resolve : & Resolve , ty : & Type ) {
121177 match ty {
122- Type :: Id ( id) => self . add_type_id ( resolve, * id) ,
178+ Type :: Id ( id) => self . visit_type_id ( resolve, * id) ,
123179 _ => { }
124180 }
125181 }
126182}
183+
184+ #[ cfg( test) ]
185+ mod tests {
186+ use super :: { LiveTypes , Resolve } ;
187+
188+ fn live ( wit : & str , ty : & str ) -> Vec < String > {
189+ let mut resolve = Resolve :: default ( ) ;
190+ resolve. push_str ( "test.wit" , wit) . unwrap ( ) ;
191+ let ( _, interface) = resolve. interfaces . iter ( ) . next_back ( ) . unwrap ( ) ;
192+ let ty = interface. types [ ty] ;
193+ let mut live = LiveTypes :: default ( ) ;
194+ live. add_type_id ( & resolve, ty) ;
195+
196+ live. iter ( )
197+ . filter_map ( |ty| resolve. types [ ty] . name . clone ( ) )
198+ . collect ( )
199+ }
200+
201+ #[ test]
202+ fn no_deps ( ) {
203+ let types = live (
204+ "
205+ package foo:bar;
206+
207+ interface foo {
208+ type t = u32;
209+ }
210+ " ,
211+ "t" ,
212+ ) ;
213+ assert_eq ! ( types, [ "t" ] ) ;
214+ }
215+
216+ #[ test]
217+ fn one_dep ( ) {
218+ let types = live (
219+ "
220+ package foo:bar;
221+
222+ interface foo {
223+ type t = u32;
224+ type u = t;
225+ }
226+ " ,
227+ "u" ,
228+ ) ;
229+ assert_eq ! ( types, [ "t" , "u" ] ) ;
230+ }
231+
232+ #[ test]
233+ fn chain ( ) {
234+ let types = live (
235+ "
236+ package foo:bar;
237+
238+ interface foo {
239+ resource t1;
240+ record t2 {
241+ x: t1,
242+ }
243+ variant t3 {
244+ x(t2),
245+ }
246+ flags t4 { a }
247+ enum t5 { a }
248+ type t6 = tuple<t5, t4, t3>;
249+ }
250+ " ,
251+ "t6" ,
252+ ) ;
253+ assert_eq ! ( types, [ "t5" , "t4" , "t1" , "t2" , "t3" , "t6" ] ) ;
254+ }
255+ }
0 commit comments