@@ -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 } ;
1718use intern:: Interned ;
1819use la_arena:: ArenaMap ;
1920use 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(
506507impl 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+
23912440pub 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 } ;
0 commit comments