Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 147649d

Browse files
committed
Suggest changing impl parameter types to match trait
This is particularly useful for cases where arbitrary self types are used, like in custom `Future`s.
1 parent d43ede1 commit 147649d

File tree

12 files changed

+151
-25
lines changed

12 files changed

+151
-25
lines changed

compiler/rustc_typeck/src/check/compare_method.rs

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -290,18 +290,55 @@ fn compare_predicate_entailment<'tcx>(
290290
"method `{}` has an incompatible type for trait",
291291
trait_m.ident
292292
);
293-
if let TypeError::ArgumentMutability(_) = terr {
294-
if let Some(trait_err_span) = trait_err_span {
295-
if let Ok(trait_err_str) = tcx.sess.source_map().span_to_snippet(trait_err_span)
293+
match &terr {
294+
TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
295+
if trait_m.fn_has_self_parameter =>
296+
{
297+
let ty = trait_sig.inputs()[0];
298+
let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty())
296299
{
300+
ExplicitSelf::ByValue => "self".to_owned(),
301+
ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
302+
ExplicitSelf::ByReference(_, hir::Mutability::Mut) => {
303+
"&mut self".to_owned()
304+
}
305+
_ => format!("self: {}", ty),
306+
};
307+
308+
// When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
309+
// span points only at the type `Box<Self`>, but we want to cover the whole
310+
// argument pattern and type.
311+
let impl_m_hir_id =
312+
tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
313+
let span = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
314+
ImplItemKind::Fn(ref sig, body) => tcx
315+
.hir()
316+
.body_param_names(body)
317+
.zip(sig.decl.inputs.iter())
318+
.map(|(param, ty)| param.span.to(ty.span))
319+
.next()
320+
.unwrap_or(impl_err_span),
321+
_ => bug!("{:?} is not a method", impl_m),
322+
};
323+
324+
diag.span_suggestion(
325+
span,
326+
"change the self-receiver type to match the trait",
327+
sugg,
328+
Applicability::MachineApplicable,
329+
);
330+
}
331+
TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
332+
if let Some(trait_ty) = trait_sig.inputs().get(*i) {
297333
diag.span_suggestion(
298334
impl_err_span,
299-
"consider changing the mutability to match the trait",
300-
trait_err_str,
335+
"change the parameter type to match the trait",
336+
trait_ty.to_string(),
301337
Applicability::MachineApplicable,
302338
);
303339
}
304340
}
341+
_ => {}
305342
}
306343

307344
infcx.note_type_err(
@@ -482,8 +519,7 @@ fn compare_self_type<'tcx>(
482519
tcx.sess,
483520
impl_m_span,
484521
E0186,
485-
"method `{}` has a `{}` declaration in the trait, but \
486-
not in the impl",
522+
"method `{}` has a `{}` declaration in the trait, but not in the impl",
487523
trait_m.ident,
488524
self_descr
489525
);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use std::future::Future;
2+
use std::task::{Context, Poll};
3+
4+
fn main() {}
5+
6+
struct MyFuture {}
7+
8+
impl Future for MyFuture {
9+
type Output = ();
10+
fn poll(self, _: &mut Context<'_>) -> Poll<()> {
11+
//~^ ERROR method `poll` has an incompatible type for trait
12+
todo!()
13+
}
14+
}
15+
16+
trait T {
17+
fn foo(self);
18+
}
19+
20+
impl T for MyFuture {
21+
fn foo(self: Box<Self>) {}
22+
//~^ ERROR method `foo` has an incompatible type for trait
23+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
error[E0053]: method `poll` has an incompatible type for trait
2+
--> $DIR/bad-self-type.rs:10:13
3+
|
4+
LL | fn poll(self, _: &mut Context<'_>) -> Poll<()> {
5+
| ^^^^
6+
| |
7+
| expected struct `Pin`, found struct `MyFuture`
8+
| help: change the self-receiver type to match the trait: `self: Pin<&mut MyFuture>`
9+
|
10+
= note: expected fn pointer `fn(Pin<&mut MyFuture>, &mut Context<'_>) -> Poll<_>`
11+
found fn pointer `fn(MyFuture, &mut Context<'_>) -> Poll<_>`
12+
13+
error[E0053]: method `foo` has an incompatible type for trait
14+
--> $DIR/bad-self-type.rs:21:18
15+
|
16+
LL | fn foo(self);
17+
| ---- type in trait
18+
...
19+
LL | fn foo(self: Box<Self>) {}
20+
| ------^^^^^^^^^
21+
| | |
22+
| | expected struct `MyFuture`, found struct `Box`
23+
| help: change the self-receiver type to match the trait: `self`
24+
|
25+
= note: expected fn pointer `fn(MyFuture)`
26+
found fn pointer `fn(Box<MyFuture>)`
27+
28+
error: aborting due to 2 previous errors
29+
30+
For more information about this error, try `rustc --explain E0053`.

src/test/ui/compare-method/reordered-type-param.stderr

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ LL | fn b<C:Clone,D>(&self, x: C) -> C;
55
| - type in trait
66
...
77
LL | fn b<F:Clone,G>(&self, _x: G) -> G { panic!() }
8-
| - - ^ expected type parameter `F`, found type parameter `G`
9-
| | |
8+
| - - ^
9+
| | | |
10+
| | | expected type parameter `F`, found type parameter `G`
11+
| | | help: change the parameter type to match the trait: `F`
1012
| | found type parameter
1113
| expected type parameter
1214
|

src/test/ui/impl-trait/impl-generic-mismatch-ab.stderr

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ LL | fn foo<A: Debug>(&self, a: &A, b: &impl Debug);
55
| -- type in trait
66
...
77
LL | fn foo<B: Debug>(&self, a: &impl Debug, b: &B) { }
8-
| - ^^^^^^^^^^^ expected type parameter `B`, found type parameter `impl Debug`
9-
| |
8+
| - ^^^^^^^^^^^
9+
| | |
10+
| | expected type parameter `B`, found type parameter `impl Debug`
11+
| | help: change the parameter type to match the trait: `&B`
1012
| expected type parameter
1113
|
1214
= note: expected fn pointer `fn(&(), &B, &impl Debug)`

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ error[E0053]: method `fmt` has an incompatible type for trait
22
--> $DIR/trait_type.rs:7:21
33
|
44
LL | fn fmt(&self, x: &str) -> () { }
5-
| ^^^^ types differ in mutability
5+
| ^^^^
6+
| |
7+
| types differ in mutability
8+
| help: change the parameter type to match the trait: `&mut Formatter<'_>`
69
|
710
= note: expected fn pointer `fn(&MyType, &mut Formatter<'_>) -> Result<(), std::fmt::Error>`
811
found fn pointer `fn(&MyType, &str)`

src/test/ui/issues/issue-13033.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ LL | fn bar(&mut self, other: &dyn Foo) {}
88
| ^^^^^^^^
99
| |
1010
| types differ in mutability
11-
| help: consider changing the mutability to match the trait: `&mut dyn Foo`
11+
| help: change the parameter type to match the trait: `&mut dyn Foo`
1212
|
1313
= note: expected fn pointer `fn(&mut Baz, &mut dyn Foo)`
1414
found fn pointer `fn(&mut Baz, &dyn Foo)`

src/test/ui/issues/issue-20225.stderr

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ error[E0053]: method `call` has an incompatible type for trait
44
LL | impl<'a, T> Fn<(&'a T,)> for Foo {
55
| - this type parameter
66
LL | extern "rust-call" fn call(&self, (_,): (T,)) {}
7-
| ^^^^ expected `&T`, found type parameter `T`
7+
| ^^^^
8+
| |
9+
| expected `&T`, found type parameter `T`
10+
| help: change the parameter type to match the trait: `(&'a T,)`
811
|
912
= note: expected fn pointer `extern "rust-call" fn(&Foo, (&'a T,))`
1013
found fn pointer `extern "rust-call" fn(&Foo, (T,))`
@@ -15,7 +18,10 @@ error[E0053]: method `call_mut` has an incompatible type for trait
1518
LL | impl<'a, T> FnMut<(&'a T,)> for Foo {
1619
| - this type parameter
1720
LL | extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {}
18-
| ^^^^ expected `&T`, found type parameter `T`
21+
| ^^^^
22+
| |
23+
| expected `&T`, found type parameter `T`
24+
| help: change the parameter type to match the trait: `(&'a T,)`
1925
|
2026
= note: expected fn pointer `extern "rust-call" fn(&mut Foo, (&'a T,))`
2127
found fn pointer `extern "rust-call" fn(&mut Foo, (T,))`
@@ -27,7 +33,10 @@ LL | impl<'a, T> FnOnce<(&'a T,)> for Foo {
2733
| - this type parameter
2834
...
2935
LL | extern "rust-call" fn call_once(self, (_,): (T,)) {}
30-
| ^^^^ expected `&T`, found type parameter `T`
36+
| ^^^^
37+
| |
38+
| expected `&T`, found type parameter `T`
39+
| help: change the parameter type to match the trait: `(&'a T,)`
3140
|
3241
= note: expected fn pointer `extern "rust-call" fn(Foo, (&'a T,))`
3342
found fn pointer `extern "rust-call" fn(Foo, (T,))`

src/test/ui/issues/issue-35869.stderr

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ LL | fn foo(_: fn(u8) -> ());
55
| ------------ type in trait
66
...
77
LL | fn foo(_: fn(u16) -> ()) {}
8-
| ^^^^^^^^^^^^^ expected `u8`, found `u16`
8+
| ^^^^^^^^^^^^^
9+
| |
10+
| expected `u8`, found `u16`
11+
| help: change the parameter type to match the trait: `fn(u8)`
912
|
1013
= note: expected fn pointer `fn(fn(u8))`
1114
found fn pointer `fn(fn(u16))`
@@ -17,7 +20,10 @@ LL | fn bar(_: Option<u8>);
1720
| ---------- type in trait
1821
...
1922
LL | fn bar(_: Option<u16>) {}
20-
| ^^^^^^^^^^^ expected `u8`, found `u16`
23+
| ^^^^^^^^^^^
24+
| |
25+
| expected `u8`, found `u16`
26+
| help: change the parameter type to match the trait: `Option<u8>`
2127
|
2228
= note: expected fn pointer `fn(Option<u8>)`
2329
found fn pointer `fn(Option<u16>)`
@@ -29,7 +35,10 @@ LL | fn baz(_: (u8, u16));
2935
| --------- type in trait
3036
...
3137
LL | fn baz(_: (u16, u16)) {}
32-
| ^^^^^^^^^^ expected `u8`, found `u16`
38+
| ^^^^^^^^^^
39+
| |
40+
| expected `u8`, found `u16`
41+
| help: change the parameter type to match the trait: `(u8, u16)`
3342
|
3443
= note: expected fn pointer `fn((u8, _))`
3544
found fn pointer `fn((u16, _))`

src/test/ui/mismatched_types/E0053.stderr

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ LL | fn foo(x: u16);
55
| --- type in trait
66
...
77
LL | fn foo(x: i16) { }
8-
| ^^^ expected `u16`, found `i16`
8+
| ^^^
9+
| |
10+
| expected `u16`, found `i16`
11+
| help: change the parameter type to match the trait: `u16`
912
|
1013
= note: expected fn pointer `fn(u16)`
1114
found fn pointer `fn(i16)`
@@ -20,7 +23,7 @@ LL | fn bar(&mut self) { }
2023
| ^^^^^^^^^
2124
| |
2225
| types differ in mutability
23-
| help: consider changing the mutability to match the trait: `&self`
26+
| help: change the self-receiver type to match the trait: `self: &Bar`
2427
|
2528
= note: expected fn pointer `fn(&Bar)`
2629
found fn pointer `fn(&mut Bar)`

src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ LL | fn foo(x: u16);
55
| --- type in trait
66
...
77
LL | fn foo(x: i16) { }
8-
| ^^^ expected `u16`, found `i16`
8+
| ^^^
9+
| |
10+
| expected `u16`, found `i16`
11+
| help: change the parameter type to match the trait: `u16`
912
|
1013
= note: expected fn pointer `fn(u16)`
1114
found fn pointer `fn(i16)`
@@ -20,7 +23,7 @@ LL | fn bar(&mut self, bar: &Bar) { }
2023
| ^^^^
2124
| |
2225
| types differ in mutability
23-
| help: consider changing the mutability to match the trait: `&mut Bar`
26+
| help: change the parameter type to match the trait: `&mut Bar`
2427
|
2528
= note: expected fn pointer `fn(&mut Bar, &mut Bar)`
2629
found fn pointer `fn(&mut Bar, &Bar)`

src/test/ui/wrong-mul-method-signature.stderr

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ error[E0053]: method `mul` has an incompatible type for trait
22
--> $DIR/wrong-mul-method-signature.rs:16:21
33
|
44
LL | fn mul(self, s: &f64) -> Vec1 {
5-
| ^^^^ expected `f64`, found `&f64`
5+
| ^^^^
6+
| |
7+
| expected `f64`, found `&f64`
8+
| help: change the parameter type to match the trait: `f64`
69
|
710
= note: expected fn pointer `fn(Vec1, f64) -> Vec1`
811
found fn pointer `fn(Vec1, &f64) -> Vec1`
@@ -11,7 +14,10 @@ error[E0053]: method `mul` has an incompatible type for trait
1114
--> $DIR/wrong-mul-method-signature.rs:33:21
1215
|
1316
LL | fn mul(self, s: f64) -> Vec2 {
14-
| ^^^ expected struct `Vec2`, found `f64`
17+
| ^^^
18+
| |
19+
| expected struct `Vec2`, found `f64`
20+
| help: change the parameter type to match the trait: `Vec2`
1521
|
1622
= note: expected fn pointer `fn(Vec2, Vec2) -> f64`
1723
found fn pointer `fn(Vec2, f64) -> Vec2`

0 commit comments

Comments
 (0)