Skip to content

fix: Render size, align and offset hover values in hex #14904

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 26, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 18 additions & 17 deletions crates/hir-ty/src/layout.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! 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, LayoutCalculator, LayoutS, Primitive, ReprOptions, Scalar, Size,
@@ -83,7 +83,7 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
let dl = &*cx.current_data_layout();
let trait_env = Arc::new(TraitEnvironment::empty(krate));
let ty = normalize(db, trait_env, ty.clone());
Ok(match ty.kind(Interner) {
let layout = match ty.kind(Interner) {
TyKind::Adt(AdtId(def), subst) => db.layout_of_adt(*def, subst.clone(), krate)?,
TyKind::Scalar(s) => match s {
chalk_ir::Scalar::Bool => Layout::scalar(
@@ -104,12 +104,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,
),
@@ -118,21 +118,21 @@ 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,
),
),
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,
},
),
},
@@ -283,7 +283,8 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
| TyKind::Placeholder(_)
| TyKind::BoundVar(_)
| TyKind::InferenceVar(_, _) => return Err(LayoutError::HasPlaceholder),
})
};
Ok(layout)
}

fn layout_of_unit(cx: &LayoutCx<'_>, dl: &TargetDataLayout) -> Result<Layout, LayoutError> {
44 changes: 28 additions & 16 deletions crates/hir/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1125,6 +1125,25 @@ impl Enum {
pub fn is_data_carrying(self, db: &dyn HirDatabase) -> bool {
self.variants(db).iter().any(|v| !matches!(v.kind(db), StructKind::Unit))
}

pub fn layout(self, db: &dyn HirDatabase) -> Result<(Layout, usize), LayoutError> {
let layout = Adt::from(self).layout(db)?;
let tag_size =
if let layout::Variants::Multiple { tag, tag_encoding, .. } = &layout.variants {
match tag_encoding {
TagEncoding::Direct => {
let target_data_layout = db
.target_data_layout(self.module(db).krate().id)
.ok_or(LayoutError::TargetLayoutNotAvailable)?;
tag.size(&*target_data_layout).bytes_usize()
}
TagEncoding::Niche { .. } => 0,
}
} else {
0
};
Ok((layout, tag_size))
}
}

impl HasVisibility for Enum {
@@ -1185,23 +1204,16 @@ impl Variant {
/// Return layout of the variant and tag size of the parent enum.
pub fn layout(&self, db: &dyn HirDatabase) -> Result<(Layout, usize), LayoutError> {
let parent_enum = self.parent_enum(db);
let parent_layout = Adt::from(parent_enum).layout(db)?;
if let layout::Variants::Multiple { variants, tag, tag_encoding, tag_field: _ } =
parent_layout.variants
{
let tag_size = match tag_encoding {
TagEncoding::Direct => {
let target_data_layout = db
.target_data_layout(parent_enum.module(db).krate().id)
.ok_or(LayoutError::TargetLayoutNotAvailable)?;
tag.size(&*target_data_layout).bytes_usize()
let (parent_layout, tag_size) = parent_enum.layout(db)?;
Ok((
match parent_layout.variants {
layout::Variants::Multiple { variants, .. } => {
variants[RustcEnumVariantIdx(self.id)].clone()
}
TagEncoding::Niche { .. } => 0,
};
Ok((variants[RustcEnumVariantIdx(self.id)].clone(), tag_size))
} else {
Ok((parent_layout, 0))
}
_ => parent_layout,
},
tag_size,
))
}
}

75 changes: 45 additions & 30 deletions crates/ide/src/hover/render.rs
Original file line number Diff line number Diff line change
@@ -401,11 +401,11 @@ pub(super) fn definition(
hir::VariantDef::Struct(s) => Adt::from(s)
.layout(db)
.ok()
.map(|layout| format!(", offset = {}", layout.fields.offset(id).bytes())),
.map(|layout| format!(", offset = {:#X}", layout.fields.offset(id).bytes())),
_ => None,
};
Some(format!(
"size = {}, align = {}{}",
"size = {:#X}, align = {:#X}{}",
layout.size.bytes(),
layout.align.abi.bytes(),
offset.as_deref().unwrap_or_default()
@@ -415,28 +415,38 @@ pub(super) fn definition(
Definition::Function(it) => label_and_docs(db, it),
Definition::Adt(it) => label_and_layout_info_and_docs(db, it, config, |&it| {
let layout = it.layout(db).ok()?;
Some(format!("size = {}, align = {}", layout.size.bytes(), layout.align.abi.bytes()))
Some(format!(
"size = {:#X}, align = {:#X}",
layout.size.bytes(),
layout.align.abi.bytes()
))
}),
Definition::Variant(it) => label_value_and_layout_info_and_docs(db, it, config, |&it| {
let layout = (|| {
Definition::Variant(it) => label_value_and_layout_info_and_docs(
db,
it,
config,
|&it| {
if !it.parent_enum(db).is_data_carrying(db) {
match it.eval(db) {
Ok(x) => {
Some(if x >= 10 { format!("{x} ({x:#X})") } else { format!("{x}") })
}
Err(_) => it.value(db).map(|x| format!("{x:?}")),
}
} else {
None
}
},
|it| {
let (layout, tag_size) = it.layout(db).ok()?;
let size = layout.size.bytes_usize() - tag_size;
if size == 0 {
// There is no value in showing layout info for fieldless variants
return None;
}
Some(format!("size = {}", layout.size.bytes()))
})();
let value = if !it.parent_enum(db).is_data_carrying(db) {
match it.eval(db) {
Ok(x) => Some(if x >= 10 { format!("{x} ({x:#X})") } else { format!("{x}") }),
Err(_) => it.value(db).map(|x| format!("{x:?}")),
}
} else {
None
};
(value, layout)
}),
Some(format!("size = {:#X}", layout.size.bytes()))
},
),
Definition::Const(it) => label_value_and_docs(db, it, |it| {
let body = it.render_eval(db);
match body {
@@ -463,7 +473,11 @@ pub(super) fn definition(
Definition::TraitAlias(it) => label_and_docs(db, it),
Definition::TypeAlias(it) => label_and_layout_info_and_docs(db, it, config, |&it| {
let layout = it.ty(db).layout(db).ok()?;
Some(format!("size = {}, align = {}", layout.size.bytes(), layout.align.abi.bytes()))
Some(format!(
"size = {:#X}, align = {:#X}",
layout.size.bytes(),
layout.align.abi.bytes()
))
}),
Definition::BuiltinType(it) => {
return famous_defs
@@ -634,41 +648,42 @@ fn label_and_layout_info_and_docs<D, E, V>(
db: &RootDatabase,
def: D,
config: &HoverConfig,
value_extractor: E,
layout_extractor: E,
) -> (String, Option<hir::Documentation>)
where
D: HasAttrs + HirDisplay,
E: Fn(&D) -> Option<V>,
V: Display,
{
let label = match value_extractor(&def) {
Some(value) if config.memory_layout => format!("{} // {value}", def.display(db)),
let label = match config.memory_layout.then(|| layout_extractor(&def)).flatten() {
Some(layout) => format!("{} // {layout}", def.display(db)),
_ => def.display(db).to_string(),
};
let docs = def.attrs(db).docs();
(label, docs)
}

fn label_value_and_layout_info_and_docs<D, E, V, L>(
fn label_value_and_layout_info_and_docs<D, E, E2, V, L>(
db: &RootDatabase,
def: D,
config: &HoverConfig,
value_extractor: E,
layout_extractor: E2,
) -> (String, Option<hir::Documentation>)
where
D: HasAttrs + HirDisplay,
E: Fn(&D) -> (Option<V>, Option<L>),
E: Fn(&D) -> Option<V>,
E2: Fn(&D) -> Option<L>,
V: Display,
L: Display,
{
let (value, layout) = value_extractor(&def);
let label = if let Some(value) = value {
format!("{} = {value}", def.display(db))
} else {
def.display(db).to_string()
let value = value_extractor(&def);
let label = match value {
Some(value) => format!("{} = {value}", def.display(db)),
None => def.display(db).to_string(),
};
let label = match layout {
Some(layout) if config.memory_layout => format!("{} // {layout}", label),
let label = match config.memory_layout.then(|| layout_extractor(&def)).flatten() {
Some(layout) => format!("{} // {layout}", label),
_ => label,
};
let docs = def.attrs(db).docs();
Loading