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: ``` 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>` ```
This commit is contained in:
parent
4ed2edaafe
commit
e324919ec5
@ -221,6 +221,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)]
|
||||
|
@ -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
|
||||
|
@ -543,6 +543,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);
|
||||
@ -690,6 +693,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 {}",
|
||||
|
@ -1334,18 +1334,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: `{}`",
|
||||
@ -1360,9 +1348,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();
|
||||
|
30
src/test/ui/impl-trait/trait_type.rs
Normal file
30
src/test/ui/impl-trait/trait_type.rs
Normal file
@ -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() {}
|
35
src/test/ui/impl-trait/trait_type.stderr
Normal file
35
src/test/ui/impl-trait/trait_type.stderr
Normal file
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user