Rollup merge of #90939 - estebank:wg-af-polish, r=tmandry

Tweak errors coming from `for`-loop, `?` and `.await` desugaring

 * Suggest removal of `.await` on non-`Future` expression
 * Keep track of obligations introduced by desugaring
 * Remove span pointing at method for obligation errors coming from desugaring
 * Point at called local sync `fn` and suggest making it `async`

```
error[E0277]: `()` is not a future
  --> $DIR/unnecessary-await.rs:9:10
   |
LL |     boo().await;
   |     -----^^^^^^ `()` is not a future
   |     |
   |     this call returns `()`
   |
   = help: the trait `Future` is not implemented for `()`
help: do not `.await` the expression
   |
LL -     boo().await;
LL +     boo();
   |
help: alternatively, consider making `fn boo` asynchronous
   |
LL | async fn boo () {}
   | +++++
```

Fix #66731.
This commit is contained in:
Matthias Krüger 2021-12-15 01:28:04 +01:00 committed by GitHub
commit b166642c35
13 changed files with 47 additions and 80 deletions

View File

@ -204,7 +204,7 @@ fn parse_iter_usage(
match e.kind {
ExprKind::Call(
Expr {
kind: ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, _)),
kind: ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, ..)),
..
},
_,

View File

@ -73,7 +73,7 @@ fn contains_assign_expr<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) ->
seen
}
#[derive(Debug)]
#[derive(Debug, Clone)]
struct LocalAssign {
lhs_id: HirId,
lhs_span: Span,
@ -154,9 +154,14 @@ fn assignment_suggestions<'tcx>(
assignments.push(assign);
}
let suggestions = assignments
let suggestions = assignments.clone()
.into_iter()
.map(|assignment| Some((assignment.span, snippet_opt(cx, assignment.rhs_span)?)))
.map(|assignment| Some((assignment.span.until(assignment.rhs_span), String::new())))
.chain(
assignments
.into_iter()
.map(|assignment| Some((assignment.rhs_span.shrink_to_hi().with_hi(assignment.span.hi()), String::new())))
)
.collect::<Option<Vec<(Span, String)>>>()?;
let applicability = if suggestions.len() > 1 {

View File

@ -105,7 +105,7 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
};
if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &arg.kind;
if let ExprKind::Call(called, [inner_expr]) = &inner_expr_with_q.kind;
if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, _)) = &called.kind;
if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, ..)) = &called.kind;
if expr.span.ctxt() == inner_expr.span.ctxt();
let expr_ty = cx.typeck_results().expr_ty(expr);
let inner_ty = cx.typeck_results().expr_ty(inner_expr);

View File

@ -260,7 +260,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
if method_names[0] == sym!(as_bytes);
// Check for slicer
if let ExprKind::Struct(QPath::LangItem(LangItem::Range, _), _, _) = right.kind;
if let ExprKind::Struct(QPath::LangItem(LangItem::Range, ..), _, _) = right.kind;
then {
let mut applicability = Applicability::MachineApplicable;

View File

@ -65,7 +65,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::Match(match_arg, _, MatchSource::TryDesugar) = expr.kind;
if let ExprKind::Call(match_fun, try_args) = match_arg.kind;
if let ExprKind::Path(ref match_fun_path) = match_fun.kind;
if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, _));
if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..));
if let Some(try_arg) = try_args.get(0);
if let ExprKind::Call(err_fun, err_args) = try_arg.kind;
if let Some(err_arg) = err_args.get(0);

View File

@ -49,7 +49,7 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
if let hir::ExprKind::Call(func, [ref arg_0, ..]) = res.kind {
if matches!(
func.kind,
hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, _))
hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, ..))
) {
check_map_error(cx, arg_0, expr);
}

View File

@ -260,7 +260,7 @@ fn symbol(&self, symbol: &Binding<Symbol>) {
}
fn qpath(&self, qpath: &Binding<&QPath<'_>>) {
if let QPath::LangItem(lang_item, _) = *qpath.value {
if let QPath::LangItem(lang_item, ..) = *qpath.value {
out!("if matches!({qpath}, QPath::LangItem(LangItem::{lang_item:?}, _));");
} else {
out!("if match_qpath({qpath}, &[{}]);", path_to_string(qpath.value));

View File

@ -218,7 +218,7 @@ fn get_field<'c>(name: &str, fields: &'c [hir::ExprField<'_>]) -> Option<&'c hir
hir::ExprKind::Call(path, args)
if matches!(
path.kind,
hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, _))
hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, ..))
) =>
{
Some(Range {
@ -228,27 +228,27 @@ fn get_field<'c>(name: &str, fields: &'c [hir::ExprField<'_>]) -> Option<&'c hir
})
},
hir::ExprKind::Struct(path, fields, None) => match &path {
hir::QPath::LangItem(hir::LangItem::RangeFull, _) => Some(Range {
hir::QPath::LangItem(hir::LangItem::RangeFull, ..) => Some(Range {
start: None,
end: None,
limits: ast::RangeLimits::HalfOpen,
}),
hir::QPath::LangItem(hir::LangItem::RangeFrom, _) => Some(Range {
hir::QPath::LangItem(hir::LangItem::RangeFrom, ..) => Some(Range {
start: Some(get_field("start", fields)?),
end: None,
limits: ast::RangeLimits::HalfOpen,
}),
hir::QPath::LangItem(hir::LangItem::Range, _) => Some(Range {
hir::QPath::LangItem(hir::LangItem::Range, ..) => Some(Range {
start: Some(get_field("start", fields)?),
end: Some(get_field("end", fields)?),
limits: ast::RangeLimits::HalfOpen,
}),
hir::QPath::LangItem(hir::LangItem::RangeToInclusive, _) => Some(Range {
hir::QPath::LangItem(hir::LangItem::RangeToInclusive, ..) => Some(Range {
start: None,
end: Some(get_field("end", fields)?),
limits: ast::RangeLimits::Closed,
}),
hir::QPath::LangItem(hir::LangItem::RangeTo, _) => Some(Range {
hir::QPath::LangItem(hir::LangItem::RangeTo, ..) => Some(Range {
start: None,
end: Some(get_field("end", fields)?),
limits: ast::RangeLimits::HalfOpen,

View File

@ -346,7 +346,7 @@ fn eq_qpath(&mut self, left: &QPath<'_>, right: &QPath<'_>) -> bool {
(&QPath::TypeRelative(lty, lseg), &QPath::TypeRelative(rty, rseg)) => {
self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg)
},
(&QPath::LangItem(llang_item, _), &QPath::LangItem(rlang_item, _)) => llang_item == rlang_item,
(&QPath::LangItem(llang_item, ..), &QPath::LangItem(rlang_item, ..)) => llang_item == rlang_item,
_ => false,
}
}

View File

@ -6,22 +6,22 @@ LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
|
= note: `-D clippy::future-not-send` implied by `-D warnings`
note: future is not `Send` as this value is used across an await
--> $DIR/future_not_send.rs:8:5
--> $DIR/future_not_send.rs:8:19
|
LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
| -- has type `std::rc::Rc<[u8]>` which is not `Send`
LL | async { true }.await
| ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `rc` maybe used later
| ^^^^^^ await occurs here, with `rc` maybe used later
LL | }
| - `rc` is later dropped here
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
note: future is not `Send` as this value is used across an await
--> $DIR/future_not_send.rs:8:5
--> $DIR/future_not_send.rs:8:19
|
LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
| ---- has type `&std::cell::Cell<usize>` which is not `Send`
LL | async { true }.await
| ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `cell` maybe used later
| ^^^^^^ await occurs here, with `cell` maybe used later
LL | }
| - `cell` is later dropped here
= note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync`
@ -33,12 +33,12 @@ LL | pub async fn public_future(rc: Rc<[u8]>) {
| ^ future returned by `public_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
--> $DIR/future_not_send.rs:12:5
--> $DIR/future_not_send.rs:12:19
|
LL | pub async fn public_future(rc: Rc<[u8]>) {
| -- has type `std::rc::Rc<[u8]>` which is not `Send`
LL | async { true }.await;
| ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `rc` maybe used later
| ^^^^^^ await occurs here, with `rc` maybe used later
LL | }
| - `rc` is later dropped here
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
@ -82,12 +82,12 @@ LL | async fn private_future(&self) -> usize {
| ^^^^^ future returned by `private_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
--> $DIR/future_not_send.rs:35:9
--> $DIR/future_not_send.rs:35:23
|
LL | async fn private_future(&self) -> usize {
| ----- has type `&Dummy` which is not `Send`
LL | async { true }.await;
| ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `&self` maybe used later
| ^^^^^^ await occurs here, with `&self` maybe used later
LL | self.rc.len()
LL | }
| - `&self` is later dropped here
@ -100,12 +100,12 @@ LL | pub async fn public_future(&self) {
| ^ future returned by `public_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
--> $DIR/future_not_send.rs:40:9
--> $DIR/future_not_send.rs:40:30
|
LL | pub async fn public_future(&self) {
| ----- has type `&Dummy` which is not `Send`
LL | self.private_future().await;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here, with `&self` maybe used later
| ^^^^^^ await occurs here, with `&self` maybe used later
LL | }
| - `&self` is later dropped here
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
@ -117,12 +117,12 @@ LL | async fn generic_future<T>(t: T) -> T
| ^ future returned by `generic_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
--> $DIR/future_not_send.rs:54:5
--> $DIR/future_not_send.rs:54:19
|
LL | let rt = &t;
| -- has type `&T` which is not `Send`
LL | async { true }.await;
| ^^^^^^^^^^^^^^^^^^^^ await occurs here, with `rt` maybe used later
| ^^^^^^ await occurs here, with `rt` maybe used later
LL | t
LL | }
| - `rt` is later dropped here

View File

@ -1,38 +0,0 @@
// run-rustfix
#![allow(unused, clippy::assign_op_pattern)]
fn main() {
let a = "zero";
let b = 1;
let c = 2;
let d: usize = 1;
let mut e = 1;
e = 2;
let f = match 1 {
1 => "three",
_ => return,
}; // has semi
let g: usize = if true {
5
} else {
panic!();
};
let h = format!("{}", e);
println!("{}", a);
}

View File

@ -1,5 +1,3 @@
// run-rustfix
#![allow(unused, clippy::assign_op_pattern)]
fn main() {

View File

@ -1,5 +1,5 @@
error: unneeded late initalization
--> $DIR/needless_late_init_fixable.rs:6:5
--> $DIR/needless_late_init_fixable.rs:4:5
|
LL | let a;
| ^^^^^^
@ -11,7 +11,7 @@ LL | let a = "zero";
| ~~~~~
error: unneeded late initalization
--> $DIR/needless_late_init_fixable.rs:9:5
--> $DIR/needless_late_init_fixable.rs:7:5
|
LL | let b;
| ^^^^^^
@ -22,7 +22,7 @@ LL | let b = 1;
| ~~~~~
error: unneeded late initalization
--> $DIR/needless_late_init_fixable.rs:10:5
--> $DIR/needless_late_init_fixable.rs:8:5
|
LL | let c;
| ^^^^^^
@ -33,7 +33,7 @@ LL | let c = 2;
| ~~~~~
error: unneeded late initalization
--> $DIR/needless_late_init_fixable.rs:14:5
--> $DIR/needless_late_init_fixable.rs:12:5
|
LL | let d: usize;
| ^^^^^^^^^^^^^
@ -44,7 +44,7 @@ LL | let d: usize = 1;
| ~~~~~~~~~~~~
error: unneeded late initalization
--> $DIR/needless_late_init_fixable.rs:17:5
--> $DIR/needless_late_init_fixable.rs:15:5
|
LL | let mut e;
| ^^^^^^^^^^
@ -55,7 +55,7 @@ LL | let mut e = 1;
| ~~~~~~~~~
error: unneeded late initalization
--> $DIR/needless_late_init_fixable.rs:21:5
--> $DIR/needless_late_init_fixable.rs:19:5
|
LL | let f;
| ^^^^^^
@ -66,11 +66,12 @@ LL | let f = match 1 {
| +++++++
help: remove the assignments from the `match` arms
|
LL | 1 => "three",
| ~~~~~~~
LL - 1 => f = "three",
LL + 1 => "three",
|
error: unneeded late initalization
--> $DIR/needless_late_init_fixable.rs:27:5
--> $DIR/needless_late_init_fixable.rs:25:5
|
LL | let g: usize;
| ^^^^^^^^^^^^^
@ -81,15 +82,16 @@ LL | let g: usize = if true {
| ++++++++++++++
help: remove the assignments from the branches
|
LL | 5
|
LL - g = 5;
LL + 5
|
help: add a semicolon after the `if` expression
|
LL | };
| +
error: unneeded late initalization
--> $DIR/needless_late_init_fixable.rs:34:5
--> $DIR/needless_late_init_fixable.rs:32:5
|
LL | let h;
| ^^^^^^