about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libcollections/btree/node.rs3
-rw-r--r--src/libcollections/lib.rs1
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/lint/builtin.rs1
-rw-r--r--src/librustc/util/ppaux.rs1
-rw-r--r--src/librustc_typeck/collect.rs100
-rw-r--r--src/libserialize/collection_impls.rs4
-rw-r--r--src/libserialize/lib.rs1
-rw-r--r--src/libstd/collections/hash/map.rs10
-rw-r--r--src/libstd/collections/hash/set.rs15
-rw-r--r--src/libstd/io/mod.rs1
-rw-r--r--src/libstd/lib.rs1
-rw-r--r--src/libsyntax/ast.rs4
-rw-r--r--src/libsyntax/feature_gate.rs10
-rw-r--r--src/test/auxiliary/nested_item.rs8
-rw-r--r--src/test/compile-fail/coherence-all-remote.rs4
-rw-r--r--src/test/compile-fail/impl-unused-tps-inherent.rs35
-rw-r--r--src/test/compile-fail/impl-unused-tps.rs72
-rw-r--r--src/test/compile-fail/issue-12028.rs19
-rw-r--r--src/test/compile-fail/issue-13853-5.rs2
-rw-r--r--src/test/compile-fail/issue-16562.rs2
-rw-r--r--src/test/run-pass/issue-3743.rs12
22 files changed, 283 insertions, 24 deletions
diff --git a/src/libcollections/btree/node.rs b/src/libcollections/btree/node.rs
index a764264fd1e..82d8dc286ee 100644
--- a/src/libcollections/btree/node.rs
+++ b/src/libcollections/btree/node.rs
@@ -1417,7 +1417,7 @@ pub type MutTraversal<'a, K, V> = AbsTraversal<ElemsAndEdges<Zip<slice::Iter<'a,
 /// An owning traversal over a node's entries and edges
 pub type MoveTraversal<K, V> = AbsTraversal<MoveTraversalImpl<K, V>>;
 
-
+#[old_impl_check]
 impl<K, V, E, Impl: TraversalImpl<K, V, E>> Iterator for AbsTraversal<Impl> {
     type Item = TraversalItem<K, V, E>;
 
@@ -1433,6 +1433,7 @@ impl<K, V, E, Impl: TraversalImpl<K, V, E>> Iterator for AbsTraversal<Impl> {
     }
 }
 
+#[old_impl_check]
 impl<K, V, E, Impl: TraversalImpl<K, V, E>> DoubleEndedIterator for AbsTraversal<Impl> {
     fn next_back(&mut self) -> Option<TraversalItem<K, V, E>> {
         let tail_is_edge = self.tail_is_edge;
diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs
index 82dfa41d9d8..64005e89dde 100644
--- a/src/libcollections/lib.rs
+++ b/src/libcollections/lib.rs
@@ -22,6 +22,7 @@
        html_playground_url = "http://play.rust-lang.org/")]
 
 #![feature(unsafe_destructor, slicing_syntax)]
+#![feature(old_impl_check)]
 #![no_std]
 
 #[macro_use]
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 0aebbf2970f..1a5746e8e12 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -25,6 +25,7 @@
 #![feature(quote)]
 #![feature(slicing_syntax, unsafe_destructor)]
 #![feature(rustc_diagnostic_macros)]
+#![feature(old_impl_check)]
 
 extern crate arena;
 extern crate flate;
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 0adf46cae07..1af8e2f29eb 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -669,6 +669,7 @@ impl LintPass for UnusedAttributes {
 
             // FIXME: #19470 this shouldn't be needed forever
             "old_orphan_check",
+            "old_impl_check",
         ];
 
         static CRATE_ATTRS: &'static [&'static str] = &[
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index ded8713079a..2d433369366 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -1350,6 +1350,7 @@ impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for ty::Binder<T> {
     }
 }
 
+#[old_impl_check]
 impl<'tcx, S, H, K, V> Repr<'tcx> for HashMap<K,V,H>
     where K : Hash<S> + Eq + Repr<'tcx>,
           V : Repr<'tcx>,
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 7c13696118a..d106a380222 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -35,7 +35,7 @@ use middle::lang_items::SizedTraitLangItem;
 use middle::region;
 use middle::resolve_lifetime;
 use middle::subst;
-use middle::subst::{Substs};
+use middle::subst::{Substs, TypeSpace};
 use middle::ty::{AsPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer};
 use middle::ty::{self, RegionEscape, Ty, TypeScheme};
 use middle::ty_fold::{self, TypeFolder, TypeFoldable};
@@ -47,6 +47,7 @@ use util::ppaux;
 use util::ppaux::{Repr,UserString};
 use write_ty_to_tcx;
 
+use std::collections::HashSet;
 use std::rc::Rc;
 
 use syntax::abi;
@@ -644,6 +645,10 @@ fn convert(ccx: &CollectCtxt, it: &ast::Item) {
                                                Some(selfty),
                                                None);
             }
+
+            enforce_impl_ty_params_are_constrained(ccx.tcx,
+                                                   generics,
+                                                   local_def(it.id));
         },
         ast::ItemTrait(_, _, _, ref trait_methods) => {
             let trait_def = trait_def_of_item(ccx, it);
@@ -1605,3 +1610,96 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
         })
     }
 }
+
+/// Checks that all the type parameters on an impl
+fn enforce_impl_ty_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
+                                                ast_generics: &ast::Generics,
+                                                impl_def_id: ast::DefId)
+{
+    let impl_scheme = ty::lookup_item_type(tcx, impl_def_id);
+    let impl_trait_ref = ty::impl_trait_ref(tcx, impl_def_id);
+
+    // The trait reference is an input, so find all type parameters
+    // reachable from there, to start (if this is an inherent impl,
+    // then just examine the self type).
+    let mut input_parameters: HashSet<_> =
+        impl_trait_ref.iter()
+                      .flat_map(|t| t.input_types().iter()) // Types in trait ref, if any
+                      .chain(Some(impl_scheme.ty).iter())  // Self type, always
+                      .flat_map(|t| t.walk())
+                      .filter_map(to_opt_param_ty)
+                      .collect();
+
+    loop {
+        let num_inputs = input_parameters.len();
+
+        let mut projection_predicates =
+            impl_scheme.generics.predicates
+            .iter()
+            .filter_map(|predicate| {
+                match *predicate {
+                    // Ignore higher-ranked binders. For the purposes
+                    // of this check, they don't matter because they
+                    // only affect named regions, and we're just
+                    // concerned about type parameters here.
+                    ty::Predicate::Projection(ref data) => Some(data.0.clone()),
+                    _ => None,
+                }
+            });
+
+        for projection in projection_predicates {
+            // Special case: watch out for some kind of sneaky attempt
+            // to project out an associated type defined by this very trait.
+            if Some(projection.projection_ty.trait_ref.clone()) == impl_trait_ref {
+                continue;
+            }
+
+            let relies_only_on_inputs =
+                projection.projection_ty.trait_ref.input_types().iter()
+                .flat_map(|t| t.walk())
+                .filter_map(to_opt_param_ty)
+                .all(|t| input_parameters.contains(&t));
+
+            if relies_only_on_inputs {
+                input_parameters.extend(
+                    projection.ty.walk().filter_map(to_opt_param_ty));
+            }
+        }
+
+        if input_parameters.len() == num_inputs {
+            break;
+        }
+    }
+
+    for (index, ty_param) in ast_generics.ty_params.iter().enumerate() {
+        let param_ty = ty::ParamTy { space: TypeSpace,
+                                     idx: index as u32,
+                                     name: ty_param.ident.name };
+        if !input_parameters.contains(&param_ty) {
+            if ty::has_attr(tcx, impl_def_id, "old_impl_check") {
+                tcx.sess.span_warn(
+                    ty_param.span,
+                    format!("the type parameter `{}` is not constrained by the \
+                             impl trait, self type, or predicates",
+                            param_ty.user_string(tcx)).as_slice());
+            } else {
+                tcx.sess.span_err(
+                    ty_param.span,
+                    format!("the type parameter `{}` is not constrained by the \
+                             impl trait, self type, or predicates",
+                            param_ty.user_string(tcx)).as_slice());
+                tcx.sess.span_help(
+                    ty_param.span,
+                    format!("you can temporarily opt out of this rule by placing \
+                             the `#[old_impl_check]` attribute on the impl").as_slice());
+            }
+        }
+    }
+
+    fn to_opt_param_ty<'tcx>(ty: Ty<'tcx>) -> Option<ty::ParamTy> {
+        match ty.sty {
+            ty::ty_param(ref d) => Some(d.clone()),
+            _ => None,
+        }
+    }
+}
diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs
index 7ba329c518e..d89a4754d2e 100644
--- a/src/libserialize/collection_impls.rs
+++ b/src/libserialize/collection_impls.rs
@@ -156,6 +156,7 @@ impl<
     }
 }
 
+#[old_impl_check]
 impl<
     K: Encodable + Hash<X> + Eq,
     V: Encodable,
@@ -175,6 +176,7 @@ impl<
     }
 }
 
+#[old_impl_check]
 impl<
     K: Decodable + Hash<S> + Eq,
     V: Decodable,
@@ -195,6 +197,7 @@ impl<
     }
 }
 
+#[old_impl_check]
 impl<
     T: Encodable + Hash<X> + Eq,
     X,
@@ -212,6 +215,7 @@ impl<
     }
 }
 
+#[old_impl_check]
 impl<
     T: Decodable + Hash<S> + Eq,
     S,
diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs
index 3dfed466e60..f0a51fcea18 100644
--- a/src/libserialize/lib.rs
+++ b/src/libserialize/lib.rs
@@ -24,6 +24,7 @@ Core encoding and decoding interfaces.
        html_playground_url = "http://play.rust-lang.org/")]
 #![allow(unknown_features)]
 #![feature(slicing_syntax)]
+#![feature(old_impl_check)]
 
 // test harness access
 #[cfg(test)] extern crate test;
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index fdffdaacaba..66287a1eea5 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -439,6 +439,7 @@ impl<K, V, M> SearchResult<K, V, M> {
     }
 }
 
+#[old_impl_check]
 impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
     fn make_hash<X: ?Sized + Hash<S>>(&self, x: &X) -> SafeHash {
         table::make_hash(&self.hasher, x)
@@ -517,6 +518,7 @@ impl<K: Hash + Eq, V> HashMap<K, V, RandomSipHasher> {
     }
 }
 
+#[old_impl_check]
 impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
     /// Creates an empty hashmap which will use the given hasher to hash keys.
     ///
@@ -1188,6 +1190,7 @@ fn search_entry_hashed<'a, K: Eq, V>(table: &'a mut RawTable<K,V>, hash: SafeHas
 }
 
 #[stable]
+#[old_impl_check]
 impl<K: Eq + Hash<S>, V: PartialEq, S, H: Hasher<S>> PartialEq for HashMap<K, V, H> {
     fn eq(&self, other: &HashMap<K, V, H>) -> bool {
         if self.len() != other.len() { return false; }
@@ -1199,9 +1202,11 @@ impl<K: Eq + Hash<S>, V: PartialEq, S, H: Hasher<S>> PartialEq for HashMap<K, V,
 }
 
 #[stable]
+#[old_impl_check]
 impl<K: Eq + Hash<S>, V: Eq, S, H: Hasher<S>> Eq for HashMap<K, V, H> {}
 
 #[stable]
+#[old_impl_check]
 impl<K: Eq + Hash<S> + Show, V: Show, S, H: Hasher<S>> Show for HashMap<K, V, H> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         try!(write!(f, "HashMap {{"));
@@ -1216,6 +1221,7 @@ impl<K: Eq + Hash<S> + Show, V: Show, S, H: Hasher<S>> Show for HashMap<K, V, H>
 }
 
 #[stable]
+#[old_impl_check]
 impl<K: Eq + Hash<S>, V, S, H: Hasher<S> + Default> Default for HashMap<K, V, H> {
     #[stable]
     fn default() -> HashMap<K, V, H> {
@@ -1224,6 +1230,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S> + Default> Default for HashMap<K, V, H>
 }
 
 #[stable]
+#[old_impl_check]
 impl<K: Hash<S> + Eq, Q: ?Sized, V, S, H: Hasher<S>> Index<Q> for HashMap<K, V, H>
     where Q: BorrowFrom<K> + Hash<S> + Eq
 {
@@ -1236,6 +1243,7 @@ impl<K: Hash<S> + Eq, Q: ?Sized, V, S, H: Hasher<S>> Index<Q> for HashMap<K, V,
 }
 
 #[stable]
+#[old_impl_check]
 impl<K: Hash<S> + Eq, Q: ?Sized, V, S, H: Hasher<S>> IndexMut<Q> for HashMap<K, V, H>
     where Q: BorrowFrom<K> + Hash<S> + Eq
 {
@@ -1465,6 +1473,7 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
 }
 
 #[stable]
+#[old_impl_check]
 impl<K: Eq + Hash<S>, V, S, H: Hasher<S> + Default> FromIterator<(K, V)> for HashMap<K, V, H> {
     fn from_iter<T: Iterator<Item=(K, V)>>(iter: T) -> HashMap<K, V, H> {
         let lower = iter.size_hint().0;
@@ -1475,6 +1484,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S> + Default> FromIterator<(K, V)> for Has
 }
 
 #[stable]
+#[old_impl_check]
 impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> Extend<(K, V)> for HashMap<K, V, H> {
     fn extend<T: Iterator<Item=(K, V)>>(&mut self, mut iter: T) {
         for (k, v) in iter {
diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs
index e598923f11c..a2ffb9cb213 100644
--- a/src/libstd/collections/hash/set.rs
+++ b/src/libstd/collections/hash/set.rs
@@ -125,6 +125,7 @@ impl<T: Hash + Eq> HashSet<T, RandomSipHasher> {
     }
 }
 
+#[old_impl_check]
 impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
     /// Creates a new empty hash set which will use the given hasher to hash
     /// keys.
@@ -568,6 +569,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
 }
 
 #[stable]
+#[old_impl_check]
 impl<T: Eq + Hash<S>, S, H: Hasher<S>> PartialEq for HashSet<T, H> {
     fn eq(&self, other: &HashSet<T, H>) -> bool {
         if self.len() != other.len() { return false; }
@@ -577,9 +579,11 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> PartialEq for HashSet<T, H> {
 }
 
 #[stable]
+#[old_impl_check]
 impl<T: Eq + Hash<S>, S, H: Hasher<S>> Eq for HashSet<T, H> {}
 
 #[stable]
+#[old_impl_check]
 impl<T: Eq + Hash<S> + fmt::Show, S, H: Hasher<S>> fmt::Show for HashSet<T, H> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         try!(write!(f, "HashSet {{"));
@@ -594,6 +598,7 @@ impl<T: Eq + Hash<S> + fmt::Show, S, H: Hasher<S>> fmt::Show for HashSet<T, H> {
 }
 
 #[stable]
+#[old_impl_check]
 impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> FromIterator<T> for HashSet<T, H> {
     fn from_iter<I: Iterator<Item=T>>(iter: I) -> HashSet<T, H> {
         let lower = iter.size_hint().0;
@@ -604,6 +609,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> FromIterator<T> for HashSet<T,
 }
 
 #[stable]
+#[old_impl_check]
 impl<T: Eq + Hash<S>, S, H: Hasher<S>> Extend<T> for HashSet<T, H> {
     fn extend<I: Iterator<Item=T>>(&mut self, mut iter: I) {
         for k in iter {
@@ -613,6 +619,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> Extend<T> for HashSet<T, H> {
 }
 
 #[stable]
+#[old_impl_check]
 impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> Default for HashSet<T, H> {
     #[stable]
     fn default() -> HashSet<T, H> {
@@ -621,6 +628,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> Default for HashSet<T, H> {
 }
 
 #[stable]
+#[old_impl_check]
 impl<'a, 'b, T: Eq + Hash<S> + Clone, S, H: Hasher<S> + Default>
 BitOr<&'b HashSet<T, H>> for &'a HashSet<T, H> {
     type Output = HashSet<T, H>;
@@ -651,6 +659,7 @@ BitOr<&'b HashSet<T, H>> for &'a HashSet<T, H> {
 }
 
 #[stable]
+#[old_impl_check]
 impl<'a, 'b, T: Eq + Hash<S> + Clone, S, H: Hasher<S> + Default>
 BitAnd<&'b HashSet<T, H>> for &'a HashSet<T, H> {
     type Output = HashSet<T, H>;
@@ -681,6 +690,7 @@ BitAnd<&'b HashSet<T, H>> for &'a HashSet<T, H> {
 }
 
 #[stable]
+#[old_impl_check]
 impl<'a, 'b, T: Eq + Hash<S> + Clone, S, H: Hasher<S> + Default>
 BitXor<&'b HashSet<T, H>> for &'a HashSet<T, H> {
     type Output = HashSet<T, H>;
@@ -711,6 +721,7 @@ BitXor<&'b HashSet<T, H>> for &'a HashSet<T, H> {
 }
 
 #[stable]
+#[old_impl_check]
 impl<'a, 'b, T: Eq + Hash<S> + Clone, S, H: Hasher<S> + Default>
 Sub<&'b HashSet<T, H>> for &'a HashSet<T, H> {
     type Output = HashSet<T, H>;
@@ -813,6 +824,7 @@ impl<'a, K: 'a> Iterator for Drain<'a, K> {
 }
 
 #[stable]
+#[old_impl_check]
 impl<'a, T, S, H> Iterator for Intersection<'a, T, H>
     where T: Eq + Hash<S>, H: Hasher<S>
 {
@@ -836,6 +848,7 @@ impl<'a, T, S, H> Iterator for Intersection<'a, T, H>
 }
 
 #[stable]
+#[old_impl_check]
 impl<'a, T, S, H> Iterator for Difference<'a, T, H>
     where T: Eq + Hash<S>, H: Hasher<S>
 {
@@ -859,6 +872,7 @@ impl<'a, T, S, H> Iterator for Difference<'a, T, H>
 }
 
 #[stable]
+#[old_impl_check]
 impl<'a, T, S, H> Iterator for SymmetricDifference<'a, T, H>
     where T: Eq + Hash<S>, H: Hasher<S>
 {
@@ -869,6 +883,7 @@ impl<'a, T, S, H> Iterator for SymmetricDifference<'a, T, H>
 }
 
 #[stable]
+#[old_impl_check]
 impl<'a, T, S, H> Iterator for Union<'a, T, H>
     where T: Eq + Hash<S>, H: Hasher<S>
 {
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 5de66c02b53..dc9dd7071b1 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -1603,6 +1603,7 @@ pub struct IncomingConnections<'a, A: ?Sized +'a> {
     inc: &'a mut A,
 }
 
+#[old_impl_check]
 impl<'a, T, A: ?Sized + Acceptor<T>> Iterator for IncomingConnections<'a, A> {
     type Item = IoResult<T>;
 
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 25cc574bb5d..660487f3edb 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -107,6 +107,7 @@
 #![feature(linkage, thread_local, asm)]
 #![feature(phase, lang_items, unsafe_destructor)]
 #![feature(slicing_syntax, unboxed_closures)]
+#![feature(old_impl_check)]
 
 // Don't link to std. We are std.
 #![no_std]
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 45233dd5225..beb7246a734 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -979,8 +979,8 @@ pub enum Sign {
     Plus
 }
 
-impl<T> Sign where T: Int {
-    pub fn new(n: T) -> Sign {
+impl Sign {
+    pub fn new<T:Int>(n: T) -> Sign {
         if n < Int::zero() {
             Minus
         } else {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 38a369bdb57..75d231d68b5 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -86,6 +86,9 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
     // A way to temporarily opt out of the new orphan rules. This will *never* be accepted.
     ("old_orphan_check", Deprecated),
 
+    // A way to temporarily opt out of the new impl rules. This will *never* be accepted.
+    ("old_impl_check", Deprecated),
+
     // OIBIT specific features
     ("optin_builtin_traits", Active),
 
@@ -294,6 +297,13 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
                         i.span,
                         "the new orphan check rules will eventually be strictly enforced");
                 }
+
+                if attr::contains_name(i.attrs[],
+                                       "old_impl_check") {
+                    self.gate_feature("old_impl_check",
+                                      i.span,
+                                      "`#[old_impl_check]` will be removed in the future");
+                }
             }
 
             _ => {}
diff --git a/src/test/auxiliary/nested_item.rs b/src/test/auxiliary/nested_item.rs
index 1a2f429c9eb..21784bda27a 100644
--- a/src/test/auxiliary/nested_item.rs
+++ b/src/test/auxiliary/nested_item.rs
@@ -18,8 +18,8 @@ pub fn foo<T>() -> int {
 
 // issue 8134
 struct Foo;
-impl<T> Foo {
-    pub fn foo(&self) {
+impl Foo {
+    pub fn foo<T>(&self) {
         static X: uint = 1;
     }
 }
@@ -33,8 +33,8 @@ impl<T: std::iter::Iterator<Item=char>> Parser<T> {
 }
 
 struct Bar;
-impl<T> Foo {
-    pub fn bar(&self) {
+impl Foo {
+    pub fn bar<T>(&self) {
         static X: uint = 1;
     }
 }
diff --git a/src/test/compile-fail/coherence-all-remote.rs b/src/test/compile-fail/coherence-all-remote.rs
index d88b8751ea7..d86256a7776 100644
--- a/src/test/compile-fail/coherence-all-remote.rs
+++ b/src/test/compile-fail/coherence-all-remote.rs
@@ -11,9 +11,9 @@
 // aux-build:coherence-lib.rs
 
 extern crate "coherence-lib" as lib;
-use lib::Remote;
+use lib::Remote1;
 
-impl<T> Remote for int { }
+impl<T> Remote1<T> for int { }
 //~^ ERROR E0117
 
 fn main() { }
diff --git a/src/test/compile-fail/impl-unused-tps-inherent.rs b/src/test/compile-fail/impl-unused-tps-inherent.rs
new file mode 100644
index 00000000000..3803bb9b045
--- /dev/null
+++ b/src/test/compile-fail/impl-unused-tps-inherent.rs
@@ -0,0 +1,35 @@
+// Copyright 2015 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.
+
+struct MyType;
+
+struct MyType1<T>(T);
+
+trait Bar {
+    type Out;
+}
+
+impl<T> MyType {
+    //~^ ERROR  the type parameter `T` is not constrained
+}
+
+impl<T> MyType1<T> {
+    // OK, T is used in `Foo<T>`.
+}
+
+impl<T,U> MyType1<T> {
+    //~^ ERROR  the type parameter `U` is not constrained
+}
+
+impl<T,U> MyType1<T> where T: Bar<Out=U> {
+    // OK, T is used in `Foo<T>`.
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/impl-unused-tps.rs b/src/test/compile-fail/impl-unused-tps.rs
new file mode 100644
index 00000000000..99c6c6b8985
--- /dev/null
+++ b/src/test/compile-fail/impl-unused-tps.rs
@@ -0,0 +1,72 @@
+// Copyright 2015 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.
+
+trait Foo<A> {
+    fn get(&self, A: &A) { }
+}
+
+trait Bar {
+    type Out;
+}
+
+impl<T> Foo<T> for [int;0] {
+    // OK, T is used in `Foo<T>`.
+}
+
+impl<T,U> Foo<T> for [int;1] {
+    //~^ ERROR the type parameter `U` is not constrained
+}
+
+impl<T,U> Foo<T> for [int;2] where T : Bar<Out=U> {
+    // OK, `U` is now constrained by the output type parameter.
+}
+
+impl<T:Bar<Out=U>,U> Foo<T> for [int;3] {
+    // OK, same as above but written differently.
+}
+
+impl<T,U> Foo<T> for U {
+    // OK, T, U are used everywhere. Note that the coherence check
+    // hasn't executed yet, so no errors about overlap.
+}
+
+impl<T,U> Bar for T {
+    //~^ ERROR the type parameter `U` is not constrained
+
+    type Out = U;
+
+    // Using `U` in an associated type within the impl is not good enough!
+}
+
+impl<T,U> Bar for T
+    where T : Bar<Out=U>
+{
+    //~^^^ ERROR the type parameter `U` is not constrained
+
+    // This crafty self-referential attempt is still no good.
+}
+
+impl<T,U,V> Foo<T> for T
+    where (T,U): Bar<Out=V>
+{
+    //~^^^ ERROR the type parameter `U` is not constrained
+    //~|   ERROR the type parameter `V` is not constrained
+
+    // Here, `V` is bound by an output type parameter, but the inputs
+    // are not themselves constrained.
+}
+
+impl<T,U,V> Foo<(T,U)> for T
+    where (T,U): Bar<Out=V>
+{
+    // As above, but both T and U ARE constrained.
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/issue-12028.rs b/src/test/compile-fail/issue-12028.rs
index 78502efdec5..24ffc5e9ee3 100644
--- a/src/test/compile-fail/issue-12028.rs
+++ b/src/test/compile-fail/issue-12028.rs
@@ -22,27 +22,28 @@ trait Stream {
     fn result(&self) -> u64;
 }
 
-trait StreamHasher<S: Stream> {
-    fn stream(&self) -> S;
+trait StreamHasher {
+    type S : Stream;
+    fn stream(&self) -> Self::S;
 }
 
 //////////////////////////////////////////////////////////////////////////////
 
-trait StreamHash<S: Stream, H: StreamHasher<S>>: Hash<H> {
-    fn input_stream(&self, stream: &mut S);
+trait StreamHash<H: StreamHasher>: Hash<H> {
+    fn input_stream(&self, stream: &mut H::S);
 }
 
-impl<S: Stream, H: StreamHasher<S>> Hash<H> for u8 {
+impl<H: StreamHasher> Hash<H> for u8 {
     fn hash2(&self, hasher: &H) -> u64 {
         let mut stream = hasher.stream();
         self.input_stream(&mut stream); //~ ERROR type annotations required
-        stream.result()
+        Stream::result(&stream)
     }
 }
 
-impl<S: Stream, H: StreamHasher<S>> StreamHash<S, H> for u8 {
-    fn input_stream(&self, stream: &mut S) {
-        stream.input(&[*self]);
+impl<H: StreamHasher> StreamHash<H> for u8 {
+    fn input_stream(&self, stream: &mut H::S) {
+        Stream::input(&*stream, &[*self]);
     }
 }
 
diff --git a/src/test/compile-fail/issue-13853-5.rs b/src/test/compile-fail/issue-13853-5.rs
index b3a4f341f84..6a017f7bb30 100644
--- a/src/test/compile-fail/issue-13853-5.rs
+++ b/src/test/compile-fail/issue-13853-5.rs
@@ -15,7 +15,7 @@ trait Deserializable {
 }
 
 impl<'a, T: Deserializable> Deserializable for &'a str {
-    //~^ ERROR unable to infer enough type information
+    //~^ ERROR type parameter `T` is not constrained
     fn deserialize_token<D: Deserializer<'a>>(_x: D, _y: &'a str) -> &'a str {
     }
 }
diff --git a/src/test/compile-fail/issue-16562.rs b/src/test/compile-fail/issue-16562.rs
index 3c784c3b770..626a442a2c3 100644
--- a/src/test/compile-fail/issue-16562.rs
+++ b/src/test/compile-fail/issue-16562.rs
@@ -18,7 +18,7 @@ struct Col<D, C> {
 trait Collection { fn len(&self) -> uint; }
 
 impl<T, M: MatrixShape> Collection for Col<M, uint> {
-//~^ ERROR unable to infer enough type information
+//~^ ERROR type parameter `T` is not constrained
     fn len(&self) -> uint {
         unimplemented!()
     }
diff --git a/src/test/run-pass/issue-3743.rs b/src/test/run-pass/issue-3743.rs
index 43852fb3324..382ea0c5758 100644
--- a/src/test/run-pass/issue-3743.rs
+++ b/src/test/run-pass/issue-3743.rs
@@ -30,17 +30,23 @@ impl Vec2 {
 }
 
 // Right-hand-side operator visitor pattern
-trait RhsOfVec2Mul<Result> { fn mul_vec2_by(&self, lhs: &Vec2) -> Result; }
+trait RhsOfVec2Mul {
+    type Result;
+
+    fn mul_vec2_by(&self, lhs: &Vec2) -> Self::Result;
+}
 
 // Vec2's implementation of Mul "from the other side" using the above trait
-impl<Res, Rhs: RhsOfVec2Mul<Res>> Mul<Rhs> for Vec2 {
+impl<Res, Rhs: RhsOfVec2Mul<Result=Res>> Mul<Rhs> for Vec2 {
     type Output = Res;
 
     fn mul(self, rhs: Rhs) -> Res { rhs.mul_vec2_by(&self) }
 }
 
 // Implementation of 'f64 as right-hand-side of Vec2::Mul'
-impl RhsOfVec2Mul<Vec2> for f64 {
+impl RhsOfVec2Mul for f64 {
+    type Result = Vec2;
+
     fn mul_vec2_by(&self, lhs: &Vec2) -> Vec2 { lhs.vmul(*self) }
 }