Skip to content

Commit f5fd66e

Browse files
committed
Elaborate trait ref to compute object safety.
1 parent 8796e7a commit f5fd66e

File tree

3 files changed

+73
-29
lines changed

3 files changed

+73
-29
lines changed

compiler/rustc_trait_selection/src/traits/object_safety.rs

+15-29
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
//! - not reference the erased type `Self` except for in this receiver;
99
//! - not have generic type parameters.
1010
11-
use super::elaborate_predicates;
11+
use super::{elaborate_predicates, elaborate_trait_ref};
1212

1313
use crate::infer::TyCtxtInferExt;
1414
use crate::traits::query::evaluate_obligation::InferCtxtExt;
@@ -567,51 +567,37 @@ fn receiver_for_self_ty<'tcx>(
567567
/// Creates the object type for the current trait. For example,
568568
/// if the current trait is `Deref`, then this will be
569569
/// `dyn Deref<Target = Self::Target> + 'static`.
570+
#[instrument(level = "trace", skip(tcx), ret)]
570571
fn object_ty_for_trait<'tcx>(
571572
tcx: TyCtxt<'tcx>,
572573
trait_def_id: DefId,
573574
lifetime: ty::Region<'tcx>,
574575
) -> Ty<'tcx> {
575-
debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id);
576-
577576
let trait_ref = ty::TraitRef::identity(tcx, trait_def_id);
577+
debug!(?trait_ref);
578578

579579
let trait_predicate = trait_ref.map_bound(|trait_ref| {
580580
ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref))
581581
});
582+
debug!(?trait_predicate);
582583

583-
let mut associated_types = traits::supertraits(tcx, trait_ref)
584-
.flat_map(|super_trait_ref| {
585-
tcx.associated_items(super_trait_ref.def_id())
586-
.in_definition_order()
587-
.map(move |item| (super_trait_ref, item))
588-
})
589-
.filter(|(_, item)| item.kind == ty::AssocKind::Type)
590-
.collect::<Vec<_>>();
591-
592-
// existential predicates need to be in a specific order
593-
associated_types.sort_by_cached_key(|(_, item)| tcx.def_path_hash(item.def_id));
594-
595-
let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| {
596-
// We *can* get bound lifetimes here in cases like
597-
// `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`.
598-
super_trait_ref.map_bound(|super_trait_ref| {
584+
let elaborated_predicates = elaborate_trait_ref(tcx, trait_ref).filter_map(|obligation| {
585+
debug!(?obligation);
586+
let pred = obligation.predicate.to_opt_poly_projection_pred()?;
587+
Some(pred.map_bound(|p| {
599588
ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
600-
term: tcx.mk_projection(item.def_id, super_trait_ref.substs).into(),
601-
item_def_id: item.def_id,
602-
substs: super_trait_ref.substs,
589+
item_def_id: p.projection_ty.item_def_id,
590+
substs: p.projection_ty.substs,
591+
term: p.term,
603592
})
604-
})
593+
}))
605594
});
606595

607596
let existential_predicates = tcx
608-
.mk_poly_existential_predicates(iter::once(trait_predicate).chain(projection_predicates));
609-
610-
let object_ty = tcx.mk_dynamic(existential_predicates, lifetime, ty::Dyn);
611-
612-
debug!("object_ty_for_trait: object_ty=`{}`", object_ty);
597+
.mk_poly_existential_predicates(iter::once(trait_predicate).chain(elaborated_predicates));
598+
debug!(?existential_predicates);
613599

614-
object_ty
600+
tcx.mk_dynamic(existential_predicates, lifetime, ty::Dyn)
615601
}
616602

617603
/// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//~ ERROR the parameter type `Self` may not live long enough
2+
3+
trait GatTrait {
4+
type Gat<'a>
5+
where
6+
Self: 'a;
7+
}
8+
9+
trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = T> {
10+
fn c(&self) -> dyn SuperTrait<T>;
11+
//~^ ERROR associated item referring to unboxed trait object for its own trait
12+
//~| ERROR the trait `SuperTrait` cannot be made into an object
13+
}
14+
15+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
error[E0311]: the parameter type `Self` may not live long enough
2+
|
3+
= help: consider adding an explicit lifetime bound `Self: 'a`...
4+
= note: ...so that the type `Self` will meet its required lifetime bounds...
5+
note: ...that is required by this bound
6+
--> $DIR/object-safety-supertrait-mentions-GAT.rs:9:39
7+
|
8+
LL | trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = T> {
9+
| ^^^^^^^^^^^
10+
11+
error: associated item referring to unboxed trait object for its own trait
12+
--> $DIR/object-safety-supertrait-mentions-GAT.rs:10:20
13+
|
14+
LL | trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = T> {
15+
| ---------- in this trait
16+
LL | fn c(&self) -> dyn SuperTrait<T>;
17+
| ^^^^^^^^^^^^^^^^^
18+
|
19+
help: you might have meant to use `Self` to refer to the implementing type
20+
|
21+
LL | fn c(&self) -> Self;
22+
| ~~~~
23+
24+
error[E0038]: the trait `SuperTrait` cannot be made into an object
25+
--> $DIR/object-safety-supertrait-mentions-GAT.rs:10:20
26+
|
27+
LL | fn c(&self) -> dyn SuperTrait<T>;
28+
| ^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object
29+
|
30+
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>
31+
--> $DIR/object-safety-supertrait-mentions-GAT.rs:4:10
32+
|
33+
LL | type Gat<'a>
34+
| ^^^ ...because it contains the generic associated type `Gat`
35+
...
36+
LL | trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = T> {
37+
| ---------- this trait cannot be made into an object...
38+
= help: consider moving `Gat` to another trait
39+
40+
error: aborting due to 3 previous errors
41+
42+
Some errors have detailed explanations: E0038, E0311.
43+
For more information about an error, try `rustc --explain E0038`.

0 commit comments

Comments
 (0)