Skip to content

Commit 61f79cf

Browse files
committed
Documentation
1 parent 8cb85b7 commit 61f79cf

5 files changed

Lines changed: 124 additions & 40 deletions

File tree

compiler/rustc_middle/src/ty/generics.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,8 @@ impl<'tcx> GenericPredicates<'tcx> {
424424
instantiated.spans.extend(self.predicates.iter().map(|(_, s)| s));
425425
}
426426

427+
/// Allow simple where bounds like `T: Debug`, but prevent any kind of
428+
/// outlives bounds or uses of generic parameters on the right hand side.
427429
pub fn is_fully_generic_for_reflection(self) -> bool {
428430
struct ParamChecker;
429431
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParamChecker {

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -280,9 +280,9 @@ pub struct ImplTraitHeader<'tcx> {
280280
}
281281

282282
impl<'tcx> ImplTraitHeader<'tcx> {
283-
/// For trait impls, checks whether the type and trait only have generic parameters in their
284-
/// arguments and only uses each generic param once, too.
285-
/// Pessimistic analysis, so it will reject projection types (except for weak aliases)
283+
/// For trait impls, checks whether the type and trait only have generic lifetime parameters in their
284+
/// arguments and only use any generic param once.
285+
/// This is a pessimistic analysis, so it will reject projection types (except for weak aliases)
286286
/// and other types that may be actually ok. We can allow more in the future.
287287
pub fn is_fully_generic_for_reflection(self) -> bool {
288288
#[derive(Default)]

library/core/src/any.rs

Lines changed: 43 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -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]
924923
pub 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")]
10091015
pub const fn try_as_dyn_mut<T, U: TryAsDynCompatible<T> + ?Sized>(t: &mut T) -> Option<&mut U> {

tests/ui/any/reject_manual_impl.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#![feature(try_as_dyn)]
2+
3+
use std::any::TryAsDynCompatible;
4+
5+
struct Foo(dyn Iterator<Item = u32>);
6+
7+
impl TryAsDynCompatible<u32> for Foo {}
8+
//~^ ERROR: explicit impls for the `TryAsDynCompatible` trait are not permitted
9+
10+
struct Bar(dyn Iterator<Item = u32>);
11+
12+
impl<T> TryAsDynCompatible<T> for Bar {}
13+
//~^ ERROR: explicit impls for the `TryAsDynCompatible` trait are not permitted
14+
15+
struct Baz;
16+
17+
impl<T> TryAsDynCompatible<T> for Baz {}
18+
//~^ ERROR: explicit impls for the `TryAsDynCompatible` trait are not permitted
19+
20+
trait Trait {}
21+
22+
impl<T> TryAsDynCompatible<T> for dyn Trait {}
23+
//~^ ERROR: explicit impls for the `TryAsDynCompatible` trait are not permitted
24+
25+
impl TryAsDynCompatible<u32> for dyn Iterator<Item = u32> {}
26+
//~^ ERROR: explicit impls for the `TryAsDynCompatible` trait are not permitted
27+
//~| ERROR: only traits defined in the current crate can be implemented for arbitrary types
28+
29+
fn main() {}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
error[E0322]: explicit impls for the `TryAsDynCompatible` trait are not permitted
2+
--> $DIR/reject_manual_impl.rs:7:1
3+
|
4+
LL | impl TryAsDynCompatible<u32> for Foo {}
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `TryAsDynCompatible` not allowed
6+
7+
error[E0322]: explicit impls for the `TryAsDynCompatible` trait are not permitted
8+
--> $DIR/reject_manual_impl.rs:12:1
9+
|
10+
LL | impl<T> TryAsDynCompatible<T> for Bar {}
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `TryAsDynCompatible` not allowed
12+
13+
error[E0322]: explicit impls for the `TryAsDynCompatible` trait are not permitted
14+
--> $DIR/reject_manual_impl.rs:17:1
15+
|
16+
LL | impl<T> TryAsDynCompatible<T> for Baz {}
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `TryAsDynCompatible` not allowed
18+
19+
error[E0322]: explicit impls for the `TryAsDynCompatible` trait are not permitted
20+
--> $DIR/reject_manual_impl.rs:22:1
21+
|
22+
LL | impl<T> TryAsDynCompatible<T> for dyn Trait {}
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `TryAsDynCompatible` not allowed
24+
25+
error[E0322]: explicit impls for the `TryAsDynCompatible` trait are not permitted
26+
--> $DIR/reject_manual_impl.rs:25:1
27+
|
28+
LL | impl TryAsDynCompatible<u32> for dyn Iterator<Item = u32> {}
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `TryAsDynCompatible` not allowed
30+
31+
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
32+
--> $DIR/reject_manual_impl.rs:25:1
33+
|
34+
LL | impl TryAsDynCompatible<u32> for dyn Iterator<Item = u32> {}
35+
| ^^^^^-----------------------^^^^^------------------------
36+
| | |
37+
| | `dyn Iterator<Item = u32>` is not defined in the current crate
38+
| `u32` is not defined in the current crate
39+
|
40+
= note: impl doesn't have any local type before any uncovered type parameters
41+
= note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules
42+
= note: define and implement a trait or new type instead
43+
44+
error: aborting due to 6 previous errors
45+
46+
Some errors have detailed explanations: E0117, E0322.
47+
For more information about an error, try `rustc --explain E0117`.

0 commit comments

Comments
 (0)