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.
This commit is contained in:
parent
d43ede10e4
commit
147649d4b9
12 changed files with 151 additions and 25 deletions
|
@ -290,18 +290,55 @@ fn compare_predicate_entailment<'tcx>(
|
||||||
"method `{}` has an incompatible type for trait",
|
"method `{}` has an incompatible type for trait",
|
||||||
trait_m.ident
|
trait_m.ident
|
||||||
);
|
);
|
||||||
if let TypeError::ArgumentMutability(_) = terr {
|
match &terr {
|
||||||
if let Some(trait_err_span) = trait_err_span {
|
TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
|
||||||
if let Ok(trait_err_str) = tcx.sess.source_map().span_to_snippet(trait_err_span)
|
if trait_m.fn_has_self_parameter =>
|
||||||
|
{
|
||||||
|
let ty = trait_sig.inputs()[0];
|
||||||
|
let sugg = match ExplicitSelf::determine(ty, |_| ty == impl_trait_ref.self_ty())
|
||||||
{
|
{
|
||||||
|
ExplicitSelf::ByValue => "self".to_owned(),
|
||||||
|
ExplicitSelf::ByReference(_, hir::Mutability::Not) => "&self".to_owned(),
|
||||||
|
ExplicitSelf::ByReference(_, hir::Mutability::Mut) => {
|
||||||
|
"&mut self".to_owned()
|
||||||
|
}
|
||||||
|
_ => format!("self: {}", ty),
|
||||||
|
};
|
||||||
|
|
||||||
|
// When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
|
||||||
|
// span points only at the type `Box<Self`>, but we want to cover the whole
|
||||||
|
// argument pattern and type.
|
||||||
|
let impl_m_hir_id =
|
||||||
|
tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local());
|
||||||
|
let span = match tcx.hir().expect_impl_item(impl_m_hir_id).kind {
|
||||||
|
ImplItemKind::Fn(ref sig, body) => tcx
|
||||||
|
.hir()
|
||||||
|
.body_param_names(body)
|
||||||
|
.zip(sig.decl.inputs.iter())
|
||||||
|
.map(|(param, ty)| param.span.to(ty.span))
|
||||||
|
.next()
|
||||||
|
.unwrap_or(impl_err_span),
|
||||||
|
_ => bug!("{:?} is not a method", impl_m),
|
||||||
|
};
|
||||||
|
|
||||||
|
diag.span_suggestion(
|
||||||
|
span,
|
||||||
|
"change the self-receiver type to match the trait",
|
||||||
|
sugg,
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => {
|
||||||
|
if let Some(trait_ty) = trait_sig.inputs().get(*i) {
|
||||||
diag.span_suggestion(
|
diag.span_suggestion(
|
||||||
impl_err_span,
|
impl_err_span,
|
||||||
"consider changing the mutability to match the trait",
|
"change the parameter type to match the trait",
|
||||||
trait_err_str,
|
trait_ty.to_string(),
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
infcx.note_type_err(
|
infcx.note_type_err(
|
||||||
|
@ -482,8 +519,7 @@ fn compare_self_type<'tcx>(
|
||||||
tcx.sess,
|
tcx.sess,
|
||||||
impl_m_span,
|
impl_m_span,
|
||||||
E0186,
|
E0186,
|
||||||
"method `{}` has a `{}` declaration in the trait, but \
|
"method `{}` has a `{}` declaration in the trait, but not in the impl",
|
||||||
not in the impl",
|
|
||||||
trait_m.ident,
|
trait_m.ident,
|
||||||
self_descr
|
self_descr
|
||||||
);
|
);
|
||||||
|
|
23
src/test/ui/compare-method/bad-self-type.rs
Normal file
23
src/test/ui/compare-method/bad-self-type.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
use std::future::Future;
|
||||||
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
struct MyFuture {}
|
||||||
|
|
||||||
|
impl Future for MyFuture {
|
||||||
|
type Output = ();
|
||||||
|
fn poll(self, _: &mut Context<'_>) -> Poll<()> {
|
||||||
|
//~^ ERROR method `poll` has an incompatible type for trait
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait T {
|
||||||
|
fn foo(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl T for MyFuture {
|
||||||
|
fn foo(self: Box<Self>) {}
|
||||||
|
//~^ ERROR method `foo` has an incompatible type for trait
|
||||||
|
}
|
30
src/test/ui/compare-method/bad-self-type.stderr
Normal file
30
src/test/ui/compare-method/bad-self-type.stderr
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
error[E0053]: method `poll` has an incompatible type for trait
|
||||||
|
--> $DIR/bad-self-type.rs:10:13
|
||||||
|
|
|
||||||
|
LL | fn poll(self, _: &mut Context<'_>) -> Poll<()> {
|
||||||
|
| ^^^^
|
||||||
|
| |
|
||||||
|
| expected struct `Pin`, found struct `MyFuture`
|
||||||
|
| help: change the self-receiver type to match the trait: `self: Pin<&mut MyFuture>`
|
||||||
|
|
|
||||||
|
= note: expected fn pointer `fn(Pin<&mut MyFuture>, &mut Context<'_>) -> Poll<_>`
|
||||||
|
found fn pointer `fn(MyFuture, &mut Context<'_>) -> Poll<_>`
|
||||||
|
|
||||||
|
error[E0053]: method `foo` has an incompatible type for trait
|
||||||
|
--> $DIR/bad-self-type.rs:21:18
|
||||||
|
|
|
||||||
|
LL | fn foo(self);
|
||||||
|
| ---- type in trait
|
||||||
|
...
|
||||||
|
LL | fn foo(self: Box<Self>) {}
|
||||||
|
| ------^^^^^^^^^
|
||||||
|
| | |
|
||||||
|
| | expected struct `MyFuture`, found struct `Box`
|
||||||
|
| help: change the self-receiver type to match the trait: `self`
|
||||||
|
|
|
||||||
|
= note: expected fn pointer `fn(MyFuture)`
|
||||||
|
found fn pointer `fn(Box<MyFuture>)`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0053`.
|
|
@ -5,8 +5,10 @@ LL | fn b<C:Clone,D>(&self, x: C) -> C;
|
||||||
| - type in trait
|
| - type in trait
|
||||||
...
|
...
|
||||||
LL | fn b<F:Clone,G>(&self, _x: G) -> G { panic!() }
|
LL | fn b<F:Clone,G>(&self, _x: G) -> G { panic!() }
|
||||||
| - - ^ expected type parameter `F`, found type parameter `G`
|
| - - ^
|
||||||
| | |
|
| | | |
|
||||||
|
| | | expected type parameter `F`, found type parameter `G`
|
||||||
|
| | | help: change the parameter type to match the trait: `F`
|
||||||
| | found type parameter
|
| | found type parameter
|
||||||
| expected type parameter
|
| expected type parameter
|
||||||
|
|
|
|
||||||
|
|
|
@ -5,8 +5,10 @@ LL | fn foo<A: Debug>(&self, a: &A, b: &impl Debug);
|
||||||
| -- type in trait
|
| -- type in trait
|
||||||
...
|
...
|
||||||
LL | fn foo<B: Debug>(&self, a: &impl Debug, b: &B) { }
|
LL | fn foo<B: Debug>(&self, a: &impl Debug, b: &B) { }
|
||||||
| - ^^^^^^^^^^^ expected type parameter `B`, found type parameter `impl Debug`
|
| - ^^^^^^^^^^^
|
||||||
| |
|
| | |
|
||||||
|
| | expected type parameter `B`, found type parameter `impl Debug`
|
||||||
|
| | help: change the parameter type to match the trait: `&B`
|
||||||
| expected type parameter
|
| expected type parameter
|
||||||
|
|
|
|
||||||
= note: expected fn pointer `fn(&(), &B, &impl Debug)`
|
= note: expected fn pointer `fn(&(), &B, &impl Debug)`
|
||||||
|
|
|
@ -2,7 +2,10 @@ error[E0053]: method `fmt` has an incompatible type for trait
|
||||||
--> $DIR/trait_type.rs:7:21
|
--> $DIR/trait_type.rs:7:21
|
||||||
|
|
|
|
||||||
LL | fn fmt(&self, x: &str) -> () { }
|
LL | fn fmt(&self, x: &str) -> () { }
|
||||||
| ^^^^ types differ in mutability
|
| ^^^^
|
||||||
|
| |
|
||||||
|
| types differ in mutability
|
||||||
|
| help: change the parameter type to match the trait: `&mut Formatter<'_>`
|
||||||
|
|
|
|
||||||
= note: expected fn pointer `fn(&MyType, &mut Formatter<'_>) -> Result<(), std::fmt::Error>`
|
= note: expected fn pointer `fn(&MyType, &mut Formatter<'_>) -> Result<(), std::fmt::Error>`
|
||||||
found fn pointer `fn(&MyType, &str)`
|
found fn pointer `fn(&MyType, &str)`
|
||||||
|
|
|
@ -8,7 +8,7 @@ LL | fn bar(&mut self, other: &dyn Foo) {}
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
| |
|
| |
|
||||||
| types differ in mutability
|
| types differ in mutability
|
||||||
| help: consider changing the mutability to match the trait: `&mut dyn Foo`
|
| help: change the parameter type to match the trait: `&mut dyn Foo`
|
||||||
|
|
|
|
||||||
= note: expected fn pointer `fn(&mut Baz, &mut dyn Foo)`
|
= note: expected fn pointer `fn(&mut Baz, &mut dyn Foo)`
|
||||||
found fn pointer `fn(&mut Baz, &dyn Foo)`
|
found fn pointer `fn(&mut Baz, &dyn Foo)`
|
||||||
|
|
|
@ -4,7 +4,10 @@ error[E0053]: method `call` has an incompatible type for trait
|
||||||
LL | impl<'a, T> Fn<(&'a T,)> for Foo {
|
LL | impl<'a, T> Fn<(&'a T,)> for Foo {
|
||||||
| - this type parameter
|
| - this type parameter
|
||||||
LL | extern "rust-call" fn call(&self, (_,): (T,)) {}
|
LL | extern "rust-call" fn call(&self, (_,): (T,)) {}
|
||||||
| ^^^^ expected `&T`, found type parameter `T`
|
| ^^^^
|
||||||
|
| |
|
||||||
|
| expected `&T`, found type parameter `T`
|
||||||
|
| help: change the parameter type to match the trait: `(&'a T,)`
|
||||||
|
|
|
|
||||||
= note: expected fn pointer `extern "rust-call" fn(&Foo, (&'a T,))`
|
= note: expected fn pointer `extern "rust-call" fn(&Foo, (&'a T,))`
|
||||||
found fn pointer `extern "rust-call" fn(&Foo, (T,))`
|
found fn pointer `extern "rust-call" fn(&Foo, (T,))`
|
||||||
|
@ -15,7 +18,10 @@ error[E0053]: method `call_mut` has an incompatible type for trait
|
||||||
LL | impl<'a, T> FnMut<(&'a T,)> for Foo {
|
LL | impl<'a, T> FnMut<(&'a T,)> for Foo {
|
||||||
| - this type parameter
|
| - this type parameter
|
||||||
LL | extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {}
|
LL | extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {}
|
||||||
| ^^^^ expected `&T`, found type parameter `T`
|
| ^^^^
|
||||||
|
| |
|
||||||
|
| expected `&T`, found type parameter `T`
|
||||||
|
| help: change the parameter type to match the trait: `(&'a T,)`
|
||||||
|
|
|
|
||||||
= note: expected fn pointer `extern "rust-call" fn(&mut Foo, (&'a T,))`
|
= note: expected fn pointer `extern "rust-call" fn(&mut Foo, (&'a T,))`
|
||||||
found fn pointer `extern "rust-call" fn(&mut Foo, (T,))`
|
found fn pointer `extern "rust-call" fn(&mut Foo, (T,))`
|
||||||
|
@ -27,7 +33,10 @@ LL | impl<'a, T> FnOnce<(&'a T,)> for Foo {
|
||||||
| - this type parameter
|
| - this type parameter
|
||||||
...
|
...
|
||||||
LL | extern "rust-call" fn call_once(self, (_,): (T,)) {}
|
LL | extern "rust-call" fn call_once(self, (_,): (T,)) {}
|
||||||
| ^^^^ expected `&T`, found type parameter `T`
|
| ^^^^
|
||||||
|
| |
|
||||||
|
| expected `&T`, found type parameter `T`
|
||||||
|
| help: change the parameter type to match the trait: `(&'a T,)`
|
||||||
|
|
|
|
||||||
= note: expected fn pointer `extern "rust-call" fn(Foo, (&'a T,))`
|
= note: expected fn pointer `extern "rust-call" fn(Foo, (&'a T,))`
|
||||||
found fn pointer `extern "rust-call" fn(Foo, (T,))`
|
found fn pointer `extern "rust-call" fn(Foo, (T,))`
|
||||||
|
|
|
@ -5,7 +5,10 @@ LL | fn foo(_: fn(u8) -> ());
|
||||||
| ------------ type in trait
|
| ------------ type in trait
|
||||||
...
|
...
|
||||||
LL | fn foo(_: fn(u16) -> ()) {}
|
LL | fn foo(_: fn(u16) -> ()) {}
|
||||||
| ^^^^^^^^^^^^^ expected `u8`, found `u16`
|
| ^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| expected `u8`, found `u16`
|
||||||
|
| help: change the parameter type to match the trait: `fn(u8)`
|
||||||
|
|
|
|
||||||
= note: expected fn pointer `fn(fn(u8))`
|
= note: expected fn pointer `fn(fn(u8))`
|
||||||
found fn pointer `fn(fn(u16))`
|
found fn pointer `fn(fn(u16))`
|
||||||
|
@ -17,7 +20,10 @@ LL | fn bar(_: Option<u8>);
|
||||||
| ---------- type in trait
|
| ---------- type in trait
|
||||||
...
|
...
|
||||||
LL | fn bar(_: Option<u16>) {}
|
LL | fn bar(_: Option<u16>) {}
|
||||||
| ^^^^^^^^^^^ expected `u8`, found `u16`
|
| ^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| expected `u8`, found `u16`
|
||||||
|
| help: change the parameter type to match the trait: `Option<u8>`
|
||||||
|
|
|
|
||||||
= note: expected fn pointer `fn(Option<u8>)`
|
= note: expected fn pointer `fn(Option<u8>)`
|
||||||
found fn pointer `fn(Option<u16>)`
|
found fn pointer `fn(Option<u16>)`
|
||||||
|
@ -29,7 +35,10 @@ LL | fn baz(_: (u8, u16));
|
||||||
| --------- type in trait
|
| --------- type in trait
|
||||||
...
|
...
|
||||||
LL | fn baz(_: (u16, u16)) {}
|
LL | fn baz(_: (u16, u16)) {}
|
||||||
| ^^^^^^^^^^ expected `u8`, found `u16`
|
| ^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| expected `u8`, found `u16`
|
||||||
|
| help: change the parameter type to match the trait: `(u8, u16)`
|
||||||
|
|
|
|
||||||
= note: expected fn pointer `fn((u8, _))`
|
= note: expected fn pointer `fn((u8, _))`
|
||||||
found fn pointer `fn((u16, _))`
|
found fn pointer `fn((u16, _))`
|
||||||
|
|
|
@ -5,7 +5,10 @@ LL | fn foo(x: u16);
|
||||||
| --- type in trait
|
| --- type in trait
|
||||||
...
|
...
|
||||||
LL | fn foo(x: i16) { }
|
LL | fn foo(x: i16) { }
|
||||||
| ^^^ expected `u16`, found `i16`
|
| ^^^
|
||||||
|
| |
|
||||||
|
| expected `u16`, found `i16`
|
||||||
|
| help: change the parameter type to match the trait: `u16`
|
||||||
|
|
|
|
||||||
= note: expected fn pointer `fn(u16)`
|
= note: expected fn pointer `fn(u16)`
|
||||||
found fn pointer `fn(i16)`
|
found fn pointer `fn(i16)`
|
||||||
|
@ -20,7 +23,7 @@ LL | fn bar(&mut self) { }
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
| |
|
| |
|
||||||
| types differ in mutability
|
| types differ in mutability
|
||||||
| help: consider changing the mutability to match the trait: `&self`
|
| help: change the self-receiver type to match the trait: `self: &Bar`
|
||||||
|
|
|
|
||||||
= note: expected fn pointer `fn(&Bar)`
|
= note: expected fn pointer `fn(&Bar)`
|
||||||
found fn pointer `fn(&mut Bar)`
|
found fn pointer `fn(&mut Bar)`
|
||||||
|
|
|
@ -5,7 +5,10 @@ LL | fn foo(x: u16);
|
||||||
| --- type in trait
|
| --- type in trait
|
||||||
...
|
...
|
||||||
LL | fn foo(x: i16) { }
|
LL | fn foo(x: i16) { }
|
||||||
| ^^^ expected `u16`, found `i16`
|
| ^^^
|
||||||
|
| |
|
||||||
|
| expected `u16`, found `i16`
|
||||||
|
| help: change the parameter type to match the trait: `u16`
|
||||||
|
|
|
|
||||||
= note: expected fn pointer `fn(u16)`
|
= note: expected fn pointer `fn(u16)`
|
||||||
found fn pointer `fn(i16)`
|
found fn pointer `fn(i16)`
|
||||||
|
@ -20,7 +23,7 @@ LL | fn bar(&mut self, bar: &Bar) { }
|
||||||
| ^^^^
|
| ^^^^
|
||||||
| |
|
| |
|
||||||
| types differ in mutability
|
| types differ in mutability
|
||||||
| help: consider changing the mutability to match the trait: `&mut Bar`
|
| help: change the parameter type to match the trait: `&mut Bar`
|
||||||
|
|
|
|
||||||
= note: expected fn pointer `fn(&mut Bar, &mut Bar)`
|
= note: expected fn pointer `fn(&mut Bar, &mut Bar)`
|
||||||
found fn pointer `fn(&mut Bar, &Bar)`
|
found fn pointer `fn(&mut Bar, &Bar)`
|
||||||
|
|
|
@ -2,7 +2,10 @@ error[E0053]: method `mul` has an incompatible type for trait
|
||||||
--> $DIR/wrong-mul-method-signature.rs:16:21
|
--> $DIR/wrong-mul-method-signature.rs:16:21
|
||||||
|
|
|
|
||||||
LL | fn mul(self, s: &f64) -> Vec1 {
|
LL | fn mul(self, s: &f64) -> Vec1 {
|
||||||
| ^^^^ expected `f64`, found `&f64`
|
| ^^^^
|
||||||
|
| |
|
||||||
|
| expected `f64`, found `&f64`
|
||||||
|
| help: change the parameter type to match the trait: `f64`
|
||||||
|
|
|
|
||||||
= note: expected fn pointer `fn(Vec1, f64) -> Vec1`
|
= note: expected fn pointer `fn(Vec1, f64) -> Vec1`
|
||||||
found fn pointer `fn(Vec1, &f64) -> Vec1`
|
found fn pointer `fn(Vec1, &f64) -> Vec1`
|
||||||
|
@ -11,7 +14,10 @@ error[E0053]: method `mul` has an incompatible type for trait
|
||||||
--> $DIR/wrong-mul-method-signature.rs:33:21
|
--> $DIR/wrong-mul-method-signature.rs:33:21
|
||||||
|
|
|
|
||||||
LL | fn mul(self, s: f64) -> Vec2 {
|
LL | fn mul(self, s: f64) -> Vec2 {
|
||||||
| ^^^ expected struct `Vec2`, found `f64`
|
| ^^^
|
||||||
|
| |
|
||||||
|
| expected struct `Vec2`, found `f64`
|
||||||
|
| help: change the parameter type to match the trait: `Vec2`
|
||||||
|
|
|
|
||||||
= note: expected fn pointer `fn(Vec2, Vec2) -> f64`
|
= note: expected fn pointer `fn(Vec2, Vec2) -> f64`
|
||||||
found fn pointer `fn(Vec2, f64) -> Vec2`
|
found fn pointer `fn(Vec2, f64) -> Vec2`
|
||||||
|
|
Loading…
Add table
Reference in a new issue