about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_typeck/check/wf.rs39
-rw-r--r--src/test/compile-fail/where-clauses-not-parameter.rs29
-rw-r--r--src/test/run-pass/where-clauses-not-parameter.rs17
3 files changed, 59 insertions, 26 deletions
diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs
index d4a5bda5f97..329ae85082f 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 9e81703787f..61ef2dd36fc 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, _: &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<T: Eq>() -> bool where Option<T> : Eq {}
+
+// This should be rejected as well.
+fn test2() -> bool where Option<int> : Eq {}
 
-trait U {}
+#[derive(PartialEq)]
+//~^ ERROR cannot bound type `int`, where clause bounds
+enum Foo<T> where int : Eq { MkFoo }
 
-// impl U for A {}
+fn test3<T: Eq>() -> bool where Option<Foo<T>> : Eq {}
+
+fn test4() -> bool where Option<Foo<int>> : Eq {}
+//~^ ERROR cannot bound type `core::option::Option<Foo<int>>`, where clause bounds
+
+trait Baz<T> where int : Eq {
+    fn baz() where String : Eq;
+}
 
-fn equal<T>(_: &T, _: &T) -> bool where A : U {
-    true
+impl Baz<int> 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 bc5fc388ca1..00000000000
--- 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn equal<T>(_: &T, _: &T) -> bool where int : Eq {
-    true
-}
-
-fn main() {
-    equal(&0i, &0i);
-}