Skip to content

Commit b76c9be

Browse files
committed
Handle desugaring in impl trait bound suggestion
1 parent 1b6b06a commit b76c9be

File tree

5 files changed

+95
-13
lines changed

5 files changed

+95
-13
lines changed

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -254,27 +254,21 @@ fn suggest_restriction(
254254
let pred = trait_ref.without_const().to_predicate(tcx).to_string();
255255
let pred = pred.replace(&impl_trait_str, &type_param_name);
256256
let mut sugg = vec![
257+
// Find the last of the generic parameters contained within the span of
258+
// the generics
257259
match generics
258260
.params
259261
.iter()
260-
.filter(|p| match p.kind {
261-
hir::GenericParamKind::Type {
262-
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
263-
..
264-
} => false,
265-
_ => true,
266-
})
267-
.last()
262+
.map(|p| p.bounds_span().unwrap_or(p.span))
263+
.filter(|&span| generics.span.contains(span) && span.desugaring_kind().is_none())
264+
.max_by_key(|span| span.hi())
268265
{
269266
// `fn foo(t: impl Trait)`
270267
// ^ suggest `<T: Trait>` here
271268
None => (generics.span, format!("<{}>", type_param)),
272269
// `fn foo<A>(t: impl Trait)`
273270
// ^^^ suggest `<A, T: Trait>` here
274-
Some(param) => (
275-
param.bounds_span().unwrap_or(param.span).shrink_to_hi(),
276-
format!(", {}", type_param),
277-
),
271+
Some(span) => (span.shrink_to_hi(), format!(", {}", type_param)),
278272
},
279273
// `fn foo(t: impl Trait)`
280274
// ^ suggest `where <T as Trait>::A: Bound`

src/test/ui/suggestions/impl-trait-with-missing-bounds.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ fn bak(constraints: impl Iterator + std::fmt::Debug) {
3939
}
4040
}
4141

42+
#[rustfmt::skip]
43+
fn baw<>(constraints: impl Iterator) {
44+
for constraint in constraints {
45+
qux(constraint);
46+
//~^ ERROR `<impl Iterator as Iterator>::Item` doesn't implement `Debug`
47+
}
48+
}
49+
4250
fn qux(_: impl std::fmt::Debug) {}
4351

4452
fn main() {}

src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,21 @@ help: introduce a type parameter with a trait bound instead of using `impl Trait
7373
LL | fn bak<I: Iterator + std::fmt::Debug>(constraints: I) where <I as Iterator>::Item: Debug {
7474
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7575

76-
error: aborting due to 5 previous errors
76+
error[E0277]: `<impl Iterator as Iterator>::Item` doesn't implement `Debug`
77+
--> $DIR/impl-trait-with-missing-bounds.rs:45:13
78+
|
79+
LL | qux(constraint);
80+
| ^^^^^^^^^^ `<impl Iterator as Iterator>::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug`
81+
...
82+
LL | fn qux(_: impl std::fmt::Debug) {}
83+
| --------------- required by this bound in `qux`
84+
|
85+
= help: the trait `Debug` is not implemented for `<impl Iterator as Iterator>::Item`
86+
help: introduce a type parameter with a trait bound instead of using `impl Trait`
87+
|
88+
LL | fn baw<I: Iterator>(constraints: I) where <I as Iterator>::Item: Debug {
89+
| ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
90+
91+
error: aborting due to 6 previous errors
7792

7893
For more information about this error, try `rustc --explain E0277`.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Regression test: if we suggest replacing an `impl Trait` argument to an async
2+
// fn with a named type parameter in order to add bounds, the suggested function
3+
// signature should be well-formed.
4+
//
5+
// edition:2018
6+
7+
trait Foo {
8+
type Bar;
9+
fn bar(&self) -> Self::Bar;
10+
}
11+
12+
async fn run(_: &(), foo: impl Foo) -> std::io::Result<()> {
13+
let bar = foo.bar();
14+
assert_is_send(&bar);
15+
//~^ ERROR: `<impl Foo as Foo>::Bar` cannot be sent between threads safely
16+
17+
Ok(())
18+
}
19+
20+
// Test our handling of cases where there is a generic parameter list in the
21+
// source, but only synthetic generic parameters
22+
async fn run2< >(_: &(), foo: impl Foo) -> std::io::Result<()> {
23+
let bar = foo.bar();
24+
assert_is_send(&bar);
25+
//~^ ERROR: `<impl Foo as Foo>::Bar` cannot be sent between threads safely
26+
27+
Ok(())
28+
}
29+
30+
fn assert_is_send<T: Send>(_: &T) {}
31+
32+
fn main() {}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
error[E0277]: `<impl Foo as Foo>::Bar` cannot be sent between threads safely
2+
--> $DIR/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs:14:20
3+
|
4+
LL | assert_is_send(&bar);
5+
| ^^^^ `<impl Foo as Foo>::Bar` cannot be sent between threads safely
6+
...
7+
LL | fn assert_is_send<T: Send>(_: &T) {}
8+
| ---- required by this bound in `assert_is_send`
9+
|
10+
= help: the trait `Send` is not implemented for `<impl Foo as Foo>::Bar`
11+
help: introduce a type parameter with a trait bound instead of using `impl Trait`
12+
|
13+
LL | async fn run<F: Foo>(_: &(), foo: F) -> std::io::Result<()> where <F as Foo>::Bar: Send {
14+
| ^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
15+
16+
error[E0277]: `<impl Foo as Foo>::Bar` cannot be sent between threads safely
17+
--> $DIR/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs:24:20
18+
|
19+
LL | assert_is_send(&bar);
20+
| ^^^^ `<impl Foo as Foo>::Bar` cannot be sent between threads safely
21+
...
22+
LL | fn assert_is_send<T: Send>(_: &T) {}
23+
| ---- required by this bound in `assert_is_send`
24+
|
25+
= help: the trait `Send` is not implemented for `<impl Foo as Foo>::Bar`
26+
help: introduce a type parameter with a trait bound instead of using `impl Trait`
27+
|
28+
LL | async fn run2<F: Foo>(_: &(), foo: F) -> std::io::Result<()> where <F as Foo>::Bar: Send {
29+
| ^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
30+
31+
error: aborting due to 2 previous errors
32+
33+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)