Skip to content

Implement built-in await syntax #60586

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

Merged
merged 1 commit into from
May 8, 2019
Merged
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
@@ -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
@@ -1606,6 +1606,8 @@ pub enum LocalSource {
/// }
/// ```
AsyncFn,
/// A desugared `<expr>.await`.
AwaitDesugar,
}

/// Hints at the original code for a `match _ { .. }`.
@@ -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`.
1 change: 1 addition & 0 deletions src/librustc/ich/impls_syntax.rs
Original file line number Diff line number Diff line change
@@ -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,
43 changes: 5 additions & 38 deletions src/librustc_lint/builtin.rs
Original file line number Diff line number Diff line change
@@ -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};

@@ -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
@@ -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;
}

6 changes: 4 additions & 2 deletions src/librustc_mir/hair/pattern/check_match.rs
Original file line number Diff line number Diff line change
@@ -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.
@@ -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 => {}
}
}
13 changes: 13 additions & 0 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
@@ -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,
@@ -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>),

@@ -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.
/// 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
18 changes: 18 additions & 0 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
@@ -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),

@@ -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."
),
}
}
_ => {}
}
visit::walk_expr(self, e);
1 change: 1 addition & 0 deletions src/libsyntax/mut_visit.rs
Original file line number Diff line number Diff line change
@@ -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);
17 changes: 17 additions & 0 deletions src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
@@ -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
// 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)?;

@@ -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));

5 changes: 5 additions & 0 deletions src/libsyntax/parse/token.rs
Original file line number Diff line number Diff line change
@@ -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(),
12 changes: 12 additions & 0 deletions src/libsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
@@ -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)?;
3 changes: 3 additions & 0 deletions src/libsyntax/util/parser.rs
Original file line number Diff line number Diff line change
@@ -267,6 +267,7 @@ pub enum ExprPrecedence {
TryBlock,
Struct,
Async,
Await,
Err,
}

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

// Unary, postfix
ExprPrecedence::Await |
ExprPrecedence::Call |
ExprPrecedence::MethodCall |
ExprPrecedence::Field |
@@ -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, _) |
1 change: 1 addition & 0 deletions src/libsyntax/visit.rs
Original file line number Diff line number Diff line change
@@ -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);
2 changes: 2 additions & 0 deletions src/libsyntax_pos/hygiene.rs
Original file line number Diff line number Diff line change
@@ -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",
1 change: 1 addition & 0 deletions src/libsyntax_pos/symbol.rs
Original file line number Diff line number Diff line change
@@ -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
36 changes: 18 additions & 18 deletions src/test/run-pass/async-await.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// edition:2018
// aux-build:arc_wake.rs

#![feature(async_await, await_macro)]
#![feature(async_await)]

extern crate arc_wake;

@@ -46,58 +46,58 @@ impl Future for WakeOnceThenComplete {

fn async_block(x: u8) -> impl Future<Output = u8> {
async move {
await!(wake_and_yield_once());
wake_and_yield_once().await;
x
}
}

fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
async move {
await!(wake_and_yield_once());
wake_and_yield_once().await;
*x
}
}

fn async_nonmove_block(x: u8) -> impl Future<Output = u8> {
async move {
let future = async {
await!(wake_and_yield_once());
wake_and_yield_once().await;
x
};
await!(future)
future.await
}
}

fn async_closure(x: u8) -> impl Future<Output = u8> {
(async move |x: u8| -> u8 {
await!(wake_and_yield_once());
wake_and_yield_once().await;
x
})(x)
}

async fn async_fn(x: u8) -> u8 {
await!(wake_and_yield_once());
wake_and_yield_once().await;
x
}

async fn generic_async_fn<T>(x: T) -> T {
await!(wake_and_yield_once());
wake_and_yield_once().await;
x
}

async fn async_fn_with_borrow(x: &u8) -> u8 {
await!(wake_and_yield_once());
wake_and_yield_once().await;
*x
}

async fn async_fn_with_borrow_named_lifetime<'a>(x: &'a u8) -> u8 {
await!(wake_and_yield_once());
wake_and_yield_once().await;
*x
}

fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
async move {
await!(wake_and_yield_once());
wake_and_yield_once().await;
*x
}
}
@@ -110,18 +110,18 @@ async fn async_fn_multiple_args(x: &u8, _y: &u8) -> u8 {
*/

async fn async_fn_multiple_args_named_lifetime<'a>(x: &'a u8, _y: &'a u8) -> u8 {
await!(wake_and_yield_once());
wake_and_yield_once().await;
*x
}

fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> {
async move {
await!(async_fn_with_borrow_named_lifetime(&y))
async_fn_with_borrow_named_lifetime(&y).await
}
}

unsafe async fn unsafe_async_fn(x: u8) -> u8 {
await!(wake_and_yield_once());
wake_and_yield_once().await;
x
}

@@ -134,7 +134,7 @@ trait Bar {
impl Foo {
async fn async_method(x: u8) -> u8 {
unsafe {
await!(unsafe_async_fn(x))
unsafe_async_fn(x).await
}
}
}
@@ -165,7 +165,7 @@ fn main() {
($($fn_name:expr,)*) => { $(
test_future_yields_once_then_returns(|x| {
async move {
await!($fn_name(&x))
$fn_name(&x).await
}
});
)* }
@@ -181,7 +181,7 @@ fn main() {
Foo::async_method,
|x| {
async move {
unsafe { await!(unsafe_async_fn(x)) }
unsafe { unsafe_async_fn(x).await }
}
},
}
@@ -192,7 +192,7 @@ fn main() {
async_fn_with_impl_future_named_lifetime,
|x| {
async move {
await!(async_fn_multiple_args_named_lifetime(x, x))
async_fn_multiple_args_named_lifetime(x, x).await
}
},
}
199 changes: 199 additions & 0 deletions src/test/run-pass/await-macro.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
// edition:2018
// aux-build:arc_wake.rs

#![feature(async_await, await_macro)]

extern crate arc_wake;

use std::pin::Pin;
use std::future::Future;
use std::sync::{
Arc,
atomic::{self, AtomicUsize},
};
use std::task::{Context, Poll};
use arc_wake::ArcWake;

struct Counter {
wakes: AtomicUsize,
}

impl ArcWake for Counter {
fn wake(self: Arc<Self>) {
Self::wake_by_ref(&self)
}
fn wake_by_ref(arc_self: &Arc<Self>) {
arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst);
}
}

struct WakeOnceThenComplete(bool);

fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) }

impl Future for WakeOnceThenComplete {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
if self.0 {
Poll::Ready(())
} else {
cx.waker().wake_by_ref();
self.0 = true;
Poll::Pending
}
}
}

fn async_block(x: u8) -> impl Future<Output = u8> {
async move {
await!(wake_and_yield_once());
x
}
}

fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
async move {
await!(wake_and_yield_once());
*x
}
}

fn async_nonmove_block(x: u8) -> impl Future<Output = u8> {
async move {
let future = async {
await!(wake_and_yield_once());
x
};
await!(future)
}
}

fn async_closure(x: u8) -> impl Future<Output = u8> {
(async move |x: u8| -> u8 {
await!(wake_and_yield_once());
x
})(x)
}

async fn async_fn(x: u8) -> u8 {
await!(wake_and_yield_once());
x
}

async fn generic_async_fn<T>(x: T) -> T {
await!(wake_and_yield_once());
x
}

async fn async_fn_with_borrow(x: &u8) -> u8 {
await!(wake_and_yield_once());
*x
}

async fn async_fn_with_borrow_named_lifetime<'a>(x: &'a u8) -> u8 {
await!(wake_and_yield_once());
*x
}

fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future<Output = u8> + 'a {
async move {
await!(wake_and_yield_once());
*x
}
}

/* FIXME(cramertj) support when `existential type T<'a, 'b>:;` works
async fn async_fn_multiple_args(x: &u8, _y: &u8) -> u8 {
await!(wake_and_yield_once());
*x
}
*/

async fn async_fn_multiple_args_named_lifetime<'a>(x: &'a u8, _y: &'a u8) -> u8 {
await!(wake_and_yield_once());
*x
}

fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> {
async move {
await!(async_fn_with_borrow_named_lifetime(&y))
}
}

unsafe async fn unsafe_async_fn(x: u8) -> u8 {
await!(wake_and_yield_once());
x
}

struct Foo;

trait Bar {
fn foo() {}
}

impl Foo {
async fn async_method(x: u8) -> u8 {
unsafe {
await!(unsafe_async_fn(x))
}
}
}

fn test_future_yields_once_then_returns<F, Fut>(f: F)
where
F: FnOnce(u8) -> Fut,
Fut: Future<Output = u8>,
{
let mut fut = Box::pin(f(9));
let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) });
let waker = ArcWake::into_waker(counter.clone());
let mut cx = Context::from_waker(&waker);
assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst));
assert_eq!(Poll::Pending, fut.as_mut().poll(&mut cx));
assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst));
assert_eq!(Poll::Ready(9), fut.as_mut().poll(&mut cx));
}

fn main() {
macro_rules! test {
($($fn_name:expr,)*) => { $(
test_future_yields_once_then_returns($fn_name);
)* }
}

macro_rules! test_with_borrow {
($($fn_name:expr,)*) => { $(
test_future_yields_once_then_returns(|x| {
async move {
await!($fn_name(&x))
}
});
)* }
}

test! {
async_block,
async_nonmove_block,
async_closure,
async_fn,
generic_async_fn,
async_fn_with_internal_borrow,
Foo::async_method,
|x| {
async move {
unsafe { await!(unsafe_async_fn(x)) }
}
},
}
test_with_borrow! {
async_block_with_borrow_named_lifetime,
async_fn_with_borrow,
async_fn_with_borrow_named_lifetime,
async_fn_with_impl_future_named_lifetime,
|x| {
async move {
await!(async_fn_multiple_args_named_lifetime(x, x))
}
},
}
}
10 changes: 5 additions & 5 deletions src/test/run-pass/issue-55809.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// edition:2018
// run-pass

#![feature(async_await, await_macro)]
#![feature(async_await)]

trait Foo { }

@@ -14,15 +14,15 @@ async fn foo_async<T>(_v: T) -> u8 where T: Foo {
}

async fn bad<T>(v: T) -> u8 where T: Foo {
await!(foo_async(v))
foo_async(v).await
}

async fn async_main() {
let mut v = ();

let _ = await!(bad(&mut v));
let _ = await!(foo_async(&mut v));
let _ = await!(bad(v));
let _ = bad(&mut v).await;
let _ = foo_async(&mut v).await;
let _ = bad(v).await;
}

fn main() {
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#![feature(async_await, await_macro)]
#![allow(non_camel_case_types)]
#![deny(keyword_idents)]

mod outer_mod {
pub mod await { //~ ERROR `await` is a keyword in the 2018 edition
//~^ WARN this was previously accepted by the compiler
pub struct await; //~ ERROR `await` is a keyword in the 2018 edition
//~^ WARN this was previously accepted by the compiler
}
}
use outer_mod::await::await; //~ ERROR `await` is a keyword in the 2018 edition
//~^ ERROR `await` is a keyword in the 2018 edition
//~^^ WARN this was previously accepted by the compiler
//~^^^ WARN this was previously accepted by the compiler

struct Foo { await: () }
//~^ ERROR `await` is a keyword in the 2018 edition
//~^^ WARN this was previously accepted by the compiler

impl Foo { fn await() {} }
//~^ ERROR `await` is a keyword in the 2018 edition
//~^^ WARN this was previously accepted by the compiler

macro_rules! await {
//~^ ERROR `await` is a keyword in the 2018 edition
//~^^ WARN this was previously accepted by the compiler
() => {}
}

fn main() {
match await { await => {} } //~ ERROR `await` is a keyword in the 2018 edition
//~^ ERROR `await` is a keyword in the 2018 edition
//~^^ WARN this was previously accepted by the compiler
//~^^^ WARN this was previously accepted by the compiler
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
error: `await` is a keyword in the 2018 edition
--> $DIR/2015-edition-error-in-non-macro-position.rs:6:13
|
LL | pub mod await {
| ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
|
note: lint level defined here
--> $DIR/2015-edition-error-in-non-macro-position.rs:3:9
|
LL | #![deny(keyword_idents)]
| ^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
= note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>

error: `await` is a keyword in the 2018 edition
--> $DIR/2015-edition-error-in-non-macro-position.rs:8:20
|
LL | pub struct await;
| ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
= note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>

error: `await` is a keyword in the 2018 edition
--> $DIR/2015-edition-error-in-non-macro-position.rs:12:16
|
LL | use outer_mod::await::await;
| ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
= note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>

error: `await` is a keyword in the 2018 edition
--> $DIR/2015-edition-error-in-non-macro-position.rs:12:23
|
LL | use outer_mod::await::await;
| ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
= note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>

error: `await` is a keyword in the 2018 edition
--> $DIR/2015-edition-error-in-non-macro-position.rs:17:14
|
LL | struct Foo { await: () }
| ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
= note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>

error: `await` is a keyword in the 2018 edition
--> $DIR/2015-edition-error-in-non-macro-position.rs:21:15
|
LL | impl Foo { fn await() {} }
| ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
= note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>

error: `await` is a keyword in the 2018 edition
--> $DIR/2015-edition-error-in-non-macro-position.rs:25:14
|
LL | macro_rules! await {
| ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
= note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>

error: `await` is a keyword in the 2018 edition
--> $DIR/2015-edition-error-in-non-macro-position.rs:32:11
|
LL | match await { await => {} }
| ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
= note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>

error: `await` is a keyword in the 2018 edition
--> $DIR/2015-edition-error-in-non-macro-position.rs:32:19
|
LL | match await { await => {} }
| ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
= note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>

error: aborting due to 9 previous errors

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// edition:2018

#![allow(non_camel_case_types)]
#![feature(async_await, await_macro)]

mod outer_mod {
pub mod await { //~ ERROR expected identifier, found reserved keyword `await`
pub struct await; //~ ERROR expected identifier, found reserved keyword `await`
}
}
use self::outer_mod::await::await; //~ ERROR expected identifier, found reserved keyword `await`
//~^ ERROR expected identifier, found reserved keyword `await`

struct Foo { await: () }
//~^ ERROR expected identifier, found reserved keyword `await`

impl Foo { fn await() {} }
//~^ ERROR expected identifier, found reserved keyword `await`

macro_rules! await {
//~^ ERROR expected identifier, found reserved keyword `await`
() => {}
}

fn main() {
match await { await => () } //~ ERROR expected `!`, found `{`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
error: expected identifier, found reserved keyword `await`
--> $DIR/2018-edition-error-in-non-macro-position.rs:7:13
|
LL | pub mod await {
| ^^^^^ expected identifier, found reserved keyword
help: you can escape reserved keywords to use them as identifiers
|
LL | pub mod r#await {
| ^^^^^^^

error: expected identifier, found reserved keyword `await`
--> $DIR/2018-edition-error-in-non-macro-position.rs:8:20
|
LL | pub struct await;
| ^^^^^ expected identifier, found reserved keyword
help: you can escape reserved keywords to use them as identifiers
|
LL | pub struct r#await;
| ^^^^^^^

error: expected identifier, found reserved keyword `await`
--> $DIR/2018-edition-error-in-non-macro-position.rs:11:22
|
LL | use self::outer_mod::await::await;
| ^^^^^ expected identifier, found reserved keyword
help: you can escape reserved keywords to use them as identifiers
|
LL | use self::outer_mod::r#await::await;
| ^^^^^^^

error: expected identifier, found reserved keyword `await`
--> $DIR/2018-edition-error-in-non-macro-position.rs:11:29
|
LL | use self::outer_mod::await::await;
| ^^^^^ expected identifier, found reserved keyword
help: you can escape reserved keywords to use them as identifiers
|
LL | use self::outer_mod::await::r#await;
| ^^^^^^^

error: expected identifier, found reserved keyword `await`
--> $DIR/2018-edition-error-in-non-macro-position.rs:14:14
|
LL | struct Foo { await: () }
| ^^^^^ expected identifier, found reserved keyword
help: you can escape reserved keywords to use them as identifiers
|
LL | struct Foo { r#await: () }
| ^^^^^^^

error: expected identifier, found reserved keyword `await`
--> $DIR/2018-edition-error-in-non-macro-position.rs:17:15
|
LL | impl Foo { fn await() {} }
| ^^^^^ expected identifier, found reserved keyword
help: you can escape reserved keywords to use them as identifiers
|
LL | impl Foo { fn r#await() {} }
| ^^^^^^^

error: expected identifier, found reserved keyword `await`
--> $DIR/2018-edition-error-in-non-macro-position.rs:20:14
|
LL | macro_rules! await {
| ^^^^^ expected identifier, found reserved keyword
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

11 changes: 5 additions & 6 deletions src/test/ui/await-keyword/2018-edition-error.rs
Original file line number Diff line number Diff line change
@@ -2,14 +2,13 @@
#![allow(non_camel_case_types)]

mod outer_mod {
pub mod await { //~ ERROR `await` is a keyword
pub struct await; //~ ERROR `await` is a keyword
pub mod await { //~ ERROR expected identifier
pub struct await; //~ ERROR expected identifier
}
}
use self::outer_mod::await::await; //~ ERROR `await` is a keyword
//~^ ERROR `await` is a keyword
use self::outer_mod::await::await; //~ ERROR expected identifier
//~^ ERROR expected identifier, found reserved keyword `await`

fn main() {
match await { await => () } //~ ERROR `await` is a keyword
//~^ ERROR `await` is a keyword
match await { await => () } //~ ERROR expected `!`, found `{`
}
46 changes: 29 additions & 17 deletions src/test/ui/await-keyword/2018-edition-error.stderr
Original file line number Diff line number Diff line change
@@ -1,38 +1,50 @@
error[E0721]: `await` is a keyword in the 2018 edition
error: expected identifier, found reserved keyword `await`
--> $DIR/2018-edition-error.rs:5:13
|
LL | pub mod await {
| ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
| ^^^^^ expected identifier, found reserved keyword
help: you can escape reserved keywords to use them as identifiers
|
LL | pub mod r#await {
| ^^^^^^^

error[E0721]: `await` is a keyword in the 2018 edition
error: expected identifier, found reserved keyword `await`
--> $DIR/2018-edition-error.rs:6:20
|
LL | pub struct await;
| ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
| ^^^^^ expected identifier, found reserved keyword
help: you can escape reserved keywords to use them as identifiers
|
LL | pub struct r#await;
| ^^^^^^^

error[E0721]: `await` is a keyword in the 2018 edition
error: expected identifier, found reserved keyword `await`
--> $DIR/2018-edition-error.rs:9:22
|
LL | use self::outer_mod::await::await;
| ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
| ^^^^^ expected identifier, found reserved keyword
help: you can escape reserved keywords to use them as identifiers
|
LL | use self::outer_mod::r#await::await;
| ^^^^^^^

error[E0721]: `await` is a keyword in the 2018 edition
error: expected identifier, found reserved keyword `await`
--> $DIR/2018-edition-error.rs:9:29
|
LL | use self::outer_mod::await::await;
| ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`

error[E0721]: `await` is a keyword in the 2018 edition
--> $DIR/2018-edition-error.rs:13:11
| ^^^^^ expected identifier, found reserved keyword
help: you can escape reserved keywords to use them as identifiers
|
LL | match await { await => () }
| ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
LL | use self::outer_mod::await::r#await;
| ^^^^^^^

error[E0721]: `await` is a keyword in the 2018 edition
--> $DIR/2018-edition-error.rs:13:19
error: expected `!`, found `{`
--> $DIR/2018-edition-error.rs:13:17
|
LL | match await { await => () }
| ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
| ----- ^ expected `!`
| |
| while parsing this match expression

error: aborting due to 6 previous errors
error: aborting due to 5 previous errors

This file was deleted.

2 changes: 1 addition & 1 deletion src/test/ui/await-keyword/post_expansion_error.rs
Original file line number Diff line number Diff line change
@@ -6,5 +6,5 @@ macro_rules! r#await {

fn main() {
await!()
//~^ ERROR `await` is a keyword
//~^ ERROR expected expression, found `)`
}
6 changes: 3 additions & 3 deletions src/test/ui/await-keyword/post_expansion_error.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error[E0721]: `await` is a keyword in the 2018 edition
--> $DIR/post_expansion_error.rs:8:5
error: expected expression, found `)`
--> $DIR/post_expansion_error.rs:8:12
|
LL | await!()
| ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
| ^ expected expression

error: aborting due to previous error

12 changes: 12 additions & 0 deletions src/test/ui/feature-gate/await-macro.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// gate-test-await_macro
// edition:2018

#![feature(async_await)]

async fn bar() {}

async fn foo() {
await!(bar()); //~ ERROR `await!(<expr>)` macro syntax is unstable, and will soon be removed
}

fn main() {}
12 changes: 12 additions & 0 deletions src/test/ui/feature-gate/await-macro.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0658]: `await!(<expr>)` macro syntax is unstable, and will soon be removed in favor of `<expr>.await` syntax.
--> $DIR/await-macro.rs:9:5
|
LL | await!(bar());
| ^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/50547
= help: add #![feature(await_macro)] to the crate attributes to enable

error: aborting due to previous error

For more information about this error, try `rustc --explain E0658`.
11 changes: 6 additions & 5 deletions src/test/ui/generator/unresolved_type_param.rs
Original file line number Diff line number Diff line change
@@ -2,13 +2,14 @@
// Error message should pinpoint the type parameter T as needing to be bound
// (rather than give a general error message)
// edition:2018
#![feature(futures_api, async_await, await_macro)]
#![feature(async_await)]
async fn bar<T>() -> () {}

async fn foo() {
await!(bar());
//~^ ERROR type inside generator must be known in this context
//~| NOTE cannot infer type for `T`
//~| NOTE the type is part of the generator because of this `yield`
bar().await;
//~^ ERROR type inside generator must be known in this context
//~| NOTE cannot infer type for `T`
//~| NOTE the type is part of the generator because of this `yield`
//~| NOTE in this expansion of desugaring of `await`
}
fn main() {}
13 changes: 6 additions & 7 deletions src/test/ui/generator/unresolved_type_param.stderr
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
error[E0698]: type inside generator must be known in this context
--> $DIR/unresolved_type_param.rs:9:16
--> $DIR/unresolved_type_param.rs:9:5
|
LL | await!(bar());
| ^^^ cannot infer type for `T`
LL | bar().await;
| ^^^ cannot infer type for `T`
|
note: the type is part of the generator because of this `yield`
--> $DIR/unresolved_type_param.rs:9:9
--> $DIR/unresolved_type_param.rs:9:5
|
LL | await!(bar());
| ^^^^^^^^^^^^^^
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
LL | bar().await;
| ^^^^^^^^^^^
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👀

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened #60615


error: aborting due to previous error

11 changes: 11 additions & 0 deletions src/test/ui/issues/issue-51719.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// edition:2018
//
// Tests that the .await syntax can't be used to make a generator

#![feature(async_await)]

async fn foo() {}

fn make_generator() {
let _gen = || foo.await; //~ ERROR `await` is only allowed inside `async` functions and blocks
}
8 changes: 8 additions & 0 deletions src/test/ui/issues/issue-51719.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/issue-51719.rs:10:19
|
LL | let _gen = || foo.await;
| ^^^^^^^^^

error: aborting due to previous error

13 changes: 13 additions & 0 deletions src/test/ui/issues/issue-51751.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// edition:2018

#![feature(async_await)]

async fn inc(limit: i64) -> i64 {
limit + 1
}

fn main() {
let result = inc(10000);
let finished = result.await;
//~^ ERROR `await` is only allowed inside `async` functions and blocks
}
8 changes: 8 additions & 0 deletions src/test/ui/issues/issue-51751.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error[E0728]: `await` is only allowed inside `async` functions and blocks
--> $DIR/issue-51751.rs:11:20
|
LL | let finished = result.await;
| ^^^^^^^^^^^^

error: aborting due to previous error