Skip to content

rustc: strange failure with lifetime bounds forcing explicit re-borrowing #16860

Closed
@aturon

Description

@aturon

Now that DST has landed, I've been working on refactoring various library code to take advantage of it. I tried to remove some of the extension traits currently used in core::any, but ran into a strange error for downcase_mut that was solved by explicitly reborrowing the receiver:

/// The `Any` trait is implemented by all `'static` types, and can be used for
/// dynamic typing
///
/// Every type with no non-`'static` references implements `Any`, so `Any` can
/// be used as a trait object to emulate the effects dynamic typing.
#[stable]
pub trait Any: AnyPrivate {
    /// Returns true if the boxed type is the same as `T`
    #[inline]
    #[stable]
    fn is<T: 'static>(&self) -> bool {
        // Get TypeId of the type this function is instantiated with
        let t = TypeId::of::<T>();

        // Get TypeId of the type in the trait object
        let boxed = self.get_type_id();

        // Compare both TypeIds on equality
        t == boxed
    }

    /// Returns some reference to the boxed value if it is of type `T`, or
    /// `None` if it isn't.
    #[inline]
    #[unstable = "naming conventions around acquiring references may change"]
    fn downcast_ref<T: 'static>(&self) -> Option<&T> {
        if self.is::<T>() {
            unsafe {
                // Get the raw representation of the trait object
                let to: TraitObject = transmute_copy(&self);

                // Extract the data pointer
                Some(transmute(to.data))
            }
        } else {
            None
        }
    }

    /// Returns some mutable reference to the boxed value if it is of type `T`, or
    /// `None` if it isn't.
    #[inline]
    #[unstable = "naming conventions around acquiring references may change"]
    fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
        // The following fails with: 
        //    error: instantiating a type parameter with an incompatible type `&mut Self`, 
        //    which does not fulfill `'static`
        // if self.is::<T>() {

        // Explicitly reborrowing seems to work:
        if (&*self).is::<T>() {
            unsafe {
                // Get the raw representation of the trait object
                let to: TraitObject = transmute_copy(&self);

                // Extract the data pointer
                Some(transmute(to.data))
            }
        } else {
            None
        }
    }

    /// Returns some reference to the boxed value if it is of type `T`, or
    /// `None` if it isn't.
    #[deprecated = "this function has been renamed to `downcast_ref`"]
    fn as_ref<T: 'static>(&self) -> Option<&T> {
        self.downcast_ref::<T>()
    }

    /// Returns some mutable reference to the boxed value if it is of type `T`, or
    /// `None` if it isn't.
    #[deprecated = "this function has been renamed to `downcast_mut`"]
    fn as_mut<T: 'static>(&mut self) -> Option<&mut T> {
        self.downcast_mut::<T>()
    }
}

/// An inner trait to ensure that only this module can call `get_type_id()`.
trait AnyPrivate {
    /// Get the `TypeId` of `self`
    fn get_type_id(&self) -> TypeId;
}

impl<T: 'static> AnyPrivate for T {
    fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
}

impl<T: 'static + AnyPrivate> Any for T {}

cc @nikomatsakis

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-DSTsArea: Dynamically-sized types (DSTs)A-type-systemArea: Type system

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions