Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement built-in await syntax #60586

Merged
merged 1 commit into from
May 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/librustc/error_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2205,4 +2205,6 @@ register_diagnostics! {
E0711, // a feature has been declared with conflicting stability attributes
// E0702, // replaced with a generic attribute input check
E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
E0727, // `async` generators are not yet supported
E0728, // `await` must be in an `async` function or block
}
306 changes: 275 additions & 31 deletions src/librustc/hir/lowering.rs

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1606,6 +1606,8 @@ pub enum LocalSource {
/// }
/// ```
AsyncFn,
/// A desugared `<expr>.await`.
AwaitDesugar,
}

/// Hints at the original code for a `match _ { .. }`.
Expand All @@ -1624,6 +1626,8 @@ pub enum MatchSource {
ForLoopDesugar,
/// A desugared `?` operator.
TryDesugar,
/// A desugared `<expr>.await`.
AwaitDesugar,
}

/// The loop type that yielded an `ExprKind::Loop`.
Expand Down
1 change: 1 addition & 0 deletions src/librustc/ich/impls_syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat {

impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
Async,
Await,
QuestionMark,
ExistentialReturnType,
ForLoop,
Expand Down
43 changes: 5 additions & 38 deletions src/librustc_lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ use syntax::symbol::{Symbol, keywords};
use syntax::errors::{Applicability, DiagnosticBuilder};
use syntax::print::pprust::expr_to_string;
use syntax::visit::FnKind;
use syntax::struct_span_err;

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

Expand Down Expand Up @@ -1438,15 +1437,10 @@ impl KeywordIdents {
UnderMacro(under_macro): UnderMacro,
ident: ast::Ident)
{
let ident_str = &ident.as_str()[..];
let cur_edition = cx.sess.edition();
let is_raw_ident = |ident: ast::Ident| {
cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span)
};
let next_edition = match cur_edition {
let next_edition = match cx.sess.edition() {
Edition::Edition2015 => {
match ident_str {
"async" | "try" => Edition::Edition2018,
match &ident.as_str()[..] {
"async" | "await" | "try" => Edition::Edition2018,

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

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

// There are no new keywords yet for the 2018 edition and beyond.
// However, `await` is a "false" keyword in the 2018 edition,
// and can only be used if the `async_await` feature is enabled.
// Otherwise, we emit an error.
_ => {
if "await" == ident_str
&& !cx.sess.features_untracked().async_await
&& !is_raw_ident(ident)
{
let mut err = struct_span_err!(
cx.sess,
ident.span,
E0721,
"`await` is a keyword in the {} edition", cur_edition,
);
err.span_suggestion(
ident.span,
"you can use a raw identifier to stay compatible",
"r#await".to_string(),
Applicability::MachineApplicable,
);
err.emit();
}
return
},
_ => return,
};

// don't lint `r#foo`
if is_raw_ident(ident) {
if cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span) {
return;
}

Expand Down
6 changes: 4 additions & 2 deletions src/librustc_mir/hair/pattern/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
hir::LocalSource::Normal => "local binding",
hir::LocalSource::ForLoopDesugar => "`for` loop binding",
hir::LocalSource::AsyncFn => "async fn binding",
hir::LocalSource::AwaitDesugar => "`await` future binding",
});

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

// Unreachable patterns in try expressions occur when one of the arms
// are an uninhabited type. Which is OK.
// Unreachable patterns in try and await expressions occur when one of
// the arms are an uninhabited type. Which is OK.
hir::MatchSource::AwaitDesugar |
hir::MatchSource::TryDesugar => {}
}
}
Expand Down
13 changes: 13 additions & 0 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1065,6 +1065,7 @@ impl Expr {
ExprKind::Block(..) => ExprPrecedence::Block,
ExprKind::TryBlock(..) => ExprPrecedence::TryBlock,
ExprKind::Async(..) => ExprPrecedence::Async,
ExprKind::Await(..) => ExprPrecedence::Await,
ExprKind::Assign(..) => ExprPrecedence::Assign,
ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
ExprKind::Field(..) => ExprPrecedence::Field,
Expand Down Expand Up @@ -1186,6 +1187,9 @@ pub enum ExprKind {
/// created during lowering cannot be made the parent of any other
/// preexisting defs.
Async(CaptureBy, NodeId, P<Block>),
/// An await expression (`my_future.await`).
Await(AwaitOrigin, P<Expr>),

/// A try block (`try { ... }`).
TryBlock(P<Block>),

Expand Down Expand Up @@ -1287,6 +1291,15 @@ pub enum Movability {
Movable,
}

/// Whether an `await` comes from `await!` or `.await` syntax.
/// FIXME: this should be removed when support for legacy `await!` is removed.
cramertj marked this conversation as resolved.
Show resolved Hide resolved
/// https://github.com/rust-lang/rust/issues/60610
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
pub enum AwaitOrigin {
FieldLike,
MacroLike,
}

pub type Mac = Spanned<Mac_>;

/// Represents a macro invocation. The `Path` indicates which macro
Expand Down
18 changes: 18 additions & 0 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,10 @@ declare_features! (
// Allows async and await syntax.
(active, async_await, "1.28.0", Some(50547), None),

// Allows await! macro-like syntax.
// This will likely be removed prior to stabilization of async/await.
(active, await_macro, "1.28.0", Some(50547), None),

// Allows reinterpretation of the bits of a value of one type as another type during const eval.
(active, const_transmute, "1.29.0", Some(53605), None),

Expand Down Expand Up @@ -2104,6 +2108,20 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
ast::ExprKind::Async(..) => {
gate_feature_post!(&self, async_await, e.span, "async blocks are unstable");
}
ast::ExprKind::Await(origin, _) => {
match origin {
ast::AwaitOrigin::FieldLike =>
gate_feature_post!(&self, async_await, e.span, "async/await is unstable"),
ast::AwaitOrigin::MacroLike =>
gate_feature_post!(
&self,
await_macro,
e.span,
"`await!(<expr>)` macro syntax is unstable, and will soon be removed \
in favor of `<expr>.await` syntax."
),
Centril marked this conversation as resolved.
Show resolved Hide resolved
}
}
_ => {}
}
visit::walk_expr(self, e);
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1185,6 +1185,7 @@ pub fn noop_visit_expr<T: MutVisitor>(Expr { node, id, span, attrs }: &mut Expr,
vis.visit_id(node_id);
vis.visit_block(body);
}
ExprKind::Await(_origin, expr) => vis.visit_expr(expr),
ExprKind::Assign(el, er) => {
vis.visit_expr(el);
vis.visit_expr(er);
Expand Down
17 changes: 17 additions & 0 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2751,6 +2751,14 @@ impl<'a> Parser<'a> {
db.span_label(self.span, "expected expression");
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
cramertj marked this conversation as resolved.
Show resolved Hide resolved
// 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))?;
ex = ExprKind::Await(ast::AwaitOrigin::MacroLike, expr);
} else if self.token.is_path_start() {
let path = self.parse_path(PathStyle::Expr)?;

Expand Down Expand Up @@ -3014,6 +3022,15 @@ impl<'a> Parser<'a> {

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

Expand Down
5 changes: 5 additions & 0 deletions src/libsyntax/parse/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ pub(crate) fn ident_can_begin_expr(ident: ast::Ident, is_raw: bool) -> bool {
ident_token.is_path_segment_keyword() ||
[
keywords::Async.name(),

// FIXME: remove when `await!(..)` syntax is removed
// https://github.com/rust-lang/rust/issues/60610
keywords::Await.name(),

keywords::Do.name(),
keywords::Box.name(),
keywords::Break.name(),
Expand Down
12 changes: 12 additions & 0 deletions src/libsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2250,6 +2250,18 @@ impl<'a> State<'a> {
self.ibox(0)?;
self.print_block_with_attrs(blk, attrs)?;
}
ast::ExprKind::Await(origin, ref expr) => {
match origin {
ast::AwaitOrigin::MacroLike => {
self.s.word("await!")?;
self.print_expr_maybe_paren(expr, parser::PREC_FORCE_PAREN)?;
}
ast::AwaitOrigin::FieldLike => {
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX)?;
self.s.word(".await")?;
}
}
}
ast::ExprKind::Assign(ref lhs, ref rhs) => {
let prec = AssocOp::Assign.precedence() as i8;
self.print_expr_maybe_paren(lhs, prec + 1)?;
Expand Down
3 changes: 3 additions & 0 deletions src/libsyntax/util/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ pub enum ExprPrecedence {
TryBlock,
Struct,
Async,
Await,
Err,
}

Expand Down Expand Up @@ -301,6 +302,7 @@ impl ExprPrecedence {
ExprPrecedence::Unary => PREC_PREFIX,

// Unary, postfix
ExprPrecedence::Await |
ExprPrecedence::Call |
ExprPrecedence::MethodCall |
ExprPrecedence::Field |
Expand Down Expand Up @@ -346,6 +348,7 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
// X { y: 1 } + X { y: 2 }
contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
}
ast::ExprKind::Await(_, ref x) |
ast::ExprKind::Unary(_, ref x) |
ast::ExprKind::Cast(ref x, _) |
ast::ExprKind::Type(ref x, _) |
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
ExprKind::Async(_, _, ref body) => {
visitor.visit_block(body);
}
ExprKind::Await(_, ref expr) => visitor.visit_expr(expr),
ExprKind::Assign(ref left_hand_expression, ref right_hand_expression) => {
visitor.visit_expr(left_hand_expression);
visitor.visit_expr(right_hand_expression);
Expand Down
2 changes: 2 additions & 0 deletions src/libsyntax_pos/hygiene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -598,13 +598,15 @@ pub enum CompilerDesugaringKind {
/// `impl Trait` with `Foo`.
ExistentialReturnType,
Async,
Await,
ForLoop,
}

impl CompilerDesugaringKind {
pub fn name(self) -> Symbol {
Symbol::intern(match self {
CompilerDesugaringKind::Async => "async",
CompilerDesugaringKind::Await => "await",
CompilerDesugaringKind::QuestionMark => "?",
CompilerDesugaringKind::TryBlock => "try block",
CompilerDesugaringKind::ExistentialReturnType => "existential type",
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax_pos/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ symbols! {

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

// Special lifetime names
Expand Down
Loading