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.
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
}
modules: BTreeMap<NodeId, hir::ModuleItems>,
is_generator: bool,
+ is_async_body: bool,
catch_scopes: Vec<NodeId>,
loop_scopes: Vec<NodeId>,
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,
}
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,
};
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),
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);
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;
}
})
})
}
+ 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
) => {
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::*;
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))
}
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));
}
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(
// `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(
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)]`
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);
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())
}
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 {
}
}
+ 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])
}
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());
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> {
/// }
/// ```
AsyncFn,
+ /// A desugared `<expr>.await`.
+ AwaitDesugar,
}
/// Hints at the original code for a `match _ { .. }`.
ForLoopDesugar,
/// A desugared `?` operator.
TryDesugar,
+ /// A desugared `<expr>.await`.
+ AwaitDesugar,
}
/// The loop type that yielded an `ExprKind::Loop`.
impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
Async,
+ Await,
QuestionMark,
ExistentialReturnType,
ForLoop,
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};
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
// 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;
}
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.
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 => {}
}
}
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,
/// 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>),
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
// 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),
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);
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);
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)?;
// 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));
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(),
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)?;
TryBlock,
Struct,
Async,
+ Await,
Err,
}
ExprPrecedence::Unary => PREC_PREFIX,
// Unary, postfix
+ ExprPrecedence::Await |
ExprPrecedence::Call |
ExprPrecedence::MethodCall |
ExprPrecedence::Field |
// 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, _) |
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);
/// `impl Trait` with `Foo`.
ExistentialReturnType,
Async,
+ Await,
ForLoop,
}
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",
// 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
// edition:2018
// aux-build:arc_wake.rs
-#![feature(async_await, await_macro)]
+#![feature(async_await)]
extern crate arc_wake;
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
}
}
*/
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
}
impl Foo {
async fn async_method(x: u8) -> u8 {
unsafe {
- await!(unsafe_async_fn(x))
+ unsafe_async_fn(x).await
}
}
}
($($fn_name:expr,)*) => { $(
test_future_yields_once_then_returns(|x| {
async move {
- await!($fn_name(&x))
+ $fn_name(&x).await
}
});
)* }
Foo::async_method,
|x| {
async move {
- unsafe { await!(unsafe_async_fn(x)) }
+ unsafe { unsafe_async_fn(x).await }
}
},
}
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
}
},
}
--- /dev/null
+// 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))
+ }
+ },
+ }
+}
// edition:2018
// run-pass
-#![feature(async_await, await_macro)]
+#![feature(async_await)]
trait 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() {
--- /dev/null
+#![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
+}
--- /dev/null
+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
+
+++ /dev/null
-// 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 => {} }
-}
--- /dev/null
+// 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 `{`
+}
--- /dev/null
+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
+
#![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 `{`
}
-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
+++ /dev/null
-// 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 => () }
-}
fn main() {
await!()
- //~^ ERROR `await` is a keyword
+ //~^ ERROR expected expression, found `)`
}
-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
--- /dev/null
+// 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() {}
--- /dev/null
+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`.
// 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() {}
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
--- /dev/null
+// 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
+}
--- /dev/null
+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
+
--- /dev/null
+// 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
+}
--- /dev/null
+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
+