Handle desugaring in impl trait bound suggestion
This commit is contained in:
parent
1b6b06a03a
commit
b76c9be7f5
5 changed files with 95 additions and 13 deletions
|
@ -254,27 +254,21 @@ fn suggest_restriction(
|
||||||
let pred = trait_ref.without_const().to_predicate(tcx).to_string();
|
let pred = trait_ref.without_const().to_predicate(tcx).to_string();
|
||||||
let pred = pred.replace(&impl_trait_str, &type_param_name);
|
let pred = pred.replace(&impl_trait_str, &type_param_name);
|
||||||
let mut sugg = vec![
|
let mut sugg = vec![
|
||||||
|
// Find the last of the generic parameters contained within the span of
|
||||||
|
// the generics
|
||||||
match generics
|
match generics
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|p| match p.kind {
|
.map(|p| p.bounds_span().unwrap_or(p.span))
|
||||||
hir::GenericParamKind::Type {
|
.filter(|&span| generics.span.contains(span) && span.desugaring_kind().is_none())
|
||||||
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
|
.max_by_key(|span| span.hi())
|
||||||
..
|
|
||||||
} => false,
|
|
||||||
_ => true,
|
|
||||||
})
|
|
||||||
.last()
|
|
||||||
{
|
{
|
||||||
// `fn foo(t: impl Trait)`
|
// `fn foo(t: impl Trait)`
|
||||||
// ^ suggest `<T: Trait>` here
|
// ^ suggest `<T: Trait>` here
|
||||||
None => (generics.span, format!("<{}>", type_param)),
|
None => (generics.span, format!("<{}>", type_param)),
|
||||||
// `fn foo<A>(t: impl Trait)`
|
// `fn foo<A>(t: impl Trait)`
|
||||||
// ^^^ suggest `<A, T: Trait>` here
|
// ^^^ suggest `<A, T: Trait>` here
|
||||||
Some(param) => (
|
Some(span) => (span.shrink_to_hi(), format!(", {}", type_param)),
|
||||||
param.bounds_span().unwrap_or(param.span).shrink_to_hi(),
|
|
||||||
format!(", {}", type_param),
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
// `fn foo(t: impl Trait)`
|
// `fn foo(t: impl Trait)`
|
||||||
// ^ suggest `where <T as Trait>::A: Bound`
|
// ^ suggest `where <T as Trait>::A: Bound`
|
||||||
|
|
|
@ -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 `<impl Iterator as Iterator>::Item` doesn't implement `Debug`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn qux(_: impl std::fmt::Debug) {}
|
fn qux(_: impl std::fmt::Debug) {}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -73,6 +73,21 @@ help: introduce a type parameter with a trait bound instead of using `impl Trait
|
||||||
LL | fn bak<I: Iterator + std::fmt::Debug>(constraints: I) where <I as Iterator>::Item: Debug {
|
LL | fn bak<I: Iterator + std::fmt::Debug>(constraints: I) where <I as Iterator>::Item: Debug {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 5 previous errors
|
error[E0277]: `<impl Iterator as Iterator>::Item` doesn't implement `Debug`
|
||||||
|
--> $DIR/impl-trait-with-missing-bounds.rs:45:13
|
||||||
|
|
|
||||||
|
LL | qux(constraint);
|
||||||
|
| ^^^^^^^^^^ `<impl Iterator as Iterator>::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 `<impl Iterator as Iterator>::Item`
|
||||||
|
help: introduce a type parameter with a trait bound instead of using `impl Trait`
|
||||||
|
|
|
||||||
|
LL | fn baw<I: Iterator>(constraints: I) where <I as Iterator>::Item: Debug {
|
||||||
|
| ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0277`.
|
For more information about this error, try `rustc --explain E0277`.
|
||||||
|
|
|
@ -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: `<impl Foo as Foo>::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: `<impl Foo as Foo>::Bar` cannot be sent between threads safely
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_is_send<T: Send>(_: &T) {}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,33 @@
|
||||||
|
error[E0277]: `<impl Foo as Foo>::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);
|
||||||
|
| ^^^^ `<impl Foo as Foo>::Bar` cannot be sent between threads safely
|
||||||
|
...
|
||||||
|
LL | fn assert_is_send<T: Send>(_: &T) {}
|
||||||
|
| ---- required by this bound in `assert_is_send`
|
||||||
|
|
|
||||||
|
= help: the trait `Send` is not implemented for `<impl Foo as Foo>::Bar`
|
||||||
|
help: introduce a type parameter with a trait bound instead of using `impl Trait`
|
||||||
|
|
|
||||||
|
LL | async fn run<F: Foo>(_: &(), foo: F) -> std::io::Result<()> where <F as Foo>::Bar: Send {
|
||||||
|
| ^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0277]: `<impl Foo as Foo>::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);
|
||||||
|
| ^^^^ `<impl Foo as Foo>::Bar` cannot be sent between threads safely
|
||||||
|
...
|
||||||
|
LL | fn assert_is_send<T: Send>(_: &T) {}
|
||||||
|
| ---- required by this bound in `assert_is_send`
|
||||||
|
|
|
||||||
|
= help: the trait `Send` is not implemented for `<impl Foo as Foo>::Bar`
|
||||||
|
help: introduce a type parameter with a trait bound instead of using `impl Trait`
|
||||||
|
|
|
||||||
|
LL | async fn run2<F: Foo>(_: &(), foo: F) -> std::io::Result<()> where <F as Foo>::Bar: Send {
|
||||||
|
| ^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Add table
Add a link
Reference in a new issue