Skip to content

Commit d763faf

Browse files
committed
Parse alternative incorrect uses of await and recover
1 parent 1962ade commit d763faf

12 files changed

+428
-37
lines changed

src/librustc/hir/lowering.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ pub struct LoweringContext<'a> {
9797
is_generator: bool,
9898
is_async_body: bool,
9999

100+
/// Used to get the current `fn`'s def span to point to when using `await`
101+
/// outside of an `async fn`.
102+
current_item_id: Option<hir::HirId>,
103+
100104
catch_scopes: Vec<NodeId>,
101105
loop_scopes: Vec<NodeId>,
102106
is_in_loop_condition: bool,
@@ -250,6 +254,7 @@ pub fn lower_crate(
250254
node_id_to_hir_id: IndexVec::new(),
251255
is_generator: false,
252256
is_async_body: false,
257+
current_item_id: None,
253258
is_in_trait_impl: false,
254259
lifetimes_to_define: Vec::new(),
255260
is_collecting_in_band_lifetimes: false,
@@ -3115,6 +3120,7 @@ impl<'a> LoweringContext<'a> {
31153120
}
31163121
ItemKind::Fn(ref decl, ref header, ref generics, ref body) => {
31173122
let fn_def_id = self.resolver.definitions().local_def_id(id);
3123+
let hir_id = self.lower_node_id(id);
31183124
self.with_new_scopes(|this| {
31193125
let mut lower_fn = |decl: &FnDecl| {
31203126
// Note: we don't need to change the return type from `T` to
@@ -3153,6 +3159,7 @@ impl<'a> LoweringContext<'a> {
31533159
} else {
31543160
lower_fn(decl)
31553161
};
3162+
this.current_item_id = Some(hir_id);
31563163

31573164
hir::ItemKind::Fn(
31583165
fn_decl,
@@ -5551,13 +5558,21 @@ impl<'a> LoweringContext<'a> {
55515558
// }
55525559
// }
55535560
if !self.is_async_body {
5554-
span_err!(
5561+
let mut err = struct_span_err!(
55555562
self.sess,
55565563
await_span,
55575564
E0728,
55585565
"`await` is only allowed inside `async` functions and blocks"
55595566
);
5560-
self.sess.abort_if_errors();
5567+
err.span_label(await_span, "only allowed inside `async` functions and blocks");
5568+
if let Some(item_id) = self.current_item_id {
5569+
err.span_label(
5570+
self.sess.source_map().def_span(self.items[&item_id].span),
5571+
"this function is not `async`",
5572+
);
5573+
}
5574+
err.emit();
5575+
return hir::ExprKind::Err;
55615576
}
55625577
let span = self.sess.source_map().mark_span_with_reason(
55635578
CompilerDesugaringKind::Await,

src/libsyntax/parse/parser.rs

Lines changed: 105 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2629,14 +2629,94 @@ impl<'a> Parser<'a> {
26292629
db.note("variable declaration using `let` is a statement");
26302630
return Err(db);
26312631
} else if self.span.rust_2018() && self.eat_keyword(keywords::Await) {
2632-
// FIXME: remove this branch when `await!` is no longer supported
2633-
// https://github.com/rust-lang/rust/issues/60610
2634-
self.expect(&token::Not)?;
2635-
self.expect(&token::OpenDelim(token::Paren))?;
2636-
let expr = self.parse_expr()?;
2637-
self.expect(&token::CloseDelim(token::Paren))?;
2638-
hi = self.prev_span;
2639-
ex = ExprKind::Await(ast::AwaitOrigin::MacroLike, expr);
2632+
let await_sp = self.prev_span;
2633+
match self.token {
2634+
token::Not => {
2635+
// FIXME: make this an error when `await!` is no longer supported
2636+
// https://github.com/rust-lang/rust/issues/60610
2637+
self.expect(&token::Not)?;
2638+
self.expect(&token::OpenDelim(token::Paren))?;
2639+
let expr = self.parse_expr().map_err(|mut err| {
2640+
err.span_label(
2641+
await_sp,
2642+
"while parsing this await macro call",
2643+
);
2644+
err
2645+
})?;
2646+
self.expect(&token::CloseDelim(token::Paren))?;
2647+
ex = ExprKind::Await(ast::AwaitOrigin::MacroLike, expr);
2648+
}
2649+
token::Question => {
2650+
// Handle `await? <expr>`
2651+
self.bump(); // `?`
2652+
let expr = self.parse_expr().map_err(|mut err| {
2653+
err.span_label(
2654+
await_sp,
2655+
"while parsing this incorrect await statement",
2656+
);
2657+
err
2658+
})?;
2659+
let sp = lo.to(expr.span);
2660+
let expr_str = self.sess.source_map().span_to_snippet(expr.span)
2661+
.unwrap_or_else(|_| pprust::expr_to_string(&expr));
2662+
let expr = self.mk_expr(
2663+
sp,
2664+
ExprKind::Await(ast::AwaitOrigin::FieldLike, expr),
2665+
ThinVec::new(),
2666+
);
2667+
hi = sp;
2668+
ex = ExprKind::Try(expr);
2669+
let mut err = self.struct_span_err(
2670+
await_sp,
2671+
"incorrect use of `await`",
2672+
);
2673+
err.span_suggestion(
2674+
sp,
2675+
"`await` is not a statement",
2676+
format!("{}.await?", expr_str),
2677+
Applicability::MachineApplicable,
2678+
);
2679+
err.emit();
2680+
}
2681+
ref t => {
2682+
// Handle `await <expr>`
2683+
let expr = if t == &token::OpenDelim(token::Brace) {
2684+
// Handle `await { <expr> }`
2685+
// this needs to be handled separatedly from the next arm to avoid
2686+
// interpreting `await { <expr> }?` as `<expr>?.await`
2687+
self.parse_block_expr(
2688+
None,
2689+
self.span,
2690+
BlockCheckMode::Default,
2691+
ThinVec::new(),
2692+
)
2693+
} else {
2694+
self.parse_expr()
2695+
}.map_err(|mut err| {
2696+
err.span_label(
2697+
await_sp,
2698+
"while parsing this incorrect await statement",
2699+
);
2700+
err
2701+
})?;
2702+
let expr_str = self.sess.source_map().span_to_snippet(expr.span)
2703+
.unwrap_or_else(|_| pprust::expr_to_string(&expr));
2704+
let sp = lo.to(expr.span);
2705+
hi = sp;
2706+
ex = ExprKind::Await(ast::AwaitOrigin::FieldLike, expr);
2707+
let mut err = self.struct_span_err(
2708+
await_sp,
2709+
"incorrect use of `await`",
2710+
);
2711+
err.span_suggestion(
2712+
sp,
2713+
"`await` is not a statement",
2714+
format!("{}.await", expr_str),
2715+
Applicability::MachineApplicable,
2716+
);
2717+
err.emit();
2718+
}
2719+
}
26402720
} else if self.token.is_path_start() {
26412721
let path = self.parse_path(PathStyle::Expr)?;
26422722

@@ -2913,6 +2993,23 @@ impl<'a> Parser<'a> {
29132993
ExprKind::Await(ast::AwaitOrigin::FieldLike, self_arg),
29142994
ThinVec::new(),
29152995
);
2996+
if self.token == token::OpenDelim(token::Paren) &&
2997+
self.look_ahead(1, |t| t == &token::CloseDelim(token::Paren))
2998+
{
2999+
// future.await()
3000+
let lo = self.span;
3001+
self.bump(); // (
3002+
let sp = lo.to(self.span);
3003+
self.bump(); // )
3004+
let mut err = self.struct_span_err(span, "incorrect use of `await`");
3005+
err.span_suggestion(
3006+
sp,
3007+
"`await` is not a method call, remove the parentheses",
3008+
String::new(),
3009+
Applicability::MachineApplicable,
3010+
);
3011+
err.emit()
3012+
}
29163013
return Ok(await_expr);
29173014
}
29183015
let segment = self.parse_path_segment(PathStyle::Expr)?;

src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,4 @@ macro_rules! await {
2222
() => {}
2323
}
2424

25-
fn main() {
26-
match await { await => () } //~ ERROR expected `!`, found `{`
27-
}
25+
fn main() {}

src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,5 @@ help: you can escape reserved keywords to use them as identifiers
6868
LL | macro_rules! r#await {
6969
| ^^^^^^^
7070

71-
error: expected `!`, found `{`
72-
--> $DIR/2018-edition-error-in-non-macro-position.rs:26:17
73-
|
74-
LL | match await { await => () }
75-
| ----- ^ expected `!`
76-
| |
77-
| while parsing this match expression
78-
79-
error: aborting due to 8 previous errors
71+
error: aborting due to 7 previous errors
8072

src/test/ui/await-keyword/2018-edition-error.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,4 @@ mod outer_mod {
99
use self::outer_mod::await::await; //~ ERROR expected identifier
1010
//~^ ERROR expected identifier, found reserved keyword `await`
1111

12-
fn main() {
13-
match await { await => () } //~ ERROR expected `!`, found `{`
14-
}
12+
fn main() {}

src/test/ui/await-keyword/2018-edition-error.stderr

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,5 @@ help: you can escape reserved keywords to use them as identifiers
3838
LL | use self::outer_mod::await::r#await;
3939
| ^^^^^^^
4040

41-
error: expected `!`, found `{`
42-
--> $DIR/2018-edition-error.rs:13:17
43-
|
44-
LL | match await { await => () }
45-
| ----- ^ expected `!`
46-
| |
47-
| while parsing this match expression
48-
49-
error: aborting due to 5 previous errors
41+
error: aborting due to 4 previous errors
5042

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// edition:2018
2+
3+
#![feature(async_await)]
4+
5+
async fn bar() -> Result<(), ()> {
6+
Ok(())
7+
}
8+
9+
async fn foo1() -> Result<(), ()> {
10+
let _ = await bar(); //~ ERROR incorrect use of `await`
11+
Ok(())
12+
}
13+
async fn foo2() -> Result<(), ()> {
14+
let _ = await? bar(); //~ ERROR incorrect use of `await`
15+
Ok(())
16+
}
17+
async fn foo3() -> Result<(), ()> {
18+
let _ = await bar()?; //~ ERROR incorrect use of `await`
19+
//~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try`
20+
Ok(())
21+
}
22+
async fn foo21() -> Result<(), ()> {
23+
let _ = await { bar() }; //~ ERROR incorrect use of `await`
24+
Ok(())
25+
}
26+
async fn foo22() -> Result<(), ()> {
27+
let _ = await(bar()); //~ ERROR incorrect use of `await`
28+
Ok(())
29+
}
30+
async fn foo23() -> Result<(), ()> {
31+
let _ = await { bar() }?; //~ ERROR incorrect use of `await`
32+
Ok(())
33+
}
34+
async fn foo4() -> Result<(), ()> {
35+
let _ = (await bar())?; //~ ERROR incorrect use of `await`
36+
Ok(())
37+
}
38+
async fn foo5() -> Result<(), ()> {
39+
let _ = bar().await(); //~ ERROR incorrect use of `await`
40+
Ok(())
41+
}
42+
async fn foo6() -> Result<(), ()> {
43+
let _ = bar().await()?; //~ ERROR incorrect use of `await`
44+
Ok(())
45+
}
46+
async fn foo7() -> Result<(), ()> {
47+
let _ = bar().await; // OK
48+
Ok(())
49+
}
50+
async fn foo8() -> Result<(), ()> {
51+
let _ = bar().await?; // OK
52+
Ok(())
53+
}
54+
fn foo9() -> Result<(), ()> {
55+
let _ = await bar(); //~ ERROR `await` is only allowed inside `async` functions and blocks
56+
//~^ ERROR incorrect use of `await`
57+
Ok(())
58+
}
59+
fn foo10() -> Result<(), ()> {
60+
let _ = await? bar(); //~ ERROR `await` is only allowed inside `async` functions and blocks
61+
//~^ ERROR incorrect use of `await`
62+
Ok(())
63+
}
64+
fn foo11() -> Result<(), ()> {
65+
let _ = await bar()?; //~ ERROR `await` is only allowed inside `async` functions and blocks
66+
//~^ ERROR incorrect use of `await`
67+
Ok(())
68+
}
69+
fn foo12() -> Result<(), ()> {
70+
let _ = (await bar())?; //~ ERROR `await` is only allowed inside `async` functions and blocks
71+
//~^ ERROR incorrect use of `await`
72+
Ok(())
73+
}
74+
fn foo13() -> Result<(), ()> {
75+
let _ = bar().await(); //~ ERROR `await` is only allowed inside `async` functions and blocks
76+
//~^ ERROR incorrect use of `await`
77+
Ok(())
78+
}
79+
fn foo14() -> Result<(), ()> {
80+
let _ = bar().await()?; //~ ERROR `await` is only allowed inside `async` functions and blocks
81+
//~^ ERROR incorrect use of `await`
82+
Ok(())
83+
}
84+
fn foo15() -> Result<(), ()> {
85+
let _ = bar().await; //~ ERROR `await` is only allowed inside `async` functions and blocks
86+
Ok(())
87+
}
88+
fn foo16() -> Result<(), ()> {
89+
let _ = bar().await?; //~ ERROR `await` is only allowed inside `async` functions and blocks
90+
Ok(())
91+
}
92+
93+
fn main() {}

0 commit comments

Comments
 (0)