From f5fd66e0c208262fc493175a63f6d2f41130ed8c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 9 Oct 2022 13:34:42 +0000 Subject: [PATCH] Elaborate trait ref to compute object safety. --- .../src/traits/object_safety.rs | 44 +++++++------------ .../object-safety-supertrait-mentions-GAT.rs | 15 +++++++ ...ject-safety-supertrait-mentions-GAT.stderr | 43 ++++++++++++++++++ 3 files changed, 73 insertions(+), 29 deletions(-) create mode 100644 src/test/ui/object-safety/object-safety-supertrait-mentions-GAT.rs create mode 100644 src/test/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 52ee5e6ea9361..1afa04007b8a1 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -8,7 +8,7 @@ //! - not reference the erased type `Self` except for in this receiver; //! - not have generic type parameters. -use super::elaborate_predicates; +use super::{elaborate_predicates, elaborate_trait_ref}; use crate::infer::TyCtxtInferExt; use crate::traits::query::evaluate_obligation::InferCtxtExt; @@ -567,51 +567,37 @@ fn receiver_for_self_ty<'tcx>( /// Creates the object type for the current trait. For example, /// if the current trait is `Deref`, then this will be /// `dyn Deref + 'static`. +#[instrument(level = "trace", skip(tcx), ret)] fn object_ty_for_trait<'tcx>( tcx: TyCtxt<'tcx>, trait_def_id: DefId, lifetime: ty::Region<'tcx>, ) -> Ty<'tcx> { - debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id); - let trait_ref = ty::TraitRef::identity(tcx, trait_def_id); + debug!(?trait_ref); let trait_predicate = trait_ref.map_bound(|trait_ref| { ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)) }); + debug!(?trait_predicate); - let mut associated_types = traits::supertraits(tcx, trait_ref) - .flat_map(|super_trait_ref| { - tcx.associated_items(super_trait_ref.def_id()) - .in_definition_order() - .map(move |item| (super_trait_ref, item)) - }) - .filter(|(_, item)| item.kind == ty::AssocKind::Type) - .collect::>(); - - // existential predicates need to be in a specific order - associated_types.sort_by_cached_key(|(_, item)| tcx.def_path_hash(item.def_id)); - - let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| { - // We *can* get bound lifetimes here in cases like - // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`. - super_trait_ref.map_bound(|super_trait_ref| { + let elaborated_predicates = elaborate_trait_ref(tcx, trait_ref).filter_map(|obligation| { + debug!(?obligation); + let pred = obligation.predicate.to_opt_poly_projection_pred()?; + Some(pred.map_bound(|p| { ty::ExistentialPredicate::Projection(ty::ExistentialProjection { - term: tcx.mk_projection(item.def_id, super_trait_ref.substs).into(), - item_def_id: item.def_id, - substs: super_trait_ref.substs, + item_def_id: p.projection_ty.item_def_id, + substs: p.projection_ty.substs, + term: p.term, }) - }) + })) }); let existential_predicates = tcx - .mk_poly_existential_predicates(iter::once(trait_predicate).chain(projection_predicates)); - - let object_ty = tcx.mk_dynamic(existential_predicates, lifetime, ty::Dyn); - - debug!("object_ty_for_trait: object_ty=`{}`", object_ty); + .mk_poly_existential_predicates(iter::once(trait_predicate).chain(elaborated_predicates)); + debug!(?existential_predicates); - object_ty + tcx.mk_dynamic(existential_predicates, lifetime, ty::Dyn) } /// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a diff --git a/src/test/ui/object-safety/object-safety-supertrait-mentions-GAT.rs b/src/test/ui/object-safety/object-safety-supertrait-mentions-GAT.rs new file mode 100644 index 0000000000000..14e00d2ef321d --- /dev/null +++ b/src/test/ui/object-safety/object-safety-supertrait-mentions-GAT.rs @@ -0,0 +1,15 @@ +//~ ERROR the parameter type `Self` may not live long enough + +trait GatTrait { + type Gat<'a> + where + Self: 'a; +} + +trait SuperTrait: for<'a> GatTrait = T> { + fn c(&self) -> dyn SuperTrait; + //~^ ERROR associated item referring to unboxed trait object for its own trait + //~| ERROR the trait `SuperTrait` cannot be made into an object +} + +fn main() {} diff --git a/src/test/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr b/src/test/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr new file mode 100644 index 0000000000000..c1aaad31e8125 --- /dev/null +++ b/src/test/ui/object-safety/object-safety-supertrait-mentions-GAT.stderr @@ -0,0 +1,43 @@ +error[E0311]: the parameter type `Self` may not live long enough + | + = help: consider adding an explicit lifetime bound `Self: 'a`... + = note: ...so that the type `Self` will meet its required lifetime bounds... +note: ...that is required by this bound + --> $DIR/object-safety-supertrait-mentions-GAT.rs:9:39 + | +LL | trait SuperTrait: for<'a> GatTrait = T> { + | ^^^^^^^^^^^ + +error: associated item referring to unboxed trait object for its own trait + --> $DIR/object-safety-supertrait-mentions-GAT.rs:10:20 + | +LL | trait SuperTrait: for<'a> GatTrait = T> { + | ---------- in this trait +LL | fn c(&self) -> dyn SuperTrait; + | ^^^^^^^^^^^^^^^^^ + | +help: you might have meant to use `Self` to refer to the implementing type + | +LL | fn c(&self) -> Self; + | ~~~~ + +error[E0038]: the trait `SuperTrait` cannot be made into an object + --> $DIR/object-safety-supertrait-mentions-GAT.rs:10:20 + | +LL | fn c(&self) -> dyn SuperTrait; + | ^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/object-safety-supertrait-mentions-GAT.rs:4:10 + | +LL | type Gat<'a> + | ^^^ ...because it contains the generic associated type `Gat` +... +LL | trait SuperTrait: for<'a> GatTrait = T> { + | ---------- this trait cannot be made into an object... + = help: consider moving `Gat` to another trait + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0038, E0311. +For more information about an error, try `rustc --explain E0038`.