Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit db0add1

Browse files
committed
Auto merge of rust-lang#15230 - HKalbasi:mir, r=HKalbasi
Use debug impl in rendering const eval result fix rust-lang#15188
2 parents c5ca816 + f0ba0db commit db0add1

File tree

4 files changed

+106
-58
lines changed

4 files changed

+106
-58
lines changed

crates/hir-ty/src/display.rs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -446,28 +446,6 @@ impl HirDisplay for Const {
446446
}
447447
}
448448

449-
pub struct HexifiedConst(pub Const);
450-
451-
impl HirDisplay for HexifiedConst {
452-
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
453-
let data = &self.0.data(Interner);
454-
if let TyKind::Scalar(s) = data.ty.kind(Interner) {
455-
if matches!(s, Scalar::Int(_) | Scalar::Uint(_)) {
456-
if let ConstValue::Concrete(c) = &data.value {
457-
if let ConstScalar::Bytes(b, m) = &c.interned {
458-
let value = u128::from_le_bytes(pad16(b, false));
459-
if value >= 10 {
460-
render_const_scalar(f, &b, m, &data.ty)?;
461-
return write!(f, " ({:#X})", value);
462-
}
463-
}
464-
}
465-
}
466-
}
467-
self.0.hir_fmt(f)
468-
}
469-
}
470-
471449
fn render_const_scalar(
472450
f: &mut HirFormatter<'_>,
473451
b: &[u8],

crates/hir-ty/src/mir.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ mod pretty;
2222
mod monomorphization;
2323

2424
pub use borrowck::{borrowck_query, BorrowckResult, MutabilityReason};
25-
pub use eval::{interpret_mir, pad16, Evaluator, MirEvalError, VTableMap};
25+
pub use eval::{
26+
interpret_mir, pad16, render_const_using_debug_impl, Evaluator, MirEvalError, VTableMap,
27+
};
2628
pub use lower::{
2729
lower_to_mir, mir_body_for_closure_query, mir_body_query, mir_body_recover, MirLowerError,
2830
};

crates/hir-ty/src/mir/eval.rs

Lines changed: 82 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ use hir_def::{
1010
data::adt::{StructFlags, VariantData},
1111
lang_item::LangItem,
1212
layout::{TagEncoding, Variants},
13-
AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, StaticId,
14-
VariantId,
13+
resolver::{HasResolver, TypeNs, ValueNs},
14+
AdtId, ConstId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup,
15+
StaticId, VariantId,
1516
};
16-
use hir_expand::InFile;
17+
use hir_expand::{mod_path::ModPath, InFile};
1718
use intern::Interned;
1819
use la_arena::ArenaMap;
1920
use rustc_hash::{FxHashMap, FxHashSet};
@@ -482,7 +483,7 @@ pub fn interpret_mir(
482483
assert_placeholder_ty_is_unused: bool,
483484
) -> (Result<Const>, String, String) {
484485
let ty = body.locals[return_slot()].ty.clone();
485-
let mut evaluator = Evaluator::new(db, &body, assert_placeholder_ty_is_unused);
486+
let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused);
486487
let it: Result<Const> = (|| {
487488
if evaluator.ptr_size() != std::mem::size_of::<usize>() {
488489
not_supported!("targets with different pointer size from host");
@@ -506,11 +507,11 @@ pub fn interpret_mir(
506507
impl Evaluator<'_> {
507508
pub fn new<'a>(
508509
db: &'a dyn HirDatabase,
509-
body: &MirBody,
510+
owner: DefWithBodyId,
510511
assert_placeholder_ty_is_unused: bool,
511512
) -> Evaluator<'a> {
512-
let crate_id = body.owner.module(db.upcast()).krate();
513-
let trait_env = db.trait_environment_for_body(body.owner);
513+
let crate_id = owner.module(db.upcast()).krate();
514+
let trait_env = db.trait_environment_for_body(owner);
514515
Evaluator {
515516
stack: vec![0],
516517
heap: vec![0],
@@ -1551,29 +1552,15 @@ impl Evaluator<'_> {
15511552
let addr = self.eval_static(*st, locals)?;
15521553
Interval::new(addr, self.ptr_size())
15531554
}
1554-
Operand::Constant(konst) => {
1555-
let data = &konst.data(Interner);
1556-
match &data.value {
1557-
chalk_ir::ConstValue::BoundVar(_) => not_supported!("bound var constant"),
1558-
chalk_ir::ConstValue::InferenceVar(_) => {
1559-
not_supported!("inference var constant")
1560-
}
1561-
chalk_ir::ConstValue::Placeholder(_) => not_supported!("placeholder constant"),
1562-
chalk_ir::ConstValue::Concrete(c) => {
1563-
self.allocate_const_in_heap(c, &data.ty, locals, konst)?
1564-
}
1565-
}
1566-
}
1555+
Operand::Constant(konst) => self.allocate_const_in_heap(locals, konst)?,
15671556
})
15681557
}
15691558

1570-
fn allocate_const_in_heap(
1571-
&mut self,
1572-
c: &chalk_ir::ConcreteConst<Interner>,
1573-
ty: &Ty,
1574-
locals: &Locals,
1575-
konst: &chalk_ir::Const<Interner>,
1576-
) -> Result<Interval> {
1559+
fn allocate_const_in_heap(&mut self, locals: &Locals, konst: &Const) -> Result<Interval> {
1560+
let ty = &konst.data(Interner).ty;
1561+
let chalk_ir::ConstValue::Concrete(c) = &konst.data(Interner).value else {
1562+
not_supported!("evaluating non concrete constant");
1563+
};
15771564
Ok(match &c.interned {
15781565
ConstScalar::Bytes(v, memory_map) => {
15791566
let mut v: Cow<'_, [u8]> = Cow::Borrowed(v);
@@ -2242,12 +2229,7 @@ impl Evaluator<'_> {
22422229
Box::new(e),
22432230
)
22442231
})?;
2245-
let data = &konst.data(Interner);
2246-
if let chalk_ir::ConstValue::Concrete(c) = &data.value {
2247-
self.allocate_const_in_heap(&c, &data.ty, locals, &konst)?
2248-
} else {
2249-
not_supported!("unevaluatable static");
2250-
}
2232+
self.allocate_const_in_heap(locals, &konst)?
22512233
} else {
22522234
let ty = &self.db.infer(st.into())[self.db.body(st.into()).body_expr];
22532235
let Some((size, align)) = self.size_align_of(&ty, locals)? else {
@@ -2388,6 +2370,73 @@ impl Evaluator<'_> {
23882370
}
23892371
}
23902372

2373+
pub fn render_const_using_debug_impl(
2374+
db: &dyn HirDatabase,
2375+
owner: ConstId,
2376+
c: &Const,
2377+
) -> Result<String> {
2378+
let mut evaluator = Evaluator::new(db, owner.into(), false);
2379+
let locals = &Locals {
2380+
ptr: ArenaMap::new(),
2381+
body: db
2382+
.mir_body(owner.into())
2383+
.map_err(|_| MirEvalError::NotSupported("unreachable".to_string()))?,
2384+
drop_flags: DropFlags::default(),
2385+
};
2386+
let data = evaluator.allocate_const_in_heap(locals, c)?;
2387+
let resolver = owner.resolver(db.upcast());
2388+
let Some(TypeNs::TraitId(debug_trait)) = resolver.resolve_path_in_type_ns_fully(
2389+
db.upcast(),
2390+
&hir_def::path::Path::from_known_path_with_no_generic(ModPath::from_segments(
2391+
hir_expand::mod_path::PathKind::Abs,
2392+
[name![core], name![fmt], name![Debug]].into_iter(),
2393+
)),
2394+
) else {
2395+
not_supported!("core::fmt::Debug not found");
2396+
};
2397+
let Some(debug_fmt_fn) = db.trait_data(debug_trait).method_by_name(&name![fmt]) else {
2398+
not_supported!("core::fmt::Debug::fmt not found");
2399+
};
2400+
// a1 = &[""]
2401+
let a1 = evaluator.heap_allocate(evaluator.ptr_size() * 2, evaluator.ptr_size());
2402+
// a2 = &[::core::fmt::ArgumentV1::new(&(THE_CONST), ::core::fmt::Debug::fmt)]
2403+
// FIXME: we should call the said function, but since its name is going to break in the next rustc version
2404+
// and its ABI doesn't break yet, we put it in memory manually.
2405+
let a2 = evaluator.heap_allocate(evaluator.ptr_size() * 2, evaluator.ptr_size());
2406+
evaluator.write_memory(a2, &data.addr.to_bytes())?;
2407+
let debug_fmt_fn_ptr = evaluator.vtable_map.id(TyKind::FnDef(
2408+
db.intern_callable_def(debug_fmt_fn.into()).into(),
2409+
Substitution::from1(Interner, c.data(Interner).ty.clone()),
2410+
)
2411+
.intern(Interner));
2412+
evaluator.write_memory(a2.offset(evaluator.ptr_size()), &debug_fmt_fn_ptr.to_le_bytes())?;
2413+
// a3 = ::core::fmt::Arguments::new_v1(a1, a2)
2414+
// FIXME: similarly, we should call function here, not directly working with memory.
2415+
let a3 = evaluator.heap_allocate(evaluator.ptr_size() * 6, evaluator.ptr_size());
2416+
evaluator.write_memory(a3.offset(2 * evaluator.ptr_size()), &a1.to_bytes())?;
2417+
evaluator.write_memory(a3.offset(3 * evaluator.ptr_size()), &[1])?;
2418+
evaluator.write_memory(a3.offset(4 * evaluator.ptr_size()), &a2.to_bytes())?;
2419+
evaluator.write_memory(a3.offset(5 * evaluator.ptr_size()), &[1])?;
2420+
let Some(ValueNs::FunctionId(format_fn)) = resolver.resolve_path_in_value_ns_fully(
2421+
db.upcast(),
2422+
&hir_def::path::Path::from_known_path_with_no_generic(ModPath::from_segments(
2423+
hir_expand::mod_path::PathKind::Abs,
2424+
[name![std], name![fmt], name![format]].into_iter(),
2425+
)),
2426+
) else {
2427+
not_supported!("std::fmt::format not found");
2428+
};
2429+
let message_string = evaluator.interpret_mir(
2430+
db.mir_body(format_fn.into()).map_err(|e| MirEvalError::MirLowerError(format_fn, e))?,
2431+
[IntervalOrOwned::Borrowed(Interval { addr: a3, size: evaluator.ptr_size() * 6 })]
2432+
.into_iter(),
2433+
)?;
2434+
let addr =
2435+
Address::from_bytes(&message_string[evaluator.ptr_size()..2 * evaluator.ptr_size()])?;
2436+
let size = from_bytes!(usize, message_string[2 * evaluator.ptr_size()..]);
2437+
Ok(std::string::String::from_utf8_lossy(evaluator.read_memory(addr, size)?).into_owned())
2438+
}
2439+
23912440
pub fn pad16(it: &[u8], is_signed: bool) -> [u8; 16] {
23922441
let is_negative = is_signed && it.last().unwrap_or(&0) > &127;
23932442
let fill_with = if is_negative { 255 } else { 0 };

crates/hir/src/lib.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ use hir_ty::{
6262
all_super_traits, autoderef,
6363
consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt},
6464
diagnostics::BodyValidationDiagnostic,
65-
display::HexifiedConst,
6665
layout::{Layout as TyLayout, RustcEnumVariantIdx, TagEncoding},
6766
method_resolution::{self, TyFingerprint},
6867
mir::{self, interpret_mir},
@@ -2156,7 +2155,27 @@ impl Const {
21562155

21572156
pub fn render_eval(self, db: &dyn HirDatabase) -> Result<String, ConstEvalError> {
21582157
let c = db.const_eval(self.id.into(), Substitution::empty(Interner))?;
2159-
let r = format!("{}", HexifiedConst(c).display(db));
2158+
let data = &c.data(Interner);
2159+
if let TyKind::Scalar(s) = data.ty.kind(Interner) {
2160+
if matches!(s, Scalar::Int(_) | Scalar::Uint(_)) {
2161+
if let hir_ty::ConstValue::Concrete(c) = &data.value {
2162+
if let hir_ty::ConstScalar::Bytes(b, _) = &c.interned {
2163+
let value = u128::from_le_bytes(mir::pad16(b, false));
2164+
let value_signed =
2165+
i128::from_le_bytes(mir::pad16(b, matches!(s, Scalar::Int(_))));
2166+
if value >= 10 {
2167+
return Ok(format!("{} ({:#X})", value_signed, value));
2168+
} else {
2169+
return Ok(format!("{}", value_signed));
2170+
}
2171+
}
2172+
}
2173+
}
2174+
}
2175+
if let Ok(s) = mir::render_const_using_debug_impl(db, self.id, &c) {
2176+
return Ok(s);
2177+
}
2178+
let r = format!("{}", c.display(db));
21602179
return Ok(r);
21612180
}
21622181
}

0 commit comments

Comments
 (0)