summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/hir-ty/src/layout.rs')
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs150
1 files changed, 108 insertions, 42 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
index b95bb01fc..35d3407c1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -1,19 +1,23 @@
//! Compute the binary representation of a type
use base_db::CrateId;
-use chalk_ir::{AdtId, TyKind};
+use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy};
use hir_def::{
layout::{
- Abi, FieldsShape, Integer, Layout, LayoutCalculator, LayoutError, Primitive, ReprOptions,
- RustcEnumVariantIdx, Scalar, Size, StructKind, TargetDataLayout, Variants, WrappingRange,
+ Abi, FieldsShape, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions, Scalar, Size,
+ StructKind, TargetDataLayout, WrappingRange,
},
- LocalFieldId,
+ LocalEnumVariantId, LocalFieldId,
};
+use la_arena::{Idx, RawIdx};
use stdx::never;
+use triomphe::Arc;
-use crate::{consteval::try_const_usize, db::HirDatabase, Interner, Substitution, Ty};
+use crate::{
+ consteval::try_const_usize, db::HirDatabase, infer::normalize, layout::adt::struct_variant_idx,
+ utils::ClosureSubst, Interner, Substitution, TraitEnvironment, Ty,
+};
-use self::adt::struct_variant_idx;
pub use self::{
adt::{layout_of_adt_query, layout_of_adt_recover},
target::target_data_layout_query,
@@ -28,6 +32,34 @@ macro_rules! user_error {
mod adt;
mod target;
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct RustcEnumVariantIdx(pub LocalEnumVariantId);
+
+impl rustc_index::vec::Idx for RustcEnumVariantIdx {
+ fn new(idx: usize) -> Self {
+ RustcEnumVariantIdx(Idx::from_raw(RawIdx::from(idx as u32)))
+ }
+
+ fn index(self) -> usize {
+ u32::from(self.0.into_raw()) as usize
+ }
+}
+
+pub type Layout = LayoutS<RustcEnumVariantIdx>;
+pub type TagEncoding = hir_def::layout::TagEncoding<RustcEnumVariantIdx>;
+pub type Variants = hir_def::layout::Variants<RustcEnumVariantIdx>;
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub enum LayoutError {
+ UserError(String),
+ SizeOverflow,
+ TargetLayoutNotAvailable,
+ HasPlaceholder,
+ HasErrorType,
+ NotImplemented,
+ Unknown,
+}
+
struct LayoutCx<'a> {
krate: CrateId,
target: &'a TargetDataLayout,
@@ -45,20 +77,18 @@ impl<'a> LayoutCalculator for LayoutCx<'a> {
}
}
-fn scalar_unit(dl: &TargetDataLayout, value: Primitive) -> Scalar {
- Scalar::Initialized { value, valid_range: WrappingRange::full(value.size(dl)) }
-}
-
-fn scalar(dl: &TargetDataLayout, value: Primitive) -> Layout {
- Layout::scalar(dl, scalar_unit(dl, value))
-}
-
-pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Layout, LayoutError> {
+pub fn layout_of_ty_query(
+ db: &dyn HirDatabase,
+ ty: Ty,
+ krate: CrateId,
+) -> Result<Arc<Layout>, LayoutError> {
let Some(target) = db.target_data_layout(krate) else { return Err(LayoutError::TargetLayoutNotAvailable) };
let cx = LayoutCx { krate, target: &target };
let dl = &*cx.current_data_layout();
- Ok(match ty.kind(Interner) {
- TyKind::Adt(AdtId(def), subst) => db.layout_of_adt(*def, subst.clone())?,
+ let trait_env = Arc::new(TraitEnvironment::empty(krate));
+ let ty = normalize(db, trait_env, ty.clone());
+ let result = match ty.kind(Interner) {
+ TyKind::Adt(AdtId(def), subst) => return db.layout_of_adt(*def, subst.clone(), krate),
TyKind::Scalar(s) => match s {
chalk_ir::Scalar::Bool => Layout::scalar(
dl,
@@ -78,12 +108,12 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
dl,
Primitive::Int(
match i {
- chalk_ir::IntTy::Isize => dl.ptr_sized_integer(),
- chalk_ir::IntTy::I8 => Integer::I8,
- chalk_ir::IntTy::I16 => Integer::I16,
- chalk_ir::IntTy::I32 => Integer::I32,
- chalk_ir::IntTy::I64 => Integer::I64,
- chalk_ir::IntTy::I128 => Integer::I128,
+ IntTy::Isize => dl.ptr_sized_integer(),
+ IntTy::I8 => Integer::I8,
+ IntTy::I16 => Integer::I16,
+ IntTy::I32 => Integer::I32,
+ IntTy::I64 => Integer::I64,
+ IntTy::I128 => Integer::I128,
},
true,
),
@@ -92,12 +122,12 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
dl,
Primitive::Int(
match i {
- chalk_ir::UintTy::Usize => dl.ptr_sized_integer(),
- chalk_ir::UintTy::U8 => Integer::I8,
- chalk_ir::UintTy::U16 => Integer::I16,
- chalk_ir::UintTy::U32 => Integer::I32,
- chalk_ir::UintTy::U64 => Integer::I64,
- chalk_ir::UintTy::U128 => Integer::I128,
+ UintTy::Usize => dl.ptr_sized_integer(),
+ UintTy::U8 => Integer::I8,
+ UintTy::U16 => Integer::I16,
+ UintTy::U32 => Integer::I32,
+ UintTy::U64 => Integer::I64,
+ UintTy::U128 => Integer::I128,
},
false,
),
@@ -105,8 +135,8 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
chalk_ir::Scalar::Float(f) => scalar(
dl,
match f {
- chalk_ir::FloatTy::F32 => Primitive::F32,
- chalk_ir::FloatTy::F64 => Primitive::F64,
+ FloatTy::F32 => Primitive::F32,
+ FloatTy::F64 => Primitive::F64,
},
),
},
@@ -115,17 +145,17 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
let fields = tys
.iter(Interner)
- .map(|k| layout_of_ty(db, k.assert_ty_ref(Interner), krate))
+ .map(|k| db.layout_of_ty(k.assert_ty_ref(Interner).clone(), krate))
.collect::<Result<Vec<_>, _>>()?;
- let fields = fields.iter().collect::<Vec<_>>();
+ let fields = fields.iter().map(|x| &**x).collect::<Vec<_>>();
let fields = fields.iter().collect::<Vec<_>>();
cx.univariant(dl, &fields, &ReprOptions::default(), kind).ok_or(LayoutError::Unknown)?
}
TyKind::Array(element, count) => {
- let count = try_const_usize(&count).ok_or(LayoutError::UserError(
- "mismatched type of const generic parameter".to_string(),
+ let count = try_const_usize(db, &count).ok_or(LayoutError::UserError(
+ "unevaluated or mistyped const generic parameter".to_string(),
))? as u64;
- let element = layout_of_ty(db, element, krate)?;
+ let element = db.layout_of_ty(element.clone(), krate)?;
let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow)?;
let abi = if count != 0 && matches!(element.abi, Abi::Uninhabited) {
@@ -146,7 +176,7 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
}
}
TyKind::Slice(element) => {
- let element = layout_of_ty(db, element, krate)?;
+ let element = db.layout_of_ty(element.clone(), krate)?;
Layout {
variants: Variants::Single { index: struct_variant_idx() },
fields: FieldsShape::Array { stride: element.size, count: 0 },
@@ -180,7 +210,7 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
}
_ => {
// pointee is sized
- return Ok(Layout::scalar(dl, data_ptr));
+ return Ok(Arc::new(Layout::scalar(dl, data_ptr)));
}
};
@@ -222,23 +252,51 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
match impl_trait_id {
crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => {
let infer = db.infer(func.into());
- layout_of_ty(db, &infer.type_of_rpit[idx], krate)?
+ return db.layout_of_ty(infer.type_of_rpit[idx].clone(), krate);
}
crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
return Err(LayoutError::NotImplemented)
}
}
}
- TyKind::Closure(_, _) | TyKind::Generator(_, _) | TyKind::GeneratorWitness(_, _) => {
+ TyKind::Closure(c, subst) => {
+ let (def, _) = db.lookup_intern_closure((*c).into());
+ let infer = db.infer(def);
+ let (captures, _) = infer.closure_info(c);
+ let fields = captures
+ .iter()
+ .map(|x| {
+ db.layout_of_ty(
+ x.ty.clone().substitute(Interner, ClosureSubst(subst).parent_subst()),
+ krate,
+ )
+ })
+ .collect::<Result<Vec<_>, _>>()?;
+ let fields = fields.iter().map(|x| &**x).collect::<Vec<_>>();
+ let fields = fields.iter().collect::<Vec<_>>();
+ cx.univariant(dl, &fields, &ReprOptions::default(), StructKind::AlwaysSized)
+ .ok_or(LayoutError::Unknown)?
+ }
+ TyKind::Generator(_, _) | TyKind::GeneratorWitness(_, _) => {
return Err(LayoutError::NotImplemented)
}
+ TyKind::Error => return Err(LayoutError::HasErrorType),
TyKind::AssociatedType(_, _)
- | TyKind::Error
| TyKind::Alias(_)
| TyKind::Placeholder(_)
| TyKind::BoundVar(_)
| TyKind::InferenceVar(_, _) => return Err(LayoutError::HasPlaceholder),
- })
+ };
+ Ok(Arc::new(result))
+}
+
+pub fn layout_of_ty_recover(
+ _: &dyn HirDatabase,
+ _: &[String],
+ _: &Ty,
+ _: &CrateId,
+) -> Result<Arc<Layout>, LayoutError> {
+ user_error!("infinite sized recursive type");
}
fn layout_of_unit(cx: &LayoutCx<'_>, dl: &TargetDataLayout) -> Result<Layout, LayoutError> {
@@ -274,5 +332,13 @@ fn field_ty(
db.field_types(def)[fd].clone().substitute(Interner, subst)
}
+fn scalar_unit(dl: &TargetDataLayout, value: Primitive) -> Scalar {
+ Scalar::Initialized { value, valid_range: WrappingRange::full(value.size(dl)) }
+}
+
+fn scalar(dl: &TargetDataLayout, value: Primitive) -> Layout {
+ Layout::scalar(dl, scalar_unit(dl, value))
+}
+
#[cfg(test)]
mod tests;