@@ -23,17 +23,26 @@ use crate::{
23
23
infer:: { normalize, PointerCast } ,
24
24
layout:: layout_of_ty,
25
25
mapping:: from_chalk,
26
- method_resolution:: lookup_impl_method,
26
+ method_resolution:: { is_dyn_method , lookup_impl_method} ,
27
27
traits:: FnTrait ,
28
28
CallableDefId , Const , ConstScalar , FnDefId , Interner , MemoryMap , Substitution ,
29
- TraitEnvironment , Ty , TyBuilder , TyExt ,
29
+ TraitEnvironment , Ty , TyBuilder , TyExt , GenericArgData ,
30
30
} ;
31
31
32
32
use super :: {
33
33
const_as_usize, return_slot, AggregateKind , BinOp , CastKind , LocalId , MirBody , MirLowerError ,
34
34
Operand , Place , ProjectionElem , Rvalue , StatementKind , Terminator , UnOp ,
35
35
} ;
36
36
37
+ macro_rules! from_bytes {
38
+ ( $ty: tt, $value: expr) => {
39
+ ( $ty:: from_le_bytes( match ( $value) . try_into( ) {
40
+ Ok ( x) => x,
41
+ Err ( _) => return Err ( MirEvalError :: TypeError ( "mismatched size" ) ) ,
42
+ } ) )
43
+ } ;
44
+ }
45
+
37
46
#[ derive( Debug , Default ) ]
38
47
struct VTableMap {
39
48
ty_to_id : HashMap < Ty , usize > ,
@@ -54,6 +63,11 @@ impl VTableMap {
54
63
fn ty ( & self , id : usize ) -> Result < & Ty > {
55
64
self . id_to_ty . get ( id) . ok_or ( MirEvalError :: InvalidVTableId ( id) )
56
65
}
66
+
67
+ fn ty_of_bytes ( & self , bytes : & [ u8 ] ) -> Result < & Ty > {
68
+ let id = from_bytes ! ( usize , bytes) ;
69
+ self . ty ( id)
70
+ }
57
71
}
58
72
59
73
pub struct Evaluator < ' a > {
@@ -110,15 +124,6 @@ impl IntervalOrOwned {
110
124
}
111
125
}
112
126
113
- macro_rules! from_bytes {
114
- ( $ty: tt, $value: expr) => {
115
- ( $ty:: from_le_bytes( match ( $value) . try_into( ) {
116
- Ok ( x) => x,
117
- Err ( _) => return Err ( MirEvalError :: TypeError ( "mismatched size" ) ) ,
118
- } ) )
119
- } ;
120
- }
121
-
122
127
impl Address {
123
128
fn from_bytes ( x : & [ u8 ] ) -> Result < Self > {
124
129
Ok ( Address :: from_usize ( from_bytes ! ( usize , x) ) )
@@ -781,7 +786,18 @@ impl Evaluator<'_> {
781
786
}
782
787
_ => not_supported ! ( "slice unsizing from non pointers" ) ,
783
788
} ,
784
- TyKind :: Dyn ( _) => not_supported ! ( "dyn pointer unsize cast" ) ,
789
+ TyKind :: Dyn ( _) => match & current_ty. data ( Interner ) . kind {
790
+ TyKind :: Raw ( _, ty) | TyKind :: Ref ( _, _, ty) => {
791
+ let vtable = self . vtable_map . id ( ty. clone ( ) ) ;
792
+ let addr =
793
+ self . eval_operand ( operand, locals) ?. get ( & self ) ?;
794
+ let mut r = Vec :: with_capacity ( 16 ) ;
795
+ r. extend ( addr. iter ( ) . copied ( ) ) ;
796
+ r. extend ( vtable. to_le_bytes ( ) . into_iter ( ) ) ;
797
+ Owned ( r)
798
+ }
799
+ _ => not_supported ! ( "dyn unsizing from non pointers" ) ,
800
+ } ,
785
801
_ => not_supported ! ( "unknown unsized cast" ) ,
786
802
}
787
803
}
@@ -1227,44 +1243,8 @@ impl Evaluator<'_> {
1227
1243
let arg_bytes = args
1228
1244
. iter ( )
1229
1245
. map ( |x| Ok ( self . eval_operand ( x, & locals) ?. get ( & self ) ?. to_owned ( ) ) )
1230
- . collect :: < Result < Vec < _ > > > ( ) ?
1231
- . into_iter ( ) ;
1232
- let function_data = self . db . function_data ( def) ;
1233
- let is_intrinsic = match & function_data. abi {
1234
- Some ( abi) => * abi == Interned :: new_str ( "rust-intrinsic" ) ,
1235
- None => match def. lookup ( self . db . upcast ( ) ) . container {
1236
- hir_def:: ItemContainerId :: ExternBlockId ( block) => {
1237
- let id = block. lookup ( self . db . upcast ( ) ) . id ;
1238
- id. item_tree ( self . db . upcast ( ) ) [ id. value ] . abi . as_deref ( )
1239
- == Some ( "rust-intrinsic" )
1240
- }
1241
- _ => false ,
1242
- } ,
1243
- } ;
1244
- let result = if is_intrinsic {
1245
- self . exec_intrinsic (
1246
- function_data. name . as_text ( ) . unwrap_or_default ( ) . as_str ( ) ,
1247
- arg_bytes,
1248
- generic_args,
1249
- & locals,
1250
- ) ?
1251
- } else if let Some ( x) = self . detect_lang_function ( def) {
1252
- self . exec_lang_item ( x, arg_bytes) ?
1253
- } else {
1254
- let ( imp, generic_args) = lookup_impl_method (
1255
- self . db ,
1256
- self . trait_env . clone ( ) ,
1257
- def,
1258
- generic_args. clone ( ) ,
1259
- ) ;
1260
- let generic_args = self . subst_filler ( & generic_args, & locals) ;
1261
- let def = imp. into ( ) ;
1262
- let mir_body =
1263
- self . db . mir_body ( def) . map_err ( |e| MirEvalError :: MirLowerError ( imp, e) ) ?;
1264
- self . interpret_mir ( & mir_body, arg_bytes, generic_args)
1265
- . map_err ( |e| MirEvalError :: InFunction ( imp, Box :: new ( e) ) ) ?
1266
- } ;
1267
- self . write_memory ( dest_addr, & result) ?;
1246
+ . collect :: < Result < Vec < _ > > > ( ) ?;
1247
+ self . exec_fn_with_args ( def, arg_bytes, generic_args, locals, dest_addr) ?;
1268
1248
}
1269
1249
CallableDefId :: StructId ( id) => {
1270
1250
let ( size, variant_layout, tag) =
@@ -1284,6 +1264,77 @@ impl Evaluator<'_> {
1284
1264
Ok ( ( ) )
1285
1265
}
1286
1266
1267
+ fn exec_fn_with_args (
1268
+ & mut self ,
1269
+ def : FunctionId ,
1270
+ arg_bytes : Vec < Vec < u8 > > ,
1271
+ generic_args : Substitution ,
1272
+ locals : & Locals < ' _ > ,
1273
+ dest_addr : Address ,
1274
+ ) -> Result < ( ) > {
1275
+ let function_data = self . db . function_data ( def) ;
1276
+ let is_intrinsic = match & function_data. abi {
1277
+ Some ( abi) => * abi == Interned :: new_str ( "rust-intrinsic" ) ,
1278
+ None => match def. lookup ( self . db . upcast ( ) ) . container {
1279
+ hir_def:: ItemContainerId :: ExternBlockId ( block) => {
1280
+ let id = block. lookup ( self . db . upcast ( ) ) . id ;
1281
+ id. item_tree ( self . db . upcast ( ) ) [ id. value ] . abi . as_deref ( )
1282
+ == Some ( "rust-intrinsic" )
1283
+ }
1284
+ _ => false ,
1285
+ } ,
1286
+ } ;
1287
+ let result = if is_intrinsic {
1288
+ self . exec_intrinsic (
1289
+ function_data. name . as_text ( ) . unwrap_or_default ( ) . as_str ( ) ,
1290
+ arg_bytes. iter ( ) . cloned ( ) ,
1291
+ generic_args,
1292
+ & locals,
1293
+ ) ?
1294
+ } else if let Some ( x) = self . detect_lang_function ( def) {
1295
+ self . exec_lang_item ( x, & arg_bytes) ?
1296
+ } else {
1297
+ if let Some ( self_ty_idx) =
1298
+ is_dyn_method ( self . db , self . trait_env . clone ( ) , def, generic_args. clone ( ) )
1299
+ {
1300
+ // In the layout of current possible receiver, which at the moment of writing this code is one of
1301
+ // `&T`, `&mut T`, `Box<T>`, `Rc<T>`, `Arc<T>`, and `Pin<P>` where `P` is one of possible recievers,
1302
+ // the vtable is exactly in the `[ptr_size..2*ptr_size]` bytes. So we can use it without branching on
1303
+ // the type.
1304
+ let ty = self
1305
+ . vtable_map
1306
+ . ty_of_bytes ( & arg_bytes[ 0 ] [ self . ptr_size ( ) ..self . ptr_size ( ) * 2 ] ) ?;
1307
+ let ty = GenericArgData :: Ty ( ty. clone ( ) ) . intern ( Interner ) ;
1308
+ let mut args_for_target = arg_bytes;
1309
+ args_for_target[ 0 ] = args_for_target[ 0 ] [ 0 ..self . ptr_size ( ) ] . to_vec ( ) ;
1310
+ let generics_for_target = Substitution :: from_iter (
1311
+ Interner ,
1312
+ generic_args
1313
+ . iter ( Interner )
1314
+ . enumerate ( )
1315
+ . map ( |( i, x) | if i == self_ty_idx { & ty } else { x } )
1316
+ ) ;
1317
+ return self . exec_fn_with_args (
1318
+ def,
1319
+ args_for_target,
1320
+ generics_for_target,
1321
+ locals,
1322
+ dest_addr,
1323
+ ) ;
1324
+ }
1325
+ let ( imp, generic_args) =
1326
+ lookup_impl_method ( self . db , self . trait_env . clone ( ) , def, generic_args. clone ( ) ) ;
1327
+ let generic_args = self . subst_filler ( & generic_args, & locals) ;
1328
+ let def = imp. into ( ) ;
1329
+ let mir_body =
1330
+ self . db . mir_body ( def) . map_err ( |e| MirEvalError :: MirLowerError ( imp, e) ) ?;
1331
+ self . interpret_mir ( & mir_body, arg_bytes. iter ( ) . cloned ( ) , generic_args)
1332
+ . map_err ( |e| MirEvalError :: InFunction ( imp, Box :: new ( e) ) ) ?
1333
+ } ;
1334
+ self . write_memory ( dest_addr, & result) ?;
1335
+ Ok ( ( ) )
1336
+ }
1337
+
1287
1338
fn exec_fn_trait (
1288
1339
& mut self ,
1289
1340
ft : FnTrait ,
@@ -1317,12 +1368,9 @@ impl Evaluator<'_> {
1317
1368
Ok ( ( ) )
1318
1369
}
1319
1370
1320
- fn exec_lang_item (
1321
- & self ,
1322
- x : LangItem ,
1323
- mut args : std:: vec:: IntoIter < Vec < u8 > > ,
1324
- ) -> Result < Vec < u8 > > {
1371
+ fn exec_lang_item ( & self , x : LangItem , args : & [ Vec < u8 > ] ) -> Result < Vec < u8 > > {
1325
1372
use LangItem :: * ;
1373
+ let mut args = args. iter ( ) ;
1326
1374
match x {
1327
1375
PanicFmt | BeginPanic => Err ( MirEvalError :: Panic ) ,
1328
1376
SliceLen => {
0 commit comments