Skip to content

Commit

Permalink
Check only concrete defaults for well formedness
Browse files Browse the repository at this point in the history
  • Loading branch information
leoyvens committed Feb 28, 2018
1 parent c74f85f commit a7c7c8a
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 30 deletions.
11 changes: 7 additions & 4 deletions src/librustc_typeck/check/wfcheck.rs
Expand Up @@ -363,13 +363,16 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
let generics = self.tcx.generics_of(def_id);
let is_our_default = |def: &ty::TypeParameterDef|
def.has_default && def.index >= generics.parent_count() as u32;
let defaulted_params = generics.types.iter().cloned().filter(&is_our_default);
// Check that defaults are well-formed. See test `type-check-defaults.rs`.

// Check that concrete defaults are well-formed. See test `type-check-defaults.rs`.
// For example this forbids the declaration:
// struct Foo<T = Vec<[u32]>> { .. }
// Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
for d in defaulted_params.map(|p| p.def_id) {
fcx.register_wf_obligation(fcx.tcx.type_of(d), fcx.tcx.def_span(d), self.code.clone());
for d in generics.types.iter().cloned().filter(is_our_default).map(|p| p.def_id) {
let ty = fcx.tcx.type_of(d);
if !ty.needs_subst() {
fcx.register_wf_obligation(ty, fcx.tcx.def_span(d), self.code.clone());
}
}

// Check that trait predicates are WF when params are substituted by their defaults.
Expand Down
2 changes: 2 additions & 0 deletions src/test/run-pass/defaults-well-formedness.rs
Expand Up @@ -24,5 +24,7 @@ struct DefaultedLhs<U, V=i32>(U, V) where V: Trait<U>;
// Dependent defaults are not checked.
struct Dependent<T, U = T>(T, U) where U: Copy;
trait SelfBound<T: Copy=Self> {}
// Not even for well-formedness.
struct WellFormedProjection<A, T=<A as Iterator>::Item>(A, T);

fn main() {}
3 changes: 0 additions & 3 deletions src/test/ui/type-check-defaults.rs
Expand Up @@ -18,9 +18,6 @@ struct WellFormed<Z = Foo<i32, i32>>(Z);
struct WellFormedNoBounds<Z:?Sized = Foo<i32, i32>>(Z);
//~^ error: the trait bound `i32: std::iter::FromIterator<i32>` is not satisfied [E0277]

struct WellFormedProjection<A, T=<A as Iterator>::Item>(A, T);
//~^ error: the trait bound `A: std::iter::Iterator` is not satisfied [E0277]

struct Bounds<T:Copy=String>(T);
//~^ error: the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277]

Expand Down
36 changes: 13 additions & 23 deletions src/test/ui/type-check-defaults.stderr
Expand Up @@ -24,61 +24,51 @@ note: required by `Foo`
15 | struct Foo<T, U: FromIterator<T>>(T, U);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `A: std::iter::Iterator` is not satisfied
--> $DIR/type-check-defaults.rs:21:32
|
21 | struct WellFormedProjection<A, T=<A as Iterator>::Item>(A, T);
| ^ `A` is not an iterator; maybe try calling `.iter()` or a similar method
|
= help: the trait `std::iter::Iterator` is not implemented for `A`
= help: consider adding a `where A: std::iter::Iterator` bound
= note: required by `std::iter::Iterator`

error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied
--> $DIR/type-check-defaults.rs:24:1
--> $DIR/type-check-defaults.rs:21:1
|
24 | struct Bounds<T:Copy=String>(T);
21 | struct Bounds<T:Copy=String>(T);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String`
|
= note: required by `std::marker::Copy`

error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied
--> $DIR/type-check-defaults.rs:27:1
--> $DIR/type-check-defaults.rs:24:1
|
27 | struct WhereClause<T=String>(T) where T: Copy;
24 | struct WhereClause<T=String>(T) where T: Copy;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String`
|
= note: required by `std::marker::Copy`

error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied
--> $DIR/type-check-defaults.rs:30:1
--> $DIR/type-check-defaults.rs:27:1
|
30 | trait TraitBound<T:Copy=String> {}
27 | trait TraitBound<T:Copy=String> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String`
|
= note: required by `std::marker::Copy`

error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
--> $DIR/type-check-defaults.rs:34:1
--> $DIR/type-check-defaults.rs:31:1
|
34 | trait Base<T = String>: Super<T> { }
31 | trait Base<T = String>: Super<T> { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
|
= help: consider adding a `where T: std::marker::Copy` bound
note: required by `Super`
--> $DIR/type-check-defaults.rs:33:1
--> $DIR/type-check-defaults.rs:30:1
|
33 | trait Super<T: Copy> { }
30 | trait Super<T: Copy> { }
| ^^^^^^^^^^^^^^^^^^^^

error[E0277]: cannot add `u8` to `i32`
--> $DIR/type-check-defaults.rs:37:1
--> $DIR/type-check-defaults.rs:34:1
|
37 | trait ProjectionPred<T:Iterator = IntoIter<i32>> where T::Item : Add<u8> {}
34 | trait ProjectionPred<T:Iterator = IntoIter<i32>> where T::Item : Add<u8> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u8`
|
= help: the trait `std::ops::Add<u8>` is not implemented for `i32`
= note: required by `std::ops::Add`

error: aborting due to 8 previous errors
error: aborting due to 7 previous errors

0 comments on commit a7c7c8a

Please sign in to comment.