diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index d4a5bda5f97f9..329ae85082f5f 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -86,13 +86,14 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { { let ccx = self.ccx; let item_def_id = local_def(item.id); - let polytype = ty::lookup_item_type(ccx.tcx, item_def_id); + let type_scheme = ty::lookup_item_type(ccx.tcx, item_def_id); + reject_non_type_param_bounds(ccx.tcx, item.span, &type_scheme.generics); let param_env = ty::construct_parameter_environment(ccx.tcx, - &polytype.generics, + &type_scheme.generics, item.id); let inh = Inherited::new(ccx.tcx, param_env); - let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(polytype.ty), item.id); + let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(type_scheme.ty), item.id); f(self, &fcx); vtable::select_all_fcx_obligations_or_error(&fcx); regionck::regionck_item(&fcx, item); @@ -143,10 +144,12 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { item.span, region::CodeExtent::from_node_id(item.id), Some(&mut this.cache)); + let type_scheme = ty::lookup_item_type(fcx.tcx(), local_def(item.id)); let item_ty = fcx.instantiate_type_scheme(item.span, &fcx.inh.param_env.free_substs, &type_scheme.ty); + bounds_checker.check_traits_in_ty(item_ty); }); } @@ -178,6 +181,7 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { None => { return; } Some(t) => { t } }; + let trait_ref = fcx.instantiate_type_scheme(item.span, &fcx.inh.param_env.free_substs, &trait_ref); @@ -229,6 +233,35 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { } } +// Reject any predicates that do not involve a type parameter. +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()) + } + } + _ => {} + } + } + + fn is_ty_param(ty: ty::Ty) -> bool { + match &ty.sty { + &ty::sty::ty_param(_) => true, + _ => false + } + } +} + impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> { fn visit_item(&mut self, i: &ast::Item) { self.check_item_well_formed(i); diff --git a/src/test/compile-fail/where-clauses-not-parameter.rs b/src/test/compile-fail/where-clauses-not-parameter.rs index 9e81703787f3e..61ef2dd36fcdc 100644 --- a/src/test/compile-fail/where-clauses-not-parameter.rs +++ b/src/test/compile-fail/where-clauses-not-parameter.rs @@ -8,17 +8,34 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct A; +fn equal(_: &T, _: &T) -> bool where int : Eq { + true //~^ ERROR cannot bound type `int`, where clause bounds may only be attached +} + +// This should be fine involves a type parameter. +fn test() -> bool where Option : Eq {} + +// This should be rejected as well. +fn test2() -> bool where Option : Eq {} -trait U {} +#[derive(PartialEq)] +//~^ ERROR cannot bound type `int`, where clause bounds +enum Foo where int : Eq { MkFoo } -// impl U for A {} +fn test3() -> 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; +} -fn equal(_: &T, _: &T) -> bool where A : U { - true +impl Baz for int where int : Eq { + //~^ ERROR cannot bound type `int`, where clause bounds + fn baz() where String : Eq {} } fn main() { equal(&0i, &0i); - //~^ ERROR the trait `U` is not implemented for the type `A` } diff --git a/src/test/run-pass/where-clauses-not-parameter.rs b/src/test/run-pass/where-clauses-not-parameter.rs deleted file mode 100644 index bc5fc388ca1ea..0000000000000 --- a/src/test/run-pass/where-clauses-not-parameter.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn equal(_: &T, _: &T) -> bool where int : Eq { - true -} - -fn main() { - equal(&0i, &0i); -}