diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index e73c2ee6f6..eb55ba1d53 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -837,16 +837,18 @@ impl InTypeConstId { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum GeneralConstId { ConstId(ConstId), + StaticId(StaticId), ConstBlockId(ConstBlockId), InTypeConstId(InTypeConstId), } -impl_from!(ConstId, ConstBlockId, InTypeConstId for GeneralConstId); +impl_from!(ConstId, StaticId, ConstBlockId, InTypeConstId for GeneralConstId); impl GeneralConstId { pub fn generic_def(self, db: &dyn DefDatabase) -> Option { match self { GeneralConstId::ConstId(it) => Some(it.into()), + GeneralConstId::StaticId(_) => None, GeneralConstId::ConstBlockId(it) => it.lookup(db).parent.as_generic_def_id(db), GeneralConstId::InTypeConstId(it) => it.lookup(db).owner.as_generic_def_id(db), } @@ -854,6 +856,9 @@ impl GeneralConstId { pub fn name(self, db: &dyn DefDatabase) -> String { match self { + GeneralConstId::StaticId(it) => { + db.static_data(it).name.display(db.upcast(), Edition::CURRENT).to_string() + } GeneralConstId::ConstId(const_id) => db .const_data(const_id) .name diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index 091cfcd465..a56056b077 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -8,7 +8,7 @@ use hir_def::{ path::Path, resolver::{Resolver, ValueNs}, type_ref::LiteralConstRef, - ConstBlockLoc, EnumVariantId, GeneralConstId, StaticId, + ConstBlockLoc, EnumVariantId, GeneralConstId, HasModule as _, StaticId, }; use hir_expand::Lookup; use stdx::never; @@ -236,6 +236,10 @@ pub(crate) fn const_eval_query( GeneralConstId::ConstId(c) => { db.monomorphized_mir_body(c.into(), subst, db.trait_environment(c.into()))? } + GeneralConstId::StaticId(s) => { + let krate = s.module(db.upcast()).krate(); + db.monomorphized_mir_body(s.into(), subst, TraitEnvironment::empty(krate))? + } GeneralConstId::ConstBlockId(c) => { let ConstBlockLoc { parent, root } = db.lookup_intern_anonymous_const(c); let body = db.body(parent); diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index e73b9dc27d..47026995c0 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -12,8 +12,8 @@ use hir_def::{ lang_item::LangItem, layout::{TagEncoding, Variants}, resolver::{HasResolver, TypeNs, ValueNs}, - AdtId, ConstId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, - StaticId, VariantId, + AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, StaticId, + VariantId, }; use hir_expand::{mod_path::path, name::Name, HirFileIdExt, InFile}; use intern::sym; @@ -40,8 +40,8 @@ use crate::{ static_lifetime, traits::FnTrait, utils::{detect_variant_from_bytes, ClosureSubst}, - CallableDefId, ClosureId, ComplexMemoryMap, Const, ConstScalar, FnDefId, Interner, MemoryMap, - Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, + CallableDefId, ClosureId, ComplexMemoryMap, Const, ConstData, ConstScalar, FnDefId, Interner, + MemoryMap, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, }; use super::{ @@ -1899,8 +1899,8 @@ impl Evaluator<'_> { #[allow(clippy::double_parens)] fn allocate_const_in_heap(&mut self, locals: &Locals, konst: &Const) -> Result { - let ty = &konst.data(Interner).ty; - let chalk_ir::ConstValue::Concrete(c) = &konst.data(Interner).value else { + let ConstData { ty, value: chalk_ir::ConstValue::Concrete(c) } = &konst.data(Interner) + else { not_supported!("evaluating non concrete constant"); }; let result_owner; @@ -2908,14 +2908,14 @@ impl Evaluator<'_> { pub fn render_const_using_debug_impl( db: &dyn HirDatabase, - owner: ConstId, + owner: DefWithBodyId, c: &Const, ) -> Result { - let mut evaluator = Evaluator::new(db, owner.into(), false, None)?; + let mut evaluator = Evaluator::new(db, owner, false, None)?; let locals = &Locals { ptr: ArenaMap::new(), body: db - .mir_body(owner.into()) + .mir_body(owner) .map_err(|_| MirEvalError::NotSupported("unreachable".to_owned()))?, drop_flags: DropFlags::default(), }; diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 56bf1d2742..a4045dc5ad 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2600,7 +2600,7 @@ impl Const { } } } - if let Ok(s) = mir::render_const_using_debug_impl(db, self.id, &c) { + if let Ok(s) = mir::render_const_using_debug_impl(db, self.id.into(), &c) { Ok(s) } else { Ok(format!("{}", c.display(db, edition))) @@ -2639,6 +2639,45 @@ impl Static { pub fn ty(self, db: &dyn HirDatabase) -> Type { Type::from_value_def(db, self.id) } + + /// Evaluate the constant and return the result as a string, with more detailed information. + /// + /// This function is intended for user-facing display. + pub fn render_eval( + self, + db: &dyn HirDatabase, + edition: Edition, + ) -> Result { + let c = db.const_eval(self.id.into(), Substitution::empty(Interner), None)?; + let data = &c.data(Interner); + if let TyKind::Scalar(s) = data.ty.kind(Interner) { + if matches!(s, Scalar::Int(_) | Scalar::Uint(_)) { + if let hir_ty::ConstValue::Concrete(c) = &data.value { + if let hir_ty::ConstScalar::Bytes(b, _) = &c.interned { + let value = u128::from_le_bytes(mir::pad16(b, false)); + let value_signed = + i128::from_le_bytes(mir::pad16(b, matches!(s, Scalar::Int(_)))); + let mut result = if let Scalar::Int(_) = s { + value_signed.to_string() + } else { + value.to_string() + }; + if value >= 10 { + format_to!(result, " ({value:#X})"); + return Ok(result); + } else { + return Ok(result); + } + } + } + } + } + if let Ok(s) = mir::render_const_using_debug_impl(db, self.id.into(), &c) { + Ok(s) + } else { + Ok(format!("{}", c.display(db, edition))) + } + } } impl HasVisibility for Static { diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs index 51a7728345..d9ddc2d015 100644 --- a/crates/ide/src/hover/render.rs +++ b/crates/ide/src/hover/render.rs @@ -486,13 +486,19 @@ pub(super) fn definition( } } Definition::Static(it) => { - let source = it.source(db)?; - let mut body = source.value.body()?.syntax().clone(); - if let Some(macro_file) = source.file_id.macro_file() { - let span_map = db.expansion_span_map(macro_file); - body = prettify_macro_expansion(db, body, &span_map, it.krate(db).into()); + let body = it.render_eval(db, edition); + match body { + Ok(it) => Some(it), + Err(_) => { + let source = it.source(db)?; + let mut body = source.value.body()?.syntax().clone(); + if let Some(macro_file) = source.file_id.macro_file() { + let span_map = db.expansion_span_map(macro_file); + body = prettify_macro_expansion(db, body, &span_map, it.krate(db).into()); + } + Some(body.to_string()) + } } - Some(body.to_string()) } _ => None, }; diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs index 1fad3d6bd6..0ffbf988c3 100644 --- a/crates/ide/src/hover/tests.rs +++ b/crates/ide/src/hover/tests.rs @@ -1544,7 +1544,7 @@ const foo$0: u32 = { ``` ```rust - static foo: u32 = 456 + static foo: u32 = 456 (0x1C8) ``` "#]], ); diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 51c81a0d1a..155fb6f7c8 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -172,7 +172,6 @@ impl flags::AnalysisStats { let mut num_decls = 0; let mut bodies = Vec::new(); let mut adts = Vec::new(); - let mut consts = Vec::new(); let mut file_ids = Vec::new(); while let Some(module) = visit_queue.pop() { if visited_modules.insert(module) { @@ -193,7 +192,6 @@ impl flags::AnalysisStats { } ModuleDef::Const(c) => { bodies.push(DefWithBody::from(c)); - consts.push(c) } ModuleDef::Static(s) => bodies.push(DefWithBody::from(s)), _ => (), @@ -207,7 +205,6 @@ impl flags::AnalysisStats { AssocItem::Function(f) => bodies.push(DefWithBody::from(f)), AssocItem::Const(c) => { bodies.push(DefWithBody::from(c)); - consts.push(c); } _ => (), } @@ -220,7 +217,10 @@ impl flags::AnalysisStats { visited_modules.len(), bodies.len(), adts.len(), - consts.len(), + bodies + .iter() + .filter(|it| matches!(it, DefWithBody::Const(_) | DefWithBody::Static(_))) + .count(), ); let crate_def_map_time = crate_def_map_sw.elapsed(); eprintln!("{:<20} {}", "Item Collection:", crate_def_map_time); @@ -247,7 +247,7 @@ impl flags::AnalysisStats { } if !self.skip_const_eval { - self.run_const_eval(db, &consts, verbosity); + self.run_const_eval(db, &bodies, verbosity); } if self.run_all_ide_things { @@ -320,18 +320,23 @@ impl flags::AnalysisStats { report_metric("data layout time", data_layout_time.time.as_millis() as u64, "ms"); } - fn run_const_eval(&self, db: &RootDatabase, consts: &[hir::Const], verbosity: Verbosity) { + fn run_const_eval(&self, db: &RootDatabase, bodies: &[DefWithBody], verbosity: Verbosity) { let mut sw = self.stop_watch(); let mut all = 0; let mut fail = 0; - for &c in consts { + for &b in bodies { + let res = match b { + DefWithBody::Const(c) => c.render_eval(db, Edition::LATEST), + DefWithBody::Static(s) => s.render_eval(db, Edition::LATEST), + _ => continue, + }; all += 1; - let Err(error) = c.render_eval(db, Edition::LATEST) else { + let Err(error) = res else { continue; }; if verbosity.is_spammy() { let full_name = - full_name_of_item(db, c.module(db), c.name(db).unwrap_or(Name::missing())); + full_name_of_item(db, b.module(db), b.name(db).unwrap_or(Name::missing())); println!("Const eval for {full_name} failed due {error:?}"); } fail += 1;