about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard-Mihai Burtescu <edy.burt@gmail.com>2016-08-18 06:12:23 +0300
committerGitHub <noreply@github.com>2016-08-18 06:12:23 +0300
commit8ccc11b31bbb1de3813d2baa92aed2fcaf090586 (patch)
tree811987ed9e3f941613cacc19d2a23862f278a07d
parentc3601d40ecdb3c6626919c5baf1851fad24e3d47 (diff)
parent31d56cb144ead0811935a09d32d7b2febc5b42de (diff)
downloadrust-8ccc11b31bbb1de3813d2baa92aed2fcaf090586.tar.gz
rust-8ccc11b31bbb1de3813d2baa92aed2fcaf090586.zip
Rollup merge of #35765 - KiChjang:e0053-bonus, r=jonathandturner
Additional span info for E0053

Part of #35233.
Fixes #35212.

r? @jonathandturner
-rw-r--r--src/librustc/hir/map/mod.rs7
-rw-r--r--src/librustc/infer/error_reporting.rs6
-rw-r--r--src/librustc/traits/error_reporting.rs2
-rw-r--r--src/librustc_typeck/check/compare_method.rs106
-rw-r--r--src/test/compile-fail/E0053.rs14
-rw-r--r--src/test/ui/mismatched_types/trait-impl-fn-incompatibility.rs27
-rw-r--r--src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr23
7 files changed, 158 insertions, 27 deletions
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index 7e82a4a05a7..04031fabc58 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -569,6 +569,13 @@ impl<'ast> Map<'ast> {
         }
     }
 
+    pub fn expect_impl_item(&self, id: NodeId) -> &'ast ImplItem {
+        match self.find(id) {
+            Some(NodeImplItem(item)) => item,
+            _ => bug!("expected impl item, found {}", self.node_to_string(id))
+        }
+    }
+
     pub fn expect_trait_item(&self, id: NodeId) -> &'ast TraitItem {
         match self.find(id) {
             Some(NodeTraitItem(item)) => item,
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index 9a6375719c1..1e053d6bfda 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -523,6 +523,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     pub fn note_type_err(&self,
                          diag: &mut DiagnosticBuilder<'tcx>,
                          origin: TypeOrigin,
+                         secondary_span: Option<(Span, String)>,
                          values: Option<ValuePairs<'tcx>>,
                          terr: &TypeError<'tcx>)
     {
@@ -553,6 +554,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         }
 
         diag.span_label(span, &terr);
+        if let Some((sp, msg)) = secondary_span {
+            diag.span_label(sp, &msg);
+        }
 
         self.note_error_origin(diag, &origin);
         self.check_and_note_conflicting_crates(diag, terr, span);
@@ -569,7 +573,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             self.tcx.sess, trace.origin.span(), E0308,
             "{}", trace.origin.as_failure_str()
         );
-        self.note_type_err(&mut diag, trace.origin, Some(trace.values), terr);
+        self.note_type_err(&mut diag, trace.origin, None, Some(trace.values), terr);
         diag
     }
 
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 33db0053cda..d6f263fcebe 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -161,7 +161,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 self.tcx.sess, origin.span(), E0271,
                 "type mismatch resolving `{}`", predicate
             );
-            self.note_type_err(&mut diag, origin, values, err);
+            self.note_type_err(&mut diag, origin, None, values, err);
             self.note_obligation_cause(&mut diag, obligation);
             diag.emit();
         });
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 6bcf21563cb..043883df035 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -12,10 +12,9 @@ use middle::free_region::FreeRegionMap;
 use rustc::infer::{self, InferOk, TypeOrigin};
 use rustc::ty;
 use rustc::traits::{self, Reveal};
-use rustc::ty::error::ExpectedFound;
+use rustc::ty::error::{ExpectedFound, TypeError};
 use rustc::ty::subst::{Subst, Substs};
-use rustc::hir::map::Node;
-use rustc::hir::{ImplItemKind, TraitItem_};
+use rustc::hir::{ImplItemKind, TraitItem_, Ty_};
 
 use syntax::ast;
 use syntax_pos::Span;
@@ -300,6 +299,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                                  impl_m_span,
                                                  impl_m_body_id,
                                                  &impl_sig);
+        let impl_args = impl_sig.inputs.clone();
         let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
             unsafety: impl_m.fty.unsafety,
             abi: impl_m.fty.abi,
@@ -318,6 +318,7 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                                  impl_m_span,
                                                  impl_m_body_id,
                                                  &trait_sig);
+        let trait_args = trait_sig.inputs.clone();
         let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
             unsafety: trait_m.fty.unsafety,
             abi: trait_m.fty.abi,
@@ -331,16 +332,82 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                    impl_fty,
                    trait_fty);
 
+            let impl_m_iter = match tcx.map.expect_impl_item(impl_m_node_id).node {
+                ImplItemKind::Method(ref impl_m_sig, _) => impl_m_sig.decl.inputs.iter(),
+                _ => bug!("{:?} is not a method", impl_m)
+            };
+
+            let (impl_err_span, trait_err_span) = 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 { expected, found }) => {
+                    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 impl_iter = impl_args.iter();
+                        let trait_iter = trait_args.iter();
+                        let arg_idx = impl_iter.zip(trait_iter)
+                                               .position(|(impl_arg_ty, trait_arg_ty)| {
+                                                *impl_arg_ty == found && *trait_arg_ty == expected
+                                               }).unwrap();
+                        impl_m_iter.zip(trait_m_iter)
+                                   .nth(arg_idx)
+                                   .map(|(impl_arg, trait_arg)|
+                                        (impl_arg.ty.span, Some(trait_arg.ty.span)))
+                                   .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))
+                    }
+                }
+                _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+            };
+
+            let origin = TypeOrigin::MethodCompatCheck(impl_err_span);
+
             let mut diag = struct_span_err!(
                 tcx.sess, origin.span(), E0053,
                 "method `{}` has an incompatible type for trait", trait_m.name
             );
+
             infcx.note_type_err(
-                &mut diag, origin,
+                &mut diag,
+                origin,
+                trait_err_span.map(|sp| (sp, format!("original trait requirement"))),
                 Some(infer::ValuePairs::Types(ExpectedFound {
-                    expected: trait_fty,
-                    found: impl_fty
-                })), &terr
+                     expected: trait_fty,
+                     found: impl_fty
+                })),
+                &terr
             );
             diag.emit();
             return
@@ -487,12 +554,9 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                    trait_ty);
 
             // Locate the Span containing just the type of the offending impl
-            if let Some(impl_trait_node) = tcx.map.get_if_local(impl_c.def_id) {
-                if let Node::NodeImplItem(impl_trait_item) = impl_trait_node {
-                    if let ImplItemKind::Const(ref ty, _) = impl_trait_item.node {
-                        origin = TypeOrigin::Misc(ty.span);
-                    }
-                }
+            match tcx.map.expect_impl_item(impl_c_node_id).node {
+                ImplItemKind::Const(ref ty, _) => origin = TypeOrigin::Misc(ty.span),
+                _ => bug!("{:?} is not a impl const", impl_c)
             }
 
             let mut diag = struct_span_err!(
@@ -502,16 +566,16 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             );
 
             // Add a label to the Span containing just the type of the item
-            if let Some(orig_trait_node) = tcx.map.get_if_local(trait_c.def_id) {
-                if let Node::NodeTraitItem(orig_trait_item) = orig_trait_node {
-                    if let TraitItem_::ConstTraitItem(ref ty, _) = orig_trait_item.node {
-                        diag.span_label(ty.span, &format!("original trait requirement"));
-                    }
-                }
-            }
+            let trait_c_node_id = tcx.map.as_local_node_id(trait_c.def_id).unwrap();
+            let trait_c_span = match tcx.map.expect_trait_item(trait_c_node_id).node {
+                TraitItem_::ConstTraitItem(ref ty, _) => ty.span,
+                _ => bug!("{:?} is not a trait const", trait_c)
+            };
 
             infcx.note_type_err(
-                &mut diag, origin,
+                &mut diag,
+                origin,
+                Some((trait_c_span, format!("original trait requirement"))),
                 Some(infer::ValuePairs::Types(ExpectedFound {
                     expected: trait_ty,
                     found: impl_ty
diff --git a/src/test/compile-fail/E0053.rs b/src/test/compile-fail/E0053.rs
index 4effda3c49e..7022010714a 100644
--- a/src/test/compile-fail/E0053.rs
+++ b/src/test/compile-fail/E0053.rs
@@ -9,15 +9,21 @@
 // except according to those terms.
 
 trait Foo {
-    fn foo(x: u16);
-    fn bar(&self);
+    fn foo(x: u16); //~ NOTE original trait requirement
+    fn bar(&self); //~ NOTE original trait requirement
 }
 
 struct Bar;
 
 impl Foo for Bar {
-    fn foo(x: i16) { } //~ ERROR E0053
-    fn bar(&mut self) { } //~ ERROR E0053
+    fn foo(x: i16) { }
+    //~^ ERROR method `foo` has an incompatible type for trait
+    //~| NOTE expected u16
+    fn bar(&mut self) { }
+    //~^ ERROR method `bar` has an incompatible type for trait
+    //~| NOTE values differ in mutability
+    //~| NOTE expected type `fn(&Bar)`
+    //~| NOTE found type `fn(&mut Bar)`
 }
 
 fn main() {
diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.rs b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.rs
new file mode 100644
index 00000000000..099c8699e49
--- /dev/null
+++ b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.rs
@@ -0,0 +1,27 @@
+// Copyright 2016 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.
+
+// rustc-env:RUST_NEW_ERROR_FORMAT
+
+trait Foo {
+    fn foo(x: u16);
+    fn bar(&mut self, bar: &mut Bar);
+}
+
+struct Bar;
+
+impl Foo for Bar {
+    fn foo(x: i16) { }
+    fn bar(&mut self, bar: &Bar) { }
+}
+
+fn main() {
+}
+
diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr
new file mode 100644
index 00000000000..e5dfdc8e910
--- /dev/null
+++ b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr
@@ -0,0 +1,23 @@
+error[E0053]: method `foo` has an incompatible type for trait
+  --> $DIR/trait-impl-fn-incompatibility.rs:21:15
+   |
+14 |     fn foo(x: u16);
+   |               --- original trait requirement
+...
+21 |     fn foo(x: i16) { }
+   |               ^^^ expected u16, found i16
+
+error[E0053]: method `bar` has an incompatible type for trait
+  --> $DIR/trait-impl-fn-incompatibility.rs:22:28
+   |
+15 |     fn bar(&mut self, bar: &mut Bar);
+   |                            -------- original trait requirement
+...
+22 |     fn bar(&mut self, bar: &Bar) { }
+   |                            ^^^^ values differ in mutability
+   |
+   = note: expected type `fn(&mut Bar, &mut Bar)`
+   = note:    found type `fn(&mut Bar, &Bar)`
+
+error: aborting due to 2 previous errors
+