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 for ty in func.results.iter_types() { 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 for ty in func.results.iter_types() { 105 let id = match ty { 106 Type::Id(id) => *id, 107 _ => continue, 108 }; 109 let err = match &resolve.types[id].kind { 110 TypeDefKind::Result(Result_ { err, .. }) => err, 111 _ => continue, 112 }; 113 if let Some(Type::Id(id)) = err { 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) => { 152 info = self.type_info(resolve, ty); 153 } 154 TypeDefKind::Option(ty) => { 155 info = self.type_info(resolve, ty); 156 } 157 TypeDefKind::Result(r) => { 158 info = self.optional_type_info(resolve, r.ok.as_ref()); 159 info |= self.optional_type_info(resolve, r.err.as_ref()); 160 } 161 TypeDefKind::Future(ty) => { 162 info = self.optional_type_info(resolve, ty.as_ref()); 163 } 164 TypeDefKind::Stream(stream) => { 165 info = self.optional_type_info(resolve, stream.element.as_ref()); 166 info |= self.optional_type_info(resolve, stream.end.as_ref()); 167 } 168 TypeDefKind::Handle(_) => info.has_handle = true, 169 TypeDefKind::Resource => {} 170 TypeDefKind::Unknown => unreachable!(), 171 } 172 self.type_info.insert(ty, info); 173 info 174 } 175 176 fn type_info(&mut self, resolve: &Resolve, ty: &Type) -> TypeInfo { 177 let mut info = TypeInfo::default(); 178 match ty { 179 Type::String => info.has_list = true, 180 Type::Id(id) => return self.type_id_info(resolve, *id), 181 _ => {} 182 } 183 info 184 } 185 186 fn optional_type_info(&mut self, resolve: &Resolve, ty: Option<&Type>) -> TypeInfo { 187 match ty { 188 Some(ty) => self.type_info(resolve, ty), 189 None => TypeInfo::default(), 190 } 191 } 192 } 193 194 impl TypeInfo { 195 pub fn is_copy(&self) -> bool { 196 !self.has_list && !self.has_handle 197 } 198 199 pub fn is_clone(&self) -> bool { 200 !self.has_handle 201 } 202 } 203