1 //! Compute the binary representation of a type
6 use chalk_ir::{AdtId, TyKind};
9 Abi, FieldsShape, Integer, Layout, LayoutCalculator, LayoutError, Primitive, ReprOptions,
10 RustcEnumVariantIdx, Scalar, Size, StructKind, TargetDataLayout, Variants, WrappingRange,
16 use crate::{db::HirDatabase, Interner, Substitution, Ty};
18 use self::adt::struct_variant_idx;
20 adt::{layout_of_adt_query, layout_of_adt_recover},
21 target::target_data_layout_query,
24 macro_rules! user_error {
26 return Err(LayoutError::UserError(format!($x)))
34 db: &'a dyn HirDatabase,
38 impl LayoutCalculator for LayoutCx<'_> {
39 type TargetDataLayoutRef = Arc<TargetDataLayout>;
41 fn delay_bug(&self, txt: &str) {
45 fn current_data_layout(&self) -> Arc<TargetDataLayout> {
46 self.db.target_data_layout(self.krate)
50 fn scalar_unit(dl: &TargetDataLayout, value: Primitive) -> Scalar {
51 Scalar::Initialized { value, valid_range: WrappingRange::full(value.size(dl)) }
54 fn scalar(dl: &TargetDataLayout, value: Primitive) -> Layout {
55 Layout::scalar(dl, scalar_unit(dl, value))
58 pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Layout, LayoutError> {
59 let cx = LayoutCx { db, krate };
60 let dl = &*cx.current_data_layout();
61 Ok(match ty.kind(Interner) {
62 TyKind::Adt(AdtId(def), subst) => db.layout_of_adt(*def, subst.clone())?,
63 TyKind::Scalar(s) => match s {
64 chalk_ir::Scalar::Bool => Layout::scalar(
67 value: Primitive::Int(Integer::I8, false),
68 valid_range: WrappingRange { start: 0, end: 1 },
71 chalk_ir::Scalar::Char => Layout::scalar(
74 value: Primitive::Int(Integer::I32, false),
75 valid_range: WrappingRange { start: 0, end: 0x10FFFF },
78 chalk_ir::Scalar::Int(i) => scalar(
82 chalk_ir::IntTy::Isize => dl.ptr_sized_integer(),
83 chalk_ir::IntTy::I8 => Integer::I8,
84 chalk_ir::IntTy::I16 => Integer::I16,
85 chalk_ir::IntTy::I32 => Integer::I32,
86 chalk_ir::IntTy::I64 => Integer::I64,
87 chalk_ir::IntTy::I128 => Integer::I128,
92 chalk_ir::Scalar::Uint(i) => scalar(
96 chalk_ir::UintTy::Usize => dl.ptr_sized_integer(),
97 chalk_ir::UintTy::U8 => Integer::I8,
98 chalk_ir::UintTy::U16 => Integer::I16,
99 chalk_ir::UintTy::U32 => Integer::I32,
100 chalk_ir::UintTy::U64 => Integer::I64,
101 chalk_ir::UintTy::U128 => Integer::I128,
106 chalk_ir::Scalar::Float(f) => scalar(
109 chalk_ir::FloatTy::F32 => Primitive::F32,
110 chalk_ir::FloatTy::F64 => Primitive::F64,
114 TyKind::Tuple(len, tys) => {
115 let kind = if *len == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized };
119 .map(|k| layout_of_ty(db, k.assert_ty_ref(Interner), krate))
120 .collect::<Result<Vec<_>, _>>()?;
121 let fields = fields.iter().collect::<Vec<_>>();
122 let fields = fields.iter().collect::<Vec<_>>();
123 cx.univariant(dl, &fields, &ReprOptions::default(), kind).ok_or(LayoutError::Unknown)?
125 TyKind::Array(element, count) => {
126 let count = match count.data(Interner).value {
127 chalk_ir::ConstValue::Concrete(c) => match c.interned {
128 hir_def::type_ref::ConstScalar::Int(x) => x as u64,
129 hir_def::type_ref::ConstScalar::UInt(x) => x as u64,
130 hir_def::type_ref::ConstScalar::Unknown => {
131 user_error!("unknown const generic parameter")
133 _ => user_error!("mismatched type of const generic parameter"),
135 _ => return Err(LayoutError::HasPlaceholder),
137 let element = layout_of_ty(db, element, krate)?;
138 let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow)?;
140 let abi = if count != 0 && matches!(element.abi, Abi::Uninhabited) {
143 Abi::Aggregate { sized: true }
146 let largest_niche = if count != 0 { element.largest_niche } else { None };
149 variants: Variants::Single { index: struct_variant_idx() },
150 fields: FieldsShape::Array { stride: element.size, count },
153 align: element.align,
157 TyKind::Slice(element) => {
158 let element = layout_of_ty(db, element, krate)?;
160 variants: Variants::Single { index: struct_variant_idx() },
161 fields: FieldsShape::Array { stride: element.size, count: 0 },
162 abi: Abi::Aggregate { sized: false },
164 align: element.align,
168 // Potentially-wide pointers.
169 TyKind::Ref(_, _, pointee) | TyKind::Raw(_, pointee) => {
170 let mut data_ptr = scalar_unit(dl, Primitive::Pointer);
171 if matches!(ty.kind(Interner), TyKind::Ref(..)) {
172 data_ptr.valid_range_mut().start = 1;
175 // let pointee = tcx.normalize_erasing_regions(param_env, pointee);
176 // if pointee.is_sized(tcx.at(DUMMY_SP), param_env) {
177 // return Ok(tcx.intern_layout(LayoutS::scalar(cx, data_ptr)));
180 let unsized_part = struct_tail_erasing_lifetimes(db, pointee.clone());
181 let metadata = match unsized_part.kind(Interner) {
182 TyKind::Slice(_) | TyKind::Str => {
183 scalar_unit(dl, Primitive::Int(dl.ptr_sized_integer(), false))
186 let mut vtable = scalar_unit(dl, Primitive::Pointer);
187 vtable.valid_range_mut().start = 1;
192 return Ok(Layout::scalar(dl, data_ptr));
196 // Effectively a (ptr, meta) tuple.
197 cx.scalar_pair(data_ptr, metadata)
199 TyKind::FnDef(_, _) => layout_of_unit(&cx, dl)?,
200 TyKind::Str => Layout {
201 variants: Variants::Single { index: struct_variant_idx() },
202 fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 },
203 abi: Abi::Aggregate { sized: false },
208 TyKind::Never => Layout {
209 variants: Variants::Single { index: struct_variant_idx() },
210 fields: FieldsShape::Primitive,
211 abi: Abi::Uninhabited,
216 TyKind::Dyn(_) | TyKind::Foreign(_) => {
217 let mut unit = layout_of_unit(&cx, dl)?;
219 Abi::Aggregate { ref mut sized } => *sized = false,
220 _ => user_error!("bug"),
224 TyKind::Function(_) => {
225 let mut ptr = scalar_unit(dl, Primitive::Pointer);
226 ptr.valid_range_mut().start = 1;
227 Layout::scalar(dl, ptr)
229 TyKind::Closure(_, _)
230 | TyKind::OpaqueType(_, _)
231 | TyKind::Generator(_, _)
232 | TyKind::GeneratorWitness(_, _) => return Err(LayoutError::NotImplemented),
233 TyKind::AssociatedType(_, _)
236 | TyKind::Placeholder(_)
237 | TyKind::BoundVar(_)
238 | TyKind::InferenceVar(_, _) => return Err(LayoutError::HasPlaceholder),
242 fn layout_of_unit(cx: &LayoutCx<'_>, dl: &TargetDataLayout) -> Result<Layout, LayoutError> {
243 cx.univariant::<RustcEnumVariantIdx, &&Layout>(
246 &ReprOptions::default(),
247 StructKind::AlwaysSized,
249 .ok_or(LayoutError::Unknown)
252 fn struct_tail_erasing_lifetimes(db: &dyn HirDatabase, pointee: Ty) -> Ty {
253 match pointee.kind(Interner) {
254 TyKind::Adt(AdtId(adt), subst) => match adt {
255 &hir_def::AdtId::StructId(i) => {
256 let data = db.struct_data(i);
257 let mut it = data.variant_data.fields().iter().rev();
259 Some((f, _)) => field_ty(db, i.into(), f, subst),
270 db: &dyn HirDatabase,
271 def: hir_def::VariantId,
273 subst: &Substitution,
275 db.field_types(def)[fd].clone().substitute(Interner, subst)