Skip to content

Commit be446c6

Browse files
committed
Auto merge of rust-lang#14905 - Veykril:hover-hex, r=Veykril
feat: Render niches on hover
2 parents e8dbb8e + 1275adc commit be446c6

File tree

3 files changed

+71
-41
lines changed

3 files changed

+71
-41
lines changed

crates/hir/src/lib.rs

+47-12
Original file line numberDiff line numberDiff line change
@@ -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, LayoutError, RustcEnumVariantIdx, TagEncoding},
65+
layout::{Layout as TyLayout, LayoutError, RustcEnumVariantIdx, TagEncoding},
6666
method_resolution::{self, TyFingerprint},
6767
mir::{self, interpret_mir},
6868
primitive::UintTy,
@@ -961,8 +961,8 @@ impl Field {
961961
Type::new(db, var_id, ty)
962962
}
963963

964-
pub fn layout(&self, db: &dyn HirDatabase) -> Result<Arc<Layout>, LayoutError> {
965-
db.layout_of_ty(self.ty(db).ty.clone(), self.parent.module(db).krate().into())
964+
pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
965+
db.layout_of_ty(self.ty(db).ty.clone(), self.parent.module(db).krate().into()).map(Layout)
966966
}
967967

968968
pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef {
@@ -1135,10 +1135,10 @@ impl Enum {
11351135
self.variants(db).iter().any(|v| !matches!(v.kind(db), StructKind::Unit))
11361136
}
11371137

1138-
pub fn layout(self, db: &dyn HirDatabase) -> Result<(Arc<Layout>, usize), LayoutError> {
1138+
pub fn layout(self, db: &dyn HirDatabase) -> Result<(Layout, usize), LayoutError> {
11391139
let layout = Adt::from(self).layout(db)?;
11401140
let tag_size =
1141-
if let layout::Variants::Multiple { tag, tag_encoding, .. } = &layout.variants {
1141+
if let layout::Variants::Multiple { tag, tag_encoding, .. } = &layout.0.variants {
11421142
match tag_encoding {
11431143
TagEncoding::Direct => {
11441144
let target_data_layout = db
@@ -1219,11 +1219,11 @@ impl Variant {
12191219
let parent_enum = self.parent_enum(db);
12201220
let (parent_layout, tag_size) = parent_enum.layout(db)?;
12211221
Ok((
1222-
match &parent_layout.variants {
1222+
match &parent_layout.0.variants {
12231223
layout::Variants::Multiple { variants, .. } => {
1224-
variants[RustcEnumVariantIdx(self.id)].clone()
1224+
Layout(Arc::new(variants[RustcEnumVariantIdx(self.id)].clone()))
12251225
}
1226-
_ => (*parent_layout).clone(),
1226+
_ => parent_layout,
12271227
},
12281228
tag_size,
12291229
))
@@ -1255,11 +1255,11 @@ impl Adt {
12551255
})
12561256
}
12571257

1258-
pub fn layout(self, db: &dyn HirDatabase) -> Result<Arc<Layout>, LayoutError> {
1258+
pub fn layout(self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
12591259
if db.generic_params(self.into()).iter().count() != 0 {
12601260
return Err(LayoutError::HasPlaceholder);
12611261
}
1262-
db.layout_of_adt(self.into(), Substitution::empty(Interner), self.krate(db).id)
1262+
db.layout_of_adt(self.into(), Substitution::empty(Interner), self.krate(db).id).map(Layout)
12631263
}
12641264

12651265
/// Turns this ADT into a type. Any type parameters of the ADT will be
@@ -4243,8 +4243,8 @@ impl Type {
42434243
.collect()
42444244
}
42454245

4246-
pub fn layout(&self, db: &dyn HirDatabase) -> Result<Arc<Layout>, LayoutError> {
4247-
db.layout_of_ty(self.ty.clone(), self.env.krate)
4246+
pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
4247+
db.layout_of_ty(self.ty.clone(), self.env.krate).map(Layout)
42484248
}
42494249
}
42504250

@@ -4355,6 +4355,35 @@ fn closure_source(db: &dyn HirDatabase, closure: ClosureId) -> Option<ast::Closu
43554355
}
43564356
}
43574357

4358+
#[derive(Clone, Debug, Eq, PartialEq)]
4359+
pub struct Layout(Arc<TyLayout>);
4360+
4361+
impl Layout {
4362+
pub fn size(&self) -> u64 {
4363+
self.0.size.bytes()
4364+
}
4365+
4366+
pub fn align(&self) -> u64 {
4367+
self.0.align.abi.bytes()
4368+
}
4369+
4370+
pub fn niches(&self, db: &dyn HirDatabase, krate: Crate) -> Option<u128> {
4371+
Some(self.0.largest_niche?.available(&*db.target_data_layout(krate.id)?))
4372+
}
4373+
4374+
pub fn field_offset(&self, idx: usize) -> Option<u64> {
4375+
match self.0.fields {
4376+
layout::FieldsShape::Primitive => None,
4377+
layout::FieldsShape::Union(_) => Some(0),
4378+
layout::FieldsShape::Array { stride, count } => {
4379+
let i = u64::try_from(idx).ok()?;
4380+
(i < count).then_some((stride * i).bytes())
4381+
}
4382+
layout::FieldsShape::Arbitrary { ref offsets, .. } => Some(offsets.get(idx)?.bytes()),
4383+
}
4384+
}
4385+
}
4386+
43584387
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
43594388
pub enum BindingMode {
43604389
Move,
@@ -4506,6 +4535,12 @@ impl HasCrate for Union {
45064535
}
45074536
}
45084537

4538+
impl HasCrate for Enum {
4539+
fn krate(&self, db: &dyn HirDatabase) -> Crate {
4540+
self.module(db).krate()
4541+
}
4542+
}
4543+
45094544
impl HasCrate for Field {
45104545
fn krate(&self, db: &dyn HirDatabase) -> Crate {
45114546
self.parent_def(db).module(db).krate()

crates/ide/src/hover/render.rs

+21-26
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use std::fmt::Display;
33

44
use either::Either;
55
use hir::{
6-
Adt, AsAssocItem, AttributeTemplate, CaptureKind, HasAttrs, HasSource, HirDisplay, Semantics,
7-
TypeInfo,
6+
Adt, AsAssocItem, AttributeTemplate, CaptureKind, HasAttrs, HasCrate, HasSource, HirDisplay,
7+
Layout, Semantics, TypeInfo,
88
};
99
use ide_db::{
1010
base_db::SourceDatabase,
@@ -401,25 +401,23 @@ pub(super) fn definition(
401401
hir::VariantDef::Struct(s) => Adt::from(s)
402402
.layout(db)
403403
.ok()
404-
.map(|layout| format!(", offset = {:#X}", layout.fields.offset(id).bytes())),
404+
.and_then(|layout| Some(format!(", offset = {:#X}", layout.field_offset(id)?))),
405405
_ => None,
406406
};
407+
let niches = niches(db, it, &layout).unwrap_or_default();
407408
Some(format!(
408-
"size = {:#X}, align = {:#X}{}",
409-
layout.size.bytes(),
410-
layout.align.abi.bytes(),
409+
"size = {:#X}, align = {:#X}{}{niches}",
410+
layout.size(),
411+
layout.align(),
411412
offset.as_deref().unwrap_or_default()
412413
))
413414
}),
414415
Definition::Module(it) => label_and_docs(db, it),
415416
Definition::Function(it) => label_and_docs(db, it),
416417
Definition::Adt(it) => label_and_layout_info_and_docs(db, it, config, |&it| {
417418
let layout = it.layout(db).ok()?;
418-
Some(format!(
419-
"size = {:#X}, align = {:#X}",
420-
layout.size.bytes(),
421-
layout.align.abi.bytes()
422-
))
419+
let niches = niches(db, it, &layout).unwrap_or_default();
420+
Some(format!("size = {:#X}, align = {:#X}{niches}", layout.size(), layout.align()))
423421
}),
424422
Definition::Variant(it) => label_value_and_layout_info_and_docs(
425423
db,
@@ -437,14 +435,15 @@ pub(super) fn definition(
437435
None
438436
}
439437
},
440-
|it| {
438+
|&it| {
441439
let (layout, tag_size) = it.layout(db).ok()?;
442-
let size = layout.size.bytes_usize() - tag_size;
440+
let size = layout.size() as usize - tag_size;
443441
if size == 0 {
444442
// There is no value in showing layout info for fieldless variants
445443
return None;
446444
}
447-
Some(format!("size = {:#X}", layout.size.bytes()))
445+
let niches = niches(db, it, &layout).unwrap_or_default();
446+
Some(format!("size = {:#X}{niches}", layout.size()))
448447
},
449448
),
450449
Definition::Const(it) => label_value_and_docs(db, it, |it| {
@@ -473,11 +472,8 @@ pub(super) fn definition(
473472
Definition::TraitAlias(it) => label_and_docs(db, it),
474473
Definition::TypeAlias(it) => label_and_layout_info_and_docs(db, it, config, |&it| {
475474
let layout = it.ty(db).layout(db).ok()?;
476-
Some(format!(
477-
"size = {:#X}, align = {:#X}",
478-
layout.size.bytes(),
479-
layout.align.abi.bytes()
480-
))
475+
let niches = niches(db, it, &layout).unwrap_or_default();
476+
Some(format!("size = {:#X}, align = {:#X}{niches}", layout.size(), layout.align(),))
481477
}),
482478
Definition::BuiltinType(it) => {
483479
return famous_defs
@@ -513,6 +509,10 @@ pub(super) fn definition(
513509
markup(docs, label, mod_path)
514510
}
515511

512+
fn niches(db: &RootDatabase, it: impl HasCrate, layout: &Layout) -> Option<String> {
513+
Some(format!(", niches = {}", layout.niches(db, it.krate(db).into())?))
514+
}
515+
516516
fn type_info(
517517
sema: &Semantics<'_, RootDatabase>,
518518
config: &HoverConfig,
@@ -560,7 +560,7 @@ fn closure_ty(
560560
let layout = if config.memory_layout {
561561
original
562562
.layout(sema.db)
563-
.map(|x| format!(" // size = {}, align = {}", x.size.bytes(), x.align.abi.bytes()))
563+
.map(|x| format!(" // size = {}, align = {}", x.size(), x.align()))
564564
.unwrap_or_default()
565565
} else {
566566
String::default()
@@ -771,12 +771,7 @@ fn local(db: &RootDatabase, it: hir::Local, config: &HoverConfig) -> Option<Mark
771771
};
772772
if config.memory_layout {
773773
if let Ok(layout) = it.ty(db).layout(db) {
774-
format_to!(
775-
desc,
776-
" // size = {}, align = {}",
777-
layout.size.bytes(),
778-
layout.align.abi.bytes()
779-
);
774+
format_to!(desc, " // size = {}, align = {}", layout.size(), layout.align());
780775
}
781776
}
782777
markup(None, desc, None)

crates/ide/src/hover/tests.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1528,7 +1528,7 @@ fn test_hover_function_pointer_show_identifiers() {
15281528
```
15291529
15301530
```rust
1531-
type foo = fn(a: i32, b: i32) -> i32 // size = 0x8, align = 0x8
1531+
type foo = fn(a: i32, b: i32) -> i32 // size = 0x8, align = 0x8, niches = 1
15321532
```
15331533
"#]],
15341534
);
@@ -1546,7 +1546,7 @@ fn test_hover_function_pointer_no_identifier() {
15461546
```
15471547
15481548
```rust
1549-
type foo = fn(i32, i32) -> i32 // size = 0x8, align = 0x8
1549+
type foo = fn(i32, i32) -> i32 // size = 0x8, align = 0x8, niches = 1
15501550
```
15511551
"#]],
15521552
);
@@ -1904,7 +1904,7 @@ fn test_hover_layout_of_enum() {
19041904
```
19051905
19061906
```rust
1907-
enum Foo // size = 0x10, align = 0x8
1907+
enum Foo // size = 0x10, align = 0x8, niches = 254
19081908
```
19091909
"#]],
19101910
);

0 commit comments

Comments
 (0)