Skip to content

Commit c73ee98

Browse files
Check suitability of the provided default
1 parent d3be26d commit c73ee98

File tree

3 files changed

+342
-0
lines changed

3 files changed

+342
-0
lines changed

src/librustc_typeck/check/wfcheck.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,78 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
425425

426426
for_item(tcx, item).with_fcx(|fcx, _| {
427427
check_where_clauses(tcx, fcx, item.span, trait_def_id, None);
428+
429+
// Type-check associated type defaults (if there are any):
430+
// Assuming the defaults are used, check that all predicates (bounds on
431+
// the assoc type and where clauses on the trait) hold.
432+
433+
let substs = InternalSubsts::identity_for_item(tcx, trait_def_id);
434+
435+
// For all assoc. types with defaults, build a map from
436+
// `<Self as Trait<...>>::Assoc` to the default type.
437+
let map = tcx.associated_items(trait_def_id)
438+
.filter_map(|item| {
439+
if item.kind == ty::AssocKind::Type && item.defaultness.has_value() {
440+
// `<Self as Trait<...>>::Assoc`
441+
let proj = ty::ProjectionTy {
442+
substs,
443+
item_def_id: item.def_id,
444+
};
445+
let default_ty = tcx.type_of(item.def_id);
446+
debug!("assoc. type default mapping: {} -> {}", proj, default_ty);
447+
Some((proj, default_ty))
448+
} else {
449+
None
450+
}
451+
})
452+
.collect::<FxHashMap<_, _>>();
453+
454+
struct DefaultNormalizer<'tcx> {
455+
tcx: TyCtxt<'tcx>,
456+
map: FxHashMap<ty::ProjectionTy<'tcx>, Ty<'tcx>>,
457+
}
458+
459+
impl<'tcx> ty::fold::TypeFolder<'tcx> for DefaultNormalizer<'tcx> {
460+
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
461+
self.tcx
462+
}
463+
464+
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
465+
match t.sty {
466+
ty::Projection(proj_ty) => {
467+
if let Some(default) = self.map.get(&proj_ty) {
468+
default
469+
} else {
470+
t.super_fold_with(self)
471+
}
472+
}
473+
_ => t.super_fold_with(self),
474+
}
475+
}
476+
}
477+
478+
// Now take all predicates defined on the trait, replace any mention of
479+
// the assoc. types with their default, and prove them.
480+
// We only consider predicates that directly mention the assoc. type.
481+
let mut norm = DefaultNormalizer { tcx, map };
482+
let predicates = fcx.tcx.predicates_of(trait_def_id);
483+
for &(orig_pred, span) in predicates.predicates.iter() {
484+
let pred = orig_pred.fold_with(&mut norm);
485+
if pred != orig_pred {
486+
// Mentions one of the defaulted assoc. types
487+
debug!("default suitability check: proving predicate: {} -> {}", orig_pred, pred);
488+
let pred = fcx.normalize_associated_types_in(span, &pred);
489+
let cause = traits::ObligationCause::new(
490+
span,
491+
fcx.body_id,
492+
traits::ItemObligation(trait_def_id),
493+
);
494+
let obligation = traits::Obligation::new(cause, fcx.param_env, pred);
495+
496+
fcx.register_predicate(obligation);
497+
}
498+
}
499+
428500
vec![]
429501
});
430502
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//! Checks that associated type defaults are properly validated.
2+
//!
3+
//! This means:
4+
//! * Default types are wfchecked
5+
//! * Default types are checked against where clauses on the assoc. type
6+
//! (eg. `type Assoc: Clone = NotClone`), and also against where clauses on
7+
//! the trait itself when possible
8+
9+
// compile-fail
10+
11+
#![feature(associated_type_defaults)]
12+
13+
struct NotClone;
14+
15+
// Assoc. type bounds must hold for the default type
16+
trait Tr {
17+
type Ty: Clone = NotClone;
18+
//~^ ERROR the trait bound `NotClone: std::clone::Clone` is not satisfied
19+
}
20+
21+
// Where-clauses defined on the trait must also be considered
22+
trait Tr2 where Self::Ty: Clone {
23+
//~^ ERROR the trait bound `NotClone: std::clone::Clone` is not satisfied
24+
type Ty = NotClone;
25+
}
26+
27+
// Independent of where-clauses (there are none here), default types must always be wf
28+
trait Tr3 {
29+
type Ty = Vec<[u8]>;
30+
//~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
31+
}
32+
33+
// Involved type parameters must fulfill all bounds required by defaults that mention them
34+
trait Foo<T> {
35+
type Bar: Clone = Vec<T>;
36+
//~^ ERROR the trait bound `T: std::clone::Clone` is not satisfied
37+
}
38+
39+
trait Bar: Sized {
40+
// `(): Foo<Self>` might hold for some possible impls but not all.
41+
type Assoc: Foo<Self> = ();
42+
//~^ ERROR the trait bound `(): Foo<Self>` is not satisfied
43+
}
44+
45+
trait IsU8<T> {}
46+
impl<T> IsU8<u8> for T {}
47+
48+
// Test that mentioning the assoc. type inside where clauses works
49+
trait C where
50+
Vec<Self::Assoc>: Clone,
51+
Self::Assoc: IsU8<Self::Assoc>,
52+
bool: IsU8<Self::Assoc>,
53+
{
54+
type Assoc = u8;
55+
}
56+
57+
// Test that we get all expected errors if that default is unsuitable
58+
trait D where
59+
Vec<Self::Assoc>: Clone,
60+
//~^ ERROR the trait bound `NotClone: std::clone::Clone` is not satisfied
61+
Self::Assoc: IsU8<Self::Assoc>,
62+
//~^ ERROR the trait bound `NotClone: IsU8<NotClone>` is not satisfied
63+
bool: IsU8<Self::Assoc>,
64+
//~^ ERROR the trait bound `bool: IsU8<NotClone>` is not satisfied
65+
{
66+
type Assoc = NotClone;
67+
}
68+
69+
trait Foo2<T> where
70+
<Self as Foo2<T>>::Bar: Clone,
71+
//~^ ERROR the trait bound `<Self as Foo2<T>>::Baz: std::clone::Clone` is not satisfied
72+
{
73+
type Bar = Vec<Self::Baz>;
74+
type Baz = T;
75+
}
76+
77+
trait Foo3<T: Clone> where
78+
<Self as Foo3<T>>::Bar: Clone,
79+
//~^ ERROR the trait bound `<Self as Foo3<T>>::Baz: std::clone::Clone` is not satisfied
80+
{
81+
type Bar = Vec<Self::Baz>;
82+
type Baz = T;
83+
}
84+
85+
trait Foo4<T> where
86+
<Self as Foo4<T>>::Bar: Clone,
87+
{
88+
type Bar = Vec<Self::Baz>;
89+
type Baz: Clone = T;
90+
//~^ ERROR the trait bound `T: std::clone::Clone` is not satisfied
91+
}
92+
93+
fn main() {}
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
error[E0277]: the trait bound `NotClone: std::clone::Clone` is not satisfied
2+
--> $DIR/defaults-suitability.rs:17:14
3+
|
4+
LL | type Ty: Clone = NotClone;
5+
| ^^^^^ the trait `std::clone::Clone` is not implemented for `NotClone`
6+
|
7+
note: required by `Tr`
8+
--> $DIR/defaults-suitability.rs:16:1
9+
|
10+
LL | trait Tr {
11+
| ^^^^^^^^
12+
13+
error[E0277]: the trait bound `NotClone: std::clone::Clone` is not satisfied
14+
--> $DIR/defaults-suitability.rs:22:27
15+
|
16+
LL | trait Tr2 where Self::Ty: Clone {
17+
| ^^^^^ the trait `std::clone::Clone` is not implemented for `NotClone`
18+
|
19+
note: required by `Tr2`
20+
--> $DIR/defaults-suitability.rs:22:1
21+
|
22+
LL | trait Tr2 where Self::Ty: Clone {
23+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
24+
25+
error[E0277]: the trait bound `T: std::clone::Clone` is not satisfied
26+
--> $DIR/defaults-suitability.rs:35:15
27+
|
28+
LL | type Bar: Clone = Vec<T>;
29+
| ^^^^^ the trait `std::clone::Clone` is not implemented for `T`
30+
|
31+
= help: consider adding a `where T: std::clone::Clone` bound
32+
= note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<T>`
33+
note: required by `Foo`
34+
--> $DIR/defaults-suitability.rs:34:1
35+
|
36+
LL | trait Foo<T> {
37+
| ^^^^^^^^^^^^
38+
39+
error[E0277]: the trait bound `(): Foo<Self>` is not satisfied
40+
--> $DIR/defaults-suitability.rs:41:17
41+
|
42+
LL | type Assoc: Foo<Self> = ();
43+
| ^^^^^^^^^ the trait `Foo<Self>` is not implemented for `()`
44+
|
45+
note: required by `Bar`
46+
--> $DIR/defaults-suitability.rs:39:1
47+
|
48+
LL | trait Bar: Sized {
49+
| ^^^^^^^^^^^^^^^^
50+
51+
error[E0277]: the trait bound `NotClone: IsU8<NotClone>` is not satisfied
52+
--> $DIR/defaults-suitability.rs:61:18
53+
|
54+
LL | Self::Assoc: IsU8<Self::Assoc>,
55+
| ^^^^^^^^^^^^^^^^^ the trait `IsU8<NotClone>` is not implemented for `NotClone`
56+
|
57+
note: required by `D`
58+
--> $DIR/defaults-suitability.rs:58:1
59+
|
60+
LL | / trait D where
61+
LL | | Vec<Self::Assoc>: Clone,
62+
LL | |
63+
LL | | Self::Assoc: IsU8<Self::Assoc>,
64+
... |
65+
LL | | type Assoc = NotClone;
66+
LL | | }
67+
| |_^
68+
69+
error[E0277]: the trait bound `bool: IsU8<NotClone>` is not satisfied
70+
--> $DIR/defaults-suitability.rs:63:11
71+
|
72+
LL | bool: IsU8<Self::Assoc>,
73+
| ^^^^^^^^^^^^^^^^^ the trait `IsU8<NotClone>` is not implemented for `bool`
74+
|
75+
note: required by `D`
76+
--> $DIR/defaults-suitability.rs:58:1
77+
|
78+
LL | / trait D where
79+
LL | | Vec<Self::Assoc>: Clone,
80+
LL | |
81+
LL | | Self::Assoc: IsU8<Self::Assoc>,
82+
... |
83+
LL | | type Assoc = NotClone;
84+
LL | | }
85+
| |_^
86+
87+
error[E0277]: the trait bound `NotClone: std::clone::Clone` is not satisfied
88+
--> $DIR/defaults-suitability.rs:59:23
89+
|
90+
LL | Vec<Self::Assoc>: Clone,
91+
| ^^^^^ the trait `std::clone::Clone` is not implemented for `NotClone`
92+
|
93+
= note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<NotClone>`
94+
note: required by `D`
95+
--> $DIR/defaults-suitability.rs:58:1
96+
|
97+
LL | / trait D where
98+
LL | | Vec<Self::Assoc>: Clone,
99+
LL | |
100+
LL | | Self::Assoc: IsU8<Self::Assoc>,
101+
... |
102+
LL | | type Assoc = NotClone;
103+
LL | | }
104+
| |_^
105+
106+
error[E0277]: the trait bound `<Self as Foo2<T>>::Baz: std::clone::Clone` is not satisfied
107+
--> $DIR/defaults-suitability.rs:70:29
108+
|
109+
LL | <Self as Foo2<T>>::Bar: Clone,
110+
| ^^^^^ the trait `std::clone::Clone` is not implemented for `<Self as Foo2<T>>::Baz`
111+
|
112+
= help: consider adding a `where <Self as Foo2<T>>::Baz: std::clone::Clone` bound
113+
= note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<<Self as Foo2<T>>::Baz>`
114+
note: required by `Foo2`
115+
--> $DIR/defaults-suitability.rs:69:1
116+
|
117+
LL | / trait Foo2<T> where
118+
LL | | <Self as Foo2<T>>::Bar: Clone,
119+
LL | |
120+
LL | | {
121+
LL | | type Bar = Vec<Self::Baz>;
122+
LL | | type Baz = T;
123+
LL | | }
124+
| |_^
125+
126+
error[E0277]: the trait bound `<Self as Foo3<T>>::Baz: std::clone::Clone` is not satisfied
127+
--> $DIR/defaults-suitability.rs:78:29
128+
|
129+
LL | <Self as Foo3<T>>::Bar: Clone,
130+
| ^^^^^ the trait `std::clone::Clone` is not implemented for `<Self as Foo3<T>>::Baz`
131+
|
132+
= help: consider adding a `where <Self as Foo3<T>>::Baz: std::clone::Clone` bound
133+
= note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<<Self as Foo3<T>>::Baz>`
134+
note: required by `Foo3`
135+
--> $DIR/defaults-suitability.rs:77:1
136+
|
137+
LL | / trait Foo3<T: Clone> where
138+
LL | | <Self as Foo3<T>>::Bar: Clone,
139+
LL | |
140+
LL | | {
141+
LL | | type Bar = Vec<Self::Baz>;
142+
LL | | type Baz = T;
143+
LL | | }
144+
| |_^
145+
146+
error[E0277]: the trait bound `T: std::clone::Clone` is not satisfied
147+
--> $DIR/defaults-suitability.rs:89:15
148+
|
149+
LL | type Baz: Clone = T;
150+
| ^^^^^ the trait `std::clone::Clone` is not implemented for `T`
151+
|
152+
= help: consider adding a `where T: std::clone::Clone` bound
153+
note: required by `Foo4`
154+
--> $DIR/defaults-suitability.rs:85:1
155+
|
156+
LL | / trait Foo4<T> where
157+
LL | | <Self as Foo4<T>>::Bar: Clone,
158+
LL | | {
159+
LL | | type Bar = Vec<Self::Baz>;
160+
LL | | type Baz: Clone = T;
161+
LL | |
162+
LL | | }
163+
| |_^
164+
165+
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
166+
--> $DIR/defaults-suitability.rs:29:5
167+
|
168+
LL | type Ty = Vec<[u8]>;
169+
| ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
170+
|
171+
= help: the trait `std::marker::Sized` is not implemented for `[u8]`
172+
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
173+
= note: required by `std::vec::Vec`
174+
175+
error: aborting due to 11 previous errors
176+
177+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)