Elaborate trait ref to compute object safety.
This commit is contained in:
parent
8796e7a9cf
commit
f5fd66e0c2
3 changed files with 73 additions and 29 deletions
|
@ -8,7 +8,7 @@
|
||||||
//! - not reference the erased type `Self` except for in this receiver;
|
//! - not reference the erased type `Self` except for in this receiver;
|
||||||
//! - not have generic type parameters.
|
//! - not have generic type parameters.
|
||||||
|
|
||||||
use super::elaborate_predicates;
|
use super::{elaborate_predicates, elaborate_trait_ref};
|
||||||
|
|
||||||
use crate::infer::TyCtxtInferExt;
|
use crate::infer::TyCtxtInferExt;
|
||||||
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
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,
|
/// Creates the object type for the current trait. For example,
|
||||||
/// if the current trait is `Deref`, then this will be
|
/// if the current trait is `Deref`, then this will be
|
||||||
/// `dyn Deref<Target = Self::Target> + 'static`.
|
/// `dyn Deref<Target = Self::Target> + 'static`.
|
||||||
|
#[instrument(level = "trace", skip(tcx), ret)]
|
||||||
fn object_ty_for_trait<'tcx>(
|
fn object_ty_for_trait<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
trait_def_id: DefId,
|
trait_def_id: DefId,
|
||||||
lifetime: ty::Region<'tcx>,
|
lifetime: ty::Region<'tcx>,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id);
|
|
||||||
|
|
||||||
let trait_ref = ty::TraitRef::identity(tcx, 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| {
|
let trait_predicate = trait_ref.map_bound(|trait_ref| {
|
||||||
ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, 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)
|
let elaborated_predicates = elaborate_trait_ref(tcx, trait_ref).filter_map(|obligation| {
|
||||||
.flat_map(|super_trait_ref| {
|
debug!(?obligation);
|
||||||
tcx.associated_items(super_trait_ref.def_id())
|
let pred = obligation.predicate.to_opt_poly_projection_pred()?;
|
||||||
.in_definition_order()
|
Some(pred.map_bound(|p| {
|
||||||
.map(move |item| (super_trait_ref, item))
|
|
||||||
})
|
|
||||||
.filter(|(_, item)| item.kind == ty::AssocKind::Type)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
// 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| {
|
|
||||||
ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
|
ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
|
||||||
term: tcx.mk_projection(item.def_id, super_trait_ref.substs).into(),
|
item_def_id: p.projection_ty.item_def_id,
|
||||||
item_def_id: item.def_id,
|
substs: p.projection_ty.substs,
|
||||||
substs: super_trait_ref.substs,
|
term: p.term,
|
||||||
})
|
})
|
||||||
})
|
}))
|
||||||
});
|
});
|
||||||
|
|
||||||
let existential_predicates = tcx
|
let existential_predicates = tcx
|
||||||
.mk_poly_existential_predicates(iter::once(trait_predicate).chain(projection_predicates));
|
.mk_poly_existential_predicates(iter::once(trait_predicate).chain(elaborated_predicates));
|
||||||
|
debug!(?existential_predicates);
|
||||||
|
|
||||||
let object_ty = tcx.mk_dynamic(existential_predicates, lifetime, ty::Dyn);
|
tcx.mk_dynamic(existential_predicates, lifetime, ty::Dyn)
|
||||||
|
|
||||||
debug!("object_ty_for_trait: object_ty=`{}`", object_ty);
|
|
||||||
|
|
||||||
object_ty
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
|
/// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
//~ ERROR the parameter type `Self` may not live long enough
|
||||||
|
|
||||||
|
trait GatTrait {
|
||||||
|
type Gat<'a>
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = T> {
|
||||||
|
fn c(&self) -> dyn SuperTrait<T>;
|
||||||
|
//~^ ERROR associated item referring to unboxed trait object for its own trait
|
||||||
|
//~| ERROR the trait `SuperTrait` cannot be made into an object
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -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<T>: for<'a> GatTrait<Gat<'a> = 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<T>: for<'a> GatTrait<Gat<'a> = T> {
|
||||||
|
| ---------- in this trait
|
||||||
|
LL | fn c(&self) -> dyn SuperTrait<T>;
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
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<T>;
|
||||||
|
| ^^^^^^^^^^^^^^^^^ `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 <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
|
||||||
|
--> $DIR/object-safety-supertrait-mentions-GAT.rs:4:10
|
||||||
|
|
|
||||||
|
LL | type Gat<'a>
|
||||||
|
| ^^^ ...because it contains the generic associated type `Gat`
|
||||||
|
...
|
||||||
|
LL | trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = 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`.
|
Loading…
Add table
Add a link
Reference in a new issue