diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 964aa8426ea..9fd3a170ece 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -329,7 +329,33 @@ fn compare_predicate_entailment<'tcx>( ); } TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(_, i) => { - if let Some(trait_ty) = trait_sig.inputs().get(*i) { + if trait_sig.inputs().len() == *i { + // Suggestion to change output type. We do not suggest in `async` functions + // to avoid complex logic or incorrect output. + let impl_m_hir_id = + tcx.hir().local_def_id_to_hir_id(impl_m.def_id.expect_local()); + match tcx.hir().expect_impl_item(impl_m_hir_id).kind { + ImplItemKind::Fn(ref sig, _) + if sig.header.asyncness == hir::IsAsync::NotAsync => + { + let (span, sugg) = match sig.decl.output { + hir::FnRetTy::DefaultReturn(sp) => { + (sp, format!(" -> {} ", trait_sig.output())) + } + hir::FnRetTy::Return(hir_ty) => { + (hir_ty.span, trait_sig.output().to_string()) + } + }; + diag.span_suggestion( + span, + "change the output type to match the trait", + sugg, + Applicability::MachineApplicable, + ); + } + _ => {} + }; + } else if let Some(trait_ty) = trait_sig.inputs().get(*i) { diag.span_suggestion( impl_err_span, "change the parameter type to match the trait", diff --git a/src/test/ui/associated-types/defaults-specialization.stderr b/src/test/ui/associated-types/defaults-specialization.stderr index 920f8322813..3c7dc1fc3c9 100644 --- a/src/test/ui/associated-types/defaults-specialization.stderr +++ b/src/test/ui/associated-types/defaults-specialization.stderr @@ -15,7 +15,10 @@ LL | fn make() -> Self::Ty { | -------- type in trait ... LL | fn make() -> u8 { 0 } - | ^^ expected associated type, found `u8` + | ^^ + | | + | expected associated type, found `u8` + | help: change the output type to match the trait: ` as Tr>::Ty` | = note: expected fn pointer `fn() -> as Tr>::Ty` found fn pointer `fn() -> u8` @@ -30,7 +33,10 @@ LL | default type Ty = bool; | ----------------------- expected this associated type LL | LL | fn make() -> bool { true } - | ^^^^ expected associated type, found `bool` + | ^^^^ + | | + | expected associated type, found `bool` + | help: change the output type to match the trait: ` as Tr>::Ty` | = note: expected fn pointer `fn() -> as Tr>::Ty` found fn pointer `fn() -> bool` diff --git a/src/test/ui/compare-method/bad-self-type.rs b/src/test/ui/compare-method/bad-self-type.rs index 9eb978664bf..f42a9e49abd 100644 --- a/src/test/ui/compare-method/bad-self-type.rs +++ b/src/test/ui/compare-method/bad-self-type.rs @@ -15,9 +15,12 @@ impl Future for MyFuture { trait T { fn foo(self); + fn bar(self) -> Option<()>; } impl T for MyFuture { fn foo(self: Box) {} //~^ ERROR method `foo` has an incompatible type for trait + fn bar(self) {} + //~^ ERROR method `bar` has an incompatible type for trait } diff --git a/src/test/ui/compare-method/bad-self-type.stderr b/src/test/ui/compare-method/bad-self-type.stderr index 4d85ff86df5..74e7c562aa7 100644 --- a/src/test/ui/compare-method/bad-self-type.stderr +++ b/src/test/ui/compare-method/bad-self-type.stderr @@ -11,7 +11,7 @@ LL | fn poll(self, _: &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 + --> $DIR/bad-self-type.rs:22:18 | LL | fn foo(self); | ---- type in trait @@ -25,6 +25,21 @@ LL | fn foo(self: Box) {} = note: expected fn pointer `fn(MyFuture)` found fn pointer `fn(Box)` -error: aborting due to 2 previous errors +error[E0053]: method `bar` has an incompatible type for trait + --> $DIR/bad-self-type.rs:24:18 + | +LL | fn bar(self) -> Option<()>; + | ---------- type in trait +... +LL | fn bar(self) {} + | ^ + | | + | expected enum `Option`, found `()` + | help: change the output type to match the trait: `-> Option<()>` + | + = note: expected fn pointer `fn(MyFuture) -> Option<()>` + found fn pointer `fn(MyFuture)` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0053`. diff --git a/src/test/ui/issues/issue-21332.stderr b/src/test/ui/issues/issue-21332.stderr index fd132687d71..d92966da17c 100644 --- a/src/test/ui/issues/issue-21332.stderr +++ b/src/test/ui/issues/issue-21332.stderr @@ -2,7 +2,10 @@ error[E0053]: method `next` has an incompatible type for trait --> $DIR/issue-21332.rs:5:27 | LL | fn next(&mut self) -> Result { Ok(7) } - | ^^^^^^^^^^^^^^^^ expected enum `Option`, found enum `Result` + | ^^^^^^^^^^^^^^^^ + | | + | expected enum `Option`, found enum `Result` + | help: change the output type to match the trait: `Option` | = note: expected fn pointer `fn(&mut S) -> Option` found fn pointer `fn(&mut S) -> Result` diff --git a/src/test/ui/issues/issue-35869.stderr b/src/test/ui/issues/issue-35869.stderr index c104aa30cb0..71b2a9df095 100644 --- a/src/test/ui/issues/issue-35869.stderr +++ b/src/test/ui/issues/issue-35869.stderr @@ -50,7 +50,10 @@ LL | fn qux() -> u8; | -- type in trait ... LL | fn qux() -> u16 { 5u16 } - | ^^^ expected `u8`, found `u16` + | ^^^ + | | + | expected `u8`, found `u16` + | help: change the output type to match the trait: `u8` | = note: expected fn pointer `fn() -> u8` found fn pointer `fn() -> u16` diff --git a/src/test/ui/wrong-mul-method-signature.stderr b/src/test/ui/wrong-mul-method-signature.stderr index 9be07cb1a74..9f8896f01ee 100644 --- a/src/test/ui/wrong-mul-method-signature.stderr +++ b/src/test/ui/wrong-mul-method-signature.stderr @@ -26,7 +26,10 @@ error[E0053]: method `mul` has an incompatible type for trait --> $DIR/wrong-mul-method-signature.rs:52:29 | LL | fn mul(self, s: f64) -> f64 { - | ^^^ expected `i32`, found `f64` + | ^^^ + | | + | expected `i32`, found `f64` + | help: change the output type to match the trait: `i32` | = note: expected fn pointer `fn(Vec3, _) -> i32` found fn pointer `fn(Vec3, _) -> f64`