diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 84823b0fd57da..8856a68e86e1c 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -77,6 +77,14 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { enum_variants(fcx, enum_def) }); } + ast::ItemTrait(..) => { + let trait_def = + ty::lookup_trait_def(ccx.tcx, local_def(item.id)); + reject_non_type_param_bounds( + ccx.tcx, + item.span, + &trait_def.generics); + } _ => {} } } @@ -237,21 +245,32 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { fn reject_non_type_param_bounds<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, generics: &ty::Generics<'tcx>) { + for predicate in generics.predicates.iter() { match predicate { &ty::Predicate::Trait(ty::Binder(ref tr)) => { - let self_ty = tr.self_ty(); - if !self_ty.walk().any(|t| is_ty_param(t)) { - tcx.sess.span_err( - span, - format!("cannot bound type `{}`, where clause \ - bounds may only be attached to types involving \ - type parameters", - self_ty.repr(tcx)).as_slice()) - } + let found_param = tr.input_types().iter() + .flat_map(|ty| ty.walk()) + .any(is_ty_param); + if !found_param { report_bound_error(tcx, span, tr.self_ty() )} + } + &ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(ty, _))) => { + let found_param = ty.walk().any(|t| is_ty_param(t)); + if !found_param { report_bound_error(tcx, span, ty) } } _ => {} - } + }; + } + + fn report_bound_error<'t>(tcx: &ty::ctxt<'t>, + span: Span, + bounded_ty: ty::Ty<'t>) { + tcx.sess.span_err( + span, + format!("cannot bound type `{}`, where clause \ + bounds may only be attached to types involving \ + type parameters", + bounded_ty.repr(tcx)).as_slice()) } fn is_ty_param(ty: ty::Ty) -> bool { @@ -267,6 +286,25 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> { self.check_item_well_formed(i); visit::walk_item(self, i); } + + fn visit_trait_item(&mut self, t: &'v ast::TraitItem) { + match t { + &ast::TraitItem::ProvidedMethod(_) | + &ast::TraitItem::TypeTraitItem(_) => {}, + &ast::TraitItem::RequiredMethod(ref method) => { + match ty::impl_or_trait_item(self.ccx.tcx, local_def(method.id)) { + ty::ImplOrTraitItem::MethodTraitItem(ty_method) => { + reject_non_type_param_bounds( + self.ccx.tcx, + method.span, + &ty_method.generics) + } + _ => {} + }; + } + }; + visit::walk_trait_item(self, t); + } } pub struct BoundsChecker<'cx,'tcx:'cx> { @@ -455,7 +493,6 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let arg_tys = ty::assert_no_late_bound_regions( fcx.tcx(), &ty::ty_fn_args(ctor_ty)); - AdtVariant { fields: args.iter().enumerate().map(|(index, arg)| { let arg_ty = arg_tys[index]; diff --git a/src/test/compile-fail/where-clauses-not-parameter.rs b/src/test/compile-fail/where-clauses-not-parameter.rs index 148473f898798..d8af859c081e9 100644 --- a/src/test/compile-fail/where-clauses-not-parameter.rs +++ b/src/test/compile-fail/where-clauses-not-parameter.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn equal(_: &T, _: &T) -> bool where int : Eq { +fn equal(_: &T, _: &T) -> bool where isize : Eq { true //~^ ERROR cannot bound type `isize`, where clause bounds may only be attached } @@ -16,24 +16,26 @@ fn equal(_: &T, _: &T) -> bool where int : Eq { fn test() -> bool where Option : Eq {} // This should be rejected as well. -fn test2() -> bool where Option : Eq {} -//~^ ERROR cannot bound type `core::option::Option`, where clause bounds +fn test2() -> bool where Option : Eq {} +//~^ ERROR cannot bound type `core::option::Option`, where clause bounds may #[derive(PartialEq)] //~^ ERROR cannot bound type `isize`, where clause bounds -enum Foo where int : Eq { MkFoo } +enum Foo where isize : Eq { MkFoo } //~^ ERROR cannot bound type `isize`, where clause bounds fn test3() -> bool where Option> : Eq {} -fn test4() -> bool where Option> : Eq {} +fn test4() -> bool where Option> : Eq {} //~^ ERROR cannot bound type `core::option::Option>`, where clause bounds -trait Baz where int : Eq { - fn baz() where String : Eq; +trait Baz where isize : Eq { + //~^ ERROR cannot bound type `isize`, where clause bounds may only + fn baz() where String : Eq; //~ ERROR cannot bound type `collections::string::String` + //~^ ERROR cannot bound type `isize`, where clause } -impl Baz for int where int : Eq { +impl Baz for int where isize : Eq { //~^ ERROR cannot bound type `isize`, where clause bounds fn baz() where String : Eq {} }