diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2019-05-15 19:47:18 -0700 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2019-05-16 13:56:44 -0700 |
| commit | d763faf92198e3f0c851388c71d2bb8a2f04afd9 (patch) | |
| tree | 2613a847c021be3e35e5c78480b24be0249ff770 | |
| parent | 1962adea6ad9b992516ae56ad7f8c5bc33b951cb (diff) | |
| download | rust-d763faf92198e3f0c851388c71d2bb8a2f04afd9.tar.gz rust-d763faf92198e3f0c851388c71d2bb8a2f04afd9.zip | |
Parse alternative incorrect uses of await and recover
| -rw-r--r-- | src/librustc/hir/lowering.rs | 19 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 113 | ||||
| -rw-r--r-- | src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs | 4 | ||||
| -rw-r--r-- | src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr | 10 | ||||
| -rw-r--r-- | src/test/ui/await-keyword/2018-edition-error.rs | 4 | ||||
| -rw-r--r-- | src/test/ui/await-keyword/2018-edition-error.stderr | 10 | ||||
| -rw-r--r-- | src/test/ui/await-keyword/incorrect-syntax-suggestions.rs | 93 | ||||
| -rw-r--r-- | src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr | 196 | ||||
| -rw-r--r-- | src/test/ui/await-keyword/post_expansion_error.stderr | 4 | ||||
| -rw-r--r-- | src/test/ui/issues/issue-51719.rs | 2 | ||||
| -rw-r--r-- | src/test/ui/issues/issue-51719.stderr | 5 | ||||
| -rw-r--r-- | src/test/ui/issues/issue-51751.stderr | 5 |
12 files changed, 428 insertions, 37 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index dd0d13d8f5a..12ccc79e4ab 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -97,6 +97,10 @@ pub struct LoweringContext<'a> { is_generator: bool, is_async_body: bool, + /// Used to get the current `fn`'s def span to point to when using `await` + /// outside of an `async fn`. + current_item_id: Option<hir::HirId>, + catch_scopes: Vec<NodeId>, loop_scopes: Vec<NodeId>, is_in_loop_condition: bool, @@ -250,6 +254,7 @@ pub fn lower_crate( node_id_to_hir_id: IndexVec::new(), is_generator: false, is_async_body: false, + current_item_id: None, is_in_trait_impl: false, lifetimes_to_define: Vec::new(), is_collecting_in_band_lifetimes: false, @@ -3115,6 +3120,7 @@ impl<'a> LoweringContext<'a> { } ItemKind::Fn(ref decl, ref header, ref generics, ref body) => { let fn_def_id = self.resolver.definitions().local_def_id(id); + let hir_id = self.lower_node_id(id); self.with_new_scopes(|this| { let mut lower_fn = |decl: &FnDecl| { // Note: we don't need to change the return type from `T` to @@ -3153,6 +3159,7 @@ impl<'a> LoweringContext<'a> { } else { lower_fn(decl) }; + this.current_item_id = Some(hir_id); hir::ItemKind::Fn( fn_decl, @@ -5551,13 +5558,21 @@ impl<'a> LoweringContext<'a> { // } // } if !self.is_async_body { - span_err!( + let mut err = struct_span_err!( self.sess, await_span, E0728, "`await` is only allowed inside `async` functions and blocks" ); - self.sess.abort_if_errors(); + err.span_label(await_span, "only allowed inside `async` functions and blocks"); + if let Some(item_id) = self.current_item_id { + err.span_label( + self.sess.source_map().def_span(self.items[&item_id].span), + "this function is not `async`", + ); + } + err.emit(); + return hir::ExprKind::Err; } let span = self.sess.source_map().mark_span_with_reason( CompilerDesugaringKind::Await, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 99e8db9d8e6..55e13ef00dc 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2629,14 +2629,94 @@ impl<'a> Parser<'a> { db.note("variable declaration using `let` is a statement"); return Err(db); } else if self.span.rust_2018() && self.eat_keyword(keywords::Await) { - // FIXME: remove this branch when `await!` is no longer supported - // https://github.com/rust-lang/rust/issues/60610 - self.expect(&token::Not)?; - self.expect(&token::OpenDelim(token::Paren))?; - let expr = self.parse_expr()?; - self.expect(&token::CloseDelim(token::Paren))?; - hi = self.prev_span; - ex = ExprKind::Await(ast::AwaitOrigin::MacroLike, expr); + let await_sp = self.prev_span; + match self.token { + token::Not => { + // FIXME: make this an error when `await!` is no longer supported + // https://github.com/rust-lang/rust/issues/60610 + self.expect(&token::Not)?; + self.expect(&token::OpenDelim(token::Paren))?; + let expr = self.parse_expr().map_err(|mut err| { + err.span_label( + await_sp, + "while parsing this await macro call", + ); + err + })?; + self.expect(&token::CloseDelim(token::Paren))?; + ex = ExprKind::Await(ast::AwaitOrigin::MacroLike, expr); + } + token::Question => { + // Handle `await? <expr>` + self.bump(); // `?` + let expr = self.parse_expr().map_err(|mut err| { + err.span_label( + await_sp, + "while parsing this incorrect await statement", + ); + err + })?; + let sp = lo.to(expr.span); + let expr_str = self.sess.source_map().span_to_snippet(expr.span) + .unwrap_or_else(|_| pprust::expr_to_string(&expr)); + let expr = self.mk_expr( + sp, + ExprKind::Await(ast::AwaitOrigin::FieldLike, expr), + ThinVec::new(), + ); + hi = sp; + ex = ExprKind::Try(expr); + let mut err = self.struct_span_err( + await_sp, + "incorrect use of `await`", + ); + err.span_suggestion( + sp, + "`await` is not a statement", + format!("{}.await?", expr_str), + Applicability::MachineApplicable, + ); + err.emit(); + } + ref t => { + // Handle `await <expr>` + let expr = if t == &token::OpenDelim(token::Brace) { + // Handle `await { <expr> }` + // this needs to be handled separatedly from the next arm to avoid + // interpreting `await { <expr> }?` as `<expr>?.await` + self.parse_block_expr( + None, + self.span, + BlockCheckMode::Default, + ThinVec::new(), + ) + } else { + self.parse_expr() + }.map_err(|mut err| { + err.span_label( + await_sp, + "while parsing this incorrect await statement", + ); + err + })?; + let expr_str = self.sess.source_map().span_to_snippet(expr.span) + .unwrap_or_else(|_| pprust::expr_to_string(&expr)); + let sp = lo.to(expr.span); + hi = sp; + ex = ExprKind::Await(ast::AwaitOrigin::FieldLike, expr); + let mut err = self.struct_span_err( + await_sp, + "incorrect use of `await`", + ); + err.span_suggestion( + sp, + "`await` is not a statement", + format!("{}.await", expr_str), + Applicability::MachineApplicable, + ); + err.emit(); + } + } } else if self.token.is_path_start() { let path = self.parse_path(PathStyle::Expr)?; @@ -2913,6 +2993,23 @@ impl<'a> Parser<'a> { ExprKind::Await(ast::AwaitOrigin::FieldLike, self_arg), ThinVec::new(), ); + if self.token == token::OpenDelim(token::Paren) && + self.look_ahead(1, |t| t == &token::CloseDelim(token::Paren)) + { + // future.await() + let lo = self.span; + self.bump(); // ( + let sp = lo.to(self.span); + self.bump(); // ) + let mut err = self.struct_span_err(span, "incorrect use of `await`"); + err.span_suggestion( + sp, + "`await` is not a method call, remove the parentheses", + String::new(), + Applicability::MachineApplicable, + ); + err.emit() + } return Ok(await_expr); } let segment = self.parse_path_segment(PathStyle::Expr)?; diff --git a/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs index b2e8e4be172..f59f1160e70 100644 --- a/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs +++ b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs @@ -22,6 +22,4 @@ macro_rules! await { () => {} } -fn main() { - match await { await => () } //~ ERROR expected `!`, found `{` -} +fn main() {} diff --git a/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr index 076a31bd9ce..c4b82b29f02 100644 --- a/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr +++ b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr @@ -68,13 +68,5 @@ help: you can escape reserved keywords to use them as identifiers LL | macro_rules! r#await { | ^^^^^^^ -error: expected `!`, found `{` - --> $DIR/2018-edition-error-in-non-macro-position.rs:26:17 - | -LL | match await { await => () } - | ----- ^ expected `!` - | | - | while parsing this match expression - -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors diff --git a/src/test/ui/await-keyword/2018-edition-error.rs b/src/test/ui/await-keyword/2018-edition-error.rs index e0b2962ce97..d8568696842 100644 --- a/src/test/ui/await-keyword/2018-edition-error.rs +++ b/src/test/ui/await-keyword/2018-edition-error.rs @@ -9,6 +9,4 @@ mod outer_mod { use self::outer_mod::await::await; //~ ERROR expected identifier //~^ ERROR expected identifier, found reserved keyword `await` -fn main() { - match await { await => () } //~ ERROR expected `!`, found `{` -} +fn main() {} diff --git a/src/test/ui/await-keyword/2018-edition-error.stderr b/src/test/ui/await-keyword/2018-edition-error.stderr index c8bf9b42ca5..8afe5c1a36b 100644 --- a/src/test/ui/await-keyword/2018-edition-error.stderr +++ b/src/test/ui/await-keyword/2018-edition-error.stderr @@ -38,13 +38,5 @@ help: you can escape reserved keywords to use them as identifiers LL | use self::outer_mod::await::r#await; | ^^^^^^^ -error: expected `!`, found `{` - --> $DIR/2018-edition-error.rs:13:17 - | -LL | match await { await => () } - | ----- ^ expected `!` - | | - | while parsing this match expression - -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors diff --git a/src/test/ui/await-keyword/incorrect-syntax-suggestions.rs b/src/test/ui/await-keyword/incorrect-syntax-suggestions.rs new file mode 100644 index 00000000000..ca3654d3c87 --- /dev/null +++ b/src/test/ui/await-keyword/incorrect-syntax-suggestions.rs @@ -0,0 +1,93 @@ +// edition:2018 + +#![feature(async_await)] + +async fn bar() -> Result<(), ()> { + Ok(()) +} + +async fn foo1() -> Result<(), ()> { + let _ = await bar(); //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo2() -> Result<(), ()> { + let _ = await? bar(); //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo3() -> Result<(), ()> { + let _ = await bar()?; //~ ERROR incorrect use of `await` + //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + Ok(()) +} +async fn foo21() -> Result<(), ()> { + let _ = await { bar() }; //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo22() -> Result<(), ()> { + let _ = await(bar()); //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo23() -> Result<(), ()> { + let _ = await { bar() }?; //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo4() -> Result<(), ()> { + let _ = (await bar())?; //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo5() -> Result<(), ()> { + let _ = bar().await(); //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo6() -> Result<(), ()> { + let _ = bar().await()?; //~ ERROR incorrect use of `await` + Ok(()) +} +async fn foo7() -> Result<(), ()> { + let _ = bar().await; // OK + Ok(()) +} +async fn foo8() -> Result<(), ()> { + let _ = bar().await?; // OK + Ok(()) +} +fn foo9() -> Result<(), ()> { + let _ = await bar(); //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo10() -> Result<(), ()> { + let _ = await? bar(); //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo11() -> Result<(), ()> { + let _ = await bar()?; //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo12() -> Result<(), ()> { + let _ = (await bar())?; //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo13() -> Result<(), ()> { + let _ = bar().await(); //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo14() -> Result<(), ()> { + let _ = bar().await()?; //~ ERROR `await` is only allowed inside `async` functions and blocks + //~^ ERROR incorrect use of `await` + Ok(()) +} +fn foo15() -> Result<(), ()> { + let _ = bar().await; //~ ERROR `await` is only allowed inside `async` functions and blocks + Ok(()) +} +fn foo16() -> Result<(), ()> { + let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks + Ok(()) +} + +fn main() {} diff --git a/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr new file mode 100644 index 00000000000..f39ccfcc95c --- /dev/null +++ b/src/test/ui/await-keyword/incorrect-syntax-suggestions.stderr @@ -0,0 +1,196 @@ +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:10:13 + | +LL | let _ = await bar(); + | ^^^^^------ + | | + | help: `await` is not a statement: `bar().await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:14:13 + | +LL | let _ = await? bar(); + | ^^^^^------- + | | + | help: `await` is not a statement: `bar().await?` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:18:13 + | +LL | let _ = await bar()?; + | ^^^^^------- + | | + | help: `await` is not a statement: `bar()?.await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:23:13 + | +LL | let _ = await { bar() }; + | ^^^^^---------- + | | + | help: `await` is not a statement: `{ bar() }.await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:27:13 + | +LL | let _ = await(bar()); + | ^^^^^------- + | | + | help: `await` is not a statement: `(bar()).await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:31:13 + | +LL | let _ = await { bar() }?; + | ^^^^^---------- + | | + | help: `await` is not a statement: `{ bar() }.await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:35:14 + | +LL | let _ = (await bar())?; + | ^^^^^------ + | | + | help: `await` is not a statement: `bar().await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:39:13 + | +LL | let _ = bar().await(); + | ^^^^^^^^^^^-- help: `await` is not a method call, remove the parentheses + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:43:13 + | +LL | let _ = bar().await()?; + | ^^^^^^^^^^^-- help: `await` is not a method call, remove the parentheses + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:55:13 + | +LL | let _ = await bar(); + | ^^^^^------ + | | + | help: `await` is not a statement: `bar().await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:60:13 + | +LL | let _ = await? bar(); + | ^^^^^------- + | | + | help: `await` is not a statement: `bar().await?` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:65:13 + | +LL | let _ = await bar()?; + | ^^^^^------- + | | + | help: `await` is not a statement: `bar()?.await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:70:14 + | +LL | let _ = (await bar())?; + | ^^^^^------ + | | + | help: `await` is not a statement: `bar().await` + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:75:13 + | +LL | let _ = bar().await(); + | ^^^^^^^^^^^-- help: `await` is not a method call, remove the parentheses + +error: incorrect use of `await` + --> $DIR/incorrect-syntax-suggestions.rs:80:13 + | +LL | let _ = bar().await()?; + | ^^^^^^^^^^^-- help: `await` is not a method call, remove the parentheses + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:55:13 + | +LL | async fn foo8() -> Result<(), ()> { + | --------------------------------- this function is not `async` +... +LL | let _ = await bar(); + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:60:13 + | +LL | fn foo9() -> Result<(), ()> { + | --------------------------- this function is not `async` +... +LL | let _ = await? bar(); + | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:65:13 + | +LL | fn foo10() -> Result<(), ()> { + | ---------------------------- this function is not `async` +... +LL | let _ = await bar()?; + | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:70:14 + | +LL | fn foo11() -> Result<(), ()> { + | ---------------------------- this function is not `async` +... +LL | let _ = (await bar())?; + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:75:13 + | +LL | fn foo12() -> Result<(), ()> { + | ---------------------------- this function is not `async` +... +LL | let _ = bar().await(); + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:80:13 + | +LL | fn foo13() -> Result<(), ()> { + | ---------------------------- this function is not `async` +... +LL | let _ = bar().await()?; + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:85:13 + | +LL | fn foo14() -> Result<(), ()> { + | ---------------------------- this function is not `async` +... +LL | let _ = bar().await; + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/incorrect-syntax-suggestions.rs:89:13 + | +LL | fn foo15() -> Result<(), ()> { + | ---------------------------- this function is not `async` +... +LL | let _ = bar().await?; + | ^^^^^^^^^^^ only allowed inside `async` functions and blocks + +error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` + --> $DIR/incorrect-syntax-suggestions.rs:18:19 + | +LL | let _ = await bar()?; + | ^^^^^^ the `?` operator cannot be applied to type `impl std::future::Future` + | + = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` + = note: required by `std::ops::Try::into_result` + +error: aborting due to 24 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/await-keyword/post_expansion_error.stderr b/src/test/ui/await-keyword/post_expansion_error.stderr index 0996c38b3b6..4e525974c2c 100644 --- a/src/test/ui/await-keyword/post_expansion_error.stderr +++ b/src/test/ui/await-keyword/post_expansion_error.stderr @@ -2,7 +2,9 @@ error: expected expression, found `)` --> $DIR/post_expansion_error.rs:8:12 | LL | await!() - | ^ expected expression + | ----- ^ expected expression + | | + | while parsing this await macro call error: aborting due to previous error diff --git a/src/test/ui/issues/issue-51719.rs b/src/test/ui/issues/issue-51719.rs index 2c02ac01142..b2dbadebc7c 100644 --- a/src/test/ui/issues/issue-51719.rs +++ b/src/test/ui/issues/issue-51719.rs @@ -9,3 +9,5 @@ async fn foo() {} fn make_generator() { let _gen = || foo.await; //~ ERROR `await` is only allowed inside `async` functions and blocks } + +fn main() {} \ No newline at end of file diff --git a/src/test/ui/issues/issue-51719.stderr b/src/test/ui/issues/issue-51719.stderr index 768909b66ec..cb4a5e90370 100644 --- a/src/test/ui/issues/issue-51719.stderr +++ b/src/test/ui/issues/issue-51719.stderr @@ -1,8 +1,11 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-51719.rs:10:19 | +LL | async fn foo() {} + | -------------- this function is not `async` +... LL | let _gen = || foo.await; - | ^^^^^^^^^ + | ^^^^^^^^^ only allowed inside `async` functions and blocks error: aborting due to previous error diff --git a/src/test/ui/issues/issue-51751.stderr b/src/test/ui/issues/issue-51751.stderr index 0c4cb034a93..842b99f16f2 100644 --- a/src/test/ui/issues/issue-51751.stderr +++ b/src/test/ui/issues/issue-51751.stderr @@ -1,8 +1,11 @@ error[E0728]: `await` is only allowed inside `async` functions and blocks --> $DIR/issue-51751.rs:11:20 | +LL | async fn inc(limit: i64) -> i64 { + | ------------------------------- this function is not `async` +... LL | let finished = result.await; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ only allowed inside `async` functions and blocks error: aborting due to previous error |
