Skip to content

Commit 0418fa9

Browse files
committed
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.
2 parents 9a4e13f + e324919 commit 0418fa9

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
@@ -198,6 +198,22 @@ impl AssociatedItem {
198198
AssociatedKind::Method => !self.method_has_self_argument,
199199
}
200200
}
201+
202+
pub fn signature<'a, 'tcx>(&self, tcx: &TyCtxt<'a, 'tcx, 'tcx>) -> String {
203+
match self.kind {
204+
ty::AssociatedKind::Method => {
205+
// We skip the binder here because the binder would deanonymize all
206+
// late-bound regions, and we don't want method signatures to show up
207+
// `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
208+
// regions just fine, showing `fn(&MyType)`.
209+
format!("{}", tcx.type_of(self.def_id).fn_sig().skip_binder())
210+
}
211+
ty::AssociatedKind::Type => format!("type {};", self.name.to_string()),
212+
ty::AssociatedKind::Const => {
213+
format!("const {}: {:?};", self.name.to_string(), tcx.type_of(self.def_id))
214+
}
215+
}
216+
}
201217
}
202218

203219
#[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
@@ -550,6 +550,9 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
550550
format!("expected `{}` in impl", self_descr));
551551
if let Some(span) = tcx.hir.span_if_local(trait_m.def_id) {
552552
err.span_label(span, format!("`{}` used in trait", self_descr));
553+
} else {
554+
err.note_trait_signature(trait_m.name.to_string(),
555+
trait_m.signature(&tcx));
553556
}
554557
err.emit();
555558
return Err(ErrorReported);
@@ -697,6 +700,9 @@ fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
697700
} else {
698701
format!("{} parameter", trait_number_args)
699702
}));
703+
} else {
704+
err.note_trait_signature(trait_m.name.to_string(),
705+
trait_m.signature(&tcx));
700706
}
701707
err.span_label(impl_span,
702708
format!("expected {}, found {}",

src/librustc_typeck/check/mod.rs

+2-15
Original file line numberDiff line numberDiff line change
@@ -1348,18 +1348,6 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
13481348
}
13491349
}
13501350

1351-
let signature = |item: &ty::AssociatedItem| {
1352-
match item.kind {
1353-
ty::AssociatedKind::Method => {
1354-
format!("{}", tcx.type_of(item.def_id).fn_sig().0)
1355-
}
1356-
ty::AssociatedKind::Type => format!("type {};", item.name.to_string()),
1357-
ty::AssociatedKind::Const => {
1358-
format!("const {}: {:?};", item.name.to_string(), tcx.type_of(item.def_id))
1359-
}
1360-
}
1361-
};
1362-
13631351
if !missing_items.is_empty() {
13641352
let mut err = struct_span_err!(tcx.sess, impl_span, E0046,
13651353
"not all trait items implemented, missing: `{}`",
@@ -1374,9 +1362,8 @@ fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
13741362
if let Some(span) = tcx.hir.span_if_local(trait_item.def_id) {
13751363
err.span_label(span, format!("`{}` from trait", trait_item.name));
13761364
} else {
1377-
err.note(&format!("`{}` from trait: `{}`",
1378-
trait_item.name,
1379-
signature(&trait_item)));
1365+
err.note_trait_signature(trait_item.name.to_string(),
1366+
trait_item.signature(&tcx));
13801367
}
13811368
}
13821369
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)