Skip to content

Commit b431237

Browse files
committed
Allow static initializers to be const evaluated
1 parent cf6bc48 commit b431237

File tree

7 files changed

+87
-28
lines changed

7 files changed

+87
-28
lines changed

src/tools/rust-analyzer/crates/hir-def/src/lib.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -837,23 +837,28 @@ impl InTypeConstId {
837837
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
838838
pub enum GeneralConstId {
839839
ConstId(ConstId),
840+
StaticId(StaticId),
840841
ConstBlockId(ConstBlockId),
841842
InTypeConstId(InTypeConstId),
842843
}
843844

844-
impl_from!(ConstId, ConstBlockId, InTypeConstId for GeneralConstId);
845+
impl_from!(ConstId, StaticId, ConstBlockId, InTypeConstId for GeneralConstId);
845846

846847
impl GeneralConstId {
847848
pub fn generic_def(self, db: &dyn DefDatabase) -> Option<GenericDefId> {
848849
match self {
849850
GeneralConstId::ConstId(it) => Some(it.into()),
851+
GeneralConstId::StaticId(_) => None,
850852
GeneralConstId::ConstBlockId(it) => it.lookup(db).parent.as_generic_def_id(db),
851853
GeneralConstId::InTypeConstId(it) => it.lookup(db).owner.as_generic_def_id(db),
852854
}
853855
}
854856

855857
pub fn name(self, db: &dyn DefDatabase) -> String {
856858
match self {
859+
GeneralConstId::StaticId(it) => {
860+
db.static_data(it).name.display(db.upcast(), Edition::CURRENT).to_string()
861+
}
857862
GeneralConstId::ConstId(const_id) => db
858863
.const_data(const_id)
859864
.name

src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use hir_def::{
88
path::Path,
99
resolver::{Resolver, ValueNs},
1010
type_ref::LiteralConstRef,
11-
ConstBlockLoc, EnumVariantId, GeneralConstId, StaticId,
11+
ConstBlockLoc, EnumVariantId, GeneralConstId, HasModule as _, StaticId,
1212
};
1313
use hir_expand::Lookup;
1414
use stdx::never;
@@ -236,6 +236,10 @@ pub(crate) fn const_eval_query(
236236
GeneralConstId::ConstId(c) => {
237237
db.monomorphized_mir_body(c.into(), subst, db.trait_environment(c.into()))?
238238
}
239+
GeneralConstId::StaticId(s) => {
240+
let krate = s.module(db.upcast()).krate();
241+
db.monomorphized_mir_body(s.into(), subst, TraitEnvironment::empty(krate))?
242+
}
239243
GeneralConstId::ConstBlockId(c) => {
240244
let ConstBlockLoc { parent, root } = db.lookup_intern_anonymous_const(c);
241245
let body = db.body(parent);

src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ use hir_def::{
1212
lang_item::LangItem,
1313
layout::{TagEncoding, Variants},
1414
resolver::{HasResolver, TypeNs, ValueNs},
15-
AdtId, ConstId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup,
16-
StaticId, VariantId,
15+
AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, StaticId,
16+
VariantId,
1717
};
1818
use hir_expand::{mod_path::path, name::Name, HirFileIdExt, InFile};
1919
use intern::sym;
@@ -40,8 +40,8 @@ use crate::{
4040
static_lifetime,
4141
traits::FnTrait,
4242
utils::{detect_variant_from_bytes, ClosureSubst},
43-
CallableDefId, ClosureId, ComplexMemoryMap, Const, ConstScalar, FnDefId, Interner, MemoryMap,
44-
Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind,
43+
CallableDefId, ClosureId, ComplexMemoryMap, Const, ConstData, ConstScalar, FnDefId, Interner,
44+
MemoryMap, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind,
4545
};
4646

4747
use super::{
@@ -1899,8 +1899,8 @@ impl Evaluator<'_> {
18991899

19001900
#[allow(clippy::double_parens)]
19011901
fn allocate_const_in_heap(&mut self, locals: &Locals, konst: &Const) -> Result<Interval> {
1902-
let ty = &konst.data(Interner).ty;
1903-
let chalk_ir::ConstValue::Concrete(c) = &konst.data(Interner).value else {
1902+
let ConstData { ty, value: chalk_ir::ConstValue::Concrete(c) } = &konst.data(Interner)
1903+
else {
19041904
not_supported!("evaluating non concrete constant");
19051905
};
19061906
let result_owner;
@@ -2908,14 +2908,14 @@ impl Evaluator<'_> {
29082908

29092909
pub fn render_const_using_debug_impl(
29102910
db: &dyn HirDatabase,
2911-
owner: ConstId,
2911+
owner: DefWithBodyId,
29122912
c: &Const,
29132913
) -> Result<String> {
2914-
let mut evaluator = Evaluator::new(db, owner.into(), false, None)?;
2914+
let mut evaluator = Evaluator::new(db, owner, false, None)?;
29152915
let locals = &Locals {
29162916
ptr: ArenaMap::new(),
29172917
body: db
2918-
.mir_body(owner.into())
2918+
.mir_body(owner)
29192919
.map_err(|_| MirEvalError::NotSupported("unreachable".to_owned()))?,
29202920
drop_flags: DropFlags::default(),
29212921
};

src/tools/rust-analyzer/crates/hir/src/lib.rs

+40-1
Original file line numberDiff line numberDiff line change
@@ -2600,7 +2600,7 @@ impl Const {
26002600
}
26012601
}
26022602
}
2603-
if let Ok(s) = mir::render_const_using_debug_impl(db, self.id, &c) {
2603+
if let Ok(s) = mir::render_const_using_debug_impl(db, self.id.into(), &c) {
26042604
Ok(s)
26052605
} else {
26062606
Ok(format!("{}", c.display(db, edition)))
@@ -2639,6 +2639,45 @@ impl Static {
26392639
pub fn ty(self, db: &dyn HirDatabase) -> Type {
26402640
Type::from_value_def(db, self.id)
26412641
}
2642+
2643+
/// Evaluate the constant and return the result as a string, with more detailed information.
2644+
///
2645+
/// This function is intended for user-facing display.
2646+
pub fn render_eval(
2647+
self,
2648+
db: &dyn HirDatabase,
2649+
edition: Edition,
2650+
) -> Result<String, ConstEvalError> {
2651+
let c = db.const_eval(self.id.into(), Substitution::empty(Interner), None)?;
2652+
let data = &c.data(Interner);
2653+
if let TyKind::Scalar(s) = data.ty.kind(Interner) {
2654+
if matches!(s, Scalar::Int(_) | Scalar::Uint(_)) {
2655+
if let hir_ty::ConstValue::Concrete(c) = &data.value {
2656+
if let hir_ty::ConstScalar::Bytes(b, _) = &c.interned {
2657+
let value = u128::from_le_bytes(mir::pad16(b, false));
2658+
let value_signed =
2659+
i128::from_le_bytes(mir::pad16(b, matches!(s, Scalar::Int(_))));
2660+
let mut result = if let Scalar::Int(_) = s {
2661+
value_signed.to_string()
2662+
} else {
2663+
value.to_string()
2664+
};
2665+
if value >= 10 {
2666+
format_to!(result, " ({value:#X})");
2667+
return Ok(result);
2668+
} else {
2669+
return Ok(result);
2670+
}
2671+
}
2672+
}
2673+
}
2674+
}
2675+
if let Ok(s) = mir::render_const_using_debug_impl(db, self.id.into(), &c) {
2676+
Ok(s)
2677+
} else {
2678+
Ok(format!("{}", c.display(db, edition)))
2679+
}
2680+
}
26422681
}
26432682

26442683
impl HasVisibility for Static {

src/tools/rust-analyzer/crates/ide/src/hover/render.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -486,13 +486,19 @@ pub(super) fn definition(
486486
}
487487
}
488488
Definition::Static(it) => {
489-
let source = it.source(db)?;
490-
let mut body = source.value.body()?.syntax().clone();
491-
if let Some(macro_file) = source.file_id.macro_file() {
492-
let span_map = db.expansion_span_map(macro_file);
493-
body = prettify_macro_expansion(db, body, &span_map, it.krate(db).into());
489+
let body = it.render_eval(db, edition);
490+
match body {
491+
Ok(it) => Some(it),
492+
Err(_) => {
493+
let source = it.source(db)?;
494+
let mut body = source.value.body()?.syntax().clone();
495+
if let Some(macro_file) = source.file_id.macro_file() {
496+
let span_map = db.expansion_span_map(macro_file);
497+
body = prettify_macro_expansion(db, body, &span_map, it.krate(db).into());
498+
}
499+
Some(body.to_string())
500+
}
494501
}
495-
Some(body.to_string())
496502
}
497503
_ => None,
498504
};

src/tools/rust-analyzer/crates/ide/src/hover/tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1544,7 +1544,7 @@ const foo$0: u32 = {
15441544
```
15451545
15461546
```rust
1547-
static foo: u32 = 456
1547+
static foo: u32 = 456 (0x1C8)
15481548
```
15491549
"#]],
15501550
);

src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs

+14-9
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,6 @@ impl flags::AnalysisStats {
172172
let mut num_decls = 0;
173173
let mut bodies = Vec::new();
174174
let mut adts = Vec::new();
175-
let mut consts = Vec::new();
176175
let mut file_ids = Vec::new();
177176
while let Some(module) = visit_queue.pop() {
178177
if visited_modules.insert(module) {
@@ -193,7 +192,6 @@ impl flags::AnalysisStats {
193192
}
194193
ModuleDef::Const(c) => {
195194
bodies.push(DefWithBody::from(c));
196-
consts.push(c)
197195
}
198196
ModuleDef::Static(s) => bodies.push(DefWithBody::from(s)),
199197
_ => (),
@@ -207,7 +205,6 @@ impl flags::AnalysisStats {
207205
AssocItem::Function(f) => bodies.push(DefWithBody::from(f)),
208206
AssocItem::Const(c) => {
209207
bodies.push(DefWithBody::from(c));
210-
consts.push(c);
211208
}
212209
_ => (),
213210
}
@@ -220,7 +217,10 @@ impl flags::AnalysisStats {
220217
visited_modules.len(),
221218
bodies.len(),
222219
adts.len(),
223-
consts.len(),
220+
bodies
221+
.iter()
222+
.filter(|it| matches!(it, DefWithBody::Const(_) | DefWithBody::Static(_)))
223+
.count(),
224224
);
225225
let crate_def_map_time = crate_def_map_sw.elapsed();
226226
eprintln!("{:<20} {}", "Item Collection:", crate_def_map_time);
@@ -247,7 +247,7 @@ impl flags::AnalysisStats {
247247
}
248248

249249
if !self.skip_const_eval {
250-
self.run_const_eval(db, &consts, verbosity);
250+
self.run_const_eval(db, &bodies, verbosity);
251251
}
252252

253253
if self.run_all_ide_things {
@@ -320,18 +320,23 @@ impl flags::AnalysisStats {
320320
report_metric("data layout time", data_layout_time.time.as_millis() as u64, "ms");
321321
}
322322

323-
fn run_const_eval(&self, db: &RootDatabase, consts: &[hir::Const], verbosity: Verbosity) {
323+
fn run_const_eval(&self, db: &RootDatabase, bodies: &[DefWithBody], verbosity: Verbosity) {
324324
let mut sw = self.stop_watch();
325325
let mut all = 0;
326326
let mut fail = 0;
327-
for &c in consts {
327+
for &b in bodies {
328+
let res = match b {
329+
DefWithBody::Const(c) => c.render_eval(db, Edition::LATEST),
330+
DefWithBody::Static(s) => s.render_eval(db, Edition::LATEST),
331+
_ => continue,
332+
};
328333
all += 1;
329-
let Err(error) = c.render_eval(db, Edition::LATEST) else {
334+
let Err(error) = res else {
330335
continue;
331336
};
332337
if verbosity.is_spammy() {
333338
let full_name =
334-
full_name_of_item(db, c.module(db), c.name(db).unwrap_or(Name::missing()));
339+
full_name_of_item(db, b.module(db), b.name(db).unwrap_or(Name::missing()));
335340
println!("Const eval for {full_name} failed due {error:?}");
336341
}
337342
fail += 1;

0 commit comments

Comments
 (0)