1 use std::collections::HashMap;
2 use wit_parser::*;
3 
4 #[derive(Default)]
5 pub struct Types {
6     type_info: HashMap<TypeId, TypeInfo>,
7 }
8 
9 #[derive(Default, Clone, Copy, Debug, PartialEq)]
10 pub struct TypeInfo {
11     /// Whether or not this type is ever used (transitively) within a borrowed
12     /// context, or a parameter to an export function.
13     pub borrowed: bool,
14 
15     /// Whether or not this type is ever used (transitively) within an owned
16     /// context, such as the result of an exported function or in the params or
17     /// results of an imported function.
18     pub owned: bool,
19 
20     /// Whether or not this type is ever used (transitively) within the
21     /// error case in the result of a function.
22     pub error: bool,
23 
24     /// Whether or not this type (transitively) has a list.
25     pub has_list: bool,
26 
27     /// Whether or not this type (transitively) has a handle.
28     pub has_handle: bool,
29 }
30 
31 impl std::ops::BitOrAssign for TypeInfo {
32     fn bitor_assign(&mut self, rhs: Self) {
33         self.borrowed |= rhs.borrowed;
34         self.owned |= rhs.owned;
35         self.error |= rhs.error;
36         self.has_list |= rhs.has_list;
37         self.has_handle |= rhs.has_handle;
38     }
39 }
40 
41 impl Types {
42     pub fn analyze(&mut self, resolve: &Resolve, world: WorldId) {
43         // Build up all type information first which is inherited through types,
44         // such as properties of borrows/lists/etc.
45         for (t, _) in resolve.types.iter() {
46             self.type_id_info(resolve, t);
47         }
48 
49         // ... next handle borrowed/owned flags which aren't inherited through
50         // types.
51         let world = &resolve.worlds[world];
52         for (import, (_, item)) in world
53             .imports
54             .iter()
55             .map(|i| (true, i))
56             .chain(world.exports.iter().map(|i| (false, i)))
57         {
58             match item {
59                 WorldItem::Function(f) => self.type_info_func(resolve, f, import),
60                 WorldItem::Interface { id, .. } => {
61                     let iface = &resolve.interfaces[*id];
62 
63                     for (_, t) in iface.types.iter() {
64                         self.type_id_info(resolve, *t);
65                     }
66                     for (_, f) in iface.functions.iter() {
67                         self.type_info_func(resolve, f, import);
68                     }
69                 }
70                 WorldItem::Type(id) => {
71                     self.type_id_info(resolve, *id);
72                 }
73             }
74         }
75     }
76 
77     fn type_info_func(&mut self, resolve: &Resolve, func: &Function, import: bool) {
78         let mut live = LiveTypes::default();
79         for (_, ty) in func.params.iter() {
80             self.type_info(resolve, ty);
81             live.add_type(resolve, ty);
82         }
83         for id in live.iter() {
84             if resolve.types[id].name.is_some() {
85                 let info = self.type_info.get_mut(&id).unwrap();
86                 if import {
87                     info.owned = true;
88                 } else {
89                     info.borrowed = true;
90                 }
91             }
92         }
93         let mut live = LiveTypes::default();
94         if let Some(ty) = &func.result {
95             self.type_info(resolve, ty);
96             live.add_type(resolve, ty);
97         }
98         for id in live.iter() {
99             if resolve.types[id].name.is_some() {
100                 self.type_info.get_mut(&id).unwrap().owned = true;
101             }
102         }
103 
104         if let Some(Type::Id(id)) = func.result {
105             if let TypeDefKind::Result(Result_ {
106                 err: Some(Type::Id(id)),
107                 ..
108             }) = &resolve.types[id].kind
109             {
110                 let id = super::resolve_type_definition_id(resolve, *id);
111                 self.type_info.get_mut(&id).unwrap().error = true;
112             }
113         }
114     }
115 
116     pub fn get(&self, id: TypeId) -> TypeInfo {
117         self.type_info[&id]
118     }
119 
120     fn type_id_info(&mut self, resolve: &Resolve, ty: TypeId) -> TypeInfo {
121         if let Some(info) = self.type_info.get(&ty) {
122             return *info;
123         }
124         let mut info = TypeInfo::default();
125         match &resolve.types[ty].kind {
126             TypeDefKind::Record(r) => {
127                 for field in r.fields.iter() {
128                     info |= self.type_info(resolve, &field.ty);
129                 }
130             }
131             TypeDefKind::Tuple(t) => {
132                 for ty in t.types.iter() {
133                     info |= self.type_info(resolve, ty);
134                 }
135             }
136             TypeDefKind::Flags(_) => {}
137             TypeDefKind::Enum(_) => {}
138             TypeDefKind::Variant(v) => {
139                 for case in v.cases.iter() {
140                     info |= self.optional_type_info(resolve, case.ty.as_ref());
141                 }
142             }
143             TypeDefKind::List(ty) => {
144                 info = self.type_info(resolve, ty);
145                 info.has_list = true;
146             }
147             TypeDefKind::Type(ty) | TypeDefKind::Option(ty) => {
148                 info = self.type_info(resolve, ty);
149             }
150             TypeDefKind::Result(r) => {
151                 info = self.optional_type_info(resolve, r.ok.as_ref());
152                 info |= self.optional_type_info(resolve, r.err.as_ref());
153             }
154             TypeDefKind::Future(ty) | TypeDefKind::Stream(ty) => {
155                 info = self.optional_type_info(resolve, ty.as_ref());
156             }
157             TypeDefKind::Handle(_) => info.has_handle = true,
158             TypeDefKind::Resource => {}
159             TypeDefKind::Unknown => unreachable!(),
160             TypeDefKind::FixedSizeList(..) => todo!(),
161         }
162         self.type_info.insert(ty, info);
163         info
164     }
165 
166     fn type_info(&mut self, resolve: &Resolve, ty: &Type) -> TypeInfo {
167         let mut info = TypeInfo::default();
168         match ty {
169             Type::String => info.has_list = true,
170             Type::Id(id) => return self.type_id_info(resolve, *id),
171             _ => {}
172         }
173         info
174     }
175 
176     fn optional_type_info(&mut self, resolve: &Resolve, ty: Option<&Type>) -> TypeInfo {
177         match ty {
178             Some(ty) => self.type_info(resolve, ty),
179             None => TypeInfo::default(),
180         }
181     }
182 }
183 
184 impl TypeInfo {
185     pub fn is_copy(&self) -> bool {
186         !self.has_list && !self.has_handle
187     }
188 
189     pub fn is_clone(&self) -> bool {
190         !self.has_handle
191     }
192 }
193