diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index bc925552f3..8fac7fcd87 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -45,7 +45,7 @@ use hir_def::{ hir::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat}, item_tree::ItemTreeNode, lang_item::LangItemTarget, - layout::ReprOptions, + layout::{self, ReprOptions}, macro_id_to_def_id, nameres::{self, diagnostics::DefDiagnostic, ModuleOrigin}, per_ns::PerNs, @@ -62,7 +62,7 @@ use hir_ty::{ consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt}, diagnostics::BodyValidationDiagnostic, display::HexifiedConst, - layout::{layout_of_ty, Layout, LayoutError}, + layout::{layout_of_ty, Layout, LayoutError, RustcEnumVariantIdx, TagEncoding}, method_resolution::{self, TyFingerprint}, mir::{self, interpret_mir}, primitive::UintTy, @@ -1089,7 +1089,7 @@ impl Enum { Type::new_for_crate( self.id.lookup(db.upcast()).container.krate(), TyBuilder::builtin(match db.enum_data(self.id).variant_body_type() { - hir_def::layout::IntegerType::Pointer(sign) => match sign { + layout::IntegerType::Pointer(sign) => match sign { true => hir_def::builtin_type::BuiltinType::Int( hir_def::builtin_type::BuiltinInt::Isize, ), @@ -1097,20 +1097,20 @@ impl Enum { hir_def::builtin_type::BuiltinUint::Usize, ), }, - hir_def::layout::IntegerType::Fixed(i, sign) => match sign { + layout::IntegerType::Fixed(i, sign) => match sign { true => hir_def::builtin_type::BuiltinType::Int(match i { - hir_def::layout::Integer::I8 => hir_def::builtin_type::BuiltinInt::I8, - hir_def::layout::Integer::I16 => hir_def::builtin_type::BuiltinInt::I16, - hir_def::layout::Integer::I32 => hir_def::builtin_type::BuiltinInt::I32, - hir_def::layout::Integer::I64 => hir_def::builtin_type::BuiltinInt::I64, - hir_def::layout::Integer::I128 => hir_def::builtin_type::BuiltinInt::I128, + layout::Integer::I8 => hir_def::builtin_type::BuiltinInt::I8, + layout::Integer::I16 => hir_def::builtin_type::BuiltinInt::I16, + layout::Integer::I32 => hir_def::builtin_type::BuiltinInt::I32, + layout::Integer::I64 => hir_def::builtin_type::BuiltinInt::I64, + layout::Integer::I128 => hir_def::builtin_type::BuiltinInt::I128, }), false => hir_def::builtin_type::BuiltinType::Uint(match i { - hir_def::layout::Integer::I8 => hir_def::builtin_type::BuiltinUint::U8, - hir_def::layout::Integer::I16 => hir_def::builtin_type::BuiltinUint::U16, - hir_def::layout::Integer::I32 => hir_def::builtin_type::BuiltinUint::U32, - hir_def::layout::Integer::I64 => hir_def::builtin_type::BuiltinUint::U64, - hir_def::layout::Integer::I128 => hir_def::builtin_type::BuiltinUint::U128, + layout::Integer::I8 => hir_def::builtin_type::BuiltinUint::U8, + layout::Integer::I16 => hir_def::builtin_type::BuiltinUint::U16, + layout::Integer::I32 => hir_def::builtin_type::BuiltinUint::U32, + layout::Integer::I64 => hir_def::builtin_type::BuiltinUint::U64, + layout::Integer::I128 => hir_def::builtin_type::BuiltinUint::U128, }), }, }), @@ -1177,6 +1177,28 @@ impl Variant { pub fn eval(self, db: &dyn HirDatabase) -> Result { db.const_eval_discriminant(self.into()) } + + /// 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() + } + TagEncoding::Niche { .. } => 0, + }; + Ok((variants[RustcEnumVariantIdx(self.id)].clone(), tag_size)) + } else { + Ok((parent_layout, 0)) + } + } } /// Variants inherit visibility from the parent enum. diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index c2b9222cb9..fffc837876 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -417,15 +417,25 @@ pub(super) fn definition( let layout = it.layout(db).ok()?; Some(format!("size = {}, align = {}", layout.size.bytes(), layout.align.abi.bytes())) }), - Definition::Variant(it) => label_value_and_docs(db, it, |&it| { - if !it.parent_enum(db).is_data_carrying(db) { + Definition::Variant(it) => label_value_and_layout_info_and_docs(db, it, config, |&it| { + let layout = (|| { + 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) }), Definition::Const(it) => label_value_and_docs(db, it, |it| { let body = it.render_eval(db); @@ -460,7 +470,7 @@ pub(super) fn definition( .and_then(|fd| builtin(fd, it)) .or_else(|| Some(Markup::fenced_block(&it.name()))) } - Definition::Local(it) => return local(db, it), + Definition::Local(it) => return local(db, it, config), Definition::SelfType(impl_def) => { impl_def.self_ty(db).as_adt().map(|adt| label_and_docs(db, adt))? } @@ -637,6 +647,32 @@ where (label, docs) } +fn label_value_and_layout_info_and_docs( + db: &RootDatabase, + def: D, + config: &HoverConfig, + value_extractor: E, +) -> (String, Option) +where + D: HasAttrs + HirDisplay, + E: Fn(&D) -> (Option, Option), + 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 label = match layout { + Some(layout) if config.memory_layout => format!("{} // {layout}", label), + _ => label, + }; + let docs = def.attrs(db).docs(); + (label, docs) +} + fn label_value_and_docs( db: &RootDatabase, def: D, @@ -696,11 +732,11 @@ fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option Option { +fn local(db: &RootDatabase, it: hir::Local, config: &HoverConfig) -> Option { let ty = it.ty(db); let ty = ty.display_truncated(db, None); let is_mut = if it.is_mut(db) { "mut " } else { "" }; - let desc = match it.primary_source(db).into_ident_pat() { + let mut desc = match it.primary_source(db).into_ident_pat() { Some(ident) => { let name = it.name(db); let let_kw = if ident @@ -716,6 +752,16 @@ fn local(db: &RootDatabase, it: hir::Local) -> Option { } None => format!("{is_mut}self: {ty}"), }; + if config.memory_layout { + if let Ok(layout) = it.ty(db).layout(db) { + format_to!( + desc, + " // size = {}, align = {}", + layout.size.bytes(), + layout.align.abi.bytes() + ); + } + } markup(None, desc, None) } diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 0d8fc8a5f7..60708cb42e 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -150,7 +150,7 @@ fn foo() { *local* ```rust - let local: i32 + let local: i32 // size = 4, align = 4 ``` "#]], ); @@ -396,12 +396,12 @@ fn main() { } "#, expect![[r#" - *iter* + *iter* - ```rust - let mut iter: Iter>, impl Fn(&mut u32, &u32, &mut u32) -> Option, u32>> - ``` - "#]], + ```rust + let mut iter: Iter>, impl Fn(&mut u32, &u32, &mut u32) -> Option, u32>> // size = 8, align = 4 + ``` + "#]], ); } @@ -778,12 +778,12 @@ fn main() { let zz$0 = Test { t: 23u8, k: 33 }; }"#, expect![[r#" - *zz* + *zz* - ```rust - let zz: Test - ``` - "#]], + ```rust + let zz: Test // size = 8, align = 4 + ``` + "#]], ); check_hover_range( r#" @@ -829,12 +829,12 @@ use Option::Some; fn main() { let b$0ar = Some(12); } "#, expect![[r#" - *bar* + *bar* - ```rust - let bar: Option - ``` - "#]], + ```rust + let bar: Option // size = 4, align = 4 + ``` + "#]], ); } @@ -898,12 +898,12 @@ fn hover_for_local_variable() { check( r#"fn func(foo: i32) { fo$0o; }"#, expect![[r#" - *foo* + *foo* - ```rust - foo: i32 - ``` - "#]], + ```rust + foo: i32 // size = 4, align = 4 + ``` + "#]], ) } @@ -912,12 +912,12 @@ fn hover_for_local_variable_pat() { check( r#"fn func(fo$0o: i32) {}"#, expect![[r#" - *foo* + *foo* - ```rust - foo: i32 - ``` - "#]], + ```rust + foo: i32 // size = 4, align = 4 + ``` + "#]], ) } @@ -926,12 +926,12 @@ fn hover_local_var_edge() { check( r#"fn func(foo: i32) { if true { $0foo; }; }"#, expect![[r#" - *foo* + *foo* - ```rust - foo: i32 - ``` - "#]], + ```rust + foo: i32 // size = 4, align = 4 + ``` + "#]], ) } @@ -940,12 +940,12 @@ fn hover_for_param_edge() { check( r#"fn func($0foo: i32) {}"#, expect![[r#" - *foo* + *foo* - ```rust - foo: i32 - ``` - "#]], + ```rust + foo: i32 // size = 4, align = 4 + ``` + "#]], ) } @@ -984,12 +984,12 @@ impl Thing { fn main() { let foo_$0test = Thing::new(); } "#, expect![[r#" - *foo_test* + *foo_test* - ```rust - let foo_test: Thing - ``` - "#]], + ```rust + let foo_test: Thing // size = 4, align = 4 + ``` + "#]], ) } @@ -1144,12 +1144,12 @@ fn y() { } "#, expect![[r#" - *x* + *x* - ```rust - let x: i32 - ``` - "#]], + ```rust + let x: i32 // size = 4, align = 4 + ``` + "#]], ) } @@ -1274,12 +1274,12 @@ macro_rules! id { ($($tt:tt)*) => { $($tt)* } } fn foo(bar:u32) { let a = id!(ba$0r); } "#, expect![[r#" - *bar* + *bar* - ```rust - bar: u32 - ``` - "#]], + ```rust + bar: u32 // size = 4, align = 4 + ``` + "#]], ); } @@ -1292,12 +1292,12 @@ macro_rules! id { ($($tt:tt)*) => { id_deep!($($tt)*) } } fn foo(bar:u32) { let a = id!(ba$0r); } "#, expect![[r#" - *bar* + *bar* - ```rust - bar: u32 - ``` - "#]], + ```rust + bar: u32 // size = 4, align = 4 + ``` + "#]], ); } @@ -1841,6 +1841,27 @@ pub fn fo$0o() {} ); } +#[test] +fn test_hover_layout_of_variant() { + check( + r#"enum Foo { + Va$0riant1(u8, u16), + Variant2(i32, u8, i64), + }"#, + expect![[r#" + *Variant1* + + ```rust + test::Foo + ``` + + ```rust + Variant1(u8, u16) // size = 4 + ``` + "#]], + ); +} + #[test] fn test_hover_no_memory_layout() { check_hover_no_memory_layout( @@ -3135,7 +3156,7 @@ fn main() { *f* ```rust - f: &i32 + f: &i32 // size = 8, align = 8 ``` --- @@ -3185,7 +3206,7 @@ fn main() { *value* ```rust - let value: Const<1> + let value: Const<1> // size = 0, align = 1 ``` "#]], ); @@ -3205,7 +3226,7 @@ fn main() { *value* ```rust - let value: Const<0> + let value: Const<0> // size = 0, align = 1 ``` "#]], ); @@ -3225,7 +3246,7 @@ fn main() { *value* ```rust - let value: Const<-1> + let value: Const<-1> // size = 0, align = 1 ``` "#]], ); @@ -3245,7 +3266,7 @@ fn main() { *value* ```rust - let value: Const + let value: Const // size = 0, align = 1 ``` "#]], ); @@ -3265,7 +3286,7 @@ fn main() { *value* ```rust - let value: Const<'🦀'> + let value: Const<'🦀'> // size = 0, align = 1 ``` "#]], ); @@ -3281,12 +3302,12 @@ impl Foo { } "#, expect![[r#" - *self* + *self* - ```rust - self: &Foo - ``` - "#]], + ```rust + self: &Foo // size = 8, align = 8 + ``` + "#]], ); } @@ -3301,12 +3322,12 @@ impl Foo { } "#, expect![[r#" - *self* + *self* - ```rust - self: Arc - ``` - "#]], + ```rust + self: Arc // size = 0, align = 1 + ``` + "#]], ); } @@ -4364,9 +4385,9 @@ fn main() { *tile4* ```rust - let tile4: [u32; 8] + let tile4: [u32; 8] // size = 32, align = 4 ``` - "#]], + "#]], ); } @@ -5541,7 +5562,7 @@ enum Enum { ``` ```rust - RecordV { field: u32 } + RecordV { field: u32 } // size = 4 ``` "#]], );