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:
parent
c3b8ab5199
commit
fe8760cb84
@ -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
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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`.
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 => {}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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(),
|
||||
|
@ -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)?;
|
||||
|
@ -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, _) |
|
||||
|
@ -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);
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
},
|
||||
}
|
||||
|
199
src/test/run-pass/await-macro.rs
Normal file
199
src/test/run-pass/await-macro.rs
Normal 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))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
@ -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() {
|
||||
|
@ -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
|
||||
}
|
@ -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
|
||||
|
@ -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 => {} }
|
||||
}
|
@ -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 `{`
|
||||
}
|
@ -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
|
||||
|
@ -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 `{`
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 => () }
|
||||
}
|
@ -6,5 +6,5 @@ macro_rules! r#await {
|
||||
|
||||
fn main() {
|
||||
await!()
|
||||
//~^ ERROR `await` is a keyword
|
||||
//~^ ERROR expected expression, found `)`
|
||||
}
|
||||
|
@ -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
src/test/ui/feature-gate/await-macro.rs
Normal file
12
src/test/ui/feature-gate/await-macro.rs
Normal 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() {}
|
12
src/test/ui/feature-gate/await-macro.stderr
Normal file
12
src/test/ui/feature-gate/await-macro.stderr
Normal 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`.
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
||||
|
11
src/test/ui/issues/issue-51719.rs
Normal file
11
src/test/ui/issues/issue-51719.rs
Normal 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
|
||||
}
|
8
src/test/ui/issues/issue-51719.stderr
Normal file
8
src/test/ui/issues/issue-51719.stderr
Normal 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
|
||||
|
13
src/test/ui/issues/issue-51751.rs
Normal file
13
src/test/ui/issues/issue-51751.rs
Normal 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
|
||||
}
|
8
src/test/ui/issues/issue-51751.stderr
Normal file
8
src/test/ui/issues/issue-51751.stderr
Normal 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
|
||||
|
Loading…
Reference in New Issue
Block a user