Check suitability of the provided default

This commit is contained in:
Jonas Schievink 2019-06-15 19:02:27 +02:00
parent d3be26d6a8
commit c73ee9861b
3 changed files with 342 additions and 0 deletions

View File

@ -425,6 +425,78 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
for_item(tcx, item).with_fcx(|fcx, _| {
check_where_clauses(tcx, fcx, item.span, trait_def_id, None);
// Type-check associated type defaults (if there are any):
// Assuming the defaults are used, check that all predicates (bounds on
// the assoc type and where clauses on the trait) hold.
let substs = InternalSubsts::identity_for_item(tcx, trait_def_id);
// For all assoc. types with defaults, build a map from
// `<Self as Trait<...>>::Assoc` to the default type.
let map = tcx.associated_items(trait_def_id)
.filter_map(|item| {
if item.kind == ty::AssocKind::Type && item.defaultness.has_value() {
// `<Self as Trait<...>>::Assoc`
let proj = ty::ProjectionTy {
substs,
item_def_id: item.def_id,
};
let default_ty = tcx.type_of(item.def_id);
debug!("assoc. type default mapping: {} -> {}", proj, default_ty);
Some((proj, default_ty))
} else {
None
}
})
.collect::<FxHashMap<_, _>>();
struct DefaultNormalizer<'tcx> {
tcx: TyCtxt<'tcx>,
map: FxHashMap<ty::ProjectionTy<'tcx>, Ty<'tcx>>,
}
impl<'tcx> ty::fold::TypeFolder<'tcx> for DefaultNormalizer<'tcx> {
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
self.tcx
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
match t.sty {
ty::Projection(proj_ty) => {
if let Some(default) = self.map.get(&proj_ty) {
default
} else {
t.super_fold_with(self)
}
}
_ => t.super_fold_with(self),
}
}
}
// Now take all predicates defined on the trait, replace any mention of
// the assoc. types with their default, and prove them.
// We only consider predicates that directly mention the assoc. type.
let mut norm = DefaultNormalizer { tcx, map };
let predicates = fcx.tcx.predicates_of(trait_def_id);
for &(orig_pred, span) in predicates.predicates.iter() {
let pred = orig_pred.fold_with(&mut norm);
if pred != orig_pred {
// Mentions one of the defaulted assoc. types
debug!("default suitability check: proving predicate: {} -> {}", orig_pred, pred);
let pred = fcx.normalize_associated_types_in(span, &pred);
let cause = traits::ObligationCause::new(
span,
fcx.body_id,
traits::ItemObligation(trait_def_id),
);
let obligation = traits::Obligation::new(cause, fcx.param_env, pred);
fcx.register_predicate(obligation);
}
}
vec![]
});
}

View File

@ -0,0 +1,93 @@
//! Checks that associated type defaults are properly validated.
//!
//! This means:
//! * Default types are wfchecked
//! * Default types are checked against where clauses on the assoc. type
//! (eg. `type Assoc: Clone = NotClone`), and also against where clauses on
//! the trait itself when possible
// compile-fail
#![feature(associated_type_defaults)]
struct NotClone;
// Assoc. type bounds must hold for the default type
trait Tr {
type Ty: Clone = NotClone;
//~^ ERROR the trait bound `NotClone: std::clone::Clone` is not satisfied
}
// Where-clauses defined on the trait must also be considered
trait Tr2 where Self::Ty: Clone {
//~^ ERROR the trait bound `NotClone: std::clone::Clone` is not satisfied
type Ty = NotClone;
}
// Independent of where-clauses (there are none here), default types must always be wf
trait Tr3 {
type Ty = Vec<[u8]>;
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
}
// Involved type parameters must fulfill all bounds required by defaults that mention them
trait Foo<T> {
type Bar: Clone = Vec<T>;
//~^ ERROR the trait bound `T: std::clone::Clone` is not satisfied
}
trait Bar: Sized {
// `(): Foo<Self>` might hold for some possible impls but not all.
type Assoc: Foo<Self> = ();
//~^ ERROR the trait bound `(): Foo<Self>` is not satisfied
}
trait IsU8<T> {}
impl<T> IsU8<u8> for T {}
// Test that mentioning the assoc. type inside where clauses works
trait C where
Vec<Self::Assoc>: Clone,
Self::Assoc: IsU8<Self::Assoc>,
bool: IsU8<Self::Assoc>,
{
type Assoc = u8;
}
// Test that we get all expected errors if that default is unsuitable
trait D where
Vec<Self::Assoc>: Clone,
//~^ ERROR the trait bound `NotClone: std::clone::Clone` is not satisfied
Self::Assoc: IsU8<Self::Assoc>,
//~^ ERROR the trait bound `NotClone: IsU8<NotClone>` is not satisfied
bool: IsU8<Self::Assoc>,
//~^ ERROR the trait bound `bool: IsU8<NotClone>` is not satisfied
{
type Assoc = NotClone;
}
trait Foo2<T> where
<Self as Foo2<T>>::Bar: Clone,
//~^ 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>;
type Baz = T;
}
trait Foo4<T> where
<Self as Foo4<T>>::Bar: Clone,
{
type Bar = Vec<Self::Baz>;
type Baz: Clone = T;
//~^ ERROR the trait bound `T: std::clone::Clone` is not satisfied
}
fn main() {}

View File

@ -0,0 +1,177 @@
error[E0277]: the trait bound `NotClone: std::clone::Clone` is not satisfied
--> $DIR/defaults-suitability.rs:17:14
|
LL | type Ty: Clone = NotClone;
| ^^^^^ the trait `std::clone::Clone` is not implemented for `NotClone`
|
note: required by `Tr`
--> $DIR/defaults-suitability.rs:16:1
|
LL | trait Tr {
| ^^^^^^^^
error[E0277]: the trait bound `NotClone: std::clone::Clone` is not satisfied
--> $DIR/defaults-suitability.rs:22:27
|
LL | trait Tr2 where Self::Ty: Clone {
| ^^^^^ the trait `std::clone::Clone` is not implemented for `NotClone`
|
note: required by `Tr2`
--> $DIR/defaults-suitability.rs:22:1
|
LL | trait Tr2 where Self::Ty: Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `T: std::clone::Clone` is not satisfied
--> $DIR/defaults-suitability.rs:35:15
|
LL | type Bar: Clone = Vec<T>;
| ^^^^^ the trait `std::clone::Clone` is not implemented for `T`
|
= help: consider adding a `where T: std::clone::Clone` bound
= note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<T>`
note: required by `Foo`
--> $DIR/defaults-suitability.rs:34:1
|
LL | trait Foo<T> {
| ^^^^^^^^^^^^
error[E0277]: the trait bound `(): Foo<Self>` is not satisfied
--> $DIR/defaults-suitability.rs:41:17
|
LL | type Assoc: Foo<Self> = ();
| ^^^^^^^^^ the trait `Foo<Self>` is not implemented for `()`
|
note: required by `Bar`
--> $DIR/defaults-suitability.rs:39:1
|
LL | trait Bar: Sized {
| ^^^^^^^^^^^^^^^^
error[E0277]: the trait bound `NotClone: IsU8<NotClone>` is not satisfied
--> $DIR/defaults-suitability.rs:61:18
|
LL | Self::Assoc: IsU8<Self::Assoc>,
| ^^^^^^^^^^^^^^^^^ the trait `IsU8<NotClone>` is not implemented for `NotClone`
|
note: required by `D`
--> $DIR/defaults-suitability.rs:58:1
|
LL | / trait D where
LL | | Vec<Self::Assoc>: Clone,
LL | |
LL | | Self::Assoc: IsU8<Self::Assoc>,
... |
LL | | type Assoc = NotClone;
LL | | }
| |_^
error[E0277]: the trait bound `bool: IsU8<NotClone>` is not satisfied
--> $DIR/defaults-suitability.rs:63:11
|
LL | bool: IsU8<Self::Assoc>,
| ^^^^^^^^^^^^^^^^^ the trait `IsU8<NotClone>` is not implemented for `bool`
|
note: required by `D`
--> $DIR/defaults-suitability.rs:58:1
|
LL | / trait D where
LL | | Vec<Self::Assoc>: Clone,
LL | |
LL | | Self::Assoc: IsU8<Self::Assoc>,
... |
LL | | type Assoc = NotClone;
LL | | }
| |_^
error[E0277]: the trait bound `NotClone: std::clone::Clone` is not satisfied
--> $DIR/defaults-suitability.rs:59:23
|
LL | Vec<Self::Assoc>: Clone,
| ^^^^^ the trait `std::clone::Clone` is not implemented for `NotClone`
|
= note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<NotClone>`
note: required by `D`
--> $DIR/defaults-suitability.rs:58:1
|
LL | / trait D where
LL | | Vec<Self::Assoc>: Clone,
LL | |
LL | | Self::Assoc: IsU8<Self::Assoc>,
... |
LL | | type Assoc = NotClone;
LL | | }
| |_^
error[E0277]: the trait bound `<Self as Foo2<T>>::Baz: std::clone::Clone` is not satisfied
--> $DIR/defaults-suitability.rs:70:29
|
LL | <Self as Foo2<T>>::Bar: Clone,
| ^^^^^ 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
|
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 | | }
| |_^
error[E0277]: the trait bound `<Self as Foo3<T>>::Baz: std::clone::Clone` is not satisfied
--> $DIR/defaults-suitability.rs:78:29
|
LL | <Self as Foo3<T>>::Bar: Clone,
| ^^^^^ the trait `std::clone::Clone` is not implemented for `<Self as Foo3<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
|
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 | | }
| |_^
error[E0277]: the trait bound `T: std::clone::Clone` is not satisfied
--> $DIR/defaults-suitability.rs:89:15
|
LL | type Baz: Clone = T;
| ^^^^^ 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
|
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 | |
LL | | }
| |_^
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/defaults-suitability.rs:29:5
|
LL | type Ty = Vec<[u8]>;
| ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[u8]`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required by `std::vec::Vec`
error: aborting due to 11 previous errors
For more information about this error, try `rustc --explain E0277`.