about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-06-04 20:16:09 +0000
committerbors <bors@rust-lang.org>2017-06-04 20:16:09 +0000
commit0418fa9d382a47d782cc1e195c14573be9c32095 (patch)
tree20337e568c7a68a788142cf3653ea1894c1de5ed
parent9a4e13f5c43a6eaf97ab3b62c5f1d2d9ab4f3d6e (diff)
parente324919ec57954adaa49884e5894bc7d615d413e (diff)
downloadrust-0418fa9d382a47d782cc1e195c14573be9c32095.tar.gz
rust-0418fa9d382a47d782cc1e195c14573be9c32095.zip
Auto merge of #42362 - estebank:type, r=arielb1
Show trait method signature when impl differs

When the trait's span is available, it is already being used, add a
`note` for the cases where the span isn't available:

<pre>
error[E0053]: <b>method `fmt` has an incompatible type for trait</b>
  --> $DIR/trait_type.rs:17:4
   |
17 |    fn fmt(&self, x: &str) -> () { }
   |    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability
   |
   = note: expected type `<b>fn(&MyType, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error></b>`
              found type `<b>fn(&MyType, &str)</b>`

error[E0050]: <b>method `fmt` has 1 parameter but the declaration in trait `std::fmt::Display::fmt` has 2</b>
  --> $DIR/trait_type.rs:21:11
   |
21 |    fn fmt(&self) -> () { }
   |           ^^^^^ expected 2 parameters, found 1
   |
   = note: `fmt` from trait: `<b>fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error></b>`

error[E0186]: <b>method `fmt` has a `&self` declaration in the trait, but not in the impl</b>
  --> $DIR/trait_type.rs:25:4
   |
25 |    fn fmt() -> () { }
   |    ^^^^^^^^^^^^^^^^^^ expected `&self` in impl
   |
   = note: `fmt` from trait: `<b>fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error></b>`

error[E0046]: <b>not all trait items implemented, missing: `fmt`</b>
  --> $DIR/trait_type.rs:28:1
   |
28 | impl std::fmt::Display for MyType4 {}
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `fmt` in implementation
   |
   = note: `fmt` from trait: `<b>fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error></b>`
</code></pre>

Fix #28011.
-rw-r--r--src/librustc/ty/mod.rs16
-rw-r--r--src/librustc_errors/diagnostic.rs8
-rw-r--r--src/librustc_typeck/check/compare_method.rs6
-rw-r--r--src/librustc_typeck/check/mod.rs17
-rw-r--r--src/test/ui/impl-trait/trait_type.rs30
-rw-r--r--src/test/ui/impl-trait/trait_type.stderr35
6 files changed, 97 insertions, 15 deletions
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index e4e1ebe1882..653021119aa 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -198,6 +198,22 @@ impl AssociatedItem {
             AssociatedKind::Method => !self.method_has_self_argument,
         }
     }
+
+    pub fn signature<'a, 'tcx>(&self, tcx: &TyCtxt<'a, 'tcx, 'tcx>) -> String {
+        match self.kind {
+            ty::AssociatedKind::Method => {
+                // We skip the binder here because the binder would deanonymize all
+                // late-bound regions, and we don't want method signatures to show up
+                // `as for<'r> fn(&'r MyType)`.  Pretty-printing handles late-bound
+                // regions just fine, showing `fn(&MyType)`.
+                format!("{}", tcx.type_of(self.def_id).fn_sig().skip_binder())
+            }
+            ty::AssociatedKind::Type => format!("type {};", self.name.to_string()),
+            ty::AssociatedKind::Const => {
+                format!("const {}: {:?};", self.name.to_string(), tcx.type_of(self.def_id))
+            }
+        }
+    }
 }
 
 #[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable)]
diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs
index 861880aa265..7a64cdeee65 100644
--- a/src/librustc_errors/diagnostic.rs
+++ b/src/librustc_errors/diagnostic.rs
@@ -157,6 +157,14 @@ impl Diagnostic {
         self
     }
 
+    pub fn note_trait_signature(&mut self, name: String, signature: String) -> &mut Self {
+        self.highlighted_note(vec![
+            (format!("`{}` from trait: `", name), Style::NoStyle),
+            (signature, Style::Highlight),
+            ("`".to_string(), Style::NoStyle)]);
+        self
+    }
+
     pub fn note(&mut self, msg: &str) -> &mut Self {
         self.sub(Level::Note, msg, MultiSpan::new(), None);
         self
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 7633be24477..8b76431fd2e 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -550,6 +550,9 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            format!("expected `{}` in impl", self_descr));
             if let Some(span) = tcx.hir.span_if_local(trait_m.def_id) {
                 err.span_label(span, format!("`{}` used in trait", self_descr));
+            } else {
+                err.note_trait_signature(trait_m.name.to_string(),
+                                         trait_m.signature(&tcx));
             }
             err.emit();
             return Err(ErrorReported);
@@ -697,6 +700,9 @@ fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                     } else {
                                         format!("{} parameter", trait_number_args)
                                     }));
+        } else {
+            err.note_trait_signature(trait_m.name.to_string(),
+                                     trait_m.signature(&tcx));
         }
         err.span_label(impl_span,
                        format!("expected {}, found {}",
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index ccaf9b84a45..c3bce804879 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1348,18 +1348,6 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
     }
 
-    let signature = |item: &ty::AssociatedItem| {
-        match item.kind {
-            ty::AssociatedKind::Method => {
-                format!("{}", tcx.type_of(item.def_id).fn_sig().0)
-            }
-            ty::AssociatedKind::Type => format!("type {};", item.name.to_string()),
-            ty::AssociatedKind::Const => {
-                format!("const {}: {:?};", item.name.to_string(), tcx.type_of(item.def_id))
-            }
-        }
-    };
-
     if !missing_items.is_empty() {
         let mut err = struct_span_err!(tcx.sess, impl_span, E0046,
             "not all trait items implemented, missing: `{}`",
@@ -1374,9 +1362,8 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             if let Some(span) = tcx.hir.span_if_local(trait_item.def_id) {
                 err.span_label(span, format!("`{}` from trait", trait_item.name));
             } else {
-                err.note(&format!("`{}` from trait: `{}`",
-                                  trait_item.name,
-                                  signature(&trait_item)));
+                err.note_trait_signature(trait_item.name.to_string(),
+                                         trait_item.signature(&tcx));
             }
         }
         err.emit();
diff --git a/src/test/ui/impl-trait/trait_type.rs b/src/test/ui/impl-trait/trait_type.rs
new file mode 100644
index 00000000000..3507dcfbe17
--- /dev/null
+++ b/src/test/ui/impl-trait/trait_type.rs
@@ -0,0 +1,30 @@
+// Copyright 2017 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 MyType2;
+struct MyType3;
+struct MyType4;
+
+impl std::fmt::Display for MyType {
+   fn fmt(&self, x: &str) -> () { }
+}
+
+impl std::fmt::Display for MyType2 {
+   fn fmt(&self) -> () { }
+}
+
+impl std::fmt::Display for MyType3 {
+   fn fmt() -> () { }
+}
+
+impl std::fmt::Display for MyType4 {}
+
+fn main() {}
diff --git a/src/test/ui/impl-trait/trait_type.stderr b/src/test/ui/impl-trait/trait_type.stderr
new file mode 100644
index 00000000000..cc7a7153a38
--- /dev/null
+++ b/src/test/ui/impl-trait/trait_type.stderr
@@ -0,0 +1,35 @@
+error[E0053]: method `fmt` has an incompatible type for trait
+  --> $DIR/trait_type.rs:17:4
+   |
+17 |    fn fmt(&self, x: &str) -> () { }
+   |    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability
+   |
+   = note: expected type `fn(&MyType, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
+              found type `fn(&MyType, &str)`
+
+error[E0050]: method `fmt` has 1 parameter but the declaration in trait `std::fmt::Display::fmt` has 2
+  --> $DIR/trait_type.rs:21:11
+   |
+21 |    fn fmt(&self) -> () { }
+   |           ^^^^^ expected 2 parameters, found 1
+   |
+   = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
+
+error[E0186]: method `fmt` has a `&self` declaration in the trait, but not in the impl
+  --> $DIR/trait_type.rs:25:4
+   |
+25 |    fn fmt() -> () { }
+   |    ^^^^^^^^^^^^^^^^^^ expected `&self` in impl
+   |
+   = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
+
+error[E0046]: not all trait items implemented, missing: `fmt`
+  --> $DIR/trait_type.rs:28:1
+   |
+28 | impl std::fmt::Display for MyType4 {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `fmt` in implementation
+   |
+   = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
+
+error: aborting due to previous error(s)
+