Skip to content

Commit e324919

Browse files
committed
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>` ```
1 parent 4ed2eda commit e324919

File tree

6 files changed

+97
-15
lines changed

6 files changed

+97
-15
lines changed

src/librustc/ty/mod.rs

+16
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,22 @@ impl AssociatedItem {
221221
AssociatedKind::Method => !self.method_has_self_argument,
222222
}
223223
}
224+
225+
pub fn signature<'a, 'tcx>(&self, tcx: &TyCtxt<'a, 'tcx, 'tcx>) -> String {
226+
match self.kind {
227+
ty::AssociatedKind::Method => {
228+
// We skip the binder here because the binder would deanonymize all
229+
// late-bound regions, and we don't want method signatures to show up
230+
// `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
231+
// regions just fine, showing `fn(&MyType)`.
232+
format!("{}", tcx.type_of(self.def_id).fn_sig().skip_binder())
233+
}
234+
ty::AssociatedKind::Type => format!("type {};", self.name.to_string()),
235+
ty::AssociatedKind::Const => {
236+
format!("const {}: {:?};", self.name.to_string(), tcx.type_of(self.def_id))
237+
}
238+
}
239+
}
224240
}
225241

226242
#[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable)]

src/librustc_errors/diagnostic.rs

+8
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,14 @@ impl Diagnostic {
157157
self
158158
}
159159

160+
pub fn note_trait_signature(&mut self, name: String, signature: String) -> &mut Self {
161+
self.highlighted_note(vec![
162+
(format!("`{}` from trait: `", name), Style::NoStyle),
163+
(signature, Style::Highlight),
164+
("`".to_string(), Style::NoStyle)]);
165+
self
166+
}
167+
160168
pub fn note(&mut self, msg: &str) -> &mut Self {
161169
self.sub(Level::Note, msg, MultiSpan::new(), None);
162170
self

src/librustc_typeck/check/compare_method.rs

+6
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,9 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
543543
format!("expected `{}` in impl", self_descr));
544544
if let Some(span) = tcx.hir.span_if_local(trait_m.def_id) {
545545
err.span_label(span, format!("`{}` used in trait", self_descr));
546+
} else {
547+
err.note_trait_signature(trait_m.name.to_string(),
548+
trait_m.signature(&tcx));
546549
}
547550
err.emit();
548551
return Err(ErrorReported);
@@ -690,6 +693,9 @@ fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
690693
} else {
691694
format!("{} parameter", trait_number_args)
692695
}));
696+
} else {
697+
err.note_trait_signature(trait_m.name.to_string(),
698+
trait_m.signature(&tcx));
693699
}
694700
err.span_label(impl_span,
695701
format!("expected {}, found {}",

src/librustc_typeck/check/mod.rs

+2-15
Original file line numberDiff line numberDiff line change
@@ -1334,18 +1334,6 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
13341334
}
13351335
}
13361336

1337-
let signature = |item: &ty::AssociatedItem| {
1338-
match item.kind {
1339-
ty::AssociatedKind::Method => {
1340-
format!("{}", tcx.type_of(item.def_id).fn_sig().0)
1341-
}
1342-
ty::AssociatedKind::Type => format!("type {};", item.name.to_string()),
1343-
ty::AssociatedKind::Const => {
1344-
format!("const {}: {:?};", item.name.to_string(), tcx.type_of(item.def_id))
1345-
}
1346-
}
1347-
};
1348-
13491337
if !missing_items.is_empty() {
13501338
let mut err = struct_span_err!(tcx.sess, impl_span, E0046,
13511339
"not all trait items implemented, missing: `{}`",
@@ -1360,9 +1348,8 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
13601348
if let Some(span) = tcx.hir.span_if_local(trait_item.def_id) {
13611349
err.span_label(span, format!("`{}` from trait", trait_item.name));
13621350
} else {
1363-
err.note(&format!("`{}` from trait: `{}`",
1364-
trait_item.name,
1365-
signature(&trait_item)));
1351+
err.note_trait_signature(trait_item.name.to_string(),
1352+
trait_item.signature(&tcx));
13661353
}
13671354
}
13681355
err.emit();

src/test/ui/impl-trait/trait_type.rs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct MyType;
12+
struct MyType2;
13+
struct MyType3;
14+
struct MyType4;
15+
16+
impl std::fmt::Display for MyType {
17+
fn fmt(&self, x: &str) -> () { }
18+
}
19+
20+
impl std::fmt::Display for MyType2 {
21+
fn fmt(&self) -> () { }
22+
}
23+
24+
impl std::fmt::Display for MyType3 {
25+
fn fmt() -> () { }
26+
}
27+
28+
impl std::fmt::Display for MyType4 {}
29+
30+
fn main() {}
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
error[E0053]: method `fmt` has an incompatible type for trait
2+
--> $DIR/trait_type.rs:17:4
3+
|
4+
17 | fn fmt(&self, x: &str) -> () { }
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability
6+
|
7+
= note: expected type `fn(&MyType, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
8+
found type `fn(&MyType, &str)`
9+
10+
error[E0050]: method `fmt` has 1 parameter but the declaration in trait `std::fmt::Display::fmt` has 2
11+
--> $DIR/trait_type.rs:21:11
12+
|
13+
21 | fn fmt(&self) -> () { }
14+
| ^^^^^ expected 2 parameters, found 1
15+
|
16+
= note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
17+
18+
error[E0186]: method `fmt` has a `&self` declaration in the trait, but not in the impl
19+
--> $DIR/trait_type.rs:25:4
20+
|
21+
25 | fn fmt() -> () { }
22+
| ^^^^^^^^^^^^^^^^^^ expected `&self` in impl
23+
|
24+
= note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
25+
26+
error[E0046]: not all trait items implemented, missing: `fmt`
27+
--> $DIR/trait_type.rs:28:1
28+
|
29+
28 | impl std::fmt::Display for MyType4 {}
30+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `fmt` in implementation
31+
|
32+
= note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
33+
34+
error: aborting due to previous error(s)
35+

0 commit comments

Comments
 (0)