about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2016-10-19 10:45:49 -0400
committerNiko Matsakis <niko@alum.mit.edu>2016-11-01 14:08:56 -0400
commit222349931eec0b0b68b31b2b8b01e162cee23b85 (patch)
treefede728e910513b80fdfaad4196c604ee230fd0b
parentb6597528bda5170241a46248d4ec969bd4717a0b (diff)
downloadrust-222349931eec0b0b68b31b2b8b01e162cee23b85.tar.gz
rust-222349931eec0b0b68b31b2b8b01e162cee23b85.zip
apply review feedback nits
- correct indentation
- rename `from_cause` to `from_obligation_cause`
- break up `compare_impl_method` into fns
- delete some blank lines and correct comment
-rw-r--r--src/librustc/infer/mod.rs10
-rw-r--r--src/librustc/traits/util.rs3
-rw-r--r--src/librustc_typeck/check/compare_method.rs738
-rw-r--r--src/librustc_typeck/check/regionck.rs3
4 files changed, 412 insertions, 342 deletions
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 56dc52d6103..fc91f17b8f6 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -1172,7 +1172,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.commit_if_ok(|snapshot| {
             let (ty::OutlivesPredicate(r_a, r_b), skol_map) =
                 self.skolemize_late_bound_regions(predicate, snapshot);
-            let origin = SubregionOrigin::from_cause(cause, || RelateRegionParamBound(cause.span));
+            let origin =
+                SubregionOrigin::from_obligation_cause(cause,
+                                                       || RelateRegionParamBound(cause.span));
             self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b`
             self.leak_check(false, cause.span, &skol_map, snapshot)?;
             Ok(self.pop_skolemized(skol_map, snapshot))
@@ -1809,9 +1811,9 @@ impl<'tcx> SubregionOrigin<'tcx> {
         }
     }
 
-    pub fn from_cause<F>(cause: &traits::ObligationCause<'tcx>,
-                         default: F)
-                         -> Self
+    pub fn from_obligation_cause<F>(cause: &traits::ObligationCause<'tcx>,
+                                    default: F)
+                                    -> Self
         where F: FnOnce() -> Self
     {
         match cause.code {
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index 0c5ff3cd279..a3d974216b6 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -1,4 +1,3 @@
-
 // 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.
@@ -185,7 +184,7 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
                 // `'a: 'b`.
 
                 // Ignore `for<'a> T: 'a` -- we might in the future
-                // consider this as evidence that `Foo: 'static`, but
+                // consider this as evidence that `T: 'static`, but
                 // I'm a bit wary of such constructions and so for now
                 // I want to be conservative. --nmatsakis
                 let ty_max = data.skip_binder().0;
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 19966d3ee86..6f450f57275 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -15,6 +15,7 @@ use rustc::traits::{self, Reveal};
 use rustc::ty::error::{ExpectedFound, TypeError};
 use rustc::ty::subst::{Subst, Substs};
 use rustc::hir::{ImplItemKind, TraitItem_, Ty_};
+use rustc::util::common::ErrorReported;
 
 use syntax::ast;
 use syntax_pos::Span;
@@ -45,185 +46,51 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     debug!("compare_impl_method(impl_trait_ref={:?})",
            impl_trait_ref);
 
-    debug!("compare_impl_method: impl_trait_ref (liberated) = {:?}",
-           impl_trait_ref);
-
-    let tcx = ccx.tcx;
-
-    let trait_to_impl_substs = &impl_trait_ref.substs;
-
-    // Try to give more informative error messages about self typing
-    // mismatches.  Note that any mismatch will also be detected
-    // below, where we construct a canonical function type that
-    // includes the self parameter as a normal parameter.  It's just
-    // that the error messages you get out of this code are a bit more
-    // inscrutable, particularly for cases where one method has no
-    // self.
-    match (&trait_m.explicit_self, &impl_m.explicit_self) {
-        (&ty::ExplicitSelfCategory::Static, &ty::ExplicitSelfCategory::Static) => {}
-        (&ty::ExplicitSelfCategory::Static, _) => {
-            let mut err = struct_span_err!(tcx.sess,
-                                           impl_m_span,
-                                           E0185,
-                                           "method `{}` has a `{}` declaration in the impl, but \
-                                            not in the trait",
-                                           trait_m.name,
-                                           impl_m.explicit_self);
-            err.span_label(impl_m_span,
-                           &format!("`{}` used in impl", impl_m.explicit_self));
-            if let Some(span) = tcx.map.span_if_local(trait_m.def_id) {
-                err.span_label(span,
-                               &format!("trait declared without `{}`", impl_m.explicit_self));
-            }
-            err.emit();
-            return;
-        }
-        (_, &ty::ExplicitSelfCategory::Static) => {
-            let mut err = struct_span_err!(tcx.sess,
-                                           impl_m_span,
-                                           E0186,
-                                           "method `{}` has a `{}` declaration in the trait, but \
-                                            not in the impl",
-                                           trait_m.name,
-                                           trait_m.explicit_self);
-            err.span_label(impl_m_span,
-                           &format!("expected `{}` in impl", trait_m.explicit_self));
-            if let Some(span) = tcx.map.span_if_local(trait_m.def_id) {
-                err.span_label(span, &format!("`{}` used in trait", trait_m.explicit_self));
-            }
-            err.emit();
-            return;
-        }
-        _ => {
-            // Let the type checker catch other errors below
-        }
+    if let Err(ErrorReported) = compare_self_type(ccx,
+                                                  impl_m,
+                                                  impl_m_span,
+                                                  trait_m) {
+        return;
     }
 
-    let num_impl_m_type_params = impl_m.generics.types.len();
-    let num_trait_m_type_params = trait_m.generics.types.len();
-    if num_impl_m_type_params != num_trait_m_type_params {
-        let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
-        let span = match tcx.map.expect_impl_item(impl_m_node_id).node {
-            ImplItemKind::Method(ref impl_m_sig, _) => {
-                if impl_m_sig.generics.is_parameterized() {
-                    impl_m_sig.generics.span
-                } else {
-                    impl_m_span
-                }
-            }
-            _ => bug!("{:?} is not a method", impl_m),
-        };
-
-        let mut err = struct_span_err!(tcx.sess,
-                                       span,
-                                       E0049,
-                                       "method `{}` has {} type parameter{} but its trait \
-                                        declaration has {} type parameter{}",
-                                       trait_m.name,
-                                       num_impl_m_type_params,
-                                       if num_impl_m_type_params == 1 { "" } else { "s" },
-                                       num_trait_m_type_params,
-                                       if num_trait_m_type_params == 1 {
-                                           ""
-                                       } else {
-                                           "s"
-                                       });
-
-        let mut suffix = None;
-
-        if let Some(span) = trait_item_span {
-            err.span_label(span,
-                           &format!("expected {}",
-                                    &if num_trait_m_type_params != 1 {
-                                        format!("{} type parameters", num_trait_m_type_params)
-                                    } else {
-                                        format!("{} type parameter", num_trait_m_type_params)
-                                    }));
-        } else {
-            suffix = Some(format!(", expected {}", num_trait_m_type_params));
-        }
-
-        err.span_label(span,
-                       &format!("found {}{}",
-                                &if num_impl_m_type_params != 1 {
-                                    format!("{} type parameters", num_impl_m_type_params)
-                                } else {
-                                    format!("1 type parameter")
-                                },
-                                suffix.as_ref().map(|s| &s[..]).unwrap_or("")));
-
-        err.emit();
+    if let Err(ErrorReported) = compare_number_of_generics(ccx,
+                                                           impl_m,
+                                                           impl_m_span,
+                                                           trait_m,
+                                                           trait_item_span) {
+        return;
+    }
 
+    if let Err(ErrorReported) = compare_number_of_method_arguments(ccx,
+                                                                   impl_m,
+                                                                   impl_m_span,
+                                                                   trait_m,
+                                                                   trait_item_span) {
         return;
     }
 
-    if impl_m.fty.sig.0.inputs.len() != trait_m.fty.sig.0.inputs.len() {
-        let trait_number_args = trait_m.fty.sig.0.inputs.len();
-        let impl_number_args = impl_m.fty.sig.0.inputs.len();
-        let trait_m_node_id = tcx.map.as_local_node_id(trait_m.def_id);
-        let trait_span = if let Some(trait_id) = trait_m_node_id {
-            match tcx.map.expect_trait_item(trait_id).node {
-                TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
-                    if let Some(arg) = trait_m_sig.decl.inputs.get(if trait_number_args > 0 {
-                        trait_number_args - 1
-                    } else {
-                        0
-                    }) {
-                        Some(arg.pat.span)
-                    } else {
-                        trait_item_span
-                    }
-                }
-                _ => bug!("{:?} is not a method", impl_m),
-            }
-        } else {
-            trait_item_span
-        };
-        let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
-        let impl_span = match tcx.map.expect_impl_item(impl_m_node_id).node {
-            ImplItemKind::Method(ref impl_m_sig, _) => {
-                if let Some(arg) = impl_m_sig.decl.inputs.get(if impl_number_args > 0 {
-                    impl_number_args - 1
-                } else {
-                    0
-                }) {
-                    arg.pat.span
-                } else {
-                    impl_m_span
-                }
-            }
-            _ => bug!("{:?} is not a method", impl_m),
-        };
-        let mut err = struct_span_err!(tcx.sess,
-                                       impl_span,
-                                       E0050,
-                                       "method `{}` has {} parameter{} but the declaration in \
-                                        trait `{}` has {}",
-                                       trait_m.name,
-                                       impl_number_args,
-                                       if impl_number_args == 1 { "" } else { "s" },
-                                       tcx.item_path_str(trait_m.def_id),
-                                       trait_number_args);
-        if let Some(trait_span) = trait_span {
-            err.span_label(trait_span,
-                           &format!("trait requires {}",
-                                    &if trait_number_args != 1 {
-                                        format!("{} parameters", trait_number_args)
-                                    } else {
-                                        format!("{} parameter", trait_number_args)
-                                    }));
-        }
-        err.span_label(impl_span,
-                       &format!("expected {}, found {}",
-                                &if trait_number_args != 1 {
-                                    format!("{} parameters", trait_number_args)
-                                } else {
-                                    format!("{} parameter", trait_number_args)
-                                },
-                                impl_number_args));
-        err.emit();
+    if let Err(ErrorReported) = compare_predicate_entailment(ccx,
+                                                             impl_m,
+                                                             impl_m_span,
+                                                             impl_m_body_id,
+                                                             trait_m,
+                                                             impl_trait_ref,
+                                                             old_broken_mode) {
         return;
     }
+}
+
+fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                                          impl_m: &ty::Method<'tcx>,
+                                          impl_m_span: Span,
+                                          impl_m_body_id: ast::NodeId,
+                                          trait_m: &ty::Method<'tcx>,
+                                          impl_trait_ref: &ty::TraitRef<'tcx>,
+                                          old_broken_mode: bool)
+                                          -> Result<(), ErrorReported> {
+    let tcx = ccx.tcx;
+
+    let trait_to_impl_substs = &impl_trait_ref.substs;
 
     // This code is best explained by example. Consider a trait:
     //
@@ -304,46 +171,43 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     debug!("compare_impl_method: trait_to_skol_substs={:?}",
            trait_to_skol_substs);
 
-    // Check region bounds. FIXME(@jroesch) refactor this away when removing
-    // ParamBounds.
-    if !check_region_bounds_on_impl_method(ccx,
-                                           impl_m_span,
-                                           impl_m,
-                                           &trait_m.generics,
-                                           &impl_m.generics,
-                                           trait_to_skol_substs,
-                                           impl_to_skol_substs) {
-        return;
-    }
-
-        // Create obligations for each predicate declared by the impl
-        // definition in the context of the trait's parameter
-        // environment. We can't just use `impl_env.caller_bounds`,
-        // however, because we want to replace all late-bound regions with
-        // region variables.
-        let impl_predicates = tcx.lookup_predicates(impl_m.predicates.parent.unwrap());
-        let mut hybrid_preds = impl_predicates.instantiate(tcx, impl_to_skol_substs);
-
-        debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds);
-
-        // This is the only tricky bit of the new way we check implementation methods
-        // We need to build a set of predicates where only the method-level bounds
-        // are from the trait and we assume all other bounds from the implementation
-        // to be previously satisfied.
-        //
-        // We then register the obligations from the impl_m and check to see
-        // if all constraints hold.
-        hybrid_preds.predicates
-            .extend(trait_m.predicates.instantiate_own(tcx, trait_to_skol_substs).predicates);
-
-        // Construct trait parameter environment and then shift it into the skolemized viewpoint.
-        // The key step here is to update the caller_bounds's predicates to be
-        // the new hybrid bounds we computed.
-        let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_body_id);
-        let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.predicates);
-        let trait_param_env = traits::normalize_param_env_or_error(tcx,
-                                                                   trait_param_env,
-                                                                   normalize_cause.clone());
+    // Check region bounds.
+    check_region_bounds_on_impl_method(ccx,
+                                       impl_m_span,
+                                       impl_m,
+                                       &trait_m.generics,
+                                       &impl_m.generics,
+                                       trait_to_skol_substs,
+                                       impl_to_skol_substs)?;
+
+    // Create obligations for each predicate declared by the impl
+    // definition in the context of the trait's parameter
+    // environment. We can't just use `impl_env.caller_bounds`,
+    // however, because we want to replace all late-bound regions with
+    // region variables.
+    let impl_predicates = tcx.lookup_predicates(impl_m.predicates.parent.unwrap());
+    let mut hybrid_preds = impl_predicates.instantiate(tcx, impl_to_skol_substs);
+
+    debug!("compare_impl_method: impl_bounds={:?}", hybrid_preds);
+
+    // This is the only tricky bit of the new way we check implementation methods
+    // We need to build a set of predicates where only the method-level bounds
+    // are from the trait and we assume all other bounds from the implementation
+    // to be previously satisfied.
+    //
+    // We then register the obligations from the impl_m and check to see
+    // if all constraints hold.
+    hybrid_preds.predicates
+                .extend(trait_m.predicates.instantiate_own(tcx, trait_to_skol_substs).predicates);
+
+    // Construct trait parameter environment and then shift it into the skolemized viewpoint.
+    // The key step here is to update the caller_bounds's predicates to be
+    // the new hybrid bounds we computed.
+    let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_body_id);
+    let trait_param_env = impl_param_env.with_caller_bounds(hybrid_preds.predicates);
+    let trait_param_env = traits::normalize_param_env_or_error(tcx,
+                                                               trait_param_env,
+                                                               normalize_cause.clone());
 
     tcx.infer_ctxt(None, Some(trait_param_env), Reveal::NotSpecializable).enter(|infcx| {
         let inh = Inherited::new(ccx, infcx);
@@ -464,14 +328,14 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                 })),
                                 &terr);
             diag.emit();
-            return;
+            return Err(ErrorReported);
         }
 
         // Check that all obligations are satisfied by the implementation's
         // version.
         if let Err(ref errors) = fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
             infcx.report_fulfillment_errors(errors);
-            return;
+            return Err(ErrorReported);
         }
 
         // Finally, resolve all regions. This catches wily misuses of
@@ -490,147 +354,351 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             let fcx = FnCtxt::new(&inh, tcx.types.err, impl_m_body_id);
             fcx.regionck_item(impl_m_body_id, impl_m_span, &[]);
         }
-    });
 
-    fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                                                    span: Span,
-                                                    impl_m: &ty::Method<'tcx>,
-                                                    trait_generics: &ty::Generics<'tcx>,
-                                                    impl_generics: &ty::Generics<'tcx>,
-                                                    trait_to_skol_substs: &Substs<'tcx>,
-                                                    impl_to_skol_substs: &Substs<'tcx>)
-                                                    -> bool {
-
-        let trait_params = &trait_generics.regions[..];
-        let impl_params = &impl_generics.regions[..];
-
-        debug!("check_region_bounds_on_impl_method: \
-               trait_generics={:?} \
-               impl_generics={:?} \
-               trait_to_skol_substs={:?} \
-               impl_to_skol_substs={:?}",
-               trait_generics,
-               impl_generics,
-               trait_to_skol_substs,
-               impl_to_skol_substs);
-
-        // Must have same number of early-bound lifetime parameters.
-        // Unfortunately, if the user screws up the bounds, then this
-        // will change classification between early and late.  E.g.,
-        // if in trait we have `<'a,'b:'a>`, and in impl we just have
-        // `<'a,'b>`, then we have 2 early-bound lifetime parameters
-        // in trait but 0 in the impl. But if we report "expected 2
-        // but found 0" it's confusing, because it looks like there
-        // are zero. Since I don't quite know how to phrase things at
-        // the moment, give a kind of vague error message.
-        if trait_params.len() != impl_params.len() {
-            struct_span_err!(ccx.tcx.sess,
-                             span,
-                             E0195,
-                             "lifetime parameters or bounds on method `{}` do not match the \
-                              trait declaration",
-                             impl_m.name)
-                .span_label(span, &format!("lifetimes do not match trait"))
-                .emit();
-            return false;
+        Ok(())
+    })
+}
+
+fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                                                span: Span,
+                                                impl_m: &ty::Method<'tcx>,
+                                                trait_generics: &ty::Generics<'tcx>,
+                                                impl_generics: &ty::Generics<'tcx>,
+                                                trait_to_skol_substs: &Substs<'tcx>,
+                                                impl_to_skol_substs: &Substs<'tcx>)
+                                                -> Result<(), ErrorReported> {
+    let trait_params = &trait_generics.regions[..];
+    let impl_params = &impl_generics.regions[..];
+
+    debug!("check_region_bounds_on_impl_method: \
+            trait_generics={:?} \
+            impl_generics={:?} \
+            trait_to_skol_substs={:?} \
+            impl_to_skol_substs={:?}",
+           trait_generics,
+           impl_generics,
+           trait_to_skol_substs,
+           impl_to_skol_substs);
+
+    // Must have same number of early-bound lifetime parameters.
+    // Unfortunately, if the user screws up the bounds, then this
+    // will change classification between early and late.  E.g.,
+    // if in trait we have `<'a,'b:'a>`, and in impl we just have
+    // `<'a,'b>`, then we have 2 early-bound lifetime parameters
+    // in trait but 0 in the impl. But if we report "expected 2
+    // but found 0" it's confusing, because it looks like there
+    // are zero. Since I don't quite know how to phrase things at
+    // the moment, give a kind of vague error message.
+    if trait_params.len() != impl_params.len() {
+        struct_span_err!(ccx.tcx.sess,
+                         span,
+                         E0195,
+                         "lifetime parameters or bounds on method `{}` do not match the \
+                          trait declaration",
+                         impl_m.name)
+            .span_label(span, &format!("lifetimes do not match trait"))
+            .emit();
+        return Err(ErrorReported);
+    }
+
+    return Ok(());
+}
+
+fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
+                                                     terr: &TypeError,
+                                                     origin: TypeOrigin,
+                                                     impl_m: &ty::Method,
+                                                     impl_sig: ty::FnSig<'tcx>,
+                                                     trait_m: &ty::Method,
+                                                     trait_sig: ty::FnSig<'tcx>)
+                                                     -> (Span, Option<Span>) {
+    let tcx = infcx.tcx;
+    let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
+    let (impl_m_output, impl_m_iter) = match tcx.map.expect_impl_item(impl_m_node_id).node {
+        ImplItemKind::Method(ref impl_m_sig, _) => {
+            (&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter())
+        }
+        _ => bug!("{:?} is not a method", impl_m),
+    };
+
+    match *terr {
+        TypeError::Mutability => {
+            if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
+                let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node {
+                    TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
+                        trait_m_sig.decl.inputs.iter()
+                    }
+                    _ => bug!("{:?} is not a MethodTraitItem", trait_m),
+                };
+
+                impl_m_iter.zip(trait_m_iter)
+                           .find(|&(ref impl_arg, ref trait_arg)| {
+                               match (&impl_arg.ty.node, &trait_arg.ty.node) {
+                                   (&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) |
+                                   (&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) => {
+                                       impl_mt.mutbl != trait_mt.mutbl
+                                   }
+                                   _ => false,
+                               }
+                           })
+                           .map(|(ref impl_arg, ref trait_arg)| {
+                               match (impl_arg.to_self(), trait_arg.to_self()) {
+                                   (Some(impl_self), Some(trait_self)) => {
+                                       (impl_self.span, Some(trait_self.span))
+                                   }
+                                   (None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)),
+                                   _ => {
+                                       bug!("impl and trait fns have different first args, impl: \
+                                             {:?}, trait: {:?}",
+                                            impl_arg,
+                                            trait_arg)
+                                   }
+                               }
+                           })
+                           .unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id)))
+            } else {
+                (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+            }
         }
+        TypeError::Sorts(ExpectedFound { .. }) => {
+            if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
+                let (trait_m_output, trait_m_iter) =
+                    match tcx.map.expect_trait_item(trait_m_node_id).node {
+                        TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
+                            (&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter())
+                        }
+                        _ => bug!("{:?} is not a MethodTraitItem", trait_m),
+                    };
 
-        return true;
+                let impl_iter = impl_sig.inputs.iter();
+                let trait_iter = trait_sig.inputs.iter();
+                impl_iter.zip(trait_iter)
+                         .zip(impl_m_iter)
+                         .zip(trait_m_iter)
+                         .filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| {
+                             match infcx.sub_types(true, origin, trait_arg_ty, impl_arg_ty) {
+                                 Ok(_) => None,
+                                 Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span))),
+                             }
+                         })
+                         .next()
+                         .unwrap_or_else(|| {
+                             if infcx.sub_types(false, origin, impl_sig.output, trait_sig.output)
+                                     .is_err() {
+                                         (impl_m_output.span(), Some(trait_m_output.span()))
+                                     } else {
+                                         (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+                                     }
+                         })
+            } else {
+                (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+            }
+        }
+        _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id)),
     }
+}
 
-    fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
-                                                         terr: &TypeError,
-                                                         origin: TypeOrigin,
-                                                         impl_m: &ty::Method,
-                                                         impl_sig: ty::FnSig<'tcx>,
-                                                         trait_m: &ty::Method,
-                                                         trait_sig: ty::FnSig<'tcx>)
-                                                         -> (Span, Option<Span>) {
-        let tcx = infcx.tcx;
+fn compare_self_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                               impl_m: &ty::Method<'tcx>,
+                               impl_m_span: Span,
+                               trait_m: &ty::Method<'tcx>)
+                               -> Result<(), ErrorReported>
+{
+    let tcx = ccx.tcx;
+    // Try to give more informative error messages about self typing
+    // mismatches.  Note that any mismatch will also be detected
+    // below, where we construct a canonical function type that
+    // includes the self parameter as a normal parameter.  It's just
+    // that the error messages you get out of this code are a bit more
+    // inscrutable, particularly for cases where one method has no
+    // self.
+    match (&trait_m.explicit_self, &impl_m.explicit_self) {
+        (&ty::ExplicitSelfCategory::Static, &ty::ExplicitSelfCategory::Static) => {}
+        (&ty::ExplicitSelfCategory::Static, _) => {
+            let mut err = struct_span_err!(tcx.sess,
+                                           impl_m_span,
+                                           E0185,
+                                           "method `{}` has a `{}` declaration in the impl, but \
+                                            not in the trait",
+                                           trait_m.name,
+                                           impl_m.explicit_self);
+            err.span_label(impl_m_span,
+                           &format!("`{}` used in impl", impl_m.explicit_self));
+            if let Some(span) = tcx.map.span_if_local(trait_m.def_id) {
+                err.span_label(span,
+                               &format!("trait declared without `{}`", impl_m.explicit_self));
+            }
+            err.emit();
+            return Err(ErrorReported);
+        }
+        (_, &ty::ExplicitSelfCategory::Static) => {
+            let mut err = struct_span_err!(tcx.sess,
+                                           impl_m_span,
+                                           E0186,
+                                           "method `{}` has a `{}` declaration in the trait, but \
+                                            not in the impl",
+                                           trait_m.name,
+                                           trait_m.explicit_self);
+            err.span_label(impl_m_span,
+                           &format!("expected `{}` in impl", trait_m.explicit_self));
+            if let Some(span) = tcx.map.span_if_local(trait_m.def_id) {
+                err.span_label(span, &format!("`{}` used in trait", trait_m.explicit_self));
+            }
+            err.emit();
+            return Err(ErrorReported);
+        }
+        _ => {
+            // Let the type checker catch other errors below
+        }
+    }
+
+    Ok(())
+}
+
+fn compare_number_of_generics<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                                        impl_m: &ty::Method<'tcx>,
+                                        impl_m_span: Span,
+                                        trait_m: &ty::Method<'tcx>,
+                                        trait_item_span: Option<Span>)
+                                        -> Result<(), ErrorReported> {
+    let tcx = ccx.tcx;
+    let num_impl_m_type_params = impl_m.generics.types.len();
+    let num_trait_m_type_params = trait_m.generics.types.len();
+    if num_impl_m_type_params != num_trait_m_type_params {
         let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
-        let (impl_m_output, impl_m_iter) = match tcx.map.expect_impl_item(impl_m_node_id).node {
+        let span = match tcx.map.expect_impl_item(impl_m_node_id).node {
             ImplItemKind::Method(ref impl_m_sig, _) => {
-                (&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter())
+                if impl_m_sig.generics.is_parameterized() {
+                    impl_m_sig.generics.span
+                } else {
+                    impl_m_span
+                }
             }
             _ => bug!("{:?} is not a method", impl_m),
         };
 
-        match *terr {
-            TypeError::Mutability => {
-                if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
-                    let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node {
-                        TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
-                            trait_m_sig.decl.inputs.iter()
-                        }
-                        _ => bug!("{:?} is not a MethodTraitItem", trait_m),
-                    };
+        let mut err = struct_span_err!(tcx.sess,
+                                       span,
+                                       E0049,
+                                       "method `{}` has {} type parameter{} but its trait \
+                                        declaration has {} type parameter{}",
+                                       trait_m.name,
+                                       num_impl_m_type_params,
+                                       if num_impl_m_type_params == 1 { "" } else { "s" },
+                                       num_trait_m_type_params,
+                                       if num_trait_m_type_params == 1 {
+                                           ""
+                                       } else {
+                                           "s"
+                                       });
 
-                    impl_m_iter.zip(trait_m_iter)
-                        .find(|&(ref impl_arg, ref trait_arg)| {
-                            match (&impl_arg.ty.node, &trait_arg.ty.node) {
-                                (&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) |
-                                (&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) => {
-                                    impl_mt.mutbl != trait_mt.mutbl
-                                }
-                                _ => false,
-                            }
-                        })
-                        .map(|(ref impl_arg, ref trait_arg)| {
-                            match (impl_arg.to_self(), trait_arg.to_self()) {
-                                (Some(impl_self), Some(trait_self)) => {
-                                    (impl_self.span, Some(trait_self.span))
-                                }
-                                (None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)),
-                                _ => {
-                                    bug!("impl and trait fns have different first args, impl: \
-                                          {:?}, trait: {:?}",
-                                         impl_arg,
-                                         trait_arg)
-                                }
-                            }
-                        })
-                        .unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id)))
-                } else {
-                    (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+        let mut suffix = None;
+
+        if let Some(span) = trait_item_span {
+            err.span_label(span,
+                           &format!("expected {}",
+                                    &if num_trait_m_type_params != 1 {
+                                        format!("{} type parameters", num_trait_m_type_params)
+                                    } else {
+                                        format!("{} type parameter", num_trait_m_type_params)
+                                    }));
+        } else {
+            suffix = Some(format!(", expected {}", num_trait_m_type_params));
+        }
+
+        err.span_label(span,
+                       &format!("found {}{}",
+                                &if num_impl_m_type_params != 1 {
+                                    format!("{} type parameters", num_impl_m_type_params)
+                                } else {
+                                    format!("1 type parameter")
+                                },
+                                suffix.as_ref().map(|s| &s[..]).unwrap_or("")));
+
+        err.emit();
+
+        return Err(ErrorReported);
+    }
+
+    Ok(())
+}
+
+fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                                                impl_m: &ty::Method<'tcx>,
+                                                impl_m_span: Span,
+                                                trait_m: &ty::Method<'tcx>,
+                                                trait_item_span: Option<Span>)
+                                                -> Result<(), ErrorReported> {
+    let tcx = ccx.tcx;
+    if impl_m.fty.sig.0.inputs.len() != trait_m.fty.sig.0.inputs.len() {
+        let trait_number_args = trait_m.fty.sig.0.inputs.len();
+        let impl_number_args = impl_m.fty.sig.0.inputs.len();
+        let trait_m_node_id = tcx.map.as_local_node_id(trait_m.def_id);
+        let trait_span = if let Some(trait_id) = trait_m_node_id {
+            match tcx.map.expect_trait_item(trait_id).node {
+                TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
+                    if let Some(arg) = trait_m_sig.decl.inputs.get(if trait_number_args > 0 {
+                        trait_number_args - 1
+                    } else {
+                        0
+                    }) {
+                        Some(arg.pat.span)
+                    } else {
+                        trait_item_span
+                    }
                 }
+                _ => bug!("{:?} is not a method", impl_m),
             }
-            TypeError::Sorts(ExpectedFound { .. }) => {
-                if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
-                    let (trait_m_output, trait_m_iter) =
-                        match tcx.map.expect_trait_item(trait_m_node_id).node {
-                            TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
-                                (&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter())
-                            }
-                            _ => bug!("{:?} is not a MethodTraitItem", trait_m),
-                        };
-
-                    let impl_iter = impl_sig.inputs.iter();
-                    let trait_iter = trait_sig.inputs.iter();
-                    impl_iter.zip(trait_iter)
-                        .zip(impl_m_iter)
-                        .zip(trait_m_iter)
-                        .filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| {
-                            match infcx.sub_types(true, origin, trait_arg_ty, impl_arg_ty) {
-                                Ok(_) => None,
-                                Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span))),
-                            }
-                        })
-                        .next()
-                        .unwrap_or_else(|| {
-                            if infcx.sub_types(false, origin, impl_sig.output, trait_sig.output)
-                                .is_err() {
-                                (impl_m_output.span(), Some(trait_m_output.span()))
-                            } else {
-                                (origin.span(), tcx.map.span_if_local(trait_m.def_id))
-                            }
-                        })
+        } else {
+            trait_item_span
+        };
+        let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
+        let impl_span = match tcx.map.expect_impl_item(impl_m_node_id).node {
+            ImplItemKind::Method(ref impl_m_sig, _) => {
+                if let Some(arg) = impl_m_sig.decl.inputs.get(if impl_number_args > 0 {
+                    impl_number_args - 1
                 } else {
-                    (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+                    0
+                }) {
+                    arg.pat.span
+                } else {
+                    impl_m_span
                 }
             }
-            _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id)),
+            _ => bug!("{:?} is not a method", impl_m),
+        };
+        let mut err = struct_span_err!(tcx.sess,
+                                       impl_span,
+                                       E0050,
+                                       "method `{}` has {} parameter{} but the declaration in \
+                                        trait `{}` has {}",
+                                       trait_m.name,
+                                       impl_number_args,
+                                       if impl_number_args == 1 { "" } else { "s" },
+                                       tcx.item_path_str(trait_m.def_id),
+                                       trait_number_args);
+        if let Some(trait_span) = trait_span {
+            err.span_label(trait_span,
+                           &format!("trait requires {}",
+                                    &if trait_number_args != 1 {
+                                        format!("{} parameters", trait_number_args)
+                                    } else {
+                                        format!("{} parameter", trait_number_args)
+                                    }));
         }
+        err.span_label(impl_span,
+                       &format!("expected {}, found {}",
+                                &if trait_number_args != 1 {
+                                    format!("{} parameters", trait_number_args)
+                                } else {
+                                    format!("{} parameter", trait_number_args)
+                                },
+                                impl_number_args));
+        err.emit();
+        return Err(ErrorReported);
     }
+
+    Ok(())
 }
 
 pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 536c4a9d524..9bfe80dba9d 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -369,7 +369,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                       cause: &traits::ObligationCause<'tcx>,
                       sup_type: Ty<'tcx>)
                       -> SubregionOrigin<'tcx> {
-        SubregionOrigin::from_cause(cause, || infer::RelateParamBound(cause.span, sup_type))
+        SubregionOrigin::from_obligation_cause(cause,
+                                               || infer::RelateParamBound(cause.span, sup_type))
     }
 
     /// This method populates the region map's `free_region_map`. It walks over the transformed