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 commit is contained in:
Taylor Cramer 2019-04-18 12:55:23 -07:00
parent c3b8ab5199
commit fe8760cb84
37 changed files with 932 additions and 166 deletions

View File

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

View File

@ -95,6 +95,7 @@ pub struct LoweringContext<'a> {
modules: BTreeMap<NodeId, hir::ModuleItems>,
is_generator: bool,
is_async_body: bool,
catch_scopes: Vec<NodeId>,
loop_scopes: Vec<NodeId>,
@ -248,6 +249,7 @@ pub fn lower_crate(
item_local_id_counters: Default::default(),
node_id_to_hir_id: IndexVec::new(),
is_generator: false,
is_async_body: false,
is_in_trait_impl: false,
lifetimes_to_define: Vec::new(),
is_collecting_in_band_lifetimes: false,
@ -801,8 +803,17 @@ impl<'a> LoweringContext<'a> {
}
fn record_body(&mut self, value: hir::Expr, arguments: HirVec<hir::Arg>) -> hir::BodyId {
if self.is_generator && self.is_async_body {
span_err!(
self.sess,
value.span,
E0727,
"`async` generators are not yet supported",
);
self.sess.abort_if_errors();
}
let body = hir::Body {
is_generator: self.is_generator,
is_generator: self.is_generator || self.is_async_body,
arguments,
value,
};
@ -1124,7 +1135,8 @@ impl<'a> LoweringContext<'a> {
span: Span,
body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr,
) -> hir::ExprKind {
let prev_is_generator = mem::replace(&mut self.is_generator, true);
let prev_is_generator = mem::replace(&mut self.is_generator, false);
let prev_is_async_body = mem::replace(&mut self.is_async_body, true);
let output = match ret_ty {
Some(ty) => FunctionRetTy::Ty(P(ty.clone())),
None => FunctionRetTy::Default(span),
@ -1140,6 +1152,7 @@ impl<'a> LoweringContext<'a> {
let body_expr = body(self);
let body_id = self.record_body(body_expr, arguments);
self.is_generator = prev_is_generator;
self.is_async_body = prev_is_async_body;
let capture_clause = self.lower_capture_clause(capture_clause);
let decl = self.lower_fn_decl(&decl, None, /* impl trait allowed */ false, None);
@ -1167,11 +1180,13 @@ impl<'a> LoweringContext<'a> {
where
F: FnOnce(&mut LoweringContext<'_>) -> hir::Expr,
{
let prev = mem::replace(&mut self.is_generator, false);
let prev_generator = mem::replace(&mut self.is_generator, false);
let prev_async = mem::replace(&mut self.is_async_body, false);
let arguments = self.lower_args(decl);
let result = f(self);
let r = self.record_body(result, arguments);
self.is_generator = prev;
self.is_generator = prev_generator;
self.is_async_body = prev_async;
return r;
}
@ -4205,6 +4220,7 @@ impl<'a> LoweringContext<'a> {
})
})
}
ExprKind::Await(_origin, ref expr) => self.lower_await(e.span, expr),
ExprKind::Closure(
capture_clause, ref asyncness, movability, ref decl, ref body, fn_decl_span
) => {
@ -4326,12 +4342,13 @@ impl<'a> LoweringContext<'a> {
let id = self.next_id();
let e1 = self.lower_expr(e1);
let e2 = self.lower_expr(e2);
let ty_path = P(self.std_path(e.span, &["ops", "RangeInclusive"], None, false));
let ty = P(self.ty_path(id, e.span, hir::QPath::Resolved(None, ty_path)));
let new_seg = P(hir::PathSegment::from_ident(Ident::from_str("new")));
let new_path = hir::QPath::TypeRelative(ty, new_seg);
let new = P(self.expr(e.span, hir::ExprKind::Path(new_path), ThinVec::new()));
hir::ExprKind::Call(new, hir_vec![e1, e2])
self.expr_call_std_assoc_fn(
id,
e.span,
&["ops", "RangeInclusive"],
"new",
hir_vec![e1, e2],
)
}
ExprKind::Range(ref e1, ref e2, lims) => {
use syntax::ast::RangeLimits::*;
@ -4468,9 +4485,7 @@ impl<'a> LoweringContext<'a> {
let expr = opt_expr
.as_ref()
.map(|x| self.lower_expr(x))
.unwrap_or_else(||
self.expr(e.span, hir::ExprKind::Tup(hir_vec![]), ThinVec::new())
);
.unwrap_or_else(|| self.expr_unit(e.span));
hir::ExprKind::Yield(P(expr))
}
@ -4503,7 +4518,7 @@ impl<'a> LoweringContext<'a> {
let body = if let Some(else_expr) = wildcard_arm {
P(self.lower_expr(else_expr))
} else {
self.expr_tuple(e.span, hir_vec![])
P(self.expr_tuple(e.span, hir_vec![]))
};
arms.push(self.arm(hir_vec![wildcard_pattern], body));
}
@ -4651,8 +4666,11 @@ impl<'a> LoweringContext<'a> {
let iter = P(self.expr_ident(head_sp, iter, iter_pat_nid));
let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter);
let next_path = &["iter", "Iterator", "next"];
let next_path = P(self.expr_std_path(head_sp, next_path, None, ThinVec::new()));
let next_expr = P(self.expr_call(head_sp, next_path, hir_vec![ref_mut_iter]));
let next_expr = P(self.expr_call_std_path(
head_sp,
next_path,
hir_vec![ref_mut_iter],
));
let arms = hir_vec![pat_arm, break_arm];
P(self.expr(
@ -4723,9 +4741,11 @@ impl<'a> LoweringContext<'a> {
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
let into_iter_expr = {
let into_iter_path = &["iter", "IntoIterator", "into_iter"];
let into_iter = P(self.expr_std_path(
head_sp, into_iter_path, None, ThinVec::new()));
P(self.expr_call(head_sp, into_iter, hir_vec![head]))
P(self.expr_call_std_path(
head_sp,
into_iter_path,
hir_vec![head],
))
};
let match_expr = P(self.expr_match(
@ -4778,9 +4798,11 @@ impl<'a> LoweringContext<'a> {
let sub_expr = self.lower_expr(sub_expr);
let path = &["ops", "Try", "into_result"];
let path = P(self.expr_std_path(
unstable_span, path, None, ThinVec::new()));
P(self.expr_call(e.span, path, hir_vec![sub_expr]))
P(self.expr_call_std_path(
unstable_span,
path,
hir_vec![sub_expr],
))
};
// `#[allow(unreachable_code)]`
@ -4817,12 +4839,9 @@ impl<'a> LoweringContext<'a> {
let err_ident = self.str_to_ident("err");
let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
let from_expr = {
let path = &["convert", "From", "from"];
let from = P(self.expr_std_path(
try_span, path, None, ThinVec::new()));
let from_path = &["convert", "From", "from"];
let err_expr = self.expr_ident(try_span, err_ident, err_local_nid);
self.expr_call(try_span, from, hir_vec![err_expr])
self.expr_call_std_path(try_span, from_path, hir_vec![err_expr])
};
let from_err_expr =
self.wrap_in_try_constructor("from_error", from_expr, unstable_span);
@ -5056,6 +5075,42 @@ impl<'a> LoweringContext<'a> {
self.expr(span, hir::ExprKind::Call(e, args), ThinVec::new())
}
// Note: associated functions must use `expr_call_std_path`.
fn expr_call_std_path(
&mut self,
span: Span,
path_components: &[&str],
args: hir::HirVec<hir::Expr>,
) -> hir::Expr {
let path = P(self.expr_std_path(span, path_components, None, ThinVec::new()));
self.expr_call(span, path, args)
}
// Create an expression calling an associated function of an std type.
//
// Associated functions cannot be resolved through the normal `std_path` function,
// as they are resolved differently and so cannot use `expr_call_std_path`.
//
// This function accepts the path component (`ty_path_components`) separately from
// the name of the associated function (`assoc_fn_name`) in order to facilitate
// separate resolution of the type and creation of a path referring to its associated
// function.
fn expr_call_std_assoc_fn(
&mut self,
ty_path_id: hir::HirId,
span: Span,
ty_path_components: &[&str],
assoc_fn_name: &str,
args: hir::HirVec<hir::Expr>,
) -> hir::ExprKind {
let ty_path = P(self.std_path(span, ty_path_components, None, false));
let ty = P(self.ty_path(ty_path_id, span, hir::QPath::Resolved(None, ty_path)));
let fn_seg = P(hir::PathSegment::from_ident(Ident::from_str(assoc_fn_name)));
let fn_path = hir::QPath::TypeRelative(ty, fn_seg);
let fn_expr = P(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new()));
hir::ExprKind::Call(fn_expr, args)
}
fn expr_ident(&mut self, span: Span, ident: Ident, binding: hir::HirId) -> hir::Expr {
self.expr_ident_with_attrs(span, ident, binding, ThinVec::new())
}
@ -5127,8 +5182,12 @@ impl<'a> LoweringContext<'a> {
self.expr(b.span, hir::ExprKind::Block(b, None), attrs)
}
fn expr_tuple(&mut self, sp: Span, exprs: hir::HirVec<hir::Expr>) -> P<hir::Expr> {
P(self.expr(sp, hir::ExprKind::Tup(exprs), ThinVec::new()))
fn expr_unit(&mut self, sp: Span) -> hir::Expr {
self.expr_tuple(sp, hir_vec![])
}
fn expr_tuple(&mut self, sp: Span, exprs: hir::HirVec<hir::Expr>) -> hir::Expr {
self.expr(sp, hir::ExprKind::Tup(exprs), ThinVec::new())
}
fn expr(&mut self, span: Span, node: hir::ExprKind, attrs: ThinVec<Attribute>) -> hir::Expr {
@ -5184,6 +5243,23 @@ impl<'a> LoweringContext<'a> {
}
}
fn expr_unsafe(&mut self, expr: P<hir::Expr>) -> hir::Expr {
let hir_id = self.next_id();
let span = expr.span;
self.expr(
span,
hir::ExprKind::Block(P(hir::Block {
stmts: hir_vec![],
expr: Some(expr),
hir_id,
rules: hir::UnsafeBlock(hir::CompilerGenerated),
span,
targeted_by_break: false,
}), None),
ThinVec::new(),
)
}
fn pat_ok(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
self.pat_std_enum(span, &["result", "Result", "Ok"], hir_vec![pat])
}
@ -5258,13 +5334,12 @@ impl<'a> LoweringContext<'a> {
span: Span,
components: &[&str],
params: Option<P<hir::GenericArgs>>,
is_value: bool
is_value: bool,
) -> hir::Path {
let mut path = self.resolver
.resolve_str_path(span, self.crate_root, components, is_value);
path.segments.last_mut().unwrap().args = params;
for seg in path.segments.iter_mut() {
if seg.hir_id.is_some() {
seg.hir_id = Some(self.next_id());
@ -5465,6 +5540,175 @@ impl<'a> LoweringContext<'a> {
ThinVec::new()));
P(self.expr_call(e.span, from_err, hir_vec![e]))
}
fn lower_await(
&mut self,
await_span: Span,
expr: &ast::Expr,
) -> hir::ExprKind {
// to:
//
// {
// let mut pinned = <expr>;
// loop {
// match ::std::future::poll_with_tls_context(unsafe {
// ::std::pin::Pin::new_unchecked(&mut pinned)
// }) {
// ::std::task::Poll::Ready(x) => break x,
// ::std::task::Poll::Pending => {},
// }
// yield ();
// }
// }
if !self.is_async_body {
span_err!(
self.sess,
await_span,
E0728,
"`await` is only allowed inside `async` functions and blocks"
);
self.sess.abort_if_errors();
}
let span = self.mark_span_with_reason(
CompilerDesugaringKind::Await,
await_span,
None,
);
let gen_future_span = self.mark_span_with_reason(
CompilerDesugaringKind::Await,
await_span,
Some(vec![Symbol::intern("gen_future")].into()),
);
// let mut pinned = <expr>;
let expr = P(self.lower_expr(expr));
let pinned_ident = self.str_to_ident("pinned");
let (pinned_pat, pinned_pat_hid) = self.pat_ident_binding_mode(
span,
pinned_ident,
hir::BindingAnnotation::Mutable,
);
let pinned_let = self.stmt_let_pat(
span,
Some(expr),
pinned_pat,
hir::LocalSource::AwaitDesugar,
);
// ::std::future::poll_with_tls_context(unsafe {
// ::std::pin::Pin::new_unchecked(&mut pinned)
// })`
let poll_expr = {
let pinned = P(self.expr_ident(span, pinned_ident, pinned_pat_hid));
let ref_mut_pinned = self.expr_mut_addr_of(span, pinned);
let pin_ty_id = self.next_id();
let new_unchecked_expr_kind = self.expr_call_std_assoc_fn(
pin_ty_id,
span,
&["pin", "Pin"],
"new_unchecked",
hir_vec![ref_mut_pinned],
);
let new_unchecked = P(self.expr(span, new_unchecked_expr_kind, ThinVec::new()));
let unsafe_expr = self.expr_unsafe(new_unchecked);
P(self.expr_call_std_path(
gen_future_span,
&["future", "poll_with_tls_context"],
hir_vec![unsafe_expr],
))
};
// `::std::task::Poll::Ready(x) => break x`
let loop_node_id = self.sess.next_node_id();
let loop_hir_id = self.lower_node_id(loop_node_id);
let ready_arm = {
let x_ident = self.str_to_ident("x");
let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident);
let x_expr = P(self.expr_ident(span, x_ident, x_pat_hid));
let ready_pat = self.pat_std_enum(
span,
&["task", "Poll", "Ready"],
hir_vec![x_pat],
);
let break_x = self.with_loop_scope(loop_node_id, |this| {
let expr_break = hir::ExprKind::Break(
this.lower_loop_destination(None),
Some(x_expr),
);
P(this.expr(await_span, expr_break, ThinVec::new()))
});
self.arm(hir_vec![ready_pat], break_x)
};
// `::std::task::Poll::Pending => {}`
let pending_arm = {
let pending_pat = self.pat_std_enum(
span,
&["task", "Poll", "Pending"],
hir_vec![],
);
let empty_block = P(hir::Block {
stmts: hir_vec![],
expr: None,
hir_id: self.next_id(),
rules: hir::DefaultBlock,
span,
targeted_by_break: false,
});
let empty_block = P(self.expr_block(empty_block, ThinVec::new()));
self.arm(hir_vec![pending_pat], empty_block)
};
let match_stmt = {
let match_expr = P(self.expr_match(
span,
poll_expr,
hir_vec![ready_arm, pending_arm],
hir::MatchSource::AwaitDesugar,
));
hir::Stmt {
hir_id: self.next_id(),
node: hir::StmtKind::Expr(match_expr),
span,
}
};
let yield_stmt = {
let unit = self.expr_unit(span);
let yield_expr = P(self.expr(
span,
hir::ExprKind::Yield(P(unit)),
ThinVec::new(),
));
hir::Stmt {
hir_id: self.next_id(),
node: hir::StmtKind::Expr(yield_expr),
span,
}
};
let loop_block = P(self.block_all(
span,
hir_vec![match_stmt, yield_stmt],
None,
));
let loop_expr = P(hir::Expr {
hir_id: loop_hir_id,
node: hir::ExprKind::Loop(
loop_block,
None,
hir::LoopSource::Loop,
),
span,
attrs: ThinVec::new(),
});
hir::ExprKind::Block(
P(self.block_all(span, hir_vec![pinned_let], Some(loop_expr))),
None,
)
}
}
fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body>) -> Vec<hir::BodyId> {

View File

@ -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`.

View File

@ -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,

View File

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

View File

@ -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 => {}
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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(),

View File

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

View File

@ -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, _) |

View File

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

View File

@ -598,6 +598,7 @@ pub enum CompilerDesugaringKind {
/// `impl Trait` with `Foo`.
ExistentialReturnType,
Async,
Await,
ForLoop,
}
@ -605,6 +606,7 @@ 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",

View File

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

View File

@ -1,7 +1,7 @@
// edition:2018
// aux-build:arc_wake.rs
#![feature(async_await, await_macro)]
#![feature(async_await)]
extern crate arc_wake;
@ -46,14 +46,14 @@ 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
}
}
@ -61,43 +61,43 @@ fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future<Output =
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
}
},
}

View File

@ -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))
}
},
}
}

View File

@ -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() {

View File

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

View File

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

View File

@ -1,16 +0,0 @@
// compile-pass
#![feature(async_await)]
#![allow(non_camel_case_types)]
#![deny(keyword_idents)]
mod outer_mod {
pub mod await {
pub struct await;
}
}
use outer_mod::await::await;
fn main() {
match await { await => {} }
}

View File

@ -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 `{`
}

View File

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

View File

@ -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 `{`
}

View File

@ -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`
| ^^^^^ 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[E0721]: `await` is a keyword in the 2018 edition
--> $DIR/2018-edition-error.rs:13:11
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[E0721]: `await` is a keyword in the 2018 edition
--> $DIR/2018-edition-error.rs:13:19
|
LL | match await { await => () }
| ^^^^^ help: you can use a raw identifier to stay compatible: `r#await`
error: aborting due to 6 previous errors
error: aborting due to 5 previous errors

View File

@ -1,16 +0,0 @@
// compile-pass
// edition:2018
#![allow(non_camel_case_types)]
#![feature(async_await)]
mod outer_mod {
pub mod await {
pub struct await;
}
}
use self::outer_mod::await::await;
fn main() {
match await { await => () }
}

View File

@ -6,5 +6,5 @@ macro_rules! r#await {
fn main() {
await!()
//~^ ERROR `await` is a keyword
//~^ ERROR expected expression, found `)`
}

View File

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

View File

@ -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() {}

View File

@ -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`.

View File

@ -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() {}

View File

@ -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;
| ^^^^^^^^^^^
error: aborting due to previous error

View File

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

View File

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

View File

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

View File

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