Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/mir/eval.rs')
| -rw-r--r-- | crates/hir-ty/src/mir/eval.rs | 101 |
1 files changed, 66 insertions, 35 deletions
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 78961e1982..01295a9fc3 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -1263,50 +1263,81 @@ impl Evaluator<'_> { current_ty: &Ty, target_ty: &Ty, ) -> Result<IntervalOrOwned> { - use IntervalOrOwned::*; fn for_ptr(x: &TyKind) -> Option<Ty> { match x { TyKind::Raw(_, ty) | TyKind::Ref(_, _, ty) => Some(ty.clone()), _ => None, } } - Ok(match self.coerce_unsized_look_through_fields(target_ty, for_ptr)? { - ty => match &ty.data(Interner).kind { - TyKind::Slice(_) => { - match self.coerce_unsized_look_through_fields(current_ty, for_ptr)? { - ty => match &ty.data(Interner).kind { - TyKind::Array(_, size) => { - let len = match try_const_usize(self.db, size) { - None => not_supported!( - "unevaluatble len of array in coerce unsized" - ), - Some(x) => x as usize, - }; - let mut r = Vec::with_capacity(16); - let addr = addr.get(self)?; - r.extend(addr.iter().copied()); - r.extend(len.to_le_bytes().into_iter()); - Owned(r) - } - t => { - not_supported!("slice unsizing from non array type {t:?}") - } - }, - } + let target_ty = self.coerce_unsized_look_through_fields(target_ty, for_ptr)?; + let current_ty = self.coerce_unsized_look_through_fields(current_ty, for_ptr)?; + + self.unsizing_ptr_from_addr(target_ty, current_ty, addr) + } + + /// Adds metadata to the address and create the fat pointer result of the unsizing operation. + fn unsizing_ptr_from_addr( + &mut self, + target_ty: Ty, + current_ty: Ty, + addr: Interval, + ) -> Result<IntervalOrOwned> { + use IntervalOrOwned::*; + Ok(match &target_ty.data(Interner).kind { + TyKind::Slice(_) => match ¤t_ty.data(Interner).kind { + TyKind::Array(_, size) => { + let len = match try_const_usize(self.db, size) { + None => { + not_supported!("unevaluatble len of array in coerce unsized") + } + Some(x) => x as usize, + }; + let mut r = Vec::with_capacity(16); + let addr = addr.get(self)?; + r.extend(addr.iter().copied()); + r.extend(len.to_le_bytes().into_iter()); + Owned(r) } - TyKind::Dyn(_) => match ¤t_ty.data(Interner).kind { - TyKind::Raw(_, ty) | TyKind::Ref(_, _, ty) => { - let vtable = self.vtable_map.id(ty.clone()); - let mut r = Vec::with_capacity(16); - let addr = addr.get(self)?; - r.extend(addr.iter().copied()); - r.extend(vtable.to_le_bytes().into_iter()); - Owned(r) + t => { + not_supported!("slice unsizing from non array type {t:?}") + } + }, + TyKind::Dyn(_) => { + let vtable = self.vtable_map.id(current_ty.clone()); + let mut r = Vec::with_capacity(16); + let addr = addr.get(self)?; + r.extend(addr.iter().copied()); + r.extend(vtable.to_le_bytes().into_iter()); + Owned(r) + } + TyKind::Adt(id, target_subst) => match ¤t_ty.data(Interner).kind { + TyKind::Adt(current_id, current_subst) => { + if id != current_id { + not_supported!("unsizing struct with different type"); } - _ => not_supported!("dyn unsizing from non pointers"), - }, - _ => not_supported!("unknown unsized cast"), + let id = match id.0 { + AdtId::StructId(s) => s, + AdtId::UnionId(_) => not_supported!("unsizing unions"), + AdtId::EnumId(_) => not_supported!("unsizing enums"), + }; + let Some((last_field, _)) = self.db.struct_data(id).variant_data.fields().iter().rev().next() else { + not_supported!("unsizing struct without field"); + }; + let target_last_field = self.db.field_types(id.into())[last_field] + .clone() + .substitute(Interner, target_subst); + let current_last_field = self.db.field_types(id.into())[last_field] + .clone() + .substitute(Interner, current_subst); + return self.unsizing_ptr_from_addr( + target_last_field, + current_last_field, + addr, + ); + } + _ => not_supported!("unsizing struct with non adt type"), }, + _ => not_supported!("unknown unsized cast"), }) } |