From dbee24d94992df4c1888ebc2095d251fac22c05f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 13 Jun 2023 20:41:15 +0000 Subject: [PATCH] Suggest correct signature on missing fn returning RPITIT/AFIT --- compiler/rustc_hir_analysis/src/check/mod.rs | 31 +++++++++++++++++-- .../in-trait/suggest-missing-item.fixed | 22 +++++++++++++ .../in-trait/suggest-missing-item.rs | 19 ++++++++++++ .../in-trait/suggest-missing-item.stderr | 18 +++++++++++ 4 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 tests/ui/impl-trait/in-trait/suggest-missing-item.fixed create mode 100644 tests/ui/impl-trait/in-trait/suggest-missing-item.rs create mode 100644 tests/ui/impl-trait/in-trait/suggest-missing-item.stderr diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index c9e74896ac08e..d8e9e5a01528e 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -403,7 +403,32 @@ fn fn_sig_suggestion<'tcx>( .flatten() .collect::>() .join(", "); - let output = sig.output(); + let mut output = sig.output(); + + let asyncness = if tcx.asyncness(assoc.def_id).is_async() { + output = if let ty::Alias(_, alias_ty) = *output.kind() { + tcx.explicit_item_bounds(alias_ty.def_id) + .subst_iter_copied(tcx, alias_ty.substs) + .find_map(|(bound, _)| { + bound.to_opt_poly_projection_pred()?.no_bound_vars()?.term.ty() + }) + .unwrap_or_else(|| { + span_bug!( + ident.span, + "expected async fn to have `impl Future` output, but it returns {output}" + ) + }) + } else { + span_bug!( + ident.span, + "expected async fn to have `impl Future` output, but it returns {output}" + ) + }; + "async " + } else { + "" + }; + let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() }; let unsafety = sig.unsafety.prefix_str(); @@ -414,7 +439,9 @@ fn fn_sig_suggestion<'tcx>( // lifetimes between the `impl` and the `trait`, but this should be good enough to // fill in a significant portion of the missing code, and other subsequent // suggestions can help the user fix the code. - format!("{unsafety}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}") + format!( + "{unsafety}{asyncness}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}" + ) } pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> { diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed b/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed new file mode 100644 index 0000000000000..16c4d15ddcd60 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.fixed @@ -0,0 +1,22 @@ +// edition:2021 +// run-rustfix + +#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] + +trait Trait { + async fn foo(); + + async fn bar() -> i32; + + fn test(&self) -> impl Sized + '_; +} + +struct S; + +impl Trait for S {fn test(&self) -> impl Sized + '_ { todo!() } +async fn bar() -> i32 { todo!() } +async fn foo() { todo!() } +} +//~^ ERROR not all trait items implemented + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.rs b/tests/ui/impl-trait/in-trait/suggest-missing-item.rs new file mode 100644 index 0000000000000..f218e6cb581e3 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.rs @@ -0,0 +1,19 @@ +// edition:2021 +// run-rustfix + +#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)] + +trait Trait { + async fn foo(); + + async fn bar() -> i32; + + fn test(&self) -> impl Sized + '_; +} + +struct S; + +impl Trait for S {} +//~^ ERROR not all trait items implemented + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr b/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr new file mode 100644 index 0000000000000..d96641fe16335 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/suggest-missing-item.stderr @@ -0,0 +1,18 @@ +error[E0046]: not all trait items implemented, missing: `foo`, `bar`, `test` + --> $DIR/suggest-missing-item.rs:16:1 + | +LL | async fn foo(); + | --------------- `foo` from trait +LL | +LL | async fn bar() -> i32; + | ---------------------- `bar` from trait +LL | +LL | fn test(&self) -> impl Sized + '_; + | ---------------------------------- `test` from trait +... +LL | impl Trait for S {} + | ^^^^^^^^^^^^^^^^ missing `foo`, `bar`, `test` in implementation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0046`.