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