Skip to content

Commit

Permalink
Rollup merge of #80160 - diondokter:move_async_fix, r=davidtwco
Browse files Browse the repository at this point in the history
Implemented a compiler diagnostic for move async mistake

Fixes #79694

First time contributing, so I hope I'm doing everything right.
(If not, please correct me!)

This code performs a check when a move capture clause is parsed. The check is to detect if the user has reversed the async move keywords and to provide a diagnostic with a suggestion to fix it.

Checked code:
```rust
fn main() {
    move async { };
}
```

Previous output:
```txt
PS C:\Repos\move_async_test> cargo build
   Compiling move_async_test v0.1.0 (C:\Repos\move_async_test)
error: expected one of `|` or `||`, found keyword `async`
 --> src\main.rs:2:10
  |
2 |     move async { };
  |          ^^^^^ expected one of `|` or `||`

error: aborting due to previous error

error: could not compile `move_async_test`
```

New output:
```txt
PS C:\Repos\move_async_test> cargo +dev build
   Compiling move_async_test v0.1.0 (C:\Repos\move_async_test)
error: the order of `move` and `async` is incorrect
 --> src\main.rs:2:13
  |
2 |     let _ = move async { };
  |             ^^^^^^^^^^
  |
help: try switching the order
  |
2 |     let _ = async move { };
  |             ^^^^^^^^^^

error: aborting due to previous error

error: could not compile `move_async_test`
```

Is there a file/module where these kind of things are tested?
Would love some feedback 😄
Dylan-DPC authored Dec 25, 2020
2 parents 787b016 + a272d62 commit 299c2fc
Showing 5 changed files with 61 additions and 4 deletions.
18 changes: 18 additions & 0 deletions compiler/rustc_parse/src/parser/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -1912,4 +1912,22 @@ impl<'a> Parser<'a> {
*self = snapshot;
Err(err)
}

/// Get the diagnostics for the cases where `move async` is found.
///
/// `move_async_span` starts at the 'm' of the move keyword and ends with the 'c' of the async keyword
pub(super) fn incorrect_move_async_order_found(
&self,
move_async_span: Span,
) -> DiagnosticBuilder<'a> {
let mut err =
self.struct_span_err(move_async_span, "the order of `move` and `async` is incorrect");
err.span_suggestion_verbose(
move_async_span,
"try switching the order",
"async move".to_owned(),
Applicability::MaybeIncorrect,
);
err
}
}
18 changes: 14 additions & 4 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
@@ -1603,7 +1603,7 @@ impl<'a> Parser<'a> {
self.sess.gated_spans.gate(sym::async_closure, span);
}

let capture_clause = self.parse_capture_clause();
let capture_clause = self.parse_capture_clause()?;
let decl = self.parse_fn_block_decl()?;
let decl_hi = self.prev_token.span;
let body = match decl.output {
@@ -1626,8 +1626,18 @@ impl<'a> Parser<'a> {
}

/// Parses an optional `move` prefix to a closure-like construct.
fn parse_capture_clause(&mut self) -> CaptureBy {
if self.eat_keyword(kw::Move) { CaptureBy::Value } else { CaptureBy::Ref }
fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> {
if self.eat_keyword(kw::Move) {
// Check for `move async` and recover
if self.check_keyword(kw::Async) {
let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
Err(self.incorrect_move_async_order_found(move_async_span))
} else {
Ok(CaptureBy::Value)
}
} else {
Ok(CaptureBy::Ref)
}
}

/// Parses the `|arg, arg|` header of a closure.
@@ -2019,7 +2029,7 @@ impl<'a> Parser<'a> {
fn parse_async_block(&mut self, mut attrs: AttrVec) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
self.expect_keyword(kw::Async)?;
let capture_clause = self.parse_capture_clause();
let capture_clause = self.parse_capture_clause()?;
let (iattrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs);
let kind = ExprKind::Async(capture_clause, DUMMY_NODE_ID, body);
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// run-rustfix
// edition:2018

// Regression test for issue 79694

fn main() {
let _ = async move { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect
}
8 changes: 8 additions & 0 deletions src/test/ui/parser/incorrect-move-async-order-issue-79694.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// run-rustfix
// edition:2018

// Regression test for issue 79694

fn main() {
let _ = move async { }; //~ ERROR 7:13: 7:23: the order of `move` and `async` is incorrect
}
13 changes: 13 additions & 0 deletions src/test/ui/parser/incorrect-move-async-order-issue-79694.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error: the order of `move` and `async` is incorrect
--> $DIR/incorrect-move-async-order-issue-79694.rs:7:13
|
LL | let _ = move async { };
| ^^^^^^^^^^
|
help: try switching the order
|
LL | let _ = async move { };
| ^^^^^^^^^^

error: aborting due to previous error

0 comments on commit 299c2fc

Please sign in to comment.