From b76c9be7f5fa10b95fe4f872400b4388b67a4733 Mon Sep 17 00:00:00 2001 From: William Bain Date: Sat, 19 Dec 2020 16:52:19 -0500 Subject: [PATCH] Handle desugaring in impl trait bound suggestion --- .../src/traits/error_reporting/suggestions.rs | 18 ++++------ .../impl-trait-with-missing-bounds.rs | 8 +++++ .../impl-trait-with-missing-bounds.stderr | 17 +++++++++- ...l-trait-with-missing-bounds-on-async-fn.rs | 32 ++++++++++++++++++ ...ait-with-missing-bounds-on-async-fn.stderr | 33 +++++++++++++++++++ 5 files changed, 95 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs create mode 100644 src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index b4b71a48ce9d2..79fea83a6674d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -254,27 +254,21 @@ fn suggest_restriction( let pred = trait_ref.without_const().to_predicate(tcx).to_string(); let pred = pred.replace(&impl_trait_str, &type_param_name); let mut sugg = vec![ + // Find the last of the generic parameters contained within the span of + // the generics match generics .params .iter() - .filter(|p| match p.kind { - hir::GenericParamKind::Type { - synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), - .. - } => false, - _ => true, - }) - .last() + .map(|p| p.bounds_span().unwrap_or(p.span)) + .filter(|&span| generics.span.contains(span) && span.desugaring_kind().is_none()) + .max_by_key(|span| span.hi()) { // `fn foo(t: impl Trait)` // ^ suggest `` here None => (generics.span, format!("<{}>", type_param)), // `fn foo(t: impl Trait)` // ^^^ suggest `` here - Some(param) => ( - param.bounds_span().unwrap_or(param.span).shrink_to_hi(), - format!(", {}", type_param), - ), + Some(span) => (span.shrink_to_hi(), format!(", {}", type_param)), }, // `fn foo(t: impl Trait)` // ^ suggest `where ::A: Bound` diff --git a/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs b/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs index d401328077aae..949b23600715a 100644 --- a/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs +++ b/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs @@ -39,6 +39,14 @@ fn bak(constraints: impl Iterator + std::fmt::Debug) { } } +#[rustfmt::skip] +fn baw<>(constraints: impl Iterator) { + for constraint in constraints { + qux(constraint); +//~^ ERROR `::Item` doesn't implement `Debug` + } +} + fn qux(_: impl std::fmt::Debug) {} fn main() {} diff --git a/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr b/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr index 099eb1c9d005b..0de3b9aec19e1 100644 --- a/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr +++ b/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr @@ -73,6 +73,21 @@ help: introduce a type parameter with a trait bound instead of using `impl Trait LL | fn bak(constraints: I) where ::Item: Debug { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error[E0277]: `::Item` doesn't implement `Debug` + --> $DIR/impl-trait-with-missing-bounds.rs:45:13 + | +LL | qux(constraint); + | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` +... +LL | fn qux(_: impl std::fmt::Debug) {} + | --------------- required by this bound in `qux` + | + = help: the trait `Debug` is not implemented for `::Item` +help: introduce a type parameter with a trait bound instead of using `impl Trait` + | +LL | fn baw(constraints: I) where ::Item: Debug { + | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs b/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs new file mode 100644 index 0000000000000..3cd6d336e1345 --- /dev/null +++ b/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs @@ -0,0 +1,32 @@ +// Regression test: if we suggest replacing an `impl Trait` argument to an async +// fn with a named type parameter in order to add bounds, the suggested function +// signature should be well-formed. +// +// edition:2018 + +trait Foo { + type Bar; + fn bar(&self) -> Self::Bar; +} + +async fn run(_: &(), foo: impl Foo) -> std::io::Result<()> { + let bar = foo.bar(); + assert_is_send(&bar); +//~^ ERROR: `::Bar` cannot be sent between threads safely + + Ok(()) +} + +// Test our handling of cases where there is a generic parameter list in the +// source, but only synthetic generic parameters +async fn run2< >(_: &(), foo: impl Foo) -> std::io::Result<()> { + let bar = foo.bar(); + assert_is_send(&bar); +//~^ ERROR: `::Bar` cannot be sent between threads safely + + Ok(()) +} + +fn assert_is_send(_: &T) {} + +fn main() {} diff --git a/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.stderr b/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.stderr new file mode 100644 index 0000000000000..9404c3bb58317 --- /dev/null +++ b/src/test/ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.stderr @@ -0,0 +1,33 @@ +error[E0277]: `::Bar` cannot be sent between threads safely + --> $DIR/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs:14:20 + | +LL | assert_is_send(&bar); + | ^^^^ `::Bar` cannot be sent between threads safely +... +LL | fn assert_is_send(_: &T) {} + | ---- required by this bound in `assert_is_send` + | + = help: the trait `Send` is not implemented for `::Bar` +help: introduce a type parameter with a trait bound instead of using `impl Trait` + | +LL | async fn run(_: &(), foo: F) -> std::io::Result<()> where ::Bar: Send { + | ^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `::Bar` cannot be sent between threads safely + --> $DIR/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs:24:20 + | +LL | assert_is_send(&bar); + | ^^^^ `::Bar` cannot be sent between threads safely +... +LL | fn assert_is_send(_: &T) {} + | ---- required by this bound in `assert_is_send` + | + = help: the trait `Send` is not implemented for `::Bar` +help: introduce a type parameter with a trait bound instead of using `impl Trait` + | +LL | async fn run2(_: &(), foo: F) -> std::io::Result<()> where ::Bar: Send { + | ^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`.