]> git.lizzy.rs Git - rust.git/commitdiff
Parameterize `DynMetadata` over its `dyn SomeTrait` type
authorSimon Sapin <simon.sapin@exyr.org>
Tue, 29 Dec 2020 17:31:22 +0000 (18:31 +0100)
committerSimon Sapin <simon.sapin@exyr.org>
Mon, 15 Feb 2021 13:27:16 +0000 (14:27 +0100)
compiler/rustc_middle/src/ty/sty.rs
library/core/src/ptr/metadata.rs
library/core/tests/ptr.rs

index 3992e570cdc5890152b9bdf46c0dbc8725131900..b534b5ac4d47d6d7cb7fd0ac17f86f110fd5c165 100644 (file)
@@ -2164,7 +2164,10 @@ pub fn ptr_metadata_ty(&'tcx self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
             | ty::Tuple(..) => tcx.types.unit,
 
             ty::Str | ty::Slice(_) => tcx.types.usize,
-            ty::Dynamic(..) => tcx.type_of(tcx.lang_items().dyn_metadata().unwrap()),
+            ty::Dynamic(..) => {
+                let dyn_metadata = tcx.lang_items().dyn_metadata().unwrap();
+                tcx.type_of(dyn_metadata).subst(tcx, &[tail.into()])
+            },
 
             ty::Projection(_)
             | ty::Param(_)
index 416b1b860ce88bcae76e78af29c1a2ce16b7dae3..948d7f0b0394423bbde2cd4ed4e6228c434b2f2b 100644 (file)
@@ -1,7 +1,7 @@
 #![unstable(feature = "ptr_metadata", issue = /* FIXME */ "none")]
 
 use crate::fmt;
-use crate::hash::Hash;
+use crate::hash::{Hash, Hasher};
 use crate::ptr::NonNull;
 
 /// FIXME docs
@@ -61,17 +61,60 @@ fn clone(&self) -> Self {
 
 /// The metadata for a `dyn SomeTrait` trait object type.
 #[lang = "dyn_metadata"]
-#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
-pub struct DynMetadata {
+pub struct DynMetadata<Dyn: ?Sized> {
     #[allow(unused)]
     vtable_ptr: NonNull<()>,
+    phantom: crate::marker::PhantomData<Dyn>,
 }
 
-unsafe impl Send for DynMetadata {}
-unsafe impl Sync for DynMetadata {}
+unsafe impl<Dyn: ?Sized> Send for DynMetadata<Dyn> {}
+unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {}
 
-impl fmt::Debug for DynMetadata {
+impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.write_str("DynMetadata { … }")
     }
 }
+
+// Manual impls needed to avoid `Dyn: $Trait` bounds.
+
+impl<Dyn: ?Sized> Unpin for DynMetadata<Dyn> {}
+
+impl<Dyn: ?Sized> Copy for DynMetadata<Dyn> {}
+
+impl<Dyn: ?Sized> Clone for DynMetadata<Dyn> {
+    #[inline]
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl<Dyn: ?Sized> Eq for DynMetadata<Dyn> {}
+
+impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self.vtable_ptr == other.vtable_ptr
+    }
+}
+
+impl<Dyn: ?Sized> Ord for DynMetadata<Dyn> {
+    #[inline]
+    fn cmp(&self, other: &Self) -> crate::cmp::Ordering {
+        self.vtable_ptr.cmp(&other.vtable_ptr)
+    }
+}
+
+impl<Dyn: ?Sized> PartialOrd for DynMetadata<Dyn> {
+    #[inline]
+    fn partial_cmp(&self, other: &Self) -> Option<crate::cmp::Ordering> {
+        Some(self.vtable_ptr.cmp(&other.vtable_ptr))
+    }
+}
+
+impl<Dyn: ?Sized> Hash for DynMetadata<Dyn> {
+    #[inline]
+    fn hash<H: Hasher>(&self, hasher: &mut H) {
+        self.vtable_ptr.hash(hasher)
+    }
+}
index 03d2be725ef51272d363d44bb9a07c1c32ec3149..ff3db740dfdb7b9ce4d83caeb91a82fdb07bc0e8 100644 (file)
@@ -1,6 +1,6 @@
 use core::cell::RefCell;
 use core::ptr::*;
-use std::fmt::Display;
+use std::fmt::{Debug, Display};
 
 #[test]
 fn test_const_from_raw_parts() {
@@ -452,20 +452,25 @@ fn ptr_metadata() {
         assert_eq!(metadata(dst_struct), 3_usize);
     }
 
-    let vtable_1: DynMetadata = metadata(&4_u32 as &dyn Display);
-    let vtable_2: DynMetadata = metadata(&(true, 7_u32) as &(bool, dyn Display));
-    let vtable_3: DynMetadata = metadata(&Pair(true, 7_u32) as &Pair<bool, dyn Display>);
-    let vtable_4: DynMetadata = metadata(&4_u16 as &dyn Display);
+    let vtable_1: DynMetadata<dyn Debug> = metadata(&4_u16 as &dyn Debug);
+    let vtable_2: DynMetadata<dyn Display> = metadata(&4_u16 as &dyn Display);
+    let vtable_3: DynMetadata<dyn Display> = metadata(&4_u32 as &dyn Display);
+    let vtable_4: DynMetadata<dyn Display> = metadata(&(true, 7_u32) as &(bool, dyn Display));
+    let vtable_5: DynMetadata<dyn Display> =
+        metadata(&Pair(true, 7_u32) as &Pair<bool, dyn Display>);
     unsafe {
         let address_1: usize = std::mem::transmute(vtable_1);
         let address_2: usize = std::mem::transmute(vtable_2);
         let address_3: usize = std::mem::transmute(vtable_3);
         let address_4: usize = std::mem::transmute(vtable_4);
-        // Same erased type and same trait: same vtable pointer
-        assert_eq!(address_1, address_2);
-        assert_eq!(address_1, address_3);
-        // Different erased type: different vtable pointer
-        assert_ne!(address_1, address_4);
+        let address_5: usize = std::mem::transmute(vtable_5);
+        // Different trait => different vtable pointer
+        assert_ne!(address_1, address_2);
+        // Different erased type => different vtable pointer
+        assert_ne!(address_2, address_3);
+        // Same erased type and same trait => same vtable pointer
+        assert_eq!(address_3, address_4);
+        assert_eq!(address_3, address_5);
     }
 }
 
@@ -486,11 +491,11 @@ fn metadata_eq_method_address<T: ?Sized>() -> usize {
 
     // For this reason, let’s check here that bounds are satisfied:
 
-    static_assert_expected_bounds_for_metadata::<()>();
-    static_assert_expected_bounds_for_metadata::<usize>();
-    static_assert_expected_bounds_for_metadata::<DynMetadata>();
-    fn static_assert_associated_type<T: ?Sized>() {
-        static_assert_expected_bounds_for_metadata::<<T as Pointee>::Metadata>()
+    let _ = static_assert_expected_bounds_for_metadata::<()>;
+    let _ = static_assert_expected_bounds_for_metadata::<usize>;
+    let _ = static_assert_expected_bounds_for_metadata::<DynMetadata<dyn Display>>;
+    fn _static_assert_associated_type<T: ?Sized>() {
+        let _ = static_assert_expected_bounds_for_metadata::<<T as Pointee>::Metadata>;
     }
 
     fn static_assert_expected_bounds_for_metadata<Meta>()