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, ¶m.ty); 85 live.add_type(resolve, ¶m.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