Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 1b07991

Browse files
committed
Check associated type bounds for object safety violations
1 parent 5b279c8 commit 1b07991

File tree

3 files changed

+88
-39
lines changed

3 files changed

+88
-39
lines changed

compiler/rustc_trait_selection/src/traits/object_safety.rs

Lines changed: 62 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ fn object_safety_violations_for_trait(
160160
if !spans.is_empty() {
161161
violations.push(ObjectSafetyViolation::SupertraitSelf(spans));
162162
}
163+
let spans = bounds_reference_self(tcx, trait_def_id);
164+
if !spans.is_empty() {
165+
violations.push(ObjectSafetyViolation::SupertraitSelf(spans));
166+
}
163167

164168
violations.extend(
165169
tcx.associated_items(trait_def_id)
@@ -239,51 +243,70 @@ fn predicates_reference_self(
239243
} else {
240244
tcx.predicates_of(trait_def_id)
241245
};
242-
let self_ty = tcx.types.self_param;
243-
let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into());
244246
predicates
245247
.predicates
246248
.iter()
247-
.map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp))
248-
.filter_map(|(predicate, &sp)| {
249-
match predicate.skip_binders() {
250-
ty::PredicateAtom::Trait(ref data, _) => {
251-
// In the case of a trait predicate, we can skip the "self" type.
252-
if data.trait_ref.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
253-
}
254-
ty::PredicateAtom::Projection(ref data) => {
255-
// And similarly for projections. This should be redundant with
256-
// the previous check because any projection should have a
257-
// matching `Trait` predicate with the same inputs, but we do
258-
// the check to be safe.
259-
//
260-
// Note that we *do* allow projection *outputs* to contain
261-
// `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
262-
// we just require the user to specify *both* outputs
263-
// in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
264-
//
265-
// This is ALT2 in issue #56288, see that for discussion of the
266-
// possible alternatives.
267-
if data.projection_ty.trait_ref(tcx).substs[1..].iter().any(has_self_ty) {
268-
Some(sp)
269-
} else {
270-
None
271-
}
272-
}
273-
ty::PredicateAtom::WellFormed(..)
274-
| ty::PredicateAtom::ObjectSafe(..)
275-
| ty::PredicateAtom::TypeOutlives(..)
276-
| ty::PredicateAtom::RegionOutlives(..)
277-
| ty::PredicateAtom::ClosureKind(..)
278-
| ty::PredicateAtom::Subtype(..)
279-
| ty::PredicateAtom::ConstEvaluatable(..)
280-
| ty::PredicateAtom::ConstEquate(..)
281-
| ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
282-
}
283-
})
249+
.map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), *sp))
250+
.filter_map(|predicate| predicate_references_self(tcx, predicate))
251+
.collect()
252+
}
253+
254+
fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
255+
let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id));
256+
tcx.associated_items(trait_def_id)
257+
.in_definition_order()
258+
.filter(|item| item.kind == ty::AssocKind::Type)
259+
.flat_map(|item| tcx.explicit_item_bounds(item.def_id))
260+
.map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), *sp))
261+
.filter_map(|predicate| predicate_references_self(tcx, predicate))
284262
.collect()
285263
}
286264

265+
fn predicate_references_self(
266+
tcx: TyCtxt<'tcx>,
267+
(predicate, sp): (ty::Predicate<'tcx>, Span),
268+
) -> Option<Span> {
269+
let self_ty = tcx.types.self_param;
270+
let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into());
271+
match predicate.skip_binders() {
272+
ty::PredicateAtom::Trait(ref data, _) => {
273+
// In the case of a trait predicate, we can skip the "self" type.
274+
if data.trait_ref.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
275+
}
276+
ty::PredicateAtom::Projection(ref data) => {
277+
// And similarly for projections. This should be redundant with
278+
// the previous check because any projection should have a
279+
// matching `Trait` predicate with the same inputs, but we do
280+
// the check to be safe.
281+
//
282+
// It's also won't be redundant if we allow type-generic associated
283+
// types for trait objects.
284+
//
285+
// Note that we *do* allow projection *outputs* to contain
286+
// `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
287+
// we just require the user to specify *both* outputs
288+
// in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
289+
//
290+
// This is ALT2 in issue #56288, see that for discussion of the
291+
// possible alternatives.
292+
if data.projection_ty.trait_ref(tcx).substs[1..].iter().any(has_self_ty) {
293+
Some(sp)
294+
} else {
295+
None
296+
}
297+
}
298+
ty::PredicateAtom::WellFormed(..)
299+
| ty::PredicateAtom::ObjectSafe(..)
300+
| ty::PredicateAtom::TypeOutlives(..)
301+
| ty::PredicateAtom::RegionOutlives(..)
302+
| ty::PredicateAtom::ClosureKind(..)
303+
| ty::PredicateAtom::Subtype(..)
304+
| ty::PredicateAtom::ConstEvaluatable(..)
305+
| ty::PredicateAtom::ConstEquate(..)
306+
| ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
307+
}
308+
}
309+
287310
fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
288311
generics_require_sized_self(tcx, trait_def_id)
289312
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Traits with bounds mentioning `Self` are not object safe
2+
3+
trait X {
4+
type U: PartialEq<Self>;
5+
}
6+
7+
fn f() -> Box<dyn X<U = u32>> {
8+
//~^ ERROR the trait `X` cannot be made into an object
9+
loop {}
10+
}
11+
12+
fn main() {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0038]: the trait `X` cannot be made into an object
2+
--> $DIR/object-safety-bounds.rs:7:11
3+
|
4+
LL | trait X {
5+
| - this trait cannot be made into an object...
6+
LL | type U: PartialEq<Self>;
7+
| --------------- ...because it uses `Self` as a type parameter in this
8+
...
9+
LL | fn f() -> Box<dyn X<U = u32>> {
10+
| ^^^^^^^^^^^^^^^^^^^ the trait `X` cannot be made into an object
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0038`.

0 commit comments

Comments
 (0)