Add comments and tests explaining the shallow substitution rule
This commit is contained in:
parent
5e9317a023
commit
ff5d11e043
@ -461,6 +461,27 @@ fn check_associated_type_defaults(
|
||||
})
|
||||
.collect::<FxHashMap<_, _>>();
|
||||
|
||||
/// Replaces projections of associated types with their default types.
|
||||
///
|
||||
/// This does a "shallow substitution", meaning that defaults that refer to
|
||||
/// other defaulted assoc. types will still refer to the projection
|
||||
/// afterwards, not to the other default. For example:
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// trait Tr {
|
||||
/// type A: Clone = Vec<Self::B>;
|
||||
/// type B = u8;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This will end up replacing the bound `Self::A: Clone` with
|
||||
/// `Vec<Self::B>: Clone`, not with `Vec<u8>: Clone`. If we did a deep
|
||||
/// substitution and ended up with the latter, the trait would be accepted.
|
||||
/// If an `impl` then replaced `B` with something that isn't `Clone`,
|
||||
/// suddenly the default for `A` is no longer valid. The shallow
|
||||
/// substitution forces the trait to add a `B: Clone` bound to be accepted,
|
||||
/// which means that an `impl` can replace any default without breaking
|
||||
/// others.
|
||||
struct DefaultNormalizer<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
map: FxHashMap<ty::ProjectionTy<'tcx>, Ty<'tcx>>,
|
||||
|
@ -66,28 +66,43 @@ trait D where
|
||||
type Assoc = NotClone;
|
||||
}
|
||||
|
||||
trait Foo2<T> where
|
||||
<Self as Foo2<T>>::Bar: Clone,
|
||||
// Test behavior of the check when defaults refer to other defaults:
|
||||
|
||||
// Shallow substitution rejects this trait since `Baz` isn't guaranteed to be
|
||||
// `Clone`.
|
||||
trait Foo2<T> {
|
||||
type Bar: Clone = Vec<Self::Baz>;
|
||||
//~^ ERROR the trait bound `<Self as Foo2<T>>::Baz: std::clone::Clone` is not satisfied
|
||||
{
|
||||
type Bar = Vec<Self::Baz>;
|
||||
type Baz = T;
|
||||
}
|
||||
|
||||
trait Foo3<T: Clone> where
|
||||
<Self as Foo3<T>>::Bar: Clone,
|
||||
//~^ ERROR the trait bound `<Self as Foo3<T>>::Baz: std::clone::Clone` is not satisfied
|
||||
{
|
||||
type Bar = Vec<Self::Baz>;
|
||||
// Adding a `T: Clone` bound doesn't help since the requirement doesn't see `T`
|
||||
// because of the shallow substitution. If we did a deep substitution instead,
|
||||
// this would be accepted.
|
||||
trait Foo25<T: Clone> {
|
||||
type Bar: Clone = Vec<Self::Baz>;
|
||||
//~^ ERROR the trait bound `<Self as Foo25<T>>::Baz: std::clone::Clone` is not satisfied
|
||||
type Baz = T;
|
||||
}
|
||||
|
||||
trait Foo4<T> where
|
||||
<Self as Foo4<T>>::Bar: Clone,
|
||||
{
|
||||
type Bar = Vec<Self::Baz>;
|
||||
type Baz: Clone = T;
|
||||
// Adding the `Baz: Clone` bound isn't enough since the default is type
|
||||
// parameter `T`, which also might not be `Clone`.
|
||||
trait Foo3<T> where
|
||||
Self::Bar: Clone,
|
||||
Self::Baz: Clone,
|
||||
//~^ ERROR the trait bound `T: std::clone::Clone` is not satisfied
|
||||
{
|
||||
type Bar = Vec<Self::Baz>;
|
||||
type Baz = T;
|
||||
}
|
||||
|
||||
// This one finally works, with `Clone` bounds on all assoc. types and the type
|
||||
// parameter.
|
||||
trait Foo4<T> where
|
||||
T: Clone,
|
||||
{
|
||||
type Bar: Clone = Vec<Self::Baz>;
|
||||
type Baz: Clone = T;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -104,61 +104,49 @@ LL | | }
|
||||
| |_^
|
||||
|
||||
error[E0277]: the trait bound `<Self as Foo2<T>>::Baz: std::clone::Clone` is not satisfied
|
||||
--> $DIR/defaults-suitability.rs:70:29
|
||||
--> $DIR/defaults-suitability.rs:74:15
|
||||
|
|
||||
LL | <Self as Foo2<T>>::Bar: Clone,
|
||||
| ^^^^^ the trait `std::clone::Clone` is not implemented for `<Self as Foo2<T>>::Baz`
|
||||
LL | type Bar: Clone = Vec<Self::Baz>;
|
||||
| ^^^^^ the trait `std::clone::Clone` is not implemented for `<Self as Foo2<T>>::Baz`
|
||||
|
|
||||
= help: consider adding a `where <Self as Foo2<T>>::Baz: std::clone::Clone` bound
|
||||
= note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<<Self as Foo2<T>>::Baz>`
|
||||
note: required by `Foo2`
|
||||
--> $DIR/defaults-suitability.rs:69:1
|
||||
--> $DIR/defaults-suitability.rs:73:1
|
||||
|
|
||||
LL | / trait Foo2<T> where
|
||||
LL | | <Self as Foo2<T>>::Bar: Clone,
|
||||
LL | |
|
||||
LL | | {
|
||||
LL | | type Bar = Vec<Self::Baz>;
|
||||
LL | | type Baz = T;
|
||||
LL | | }
|
||||
| |_^
|
||||
LL | trait Foo2<T> {
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `<Self as Foo3<T>>::Baz: std::clone::Clone` is not satisfied
|
||||
--> $DIR/defaults-suitability.rs:78:29
|
||||
error[E0277]: the trait bound `<Self as Foo25<T>>::Baz: std::clone::Clone` is not satisfied
|
||||
--> $DIR/defaults-suitability.rs:83:15
|
||||
|
|
||||
LL | <Self as Foo3<T>>::Bar: Clone,
|
||||
| ^^^^^ the trait `std::clone::Clone` is not implemented for `<Self as Foo3<T>>::Baz`
|
||||
LL | type Bar: Clone = Vec<Self::Baz>;
|
||||
| ^^^^^ the trait `std::clone::Clone` is not implemented for `<Self as Foo25<T>>::Baz`
|
||||
|
|
||||
= help: consider adding a `where <Self as Foo3<T>>::Baz: std::clone::Clone` bound
|
||||
= note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<<Self as Foo3<T>>::Baz>`
|
||||
note: required by `Foo3`
|
||||
--> $DIR/defaults-suitability.rs:77:1
|
||||
= help: consider adding a `where <Self as Foo25<T>>::Baz: std::clone::Clone` bound
|
||||
= note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<<Self as Foo25<T>>::Baz>`
|
||||
note: required by `Foo25`
|
||||
--> $DIR/defaults-suitability.rs:82:1
|
||||
|
|
||||
LL | / trait Foo3<T: Clone> where
|
||||
LL | | <Self as Foo3<T>>::Bar: Clone,
|
||||
LL | |
|
||||
LL | | {
|
||||
LL | | type Bar = Vec<Self::Baz>;
|
||||
LL | | type Baz = T;
|
||||
LL | | }
|
||||
| |_^
|
||||
LL | trait Foo25<T: Clone> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0277]: the trait bound `T: std::clone::Clone` is not satisfied
|
||||
--> $DIR/defaults-suitability.rs:89:15
|
||||
--> $DIR/defaults-suitability.rs:92:16
|
||||
|
|
||||
LL | type Baz: Clone = T;
|
||||
| ^^^^^ the trait `std::clone::Clone` is not implemented for `T`
|
||||
LL | Self::Baz: Clone,
|
||||
| ^^^^^ the trait `std::clone::Clone` is not implemented for `T`
|
||||
|
|
||||
= help: consider adding a `where T: std::clone::Clone` bound
|
||||
note: required by `Foo4`
|
||||
--> $DIR/defaults-suitability.rs:85:1
|
||||
note: required by `Foo3`
|
||||
--> $DIR/defaults-suitability.rs:90:1
|
||||
|
|
||||
LL | / trait Foo4<T> where
|
||||
LL | | <Self as Foo4<T>>::Bar: Clone,
|
||||
LL | | {
|
||||
LL | | type Bar = Vec<Self::Baz>;
|
||||
LL | | type Baz: Clone = T;
|
||||
LL | / trait Foo3<T> where
|
||||
LL | | Self::Bar: Clone,
|
||||
LL | | Self::Baz: Clone,
|
||||
LL | |
|
||||
... |
|
||||
LL | | type Baz = T;
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user