Don't leak rustc Layout in hir layer

This commit is contained in:
Lukas Wirth 2023-05-26 17:18:27 +02:00
parent 3514f2f2ab
commit 1275adc200
2 changed files with 54 additions and 44 deletions

View file

@ -62,7 +62,7 @@ use hir_ty::{
consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt}, consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt},
diagnostics::BodyValidationDiagnostic, diagnostics::BodyValidationDiagnostic,
display::HexifiedConst, display::HexifiedConst,
layout::{LayoutError, RustcEnumVariantIdx, TagEncoding}, layout::{Layout as TyLayout, LayoutError, RustcEnumVariantIdx, TagEncoding},
method_resolution::{self, TyFingerprint}, method_resolution::{self, TyFingerprint},
mir::{self, interpret_mir}, mir::{self, interpret_mir},
primitive::UintTy, primitive::UintTy,
@ -133,11 +133,8 @@ pub use {
}, },
hir_ty::{ hir_ty::{
display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite}, display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite},
// FIXME: This just needs a HIR wrapper
layout::Layout,
mir::MirEvalError, mir::MirEvalError,
PointerCast, PointerCast, Safety,
Safety,
}, },
}; };
@ -964,8 +961,8 @@ impl Field {
Type::new(db, var_id, ty) Type::new(db, var_id, ty)
} }
pub fn layout(&self, db: &dyn HirDatabase) -> Result<Arc<Layout>, LayoutError> { pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
db.layout_of_ty(self.ty(db).ty.clone(), self.parent.module(db).krate().into()) db.layout_of_ty(self.ty(db).ty.clone(), self.parent.module(db).krate().into()).map(Layout)
} }
pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef { pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef {
@ -1138,10 +1135,10 @@ impl Enum {
self.variants(db).iter().any(|v| !matches!(v.kind(db), StructKind::Unit)) self.variants(db).iter().any(|v| !matches!(v.kind(db), StructKind::Unit))
} }
pub fn layout(self, db: &dyn HirDatabase) -> Result<(Arc<Layout>, usize), LayoutError> { pub fn layout(self, db: &dyn HirDatabase) -> Result<(Layout, usize), LayoutError> {
let layout = Adt::from(self).layout(db)?; let layout = Adt::from(self).layout(db)?;
let tag_size = let tag_size =
if let layout::Variants::Multiple { tag, tag_encoding, .. } = &layout.variants { if let layout::Variants::Multiple { tag, tag_encoding, .. } = &layout.0.variants {
match tag_encoding { match tag_encoding {
TagEncoding::Direct => { TagEncoding::Direct => {
let target_data_layout = db let target_data_layout = db
@ -1222,11 +1219,11 @@ impl Variant {
let parent_enum = self.parent_enum(db); let parent_enum = self.parent_enum(db);
let (parent_layout, tag_size) = parent_enum.layout(db)?; let (parent_layout, tag_size) = parent_enum.layout(db)?;
Ok(( Ok((
match &parent_layout.variants { match &parent_layout.0.variants {
layout::Variants::Multiple { variants, .. } => { layout::Variants::Multiple { variants, .. } => {
variants[RustcEnumVariantIdx(self.id)].clone() Layout(Arc::new(variants[RustcEnumVariantIdx(self.id)].clone()))
} }
_ => (*parent_layout).clone(), _ => parent_layout,
}, },
tag_size, tag_size,
)) ))
@ -1258,11 +1255,11 @@ impl Adt {
}) })
} }
pub fn layout(self, db: &dyn HirDatabase) -> Result<Arc<Layout>, LayoutError> { pub fn layout(self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
if db.generic_params(self.into()).iter().count() != 0 { if db.generic_params(self.into()).iter().count() != 0 {
return Err(LayoutError::HasPlaceholder); return Err(LayoutError::HasPlaceholder);
} }
db.layout_of_adt(self.into(), Substitution::empty(Interner), self.krate(db).id) db.layout_of_adt(self.into(), Substitution::empty(Interner), self.krate(db).id).map(Layout)
} }
/// Turns this ADT into a type. Any type parameters of the ADT will be /// Turns this ADT into a type. Any type parameters of the ADT will be
@ -4246,8 +4243,8 @@ impl Type {
.collect() .collect()
} }
pub fn layout(&self, db: &dyn HirDatabase) -> Result<Arc<Layout>, LayoutError> { pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
db.layout_of_ty(self.ty.clone(), self.env.krate) db.layout_of_ty(self.ty.clone(), self.env.krate).map(Layout)
} }
} }
@ -4358,6 +4355,35 @@ fn closure_source(db: &dyn HirDatabase, closure: ClosureId) -> Option<ast::Closu
} }
} }
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Layout(Arc<TyLayout>);
impl Layout {
pub fn size(&self) -> u64 {
self.0.size.bytes()
}
pub fn align(&self) -> u64 {
self.0.align.abi.bytes()
}
pub fn niches(&self, db: &dyn HirDatabase, krate: Crate) -> Option<u128> {
Some(self.0.largest_niche?.available(&*db.target_data_layout(krate.id)?))
}
pub fn field_offset(&self, idx: usize) -> Option<u64> {
match self.0.fields {
layout::FieldsShape::Primitive => None,
layout::FieldsShape::Union(_) => Some(0),
layout::FieldsShape::Array { stride, count } => {
let i = u64::try_from(idx).ok()?;
(i < count).then_some((stride * i).bytes())
}
layout::FieldsShape::Arbitrary { ref offsets, .. } => Some(offsets.get(idx)?.bytes()),
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum BindingMode { pub enum BindingMode {
Move, Move,

View file

@ -3,8 +3,8 @@ use std::fmt::Display;
use either::Either; use either::Either;
use hir::{ use hir::{
db::HirDatabase, Adt, AsAssocItem, AttributeTemplate, CaptureKind, HasAttrs, HasCrate, Adt, AsAssocItem, AttributeTemplate, CaptureKind, HasAttrs, HasCrate, HasSource, HirDisplay,
HasSource, HirDisplay, Layout, Semantics, TypeInfo, Layout, Semantics, TypeInfo,
}; };
use ide_db::{ use ide_db::{
base_db::SourceDatabase, base_db::SourceDatabase,
@ -401,14 +401,14 @@ pub(super) fn definition(
hir::VariantDef::Struct(s) => Adt::from(s) hir::VariantDef::Struct(s) => Adt::from(s)
.layout(db) .layout(db)
.ok() .ok()
.map(|layout| format!(", offset = {:#X}", layout.fields.offset(id).bytes())), .and_then(|layout| Some(format!(", offset = {:#X}", layout.field_offset(id)?))),
_ => None, _ => None,
}; };
let niches = niches(db, it, &layout).unwrap_or_default(); let niches = niches(db, it, &layout).unwrap_or_default();
Some(format!( Some(format!(
"size = {:#X}, align = {:#X}{}{niches}", "size = {:#X}, align = {:#X}{}{niches}",
layout.size.bytes(), layout.size(),
layout.align.abi.bytes(), layout.align(),
offset.as_deref().unwrap_or_default() offset.as_deref().unwrap_or_default()
)) ))
}), }),
@ -417,11 +417,7 @@ pub(super) fn definition(
Definition::Adt(it) => label_and_layout_info_and_docs(db, it, config, |&it| { Definition::Adt(it) => label_and_layout_info_and_docs(db, it, config, |&it| {
let layout = it.layout(db).ok()?; let layout = it.layout(db).ok()?;
let niches = niches(db, it, &layout).unwrap_or_default(); let niches = niches(db, it, &layout).unwrap_or_default();
Some(format!( Some(format!("size = {:#X}, align = {:#X}{niches}", layout.size(), layout.align()))
"size = {:#X}, align = {:#X}{niches}",
layout.size.bytes(),
layout.align.abi.bytes()
))
}), }),
Definition::Variant(it) => label_value_and_layout_info_and_docs( Definition::Variant(it) => label_value_and_layout_info_and_docs(
db, db,
@ -441,13 +437,13 @@ pub(super) fn definition(
}, },
|&it| { |&it| {
let (layout, tag_size) = it.layout(db).ok()?; let (layout, tag_size) = it.layout(db).ok()?;
let size = layout.size.bytes_usize() - tag_size; let size = layout.size() as usize - tag_size;
if size == 0 { if size == 0 {
// There is no value in showing layout info for fieldless variants // There is no value in showing layout info for fieldless variants
return None; return None;
} }
let niches = niches(db, it, &layout).unwrap_or_default(); let niches = niches(db, it, &layout).unwrap_or_default();
Some(format!("size = {:#X}{niches}", layout.size.bytes())) Some(format!("size = {:#X}{niches}", layout.size()))
}, },
), ),
Definition::Const(it) => label_value_and_docs(db, it, |it| { Definition::Const(it) => label_value_and_docs(db, it, |it| {
@ -477,11 +473,7 @@ pub(super) fn definition(
Definition::TypeAlias(it) => label_and_layout_info_and_docs(db, it, config, |&it| { Definition::TypeAlias(it) => label_and_layout_info_and_docs(db, it, config, |&it| {
let layout = it.ty(db).layout(db).ok()?; let layout = it.ty(db).layout(db).ok()?;
let niches = niches(db, it, &layout).unwrap_or_default(); let niches = niches(db, it, &layout).unwrap_or_default();
Some(format!( Some(format!("size = {:#X}, align = {:#X}{niches}", layout.size(), layout.align(),))
"size = {:#X}, align = {:#X}{niches}",
layout.size.bytes(),
layout.align.abi.bytes(),
))
}), }),
Definition::BuiltinType(it) => { Definition::BuiltinType(it) => {
return famous_defs return famous_defs
@ -518,10 +510,7 @@ pub(super) fn definition(
} }
fn niches(db: &RootDatabase, it: impl HasCrate, layout: &Layout) -> Option<String> { fn niches(db: &RootDatabase, it: impl HasCrate, layout: &Layout) -> Option<String> {
Some(format!( Some(format!(", niches = {}", layout.niches(db, it.krate(db).into())?))
", niches = {}",
layout.largest_niche?.available(&*db.target_data_layout(it.krate(db).into())?)
))
} }
fn type_info( fn type_info(
@ -571,7 +560,7 @@ fn closure_ty(
let layout = if config.memory_layout { let layout = if config.memory_layout {
original original
.layout(sema.db) .layout(sema.db)
.map(|x| format!(" // size = {}, align = {}", x.size.bytes(), x.align.abi.bytes())) .map(|x| format!(" // size = {}, align = {}", x.size(), x.align()))
.unwrap_or_default() .unwrap_or_default()
} else { } else {
String::default() String::default()
@ -782,12 +771,7 @@ fn local(db: &RootDatabase, it: hir::Local, config: &HoverConfig) -> Option<Mark
}; };
if config.memory_layout { if config.memory_layout {
if let Ok(layout) = it.ty(db).layout(db) { if let Ok(layout) = it.ty(db).layout(db) {
format_to!( format_to!(desc, " // size = {}, align = {}", layout.size(), layout.align());
desc,
" // size = {}, align = {}",
layout.size.bytes(),
layout.align.abi.bytes()
);
} }
} }
markup(None, desc, None) markup(None, desc, None)