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