mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-29 10:13:54 +00:00
Check associated type bounds for object safety violations
This commit is contained in:
parent
5b279c8016
commit
1b07991574
@ -160,6 +160,10 @@ fn object_safety_violations_for_trait(
|
|||||||
if !spans.is_empty() {
|
if !spans.is_empty() {
|
||||||
violations.push(ObjectSafetyViolation::SupertraitSelf(spans));
|
violations.push(ObjectSafetyViolation::SupertraitSelf(spans));
|
||||||
}
|
}
|
||||||
|
let spans = bounds_reference_self(tcx, trait_def_id);
|
||||||
|
if !spans.is_empty() {
|
||||||
|
violations.push(ObjectSafetyViolation::SupertraitSelf(spans));
|
||||||
|
}
|
||||||
|
|
||||||
violations.extend(
|
violations.extend(
|
||||||
tcx.associated_items(trait_def_id)
|
tcx.associated_items(trait_def_id)
|
||||||
@ -239,51 +243,70 @@ fn predicates_reference_self(
|
|||||||
} else {
|
} else {
|
||||||
tcx.predicates_of(trait_def_id)
|
tcx.predicates_of(trait_def_id)
|
||||||
};
|
};
|
||||||
let self_ty = tcx.types.self_param;
|
|
||||||
let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into());
|
|
||||||
predicates
|
predicates
|
||||||
.predicates
|
.predicates
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp))
|
.map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), *sp))
|
||||||
.filter_map(|(predicate, &sp)| {
|
.filter_map(|predicate| predicate_references_self(tcx, predicate))
|
||||||
match predicate.skip_binders() {
|
|
||||||
ty::PredicateAtom::Trait(ref data, _) => {
|
|
||||||
// In the case of a trait predicate, we can skip the "self" type.
|
|
||||||
if data.trait_ref.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
|
|
||||||
}
|
|
||||||
ty::PredicateAtom::Projection(ref data) => {
|
|
||||||
// And similarly for projections. This should be redundant with
|
|
||||||
// the previous check because any projection should have a
|
|
||||||
// matching `Trait` predicate with the same inputs, but we do
|
|
||||||
// the check to be safe.
|
|
||||||
//
|
|
||||||
// Note that we *do* allow projection *outputs* to contain
|
|
||||||
// `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
|
|
||||||
// we just require the user to specify *both* outputs
|
|
||||||
// in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
|
|
||||||
//
|
|
||||||
// This is ALT2 in issue #56288, see that for discussion of the
|
|
||||||
// possible alternatives.
|
|
||||||
if data.projection_ty.trait_ref(tcx).substs[1..].iter().any(has_self_ty) {
|
|
||||||
Some(sp)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ty::PredicateAtom::WellFormed(..)
|
|
||||||
| ty::PredicateAtom::ObjectSafe(..)
|
|
||||||
| ty::PredicateAtom::TypeOutlives(..)
|
|
||||||
| ty::PredicateAtom::RegionOutlives(..)
|
|
||||||
| ty::PredicateAtom::ClosureKind(..)
|
|
||||||
| ty::PredicateAtom::Subtype(..)
|
|
||||||
| ty::PredicateAtom::ConstEvaluatable(..)
|
|
||||||
| ty::PredicateAtom::ConstEquate(..)
|
|
||||||
| ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
|
||||||
|
let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id));
|
||||||
|
tcx.associated_items(trait_def_id)
|
||||||
|
.in_definition_order()
|
||||||
|
.filter(|item| item.kind == ty::AssocKind::Type)
|
||||||
|
.flat_map(|item| tcx.explicit_item_bounds(item.def_id))
|
||||||
|
.map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), *sp))
|
||||||
|
.filter_map(|predicate| predicate_references_self(tcx, predicate))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn predicate_references_self(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
(predicate, sp): (ty::Predicate<'tcx>, Span),
|
||||||
|
) -> Option<Span> {
|
||||||
|
let self_ty = tcx.types.self_param;
|
||||||
|
let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into());
|
||||||
|
match predicate.skip_binders() {
|
||||||
|
ty::PredicateAtom::Trait(ref data, _) => {
|
||||||
|
// In the case of a trait predicate, we can skip the "self" type.
|
||||||
|
if data.trait_ref.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
|
||||||
|
}
|
||||||
|
ty::PredicateAtom::Projection(ref data) => {
|
||||||
|
// And similarly for projections. This should be redundant with
|
||||||
|
// the previous check because any projection should have a
|
||||||
|
// matching `Trait` predicate with the same inputs, but we do
|
||||||
|
// the check to be safe.
|
||||||
|
//
|
||||||
|
// It's also won't be redundant if we allow type-generic associated
|
||||||
|
// types for trait objects.
|
||||||
|
//
|
||||||
|
// Note that we *do* allow projection *outputs* to contain
|
||||||
|
// `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
|
||||||
|
// we just require the user to specify *both* outputs
|
||||||
|
// in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
|
||||||
|
//
|
||||||
|
// This is ALT2 in issue #56288, see that for discussion of the
|
||||||
|
// possible alternatives.
|
||||||
|
if data.projection_ty.trait_ref(tcx).substs[1..].iter().any(has_self_ty) {
|
||||||
|
Some(sp)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ty::PredicateAtom::WellFormed(..)
|
||||||
|
| ty::PredicateAtom::ObjectSafe(..)
|
||||||
|
| ty::PredicateAtom::TypeOutlives(..)
|
||||||
|
| ty::PredicateAtom::RegionOutlives(..)
|
||||||
|
| ty::PredicateAtom::ClosureKind(..)
|
||||||
|
| ty::PredicateAtom::Subtype(..)
|
||||||
|
| ty::PredicateAtom::ConstEvaluatable(..)
|
||||||
|
| ty::PredicateAtom::ConstEquate(..)
|
||||||
|
| ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
|
fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
|
||||||
generics_require_sized_self(tcx, trait_def_id)
|
generics_require_sized_self(tcx, trait_def_id)
|
||||||
}
|
}
|
||||||
|
12
src/test/ui/object-safety/object-safety-bounds.rs
Normal file
12
src/test/ui/object-safety/object-safety-bounds.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// Traits with bounds mentioning `Self` are not object safe
|
||||||
|
|
||||||
|
trait X {
|
||||||
|
type U: PartialEq<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f() -> Box<dyn X<U = u32>> {
|
||||||
|
//~^ ERROR the trait `X` cannot be made into an object
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
14
src/test/ui/object-safety/object-safety-bounds.stderr
Normal file
14
src/test/ui/object-safety/object-safety-bounds.stderr
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
error[E0038]: the trait `X` cannot be made into an object
|
||||||
|
--> $DIR/object-safety-bounds.rs:7:11
|
||||||
|
|
|
||||||
|
LL | trait X {
|
||||||
|
| - this trait cannot be made into an object...
|
||||||
|
LL | type U: PartialEq<Self>;
|
||||||
|
| --------------- ...because it uses `Self` as a type parameter in this
|
||||||
|
...
|
||||||
|
LL | fn f() -> Box<dyn X<U = u32>> {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^ the trait `X` cannot be made into an object
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0038`.
|
Loading…
Reference in New Issue
Block a user