@@ -907,10 +907,8 @@ pub const fn type_name_of_val<T: ?Sized>(_val: &T) -> &'static str {
907907 type_name :: < T > ( )
908908}
909909
910- /// Trait that is automatically implemented for all `dyn Trait<'b, C> + 'a`
911- /// * without assoc type bounds,
912- /// * adds `T: 'a + 'b` requirements, and
913- /// * `C: 'static` requirements on all params of the dyn trait.
910+ /// Trait that is automatically implemented for all `dyn Trait<'b, C> + 'a` without assoc type bounds.
911+ /// It implicitly adds `T: 'a` requirements, which is otherwise not representable on `Pointee`.
914912///
915913/// This is required for `try_as_dyn` to be able to soundly convert non-static
916914/// types to `dyn Trait`.
@@ -921,14 +919,52 @@ pub const fn type_name_of_val<T: ?Sized>(_val: &T) -> &'static str {
921919///
922920#[ unstable( feature = "try_as_dyn" , issue = "144361" ) ]
923921#[ lang = "try_as_dyn" ]
922+ #[ rustc_deny_explicit_impl]
924923pub trait TryAsDynCompatible < T > : ptr:: Pointee < Metadata = ptr:: DynMetadata < Self > > { }
925924
926- /// Returns `Some(&U)` if `T` can be coerced to the trait object type `U`. Otherwise, it returns `None`.
925+ /// Returns `Some(&U)` if `T` can be coerced to the dyn trait type `U`. Otherwise, it returns `None`.
926+ ///
927+ /// # Run-time failures
928+ ///
929+ /// There are multiple ways to get a `None`, and you need to manually analyze which one it is, as the
930+ /// compiler does not provide any help here.
931+ ///
932+ /// * `T` does not implement `Trait` at all,
933+ /// * `T`'s impl for `Trait` is not fully generic,
934+ /// * `T`'s impl for `Trait` is a builtin impl (e.g. `dyn Debug` implements `Debug`)
935+ ///
936+ /// ## Fully generic impls
937+ ///
938+ /// `try_as_dyn` does not have access to lifetime information, thus it cannot differentiate between
939+ /// `'static`, other lifetimes, and can't reason about outlives bounds on impls. Thus we can only accept
940+ /// impls that do not have `'static` lifetimes, or outlives bounds of any kind. You can have simple
941+ /// trait bounds, and the compiler will transitively only use impls of those simple trait bounds that satisfy
942+ /// the same rules as the main trait you're converting to.
943+ ///
944+ /// An example of a legal impl is:
945+ ///
946+ /// ```rust,ignore
947+ /// impl<'a, 'b, T: Debug, U: Display> Trait<'a, T> for Type<'b, U> {}
948+ /// ```
949+ ///
950+ /// Impls without generic parameters at all are also legal, as long as they contain no `'static` lifetimes.
951+ ///
952+ /// ## Builtin impls
953+ ///
954+ /// Builtin impls (like `impl Debug for dyn Debug`) have various obscure rules and often are not fully generic.
955+ /// To simplify reasoning about what is allowed and what not, all builtin impls are rejected and will neither
956+ /// directly nor indirectly contribute to a `Some` result.
927957///
928958/// # Compile-time failures
929- /// Determining whether `T` can be coerced to the trait object type `U` requires compiler trait resolution.
959+ /// Determining whether `T` can be coerced to the dyn trait type `U` requires compiler trait resolution.
930960/// In some cases, that resolution can exceed the recursion limit,
931961/// and compilation will fail instead of this function returning `None`.
962+ ///
963+ /// The input type `T` must outlive the lifetime `'a` on the `dyn Trait + 'a`.
964+ /// This is basically the same rule that forbids `let x: &dyn Trait + 'static = &&some_local_variable;`
965+ /// So if you see borrow check errors around `try_as_dyn`, think about whether a normal unsizing
966+ /// coercion would be possible at all if you were using concrete types or had bounds on the input type.
967+ ///
932968/// # Examples
933969///
934970/// ```rust
@@ -973,37 +1009,7 @@ pub const fn try_as_dyn<T, U: TryAsDynCompatible<T> + ?Sized>(t: &T) -> Option<&
9731009
9741010/// Returns `Some(&mut U)` if `T` can be coerced to the trait object type `U`. Otherwise, it returns `None`.
9751011///
976- /// # Compile-time failures
977- /// Determining whether `T` can be coerced to the trait object type `U` requires compiler trait resolution.
978- /// In some cases, that resolution can exceed the recursion limit,
979- /// and compilation will fail instead of this function returning `None`.
980- /// # Examples
981- ///
982- /// ```rust
983- /// #![feature(try_as_dyn)]
984- ///
985- /// use core::any::try_as_dyn_mut;
986- ///
987- /// trait Animal {
988- /// fn speak(&self) -> &'static str;
989- /// }
990- ///
991- /// struct Dog;
992- /// impl Animal for Dog {
993- /// fn speak(&self) -> &'static str { "woof" }
994- /// }
995- ///
996- /// struct Rock; // does not implement Animal
997- ///
998- /// let mut dog = Dog;
999- /// let mut rock = Rock;
1000- ///
1001- /// let as_animal: Option<&mut dyn Animal> = try_as_dyn_mut::<Dog, dyn Animal>(&mut dog);
1002- /// assert_eq!(as_animal.unwrap().speak(), "woof");
1003- ///
1004- /// let not_an_animal: Option<&mut dyn Animal> = try_as_dyn_mut::<Rock, dyn Animal>(&mut rock);
1005- /// assert!(not_an_animal.is_none());
1006- /// ```
1012+ /// See documentation of [try_as_dyn] for details about the behaviour and limitations.
10071013#[ must_use]
10081014#[ unstable( feature = "try_as_dyn" , issue = "144361" ) ]
10091015pub const fn try_as_dyn_mut < T , U : TryAsDynCompatible < T > + ?Sized > ( t : & mut T ) -> Option < & mut U > {
0 commit comments