diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 21660d817b213..258860d3d5e40 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -278,7 +278,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { fn check_trait(&mut self, item: &hir::Item) { let trait_def_id = self.tcx.hir.local_def_id(item.id); 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![] }); } @@ -354,23 +354,6 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, span: Span, 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 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. - // We don't want to overly constrain the predicates that may be written but we - // want to catch obviously wrong cases such as `struct Foo` - // or cases where defaults don't work together such as: - // `struct Foo where T: into` - // Therefore we check if a predicate in which all type params are defaulted - // is WF with those defaults simultaneously substituted. + // We don't want to overly constrain the predicates that may be written but we want to + // catch cases where a default my never be applied such as `struct Foo`. + // Therefore we check if a predicate which contains a single type param + // with a concrete default is WF with that default substituted. // For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`. // // First we build the defaulted substitution. @@ -403,30 +384,39 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> { // All regions are identity. fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data())) }, |def, _| { - if !is_our_default(def) { - // We don't want to use non-defaulted params in a substitution, mark as err. - fcx.tcx.types.err - } else { - // Substitute with default. - fcx.tcx.type_of(def.def_id) + // If the param has a default, + if is_our_default(def) { + let default_ty = fcx.tcx.type_of(def.def_id); + // and it's not a dependent default + if !default_ty.needs_subst() { + // then substitute with the default. + return default_ty; + } } + // Mark unwanted params as err. + fcx.tcx.types.err }); // Now we build the substituted predicates. for &pred in predicates.predicates.iter() { + struct CountParams { params: FxHashSet } + impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams { + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + match t.sty { + ty::TyParam(p) => { + self.params.insert(p.idx); + t.super_visit_with(self) + } + _ => t.super_visit_with(self) + } + } + } + let mut param_count = CountParams { params: FxHashSet() }; + pred.visit_with(&mut param_count); let substituted_pred = pred.subst(fcx.tcx, substs); - // If there is a non-defaulted param in the predicate, don't check it. - if substituted_pred.references_error() { + // Don't check non-defaulted params, dependent defaults or preds with multiple params. + if substituted_pred.references_error() || param_count.params.len() > 1 { continue; } - // In trait defs, don't check `Self: Sized` when `Self` is the default. - if let ty::Predicate::Trait(trait_pred) = substituted_pred { - // `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(); - let pred_sized = Some(trait_pred.def_id()) == fcx.tcx.lang_items().sized_trait(); - if is_trait && lhs_is_self && pred_sized { - continue; - } - } // Avoid duplication of predicates that contain no parameters, for example. if !predicates.predicates.contains(&substituted_pred) { substituted_predicates.push(substituted_pred); diff --git a/src/test/run-pass/defaults-well-formedness.rs b/src/test/run-pass/defaults-well-formedness.rs index 60e78e29afd8b..552665bac4e6c 100644 --- a/src/test/run-pass/defaults-well-formedness.rs +++ b/src/test/run-pass/defaults-well-formedness.rs @@ -14,12 +14,15 @@ struct Foo(U, V) where U: Trait; trait Marker {} struct TwoParams(T, U); impl Marker for TwoParams {} -// Check that defaults are substituted simultaneously. + +// Clauses with more than 1 param are not checked. struct IndividuallyBogus(TwoParams) where TwoParams: Marker; +struct BogusTogether(T, U) where TwoParams: Marker; // Clauses with non-defaulted params are not checked. struct NonDefaultedInClause(TwoParams) where TwoParams: Marker; struct DefaultedLhs(U, V) where V: Trait; -// Dependent defaults. -struct Dependent(T, U) where U: Copy; +// Dependent defaults are not checked. +struct Dependent(T, U) where U: Copy; +trait SelfBound {} fn main() {} diff --git a/src/test/ui/type-check-defaults.rs b/src/test/ui/type-check-defaults.rs index d57b39464806a..65560df9f21f2 100644 --- a/src/test/ui/type-check-defaults.rs +++ b/src/test/ui/type-check-defaults.rs @@ -30,25 +30,11 @@ struct WhereClause(T) where T: Copy; trait TraitBound {} //~^ error: the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] -trait SelfBound {} -//~^ error: the trait bound `Self: std::marker::Copy` is not satisfied [E0277] - trait Super { } trait Base: Super { } //~^ error: the trait bound `T: std::marker::Copy` is not satisfied [E0277] trait ProjectionPred> where T::Item : Add {} -//~^ error: the trait bound `i32: std::ops::Add` is not satisfied [E0277] - -// Defaults must work together. -struct TwoParams(T, U) where T: Bar; -//~^ the trait bound `u32: Bar` is not satisfied [E0277] -trait Bar {} -impl Bar for u32 { } -impl Bar for String { } - -// Dependent defaults. -struct Dependent(T, U) where U: Copy; -//~^ the trait bound `T: std::marker::Copy` is not satisfied [E0277] +//~^ error: cannot add `u8` to `i32` [E0277] fn main() { } diff --git a/src/test/ui/type-check-defaults.stderr b/src/test/ui/type-check-defaults.stderr index 032e80cdb1485..c73c0792f8e7c 100644 --- a/src/test/ui/type-check-defaults.stderr +++ b/src/test/ui/type-check-defaults.stderr @@ -25,13 +25,14 @@ note: required by `Foo` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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::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: 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 @@ -57,59 +58,27 @@ error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not sa | = 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 {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 - --> $DIR/type-check-defaults.rs:37:1 + --> $DIR/type-check-defaults.rs:34:1 | -37 | trait Base: Super { } +34 | trait Base: Super { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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:36:1 + --> $DIR/type-check-defaults.rs:33:1 | -36 | trait Super { } +33 | trait Super { } | ^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `i32: std::ops::Add` is not satisfied - --> $DIR/type-check-defaults.rs:40:1 +error[E0277]: cannot add `u8` to `i32` + --> $DIR/type-check-defaults.rs:37:1 | -40 | trait ProjectionPred> where T::Item : Add {} +37 | trait ProjectionPred> where T::Item : Add {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u8` | = help: the trait `std::ops::Add` is not implemented for `i32` = note: required by `std::ops::Add` -error[E0277]: the trait bound `u32: Bar` is not satisfied - --> $DIR/type-check-defaults.rs:44:1 - | -44 | struct TwoParams(T, U) where T: Bar; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `u32` - | - = help: the following implementations were found: - > -note: required by `Bar` - --> $DIR/type-check-defaults.rs:46:1 - | -46 | trait Bar {} - | ^^^^^^^^^^^^ - -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied - --> $DIR/type-check-defaults.rs:51:1 - | -51 | struct Dependent(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 +error: aborting due to 8 previous errors