@@ -10,10 +10,11 @@ use hir_def::{
10
10
data:: adt:: { StructFlags , VariantData } ,
11
11
lang_item:: LangItem ,
12
12
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 ,
15
16
} ;
16
- use hir_expand:: InFile ;
17
+ use hir_expand:: { mod_path :: ModPath , InFile } ;
17
18
use intern:: Interned ;
18
19
use la_arena:: ArenaMap ;
19
20
use rustc_hash:: { FxHashMap , FxHashSet } ;
@@ -482,7 +483,7 @@ pub fn interpret_mir(
482
483
assert_placeholder_ty_is_unused : bool ,
483
484
) -> ( Result < Const > , String , String ) {
484
485
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) ;
486
487
let it: Result < Const > = ( || {
487
488
if evaluator. ptr_size ( ) != std:: mem:: size_of :: < usize > ( ) {
488
489
not_supported ! ( "targets with different pointer size from host" ) ;
@@ -506,11 +507,11 @@ pub fn interpret_mir(
506
507
impl Evaluator < ' _ > {
507
508
pub fn new < ' a > (
508
509
db : & ' a dyn HirDatabase ,
509
- body : & MirBody ,
510
+ owner : DefWithBodyId ,
510
511
assert_placeholder_ty_is_unused : bool ,
511
512
) -> 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) ;
514
515
Evaluator {
515
516
stack : vec ! [ 0 ] ,
516
517
heap : vec ! [ 0 ] ,
@@ -1551,29 +1552,15 @@ impl Evaluator<'_> {
1551
1552
let addr = self . eval_static ( * st, locals) ?;
1552
1553
Interval :: new ( addr, self . ptr_size ( ) )
1553
1554
}
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) ?,
1567
1556
} )
1568
1557
}
1569
1558
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
+ } ;
1577
1564
Ok ( match & c. interned {
1578
1565
ConstScalar :: Bytes ( v, memory_map) => {
1579
1566
let mut v: Cow < ' _ , [ u8 ] > = Cow :: Borrowed ( v) ;
@@ -2242,12 +2229,7 @@ impl Evaluator<'_> {
2242
2229
Box :: new ( e) ,
2243
2230
)
2244
2231
} ) ?;
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) ?
2251
2233
} else {
2252
2234
let ty = & self . db . infer ( st. into ( ) ) [ self . db . body ( st. into ( ) ) . body_expr ] ;
2253
2235
let Some ( ( size, align) ) = self . size_align_of ( & ty, locals) ? else {
@@ -2388,6 +2370,73 @@ impl Evaluator<'_> {
2388
2370
}
2389
2371
}
2390
2372
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
+
2391
2440
pub fn pad16 ( it : & [ u8 ] , is_signed : bool ) -> [ u8 ; 16 ] {
2392
2441
let is_negative = is_signed && it. last ( ) . unwrap_or ( & 0 ) > & 127 ;
2393
2442
let fill_with = if is_negative { 255 } else { 0 } ;
0 commit comments