mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
Check suitability of the provided default
This commit is contained in:
parent
d3be26d6a8
commit
c73ee9861b
@ -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![]
|
||||
});
|
||||
}
|
||||
|
93
src/test/ui/associated-types/defaults-suitability.rs
Normal file
93
src/test/ui/associated-types/defaults-suitability.rs
Normal 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() {}
|
177
src/test/ui/associated-types/defaults-suitability.stderr
Normal file
177
src/test/ui/associated-types/defaults-suitability.stderr
Normal 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`.
|
Loading…
Reference in New Issue
Block a user