Skip to content

Commit 33cde4a

Browse files
committed
Auto merge of #60586 - cramertj:await, r=oli-obk
Implement built-in await syntax Adds support for .await under the existing async_await feature gate. Moves macro-like await! syntax to the await_macro feature gate. Removes support for `await` as a non-keyword under the `async_await` feature. This new syntax is not final, but is the consensus solution proposed by the lang team, as explained in https://boats.gitlab.io/blog/post/await-decision/ Fix #51719 Fix #51751 Fix #60016
2 parents cfdc84a + fe8760c commit 33cde4a

37 files changed

+931
-165
lines changed

src/librustc/error_codes.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2205,4 +2205,6 @@ register_diagnostics! {
22052205
E0711, // a feature has been declared with conflicting stability attributes
22062206
// E0702, // replaced with a generic attribute input check
22072207
E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
2208+
E0727, // `async` generators are not yet supported
2209+
E0728, // `await` must be in an `async` function or block
22082210
}

src/librustc/hir/lowering.rs

+275-31
Large diffs are not rendered by default.

src/librustc/hir/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1606,6 +1606,8 @@ pub enum LocalSource {
16061606
/// }
16071607
/// ```
16081608
AsyncFn,
1609+
/// A desugared `<expr>.await`.
1610+
AwaitDesugar,
16091611
}
16101612

16111613
/// Hints at the original code for a `match _ { .. }`.
@@ -1624,6 +1626,8 @@ pub enum MatchSource {
16241626
ForLoopDesugar,
16251627
/// A desugared `?` operator.
16261628
TryDesugar,
1629+
/// A desugared `<expr>.await`.
1630+
AwaitDesugar,
16271631
}
16281632

16291633
/// The loop type that yielded an `ExprKind::Loop`.

src/librustc/ich/impls_syntax.rs

+1
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,7 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat {
396396

397397
impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
398398
Async,
399+
Await,
399400
QuestionMark,
400401
ExistentialReturnType,
401402
ForLoop,

src/librustc_lint/builtin.rs

+5-38
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ use syntax::symbol::{Symbol, keywords};
4646
use syntax::errors::{Applicability, DiagnosticBuilder};
4747
use syntax::print::pprust::expr_to_string;
4848
use syntax::visit::FnKind;
49-
use syntax::struct_span_err;
5049

5150
use rustc::hir::{self, GenericParamKind, PatKind};
5251

@@ -1438,15 +1437,10 @@ impl KeywordIdents {
14381437
UnderMacro(under_macro): UnderMacro,
14391438
ident: ast::Ident)
14401439
{
1441-
let ident_str = &ident.as_str()[..];
1442-
let cur_edition = cx.sess.edition();
1443-
let is_raw_ident = |ident: ast::Ident| {
1444-
cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span)
1445-
};
1446-
let next_edition = match cur_edition {
1440+
let next_edition = match cx.sess.edition() {
14471441
Edition::Edition2015 => {
1448-
match ident_str {
1449-
"async" | "try" => Edition::Edition2018,
1442+
match &ident.as_str()[..] {
1443+
"async" | "await" | "try" => Edition::Edition2018,
14501444

14511445
// rust-lang/rust#56327: Conservatively do not
14521446
// attempt to report occurrences of `dyn` within
@@ -1462,43 +1456,16 @@ impl KeywordIdents {
14621456
// an identifier.
14631457
"dyn" if !under_macro => Edition::Edition2018,
14641458

1465-
// Only issue warnings for `await` if the `async_await`
1466-
// feature isn't being used. Otherwise, users need
1467-
// to keep using `await` for the macro exposed by std.
1468-
"await" if !cx.sess.features_untracked().async_await => Edition::Edition2018,
14691459
_ => return,
14701460
}
14711461
}
14721462

14731463
// There are no new keywords yet for the 2018 edition and beyond.
1474-
// However, `await` is a "false" keyword in the 2018 edition,
1475-
// and can only be used if the `async_await` feature is enabled.
1476-
// Otherwise, we emit an error.
1477-
_ => {
1478-
if "await" == ident_str
1479-
&& !cx.sess.features_untracked().async_await
1480-
&& !is_raw_ident(ident)
1481-
{
1482-
let mut err = struct_span_err!(
1483-
cx.sess,
1484-
ident.span,
1485-
E0721,
1486-
"`await` is a keyword in the {} edition", cur_edition,
1487-
);
1488-
err.span_suggestion(
1489-
ident.span,
1490-
"you can use a raw identifier to stay compatible",
1491-
"r#await".to_string(),
1492-
Applicability::MachineApplicable,
1493-
);
1494-
err.emit();
1495-
}
1496-
return
1497-
},
1464+
_ => return,
14981465
};
14991466

15001467
// don't lint `r#foo`
1501-
if is_raw_ident(ident) {
1468+
if cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span) {
15021469
return;
15031470
}
15041471

src/librustc_mir/hair/pattern/check_match.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
7777
hir::LocalSource::Normal => "local binding",
7878
hir::LocalSource::ForLoopDesugar => "`for` loop binding",
7979
hir::LocalSource::AsyncFn => "async fn binding",
80+
hir::LocalSource::AwaitDesugar => "`await` future binding",
8081
});
8182

8283
// Check legality of move bindings and `@` patterns.
@@ -412,8 +413,9 @@ fn check_arms<'a, 'tcx>(
412413
err.emit();
413414
}
414415

415-
// Unreachable patterns in try expressions occur when one of the arms
416-
// are an uninhabited type. Which is OK.
416+
// Unreachable patterns in try and await expressions occur when one of
417+
// the arms are an uninhabited type. Which is OK.
418+
hir::MatchSource::AwaitDesugar |
417419
hir::MatchSource::TryDesugar => {}
418420
}
419421
}

src/libsyntax/ast.rs

+13
Original file line numberDiff line numberDiff line change
@@ -1065,6 +1065,7 @@ impl Expr {
10651065
ExprKind::Block(..) => ExprPrecedence::Block,
10661066
ExprKind::TryBlock(..) => ExprPrecedence::TryBlock,
10671067
ExprKind::Async(..) => ExprPrecedence::Async,
1068+
ExprKind::Await(..) => ExprPrecedence::Await,
10681069
ExprKind::Assign(..) => ExprPrecedence::Assign,
10691070
ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
10701071
ExprKind::Field(..) => ExprPrecedence::Field,
@@ -1186,6 +1187,9 @@ pub enum ExprKind {
11861187
/// created during lowering cannot be made the parent of any other
11871188
/// preexisting defs.
11881189
Async(CaptureBy, NodeId, P<Block>),
1190+
/// An await expression (`my_future.await`).
1191+
Await(AwaitOrigin, P<Expr>),
1192+
11891193
/// A try block (`try { ... }`).
11901194
TryBlock(P<Block>),
11911195

@@ -1287,6 +1291,15 @@ pub enum Movability {
12871291
Movable,
12881292
}
12891293

1294+
/// Whether an `await` comes from `await!` or `.await` syntax.
1295+
/// FIXME: this should be removed when support for legacy `await!` is removed.
1296+
/// https://github.com/rust-lang/rust/issues/60610
1297+
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
1298+
pub enum AwaitOrigin {
1299+
FieldLike,
1300+
MacroLike,
1301+
}
1302+
12901303
pub type Mac = Spanned<Mac_>;
12911304

12921305
/// Represents a macro invocation. The `Path` indicates which macro

src/libsyntax/feature_gate.rs

+18
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,10 @@ declare_features! (
482482
// Allows async and await syntax.
483483
(active, async_await, "1.28.0", Some(50547), None),
484484

485+
// Allows await! macro-like syntax.
486+
// This will likely be removed prior to stabilization of async/await.
487+
(active, await_macro, "1.28.0", Some(50547), None),
488+
485489
// Allows reinterpretation of the bits of a value of one type as another type during const eval.
486490
(active, const_transmute, "1.29.0", Some(53605), None),
487491

@@ -2127,6 +2131,20 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
21272131
ast::ExprKind::Async(..) => {
21282132
gate_feature_post!(&self, async_await, e.span, "async blocks are unstable");
21292133
}
2134+
ast::ExprKind::Await(origin, _) => {
2135+
match origin {
2136+
ast::AwaitOrigin::FieldLike =>
2137+
gate_feature_post!(&self, async_await, e.span, "async/await is unstable"),
2138+
ast::AwaitOrigin::MacroLike =>
2139+
gate_feature_post!(
2140+
&self,
2141+
await_macro,
2142+
e.span,
2143+
"`await!(<expr>)` macro syntax is unstable, and will soon be removed \
2144+
in favor of `<expr>.await` syntax."
2145+
),
2146+
}
2147+
}
21302148
_ => {}
21312149
}
21322150
visit::walk_expr(self, e);

src/libsyntax/mut_visit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1185,6 +1185,7 @@ pub fn noop_visit_expr<T: MutVisitor>(Expr { node, id, span, attrs }: &mut Expr,
11851185
vis.visit_id(node_id);
11861186
vis.visit_block(body);
11871187
}
1188+
ExprKind::Await(_origin, expr) => vis.visit_expr(expr),
11881189
ExprKind::Assign(el, er) => {
11891190
vis.visit_expr(el);
11901191
vis.visit_expr(er);

src/libsyntax/parse/parser.rs

+17
Original file line numberDiff line numberDiff line change
@@ -2752,6 +2752,14 @@ impl<'a> Parser<'a> {
27522752
db.span_label(self.span, "expected expression");
27532753
db.note("variable declaration using `let` is a statement");
27542754
return Err(db);
2755+
} else if self.span.rust_2018() && self.eat_keyword(keywords::Await) {
2756+
// FIXME: remove this branch when `await!` is no longer supported
2757+
// https://github.com/rust-lang/rust/issues/60610
2758+
self.expect(&token::Not)?;
2759+
self.expect(&token::OpenDelim(token::Paren))?;
2760+
let expr = self.parse_expr()?;
2761+
self.expect(&token::CloseDelim(token::Paren))?;
2762+
ex = ExprKind::Await(ast::AwaitOrigin::MacroLike, expr);
27552763
} else if self.token.is_path_start() {
27562764
let path = self.parse_path(PathStyle::Expr)?;
27572765

@@ -3015,6 +3023,15 @@ impl<'a> Parser<'a> {
30153023

30163024
// Assuming we have just parsed `.`, continue parsing into an expression.
30173025
fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
3026+
if self.span.rust_2018() && self.eat_keyword(keywords::Await) {
3027+
let span = lo.to(self.prev_span);
3028+
let await_expr = self.mk_expr(
3029+
span,
3030+
ExprKind::Await(ast::AwaitOrigin::FieldLike, self_arg),
3031+
ThinVec::new(),
3032+
);
3033+
return Ok(await_expr);
3034+
}
30183035
let segment = self.parse_path_segment(PathStyle::Expr)?;
30193036
self.check_trailing_angle_brackets(&segment, token::OpenDelim(token::Paren));
30203037

src/libsyntax/parse/token.rs

+5
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ pub(crate) fn ident_can_begin_expr(ident: ast::Ident, is_raw: bool) -> bool {
9999
ident_token.is_path_segment_keyword() ||
100100
[
101101
keywords::Async.name(),
102+
103+
// FIXME: remove when `await!(..)` syntax is removed
104+
// https://github.com/rust-lang/rust/issues/60610
105+
keywords::Await.name(),
106+
102107
keywords::Do.name(),
103108
keywords::Box.name(),
104109
keywords::Break.name(),

src/libsyntax/print/pprust.rs

+12
Original file line numberDiff line numberDiff line change
@@ -2250,6 +2250,18 @@ impl<'a> State<'a> {
22502250
self.ibox(0)?;
22512251
self.print_block_with_attrs(blk, attrs)?;
22522252
}
2253+
ast::ExprKind::Await(origin, ref expr) => {
2254+
match origin {
2255+
ast::AwaitOrigin::MacroLike => {
2256+
self.s.word("await!")?;
2257+
self.print_expr_maybe_paren(expr, parser::PREC_FORCE_PAREN)?;
2258+
}
2259+
ast::AwaitOrigin::FieldLike => {
2260+
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX)?;
2261+
self.s.word(".await")?;
2262+
}
2263+
}
2264+
}
22532265
ast::ExprKind::Assign(ref lhs, ref rhs) => {
22542266
let prec = AssocOp::Assign.precedence() as i8;
22552267
self.print_expr_maybe_paren(lhs, prec + 1)?;

src/libsyntax/util/parser.rs

+3
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ pub enum ExprPrecedence {
267267
TryBlock,
268268
Struct,
269269
Async,
270+
Await,
270271
Err,
271272
}
272273

@@ -301,6 +302,7 @@ impl ExprPrecedence {
301302
ExprPrecedence::Unary => PREC_PREFIX,
302303

303304
// Unary, postfix
305+
ExprPrecedence::Await |
304306
ExprPrecedence::Call |
305307
ExprPrecedence::MethodCall |
306308
ExprPrecedence::Field |
@@ -346,6 +348,7 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
346348
// X { y: 1 } + X { y: 2 }
347349
contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
348350
}
351+
ast::ExprKind::Await(_, ref x) |
349352
ast::ExprKind::Unary(_, ref x) |
350353
ast::ExprKind::Cast(ref x, _) |
351354
ast::ExprKind::Type(ref x, _) |

src/libsyntax/visit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
768768
ExprKind::Async(_, _, ref body) => {
769769
visitor.visit_block(body);
770770
}
771+
ExprKind::Await(_, ref expr) => visitor.visit_expr(expr),
771772
ExprKind::Assign(ref left_hand_expression, ref right_hand_expression) => {
772773
visitor.visit_expr(left_hand_expression);
773774
visitor.visit_expr(right_hand_expression);

src/libsyntax_pos/hygiene.rs

+2
Original file line numberDiff line numberDiff line change
@@ -598,13 +598,15 @@ pub enum CompilerDesugaringKind {
598598
/// `impl Trait` with `Foo`.
599599
ExistentialReturnType,
600600
Async,
601+
Await,
601602
ForLoop,
602603
}
603604

604605
impl CompilerDesugaringKind {
605606
pub fn name(self) -> Symbol {
606607
Symbol::intern(match self {
607608
CompilerDesugaringKind::Async => "async",
609+
CompilerDesugaringKind::Await => "await",
608610
CompilerDesugaringKind::QuestionMark => "?",
609611
CompilerDesugaringKind::TryBlock => "try block",
610612
CompilerDesugaringKind::ExistentialReturnType => "existential type",

src/libsyntax_pos/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ symbols! {
8484

8585
// Edition-specific keywords that are used in unstable Rust or reserved for future use.
8686
Async: "async", // >= 2018 Edition only
87+
Await: "await", // >= 2018 Edition only
8788
Try: "try", // >= 2018 Edition only
8889

8990
// Special lifetime names

0 commit comments

Comments
 (0)