Autotrait bounds on dyn-safe trait methods
This commit is contained in:
parent
9e1c600f74
commit
4501d3abe1
4 changed files with 110 additions and 10 deletions
|
@ -115,6 +115,28 @@ fn do_orphan_check_impl<'tcx>(
|
||||||
// impl MyAuto for dyn Trait {} // NOT OKAY
|
// impl MyAuto for dyn Trait {} // NOT OKAY
|
||||||
// impl<T: ?Sized> MyAuto for T {} // NOT OKAY
|
// impl<T: ?Sized> MyAuto for T {} // NOT OKAY
|
||||||
//
|
//
|
||||||
|
// With this restriction, it's guaranteed that an auto-trait is
|
||||||
|
// implemented for a trait object if and only if the auto-trait is one
|
||||||
|
// of the trait object's trait bounds (or a supertrait of a bound). In
|
||||||
|
// other words `dyn Trait + AutoTrait` always implements AutoTrait,
|
||||||
|
// while `dyn Trait` never implements AutoTrait.
|
||||||
|
//
|
||||||
|
// This is necessary in order for autotrait bounds on methods of trait
|
||||||
|
// objects to be sound.
|
||||||
|
//
|
||||||
|
// auto trait AutoTrait {}
|
||||||
|
//
|
||||||
|
// trait ObjectSafeTrait {
|
||||||
|
// fn f(&self) where Self: AutoTrait;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// We can allow f to be called on `dyn ObjectSafeTrait + AutoTrait`.
|
||||||
|
//
|
||||||
|
// If we didn't deny `impl AutoTrait for dyn Trait`, it would be unsound
|
||||||
|
// for the ObjectSafeTrait shown above to be object safe because someone
|
||||||
|
// could take some type implementing ObjectSafeTrait but not AutoTrait,
|
||||||
|
// unsize it to `dyn ObjectSafeTrait`, and call .f() which has no
|
||||||
|
// concrete implementation (issue #50781).
|
||||||
enum LocalImpl {
|
enum LocalImpl {
|
||||||
Allow,
|
Allow,
|
||||||
Disallow { problematic_kind: &'static str },
|
Disallow { problematic_kind: &'static str },
|
||||||
|
|
|
@ -547,16 +547,56 @@ fn virtual_call_violation_for_method<'tcx>(
|
||||||
|
|
||||||
// NOTE: This check happens last, because it results in a lint, and not a
|
// NOTE: This check happens last, because it results in a lint, and not a
|
||||||
// hard error.
|
// hard error.
|
||||||
if tcx
|
if tcx.predicates_of(method.def_id).predicates.iter().any(|&(pred, span)| {
|
||||||
.predicates_of(method.def_id)
|
// dyn Trait is okay:
|
||||||
.predicates
|
//
|
||||||
.iter()
|
// trait Trait {
|
||||||
// A trait object can't claim to live more than the concrete type,
|
// fn f(&self) where Self: 'static;
|
||||||
// so outlives predicates will always hold.
|
// }
|
||||||
.cloned()
|
//
|
||||||
.filter(|(p, _)| p.to_opt_type_outlives().is_none())
|
// because a trait object can't claim to live longer than the concrete
|
||||||
.any(|pred| contains_illegal_self_type_reference(tcx, trait_def_id, pred))
|
// type. If the lifetime bound holds on dyn Trait then it's guaranteed
|
||||||
{
|
// to hold as well on the concrete type.
|
||||||
|
if pred.to_opt_type_outlives().is_some() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dyn Trait is okay:
|
||||||
|
//
|
||||||
|
// auto trait AutoTrait {}
|
||||||
|
//
|
||||||
|
// trait Trait {
|
||||||
|
// fn f(&self) where Self: AutoTrait;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// because `impl AutoTrait for dyn Trait` is disallowed by coherence.
|
||||||
|
// Traits with a default impl are implemented for a trait object if and
|
||||||
|
// only if the autotrait is one of the trait object's trait bounds, like
|
||||||
|
// in `dyn Trait + AutoTrait`. This guarantees that trait objects only
|
||||||
|
// implement auto traits if the underlying type does as well.
|
||||||
|
if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
|
||||||
|
trait_ref: pred_trait_ref,
|
||||||
|
constness: ty::BoundConstness::NotConst,
|
||||||
|
polarity: ty::ImplPolarity::Positive,
|
||||||
|
})) = pred.kind().skip_binder()
|
||||||
|
&& pred_trait_ref.self_ty() == tcx.types.self_param
|
||||||
|
&& tcx.trait_is_auto(pred_trait_ref.def_id)
|
||||||
|
{
|
||||||
|
// Consider bounds like `Self: Bound<Self>`. Auto traits are not
|
||||||
|
// allowed to have generic parameters so `auto trait Bound<T> {}`
|
||||||
|
// would already have reported an error at the definition of the
|
||||||
|
// auto trait.
|
||||||
|
if pred_trait_ref.substs.len() != 1 {
|
||||||
|
tcx.sess.diagnostic().delay_span_bug(
|
||||||
|
span,
|
||||||
|
"auto traits cannot have generic parameters",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
contains_illegal_self_type_reference(tcx, trait_def_id, pred.clone())
|
||||||
|
}) {
|
||||||
return Some(MethodViolationCode::WhereClauseReferencesSelf);
|
return Some(MethodViolationCode::WhereClauseReferencesSelf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
23
tests/ui/where-clauses/self-in-where-clause-allowed.rs
Normal file
23
tests/ui/where-clauses/self-in-where-clause-allowed.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// check-fail
|
||||||
|
|
||||||
|
#![feature(auto_traits)]
|
||||||
|
#![deny(where_clauses_object_safety)]
|
||||||
|
|
||||||
|
auto trait AutoTrait {}
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
fn static_lifetime_bound(&self) where Self: 'static {}
|
||||||
|
|
||||||
|
fn arg_lifetime_bound<'a>(&self, _arg: &'a ()) where Self: 'a {}
|
||||||
|
|
||||||
|
fn autotrait_bound(&self) where Self: AutoTrait {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait for () {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let trait_object = &() as &dyn Trait;
|
||||||
|
trait_object.static_lifetime_bound();
|
||||||
|
trait_object.arg_lifetime_bound(&());
|
||||||
|
trait_object.autotrait_bound(); //~ ERROR: the trait bound `dyn Trait: AutoTrait` is not satisfied
|
||||||
|
}
|
15
tests/ui/where-clauses/self-in-where-clause-allowed.stderr
Normal file
15
tests/ui/where-clauses/self-in-where-clause-allowed.stderr
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
error[E0277]: the trait bound `dyn Trait: AutoTrait` is not satisfied
|
||||||
|
--> $DIR/self-in-where-clause-allowed.rs:22:18
|
||||||
|
|
|
||||||
|
LL | trait_object.autotrait_bound();
|
||||||
|
| ^^^^^^^^^^^^^^^ the trait `AutoTrait` is not implemented for `dyn Trait`
|
||||||
|
|
|
||||||
|
note: required by a bound in `Trait::autotrait_bound`
|
||||||
|
--> $DIR/self-in-where-clause-allowed.rs:13:43
|
||||||
|
|
|
||||||
|
LL | fn autotrait_bound(&self) where Self: AutoTrait {}
|
||||||
|
| ^^^^^^^^^ required by this bound in `Trait::autotrait_bound`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Add table
Add a link
Reference in a new issue