Check only predicates with a single param with a concrete default.
This is the most conservative possible and should be always correct.
This commit is contained in:
parent
ac17948d0f
commit
c74f85f935
4 changed files with 50 additions and 102 deletions
|
@ -278,7 +278,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
|
||||||
fn check_trait(&mut self, item: &hir::Item) {
|
fn check_trait(&mut self, item: &hir::Item) {
|
||||||
let trait_def_id = self.tcx.hir.local_def_id(item.id);
|
let trait_def_id = self.tcx.hir.local_def_id(item.id);
|
||||||
self.for_item(item).with_fcx(|fcx, _| {
|
self.for_item(item).with_fcx(|fcx, _| {
|
||||||
self.check_trait_where_clauses(fcx, item.span, trait_def_id);
|
self.check_where_clauses(fcx, item.span, trait_def_id);
|
||||||
vec![]
|
vec![]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -354,23 +354,6 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
|
||||||
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
|
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
def_id: DefId) {
|
def_id: DefId) {
|
||||||
self.inner_check_where_clauses(fcx, span, def_id, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_trait_where_clauses<'fcx, 'tcx>(&mut self,
|
|
||||||
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
|
|
||||||
span: Span,
|
|
||||||
def_id: DefId) {
|
|
||||||
self.inner_check_where_clauses(fcx, span, def_id, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks where clauses and inline bounds that are declared on def_id.
|
|
||||||
fn inner_check_where_clauses<'fcx, 'tcx>(&mut self,
|
|
||||||
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
|
|
||||||
span: Span,
|
|
||||||
def_id: DefId,
|
|
||||||
is_trait: bool)
|
|
||||||
{
|
|
||||||
use ty::subst::Subst;
|
use ty::subst::Subst;
|
||||||
use rustc::ty::TypeFoldable;
|
use rustc::ty::TypeFoldable;
|
||||||
|
|
||||||
|
@ -390,12 +373,10 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that trait predicates are WF when params are substituted by their defaults.
|
// Check that trait predicates are WF when params are substituted by their defaults.
|
||||||
// We don't want to overly constrain the predicates that may be written but we
|
// We don't want to overly constrain the predicates that may be written but we want to
|
||||||
// want to catch obviously wrong cases such as `struct Foo<T: Copy = String>`
|
// catch cases where a default my never be applied such as `struct Foo<T: Copy = String>`.
|
||||||
// or cases where defaults don't work together such as:
|
// Therefore we check if a predicate which contains a single type param
|
||||||
// `struct Foo<T = i32, U = u8> where T: into<U>`
|
// with a concrete default is WF with that default substituted.
|
||||||
// Therefore we check if a predicate in which all type params are defaulted
|
|
||||||
// is WF with those defaults simultaneously substituted.
|
|
||||||
// For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`.
|
// For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`.
|
||||||
//
|
//
|
||||||
// First we build the defaulted substitution.
|
// First we build the defaulted substitution.
|
||||||
|
@ -403,30 +384,39 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
|
||||||
// All regions are identity.
|
// All regions are identity.
|
||||||
fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
|
fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
|
||||||
}, |def, _| {
|
}, |def, _| {
|
||||||
if !is_our_default(def) {
|
// If the param has a default,
|
||||||
// We don't want to use non-defaulted params in a substitution, mark as err.
|
if is_our_default(def) {
|
||||||
fcx.tcx.types.err
|
let default_ty = fcx.tcx.type_of(def.def_id);
|
||||||
} else {
|
// and it's not a dependent default
|
||||||
// Substitute with default.
|
if !default_ty.needs_subst() {
|
||||||
fcx.tcx.type_of(def.def_id)
|
// then substitute with the default.
|
||||||
|
return default_ty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// Mark unwanted params as err.
|
||||||
|
fcx.tcx.types.err
|
||||||
});
|
});
|
||||||
// Now we build the substituted predicates.
|
// Now we build the substituted predicates.
|
||||||
for &pred in predicates.predicates.iter() {
|
for &pred in predicates.predicates.iter() {
|
||||||
let substituted_pred = pred.subst(fcx.tcx, substs);
|
struct CountParams { params: FxHashSet<u32> }
|
||||||
// If there is a non-defaulted param in the predicate, don't check it.
|
impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams {
|
||||||
if substituted_pred.references_error() {
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
|
||||||
continue;
|
match t.sty {
|
||||||
}
|
ty::TyParam(p) => {
|
||||||
// In trait defs, don't check `Self: Sized` when `Self` is the default.
|
self.params.insert(p.idx);
|
||||||
if let ty::Predicate::Trait(trait_pred) = substituted_pred {
|
t.super_visit_with(self)
|
||||||
// `skip_binder()` is ok, we're only inspecting for `has_self_ty()`.
|
}
|
||||||
let lhs_is_self = trait_pred.skip_binder().self_ty().has_self_ty();
|
_ => t.super_visit_with(self)
|
||||||
let pred_sized = Some(trait_pred.def_id()) == fcx.tcx.lang_items().sized_trait();
|
}
|
||||||
if is_trait && lhs_is_self && pred_sized {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let mut param_count = CountParams { params: FxHashSet() };
|
||||||
|
pred.visit_with(&mut param_count);
|
||||||
|
let substituted_pred = pred.subst(fcx.tcx, substs);
|
||||||
|
// Don't check non-defaulted params, dependent defaults or preds with multiple params.
|
||||||
|
if substituted_pred.references_error() || param_count.params.len() > 1 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// Avoid duplication of predicates that contain no parameters, for example.
|
// Avoid duplication of predicates that contain no parameters, for example.
|
||||||
if !predicates.predicates.contains(&substituted_pred) {
|
if !predicates.predicates.contains(&substituted_pred) {
|
||||||
substituted_predicates.push(substituted_pred);
|
substituted_predicates.push(substituted_pred);
|
||||||
|
|
|
@ -14,12 +14,15 @@ struct Foo<U, V=i32>(U, V) where U: Trait<V>;
|
||||||
trait Marker {}
|
trait Marker {}
|
||||||
struct TwoParams<T, U>(T, U);
|
struct TwoParams<T, U>(T, U);
|
||||||
impl Marker for TwoParams<i32, i32> {}
|
impl Marker for TwoParams<i32, i32> {}
|
||||||
// Check that defaults are substituted simultaneously.
|
|
||||||
|
// Clauses with more than 1 param are not checked.
|
||||||
struct IndividuallyBogus<T = i32, U = i32>(TwoParams<T, U>) where TwoParams<T, U>: Marker;
|
struct IndividuallyBogus<T = i32, U = i32>(TwoParams<T, U>) where TwoParams<T, U>: Marker;
|
||||||
|
struct BogusTogether<T = u32, U = i32>(T, U) where TwoParams<T, U>: Marker;
|
||||||
// Clauses with non-defaulted params are not checked.
|
// Clauses with non-defaulted params are not checked.
|
||||||
struct NonDefaultedInClause<T, U = i32>(TwoParams<T, U>) where TwoParams<T, U>: Marker;
|
struct NonDefaultedInClause<T, U = i32>(TwoParams<T, U>) where TwoParams<T, U>: Marker;
|
||||||
struct DefaultedLhs<U, V=i32>(U, V) where V: Trait<U>;
|
struct DefaultedLhs<U, V=i32>(U, V) where V: Trait<U>;
|
||||||
// Dependent defaults.
|
// Dependent defaults are not checked.
|
||||||
struct Dependent<T: Copy, U = T>(T, U) where U: Copy;
|
struct Dependent<T, U = T>(T, U) where U: Copy;
|
||||||
|
trait SelfBound<T: Copy=Self> {}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -30,25 +30,11 @@ struct WhereClause<T=String>(T) where T: Copy;
|
||||||
trait TraitBound<T:Copy=String> {}
|
trait TraitBound<T:Copy=String> {}
|
||||||
//~^ error: the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277]
|
//~^ error: the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277]
|
||||||
|
|
||||||
trait SelfBound<T:Copy=Self> {}
|
|
||||||
//~^ error: the trait bound `Self: std::marker::Copy` is not satisfied [E0277]
|
|
||||||
|
|
||||||
trait Super<T: Copy> { }
|
trait Super<T: Copy> { }
|
||||||
trait Base<T = String>: Super<T> { }
|
trait Base<T = String>: Super<T> { }
|
||||||
//~^ error: the trait bound `T: std::marker::Copy` is not satisfied [E0277]
|
//~^ error: the trait bound `T: std::marker::Copy` is not satisfied [E0277]
|
||||||
|
|
||||||
trait ProjectionPred<T:Iterator = IntoIter<i32>> where T::Item : Add<u8> {}
|
trait ProjectionPred<T:Iterator = IntoIter<i32>> where T::Item : Add<u8> {}
|
||||||
//~^ error: the trait bound `i32: std::ops::Add<u8>` is not satisfied [E0277]
|
//~^ error: cannot add `u8` to `i32` [E0277]
|
||||||
|
|
||||||
// Defaults must work together.
|
|
||||||
struct TwoParams<T = u32, U = i32>(T, U) where T: Bar<U>;
|
|
||||||
//~^ the trait bound `u32: Bar<i32>` is not satisfied [E0277]
|
|
||||||
trait Bar<V> {}
|
|
||||||
impl Bar<String> for u32 { }
|
|
||||||
impl Bar<i32> for String { }
|
|
||||||
|
|
||||||
// Dependent defaults.
|
|
||||||
struct Dependent<T, U = T>(T, U) where U: Copy;
|
|
||||||
//~^ the trait bound `T: std::marker::Copy` is not satisfied [E0277]
|
|
||||||
|
|
||||||
fn main() { }
|
fn main() { }
|
||||||
|
|
|
@ -25,13 +25,14 @@ note: required by `Foo`
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0277]: the trait bound `A: std::iter::Iterator` is not satisfied
|
error[E0277]: the trait bound `A: std::iter::Iterator` is not satisfied
|
||||||
--> $DIR/type-check-defaults.rs:21:1
|
--> $DIR/type-check-defaults.rs:21:32
|
||||||
|
|
|
|
||||||
21 | struct WellFormedProjection<A, T=<A as Iterator>::Item>(A, T);
|
21 | struct WellFormedProjection<A, T=<A as Iterator>::Item>(A, T);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `A` is not an iterator; maybe try calling `.iter()` or a similar method
|
| ^ `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: the trait `std::iter::Iterator` is not implemented for `A`
|
||||||
= help: consider adding a `where A: std::iter::Iterator` bound
|
= 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
|
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:24:1
|
||||||
|
@ -57,59 +58,27 @@ error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not sa
|
||||||
|
|
|
|
||||||
= note: required by `std::marker::Copy`
|
= note: required by `std::marker::Copy`
|
||||||
|
|
||||||
error[E0277]: the trait bound `Self: std::marker::Copy` is not satisfied
|
|
||||||
--> $DIR/type-check-defaults.rs:33:1
|
|
||||||
|
|
|
||||||
33 | trait SelfBound<T:Copy=Self> {}
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `Self`
|
|
||||||
|
|
|
||||||
= help: consider adding a `where Self: std::marker::Copy` bound
|
|
||||||
= note: required by `std::marker::Copy`
|
|
||||||
|
|
||||||
error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
|
error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
|
||||||
--> $DIR/type-check-defaults.rs:37:1
|
--> $DIR/type-check-defaults.rs:34:1
|
||||||
|
|
|
|
||||||
37 | trait Base<T = String>: Super<T> { }
|
34 | trait Base<T = String>: Super<T> { }
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
|
||||||
|
|
|
|
||||||
= help: consider adding a `where T: std::marker::Copy` bound
|
= help: consider adding a `where T: std::marker::Copy` bound
|
||||||
note: required by `Super`
|
note: required by `Super`
|
||||||
--> $DIR/type-check-defaults.rs:36:1
|
--> $DIR/type-check-defaults.rs:33:1
|
||||||
|
|
|
|
||||||
36 | trait Super<T: Copy> { }
|
33 | trait Super<T: Copy> { }
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0277]: the trait bound `i32: std::ops::Add<u8>` is not satisfied
|
error[E0277]: cannot add `u8` to `i32`
|
||||||
--> $DIR/type-check-defaults.rs:40:1
|
--> $DIR/type-check-defaults.rs:37:1
|
||||||
|
|
|
|
||||||
40 | trait ProjectionPred<T:Iterator = IntoIter<i32>> where T::Item : Add<u8> {}
|
37 | trait ProjectionPred<T:Iterator = IntoIter<i32>> where T::Item : Add<u8> {}
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u8`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u8`
|
||||||
|
|
|
|
||||||
= help: the trait `std::ops::Add<u8>` is not implemented for `i32`
|
= help: the trait `std::ops::Add<u8>` is not implemented for `i32`
|
||||||
= note: required by `std::ops::Add`
|
= note: required by `std::ops::Add`
|
||||||
|
|
||||||
error[E0277]: the trait bound `u32: Bar<i32>` is not satisfied
|
error: aborting due to 8 previous errors
|
||||||
--> $DIR/type-check-defaults.rs:44:1
|
|
||||||
|
|
|
||||||
44 | struct TwoParams<T = u32, U = i32>(T, U) where T: Bar<U>;
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar<i32>` is not implemented for `u32`
|
|
||||||
|
|
|
||||||
= help: the following implementations were found:
|
|
||||||
<u32 as Bar<std::string::String>>
|
|
||||||
note: required by `Bar`
|
|
||||||
--> $DIR/type-check-defaults.rs:46:1
|
|
||||||
|
|
|
||||||
46 | trait Bar<V> {}
|
|
||||||
| ^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
|
|
||||||
--> $DIR/type-check-defaults.rs:51:1
|
|
||||||
|
|
|
||||||
51 | struct Dependent<T, U = T>(T, U) where U: Copy;
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
|
|
||||||
|
|
|
||||||
= help: consider adding a `where T: std::marker::Copy` bound
|
|
||||||
= note: required by `std::marker::Copy`
|
|
||||||
|
|
||||||
error: aborting due to 11 previous errors
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue