Skip to content

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)