@@ -101,6 +101,7 @@ impl TypeExt for Type {
101101 }
102102 }
103103}
104+
104105trait ExprExt {
105106 fn unit ( symbol_table : & SymbolTable ) -> Self ;
106107
@@ -354,9 +355,11 @@ impl<'tcx> GotocCtx<'tcx> {
354355 Type :: unit ( ) . to_typedef ( inner_name)
355356 }
356357
357- /// This will codegen the raw pointer to the trait data.
358+ /// Codegen the pointer type for a concrete object that implements the trait object.
359+ /// I.e.: A trait object is a fat pointer which contains a pointer to a concrete object
360+ /// and a pointer to its vtable. This method returns a type for the first pointer.
358361 pub fn codegen_trait_data_pointer ( & mut self , typ : ty:: Ty < ' tcx > ) -> Type {
359- assert ! ( typ . is_trait ( ) ) ;
362+ assert ! ( self . use_vtable_fat_pointer ( typ ) ) ;
360363 self . codegen_ty ( typ) . to_pointer ( )
361364 }
362365
@@ -440,6 +443,7 @@ impl<'tcx> GotocCtx<'tcx> {
440443
441444 vtable_base. append ( & mut flds) ;
442445 }
446+ debug ! ( ty=?t, ?vtable_base, "trait_vtable_field_types" ) ;
443447 vtable_base
444448 } else {
445449 unreachable ! ( "Expected to get a dynamic object here" ) ;
@@ -918,24 +922,35 @@ impl<'tcx> GotocCtx<'tcx> {
918922
919923 /// Generate code for a trait function declaration.
920924 ///
921- /// Dynamic function calls first parameter is the fat-pointer representing self.
922- /// For closures, the type of the first argument is dyn T not &dyn T.
923- pub fn codegen_dynamic_function_sig ( & mut self , sig : PolyFnSig < ' tcx > ) -> Type {
925+ /// Dynamic function calls first parameter is self which must be one of the following:
926+ ///
927+ /// As of Jul 2022:
928+ /// P = &Self | &mut Self | Box<Self> | Rc<Self> | Arc<Self>
929+ /// S = P | Pin<P>
930+ ///
931+ /// See <https://doc.rust-lang.org/reference/items/traits.html#object-safety> for more details.
932+ fn codegen_dynamic_function_sig ( & mut self , sig : PolyFnSig < ' tcx > ) -> Type {
924933 let sig = self . monomorphize ( sig) ;
925934 let sig = self . tcx . normalize_erasing_late_bound_regions ( ty:: ParamEnv :: reveal_all ( ) , sig) ;
926-
927935 let mut is_first = true ;
928936 let params = sig
929937 . inputs ( )
930938 . iter ( )
931939 . filter_map ( |arg_type| {
932940 if is_first {
933- // This should &dyn T or dyn T (for closures).
934941 is_first = false ;
935- let first_ty = pointee_type ( * arg_type) . unwrap_or ( * arg_type) ;
936942 debug ! ( self_type=?arg_type, fn_signature=?sig, "codegen_dynamic_function_sig" ) ;
937- assert ! ( first_ty. is_trait( ) , "Expected self type to be a trait" ) ;
938- Some ( self . codegen_trait_data_pointer ( first_ty) )
943+ if arg_type. is_ref ( ) {
944+ // Convert fat pointer to thin pointer to data portion.
945+ let first_ty = pointee_type ( * arg_type) . unwrap ( ) ;
946+ Some ( self . codegen_trait_data_pointer ( first_ty) )
947+ } else if arg_type. is_trait ( ) {
948+ // Convert dyn T to thin pointer.
949+ Some ( self . codegen_trait_data_pointer ( * arg_type) )
950+ } else {
951+ // Codegen type with thin pointer (E.g.: Box<dyn T> -> Box<data_ptr>).
952+ Some ( self . codegen_trait_receiver ( * arg_type) )
953+ }
939954 } else if self . ignore_var_ty ( * arg_type) {
940955 debug ! ( "Ignoring type {:?} in function signature" , arg_type) ;
941956 None
@@ -1367,6 +1382,52 @@ impl<'tcx> GotocCtx<'tcx> {
13671382 _ => false ,
13681383 }
13691384 }
1385+
1386+ /// Generate code for a valid object-safe trait receiver type.
1387+ ///
1388+ /// Note that all these types only contain the data pointer and ZST fields. Thus, we generate
1389+ /// the non-ZST branch manually. In some cases, this method is called from inside
1390+ /// `codegen_ty(arg_ty)` so we don't have information about the final type.
1391+ fn codegen_trait_receiver ( & mut self , arg_ty : Ty < ' tcx > ) -> Type {
1392+ // Collect structs that need to be modified
1393+ // Collect the non-ZST fields until we find a fat pointer.
1394+ let mut data_path = vec ! [ arg_ty] ;
1395+ data_path. extend ( self . receiver_data_path ( arg_ty) . map ( |( _, typ) | typ) ) ;
1396+
1397+ trace ! ( ?arg_ty, ?data_path, "codegen_trait_receiver" ) ;
1398+ let orig_pointer_ty = data_path. pop ( ) . unwrap ( ) ;
1399+ assert ! ( self . is_vtable_fat_pointer( orig_pointer_ty) ) ;
1400+
1401+ // Traverse type and replace pointer type.
1402+ let ptr_type = self . codegen_trait_data_pointer ( pointee_type ( orig_pointer_ty) . unwrap ( ) ) ;
1403+ data_path. iter ( ) . rev ( ) . fold ( ptr_type, |last_type, curr| {
1404+ // Codegen the type replacing the non-zst field.
1405+ let new_name = self . ty_mangled_name ( * curr) . to_string ( ) + "::WithDataPtr" ;
1406+ if let ty:: Adt ( adt_def, adt_substs) = curr. kind ( ) {
1407+ let fields = & adt_def. variants ( ) . get ( VariantIdx :: from_u32 ( 0 ) ) . unwrap ( ) . fields ;
1408+ self . ensure_struct ( new_name, NO_PRETTY_NAME , |ctx, s_name| {
1409+ let fields_shape = ctx. layout_of ( * curr) . layout . fields ( ) ;
1410+ let components = fields_shape
1411+ . index_by_increasing_offset ( )
1412+ . map ( |idx| {
1413+ let name = fields[ idx] . name . to_string ( ) . intern ( ) ;
1414+ let field_ty = fields[ idx] . ty ( ctx. tcx , adt_substs) ;
1415+ let typ = if !ctx. layout_of ( field_ty) . is_zst ( ) {
1416+ last_type. clone ( )
1417+ } else {
1418+ ctx. codegen_ty ( field_ty)
1419+ } ;
1420+ DatatypeComponent :: Field { name, typ }
1421+ } )
1422+ . collect ( ) ;
1423+ trace ! ( ?data_path, ?curr, ?s_name, ?components, "codegen_trait_receiver" ) ;
1424+ components
1425+ } )
1426+ } else {
1427+ unreachable ! ( "Expected structs only {:?}" , curr) ;
1428+ }
1429+ } )
1430+ }
13701431}
13711432
13721433/// Use maps instead of lists to manage mir struct components.
@@ -1412,6 +1473,70 @@ impl<'tcx> GotocCtx<'tcx> {
14121473 }
14131474 if typ. is_trait ( ) { Some ( typ) } else { None }
14141475 }
1476+
1477+ /// This function provides an iterator that traverses the data path of a receiver type. I.e.:
1478+ /// the path that leads to the data pointer.
1479+ ///
1480+ /// E.g.: For `Rc<dyn T>` where the Rc definition is:
1481+ /// ```
1482+ /// pub struct Rc<T: ?Sized> {
1483+ /// ptr: NonNull<RcBox<T>>,
1484+ /// phantom: PhantomData<RcBox<T>>,
1485+ /// }
1486+ ///
1487+ /// pub struct NonNull<T: ?Sized> {
1488+ /// pointer: *const T,
1489+ /// }
1490+ /// ```
1491+ ///
1492+ /// The behavior will be:
1493+ /// ```text
1494+ /// let it = self.receiver_data_path(rc_typ);
1495+ /// assert_eq!(it.next(), Some((String::from("ptr"), non_null_typ);
1496+ /// assert_eq!(it.next(), Some((String::from("pointer"), raw_ptr_typ);
1497+ /// assert_eq!(it.next(), None);
1498+ /// ```
1499+ ///
1500+ /// Pre-condition: The argument must be a valid receiver for dispatchable trait functions.
1501+ /// See <https://doc.rust-lang.org/reference/items/traits.html#object-safety> for more details.
1502+ pub fn receiver_data_path < ' a > (
1503+ self : & ' a Self ,
1504+ typ : Ty < ' tcx > ,
1505+ ) -> impl Iterator < Item = ( String , Ty < ' tcx > ) > + ' a {
1506+ struct ReceiverIter < ' tcx , ' a > {
1507+ pub curr : Ty < ' tcx > ,
1508+ pub ctx : & ' a GotocCtx < ' tcx > ,
1509+ }
1510+
1511+ impl < ' tcx , ' a > Iterator for ReceiverIter < ' tcx , ' a > {
1512+ type Item = ( String , Ty < ' tcx > ) ;
1513+
1514+ fn next ( & mut self ) -> Option < Self :: Item > {
1515+ if let ty:: Adt ( adt_def, adt_substs) = self . curr . kind ( ) {
1516+ assert_eq ! (
1517+ adt_def. variants( ) . len( ) ,
1518+ 1 ,
1519+ "Expected a single-variant ADT. Found {:?}" ,
1520+ self . curr
1521+ ) ;
1522+ let ctx = self . ctx ;
1523+ let fields = & adt_def. variants ( ) . get ( VariantIdx :: from_u32 ( 0 ) ) . unwrap ( ) . fields ;
1524+ let mut non_zsts = fields
1525+ . iter ( )
1526+ . filter ( |field| !ctx. layout_of ( field. ty ( ctx. tcx , adt_substs) ) . is_zst ( ) )
1527+ . map ( |non_zst| ( non_zst. name . to_string ( ) , non_zst. ty ( ctx. tcx , adt_substs) ) ) ;
1528+ let ( name, next) = non_zsts. next ( ) . expect ( "Expected one non-zst field." ) ;
1529+ self . curr = next;
1530+ assert ! ( non_zsts. next( ) . is_none( ) , "Expected only one non-zst field." ) ;
1531+ Some ( ( name, self . curr ) )
1532+ } else {
1533+ None
1534+ }
1535+ }
1536+ }
1537+
1538+ ReceiverIter { ctx : self , curr : typ }
1539+ }
14151540}
14161541
14171542/// The mir type is a mir pointer type.
0 commit comments