Skip to content

Commit e110696

Browse files
committed
Auto merge of #14845 - HKalbasi:layout, r=HKalbasi
Add layout info for enum variant and locals The size of enum variant is what rustdoc shows (rust-lang/rust#86263). I also added layout info for locals since it helps finding size of unnameable types like closures inside other structs or impl traits.
2 parents 54129fa + cae9660 commit e110696

File tree

3 files changed

+184
-95
lines changed

3 files changed

+184
-95
lines changed

crates/hir/src/lib.rs

+36-14
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use hir_def::{
4545
hir::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat},
4646
item_tree::ItemTreeNode,
4747
lang_item::LangItemTarget,
48-
layout::ReprOptions,
48+
layout::{self, ReprOptions},
4949
macro_id_to_def_id,
5050
nameres::{self, diagnostics::DefDiagnostic, ModuleOrigin},
5151
per_ns::PerNs,
@@ -62,7 +62,7 @@ use hir_ty::{
6262
consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt},
6363
diagnostics::BodyValidationDiagnostic,
6464
display::HexifiedConst,
65-
layout::{layout_of_ty, Layout, LayoutError},
65+
layout::{layout_of_ty, Layout, LayoutError, RustcEnumVariantIdx, TagEncoding},
6666
method_resolution::{self, TyFingerprint},
6767
mir::{self, interpret_mir},
6868
primitive::UintTy,
@@ -1089,28 +1089,28 @@ impl Enum {
10891089
Type::new_for_crate(
10901090
self.id.lookup(db.upcast()).container.krate(),
10911091
TyBuilder::builtin(match db.enum_data(self.id).variant_body_type() {
1092-
hir_def::layout::IntegerType::Pointer(sign) => match sign {
1092+
layout::IntegerType::Pointer(sign) => match sign {
10931093
true => hir_def::builtin_type::BuiltinType::Int(
10941094
hir_def::builtin_type::BuiltinInt::Isize,
10951095
),
10961096
false => hir_def::builtin_type::BuiltinType::Uint(
10971097
hir_def::builtin_type::BuiltinUint::Usize,
10981098
),
10991099
},
1100-
hir_def::layout::IntegerType::Fixed(i, sign) => match sign {
1100+
layout::IntegerType::Fixed(i, sign) => match sign {
11011101
true => hir_def::builtin_type::BuiltinType::Int(match i {
1102-
hir_def::layout::Integer::I8 => hir_def::builtin_type::BuiltinInt::I8,
1103-
hir_def::layout::Integer::I16 => hir_def::builtin_type::BuiltinInt::I16,
1104-
hir_def::layout::Integer::I32 => hir_def::builtin_type::BuiltinInt::I32,
1105-
hir_def::layout::Integer::I64 => hir_def::builtin_type::BuiltinInt::I64,
1106-
hir_def::layout::Integer::I128 => hir_def::builtin_type::BuiltinInt::I128,
1102+
layout::Integer::I8 => hir_def::builtin_type::BuiltinInt::I8,
1103+
layout::Integer::I16 => hir_def::builtin_type::BuiltinInt::I16,
1104+
layout::Integer::I32 => hir_def::builtin_type::BuiltinInt::I32,
1105+
layout::Integer::I64 => hir_def::builtin_type::BuiltinInt::I64,
1106+
layout::Integer::I128 => hir_def::builtin_type::BuiltinInt::I128,
11071107
}),
11081108
false => hir_def::builtin_type::BuiltinType::Uint(match i {
1109-
hir_def::layout::Integer::I8 => hir_def::builtin_type::BuiltinUint::U8,
1110-
hir_def::layout::Integer::I16 => hir_def::builtin_type::BuiltinUint::U16,
1111-
hir_def::layout::Integer::I32 => hir_def::builtin_type::BuiltinUint::U32,
1112-
hir_def::layout::Integer::I64 => hir_def::builtin_type::BuiltinUint::U64,
1113-
hir_def::layout::Integer::I128 => hir_def::builtin_type::BuiltinUint::U128,
1109+
layout::Integer::I8 => hir_def::builtin_type::BuiltinUint::U8,
1110+
layout::Integer::I16 => hir_def::builtin_type::BuiltinUint::U16,
1111+
layout::Integer::I32 => hir_def::builtin_type::BuiltinUint::U32,
1112+
layout::Integer::I64 => hir_def::builtin_type::BuiltinUint::U64,
1113+
layout::Integer::I128 => hir_def::builtin_type::BuiltinUint::U128,
11141114
}),
11151115
},
11161116
}),
@@ -1177,6 +1177,28 @@ impl Variant {
11771177
pub fn eval(self, db: &dyn HirDatabase) -> Result<i128, ConstEvalError> {
11781178
db.const_eval_discriminant(self.into())
11791179
}
1180+
1181+
/// Return layout of the variant and tag size of the parent enum.
1182+
pub fn layout(&self, db: &dyn HirDatabase) -> Result<(Layout, usize), LayoutError> {
1183+
let parent_enum = self.parent_enum(db);
1184+
let parent_layout = Adt::from(parent_enum).layout(db)?;
1185+
if let layout::Variants::Multiple { variants, tag, tag_encoding, tag_field: _ } =
1186+
parent_layout.variants
1187+
{
1188+
let tag_size = match tag_encoding {
1189+
TagEncoding::Direct => {
1190+
let target_data_layout = db
1191+
.target_data_layout(parent_enum.module(db).krate().id)
1192+
.ok_or(LayoutError::TargetLayoutNotAvailable)?;
1193+
tag.size(&*target_data_layout).bytes_usize()
1194+
}
1195+
TagEncoding::Niche { .. } => 0,
1196+
};
1197+
Ok((variants[RustcEnumVariantIdx(self.id)].clone(), tag_size))
1198+
} else {
1199+
Ok((parent_layout, 0))
1200+
}
1201+
}
11801202
}
11811203

11821204
/// Variants inherit visibility from the parent enum.

crates/ide/src/hover/render.rs

+52-6
Original file line numberDiff line numberDiff line change
@@ -417,15 +417,25 @@ pub(super) fn definition(
417417
let layout = it.layout(db).ok()?;
418418
Some(format!("size = {}, align = {}", layout.size.bytes(), layout.align.abi.bytes()))
419419
}),
420-
Definition::Variant(it) => label_value_and_docs(db, it, |&it| {
421-
if !it.parent_enum(db).is_data_carrying(db) {
420+
Definition::Variant(it) => label_value_and_layout_info_and_docs(db, it, config, |&it| {
421+
let layout = (|| {
422+
let (layout, tag_size) = it.layout(db).ok()?;
423+
let size = layout.size.bytes_usize() - tag_size;
424+
if size == 0 {
425+
// There is no value in showing layout info for fieldless variants
426+
return None;
427+
}
428+
Some(format!("size = {}", layout.size.bytes()))
429+
})();
430+
let value = if !it.parent_enum(db).is_data_carrying(db) {
422431
match it.eval(db) {
423432
Ok(x) => Some(if x >= 10 { format!("{x} ({x:#X})") } else { format!("{x}") }),
424433
Err(_) => it.value(db).map(|x| format!("{x:?}")),
425434
}
426435
} else {
427436
None
428-
}
437+
};
438+
(value, layout)
429439
}),
430440
Definition::Const(it) => label_value_and_docs(db, it, |it| {
431441
let body = it.render_eval(db);
@@ -460,7 +470,7 @@ pub(super) fn definition(
460470
.and_then(|fd| builtin(fd, it))
461471
.or_else(|| Some(Markup::fenced_block(&it.name())))
462472
}
463-
Definition::Local(it) => return local(db, it),
473+
Definition::Local(it) => return local(db, it, config),
464474
Definition::SelfType(impl_def) => {
465475
impl_def.self_ty(db).as_adt().map(|adt| label_and_docs(db, adt))?
466476
}
@@ -637,6 +647,32 @@ where
637647
(label, docs)
638648
}
639649

650+
fn label_value_and_layout_info_and_docs<D, E, V, L>(
651+
db: &RootDatabase,
652+
def: D,
653+
config: &HoverConfig,
654+
value_extractor: E,
655+
) -> (String, Option<hir::Documentation>)
656+
where
657+
D: HasAttrs + HirDisplay,
658+
E: Fn(&D) -> (Option<V>, Option<L>),
659+
V: Display,
660+
L: Display,
661+
{
662+
let (value, layout) = value_extractor(&def);
663+
let label = if let Some(value) = value {
664+
format!("{} = {value}", def.display(db))
665+
} else {
666+
def.display(db).to_string()
667+
};
668+
let label = match layout {
669+
Some(layout) if config.memory_layout => format!("{} // {layout}", label),
670+
_ => label,
671+
};
672+
let docs = def.attrs(db).docs();
673+
(label, docs)
674+
}
675+
640676
fn label_value_and_docs<D, E, V>(
641677
db: &RootDatabase,
642678
def: D,
@@ -696,11 +732,11 @@ fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option<hir::
696732
.find(|module| module.name(db).map_or(false, |module| module.to_string() == name))
697733
}
698734

699-
fn local(db: &RootDatabase, it: hir::Local) -> Option<Markup> {
735+
fn local(db: &RootDatabase, it: hir::Local, config: &HoverConfig) -> Option<Markup> {
700736
let ty = it.ty(db);
701737
let ty = ty.display_truncated(db, None);
702738
let is_mut = if it.is_mut(db) { "mut " } else { "" };
703-
let desc = match it.primary_source(db).into_ident_pat() {
739+
let mut desc = match it.primary_source(db).into_ident_pat() {
704740
Some(ident) => {
705741
let name = it.name(db);
706742
let let_kw = if ident
@@ -716,6 +752,16 @@ fn local(db: &RootDatabase, it: hir::Local) -> Option<Markup> {
716752
}
717753
None => format!("{is_mut}self: {ty}"),
718754
};
755+
if config.memory_layout {
756+
if let Ok(layout) = it.ty(db).layout(db) {
757+
format_to!(
758+
desc,
759+
" // size = {}, align = {}",
760+
layout.size.bytes(),
761+
layout.align.abi.bytes()
762+
);
763+
}
764+
}
719765
markup(None, desc, None)
720766
}
721767

0 commit comments

Comments
 (0)