Skip to content

Commit cf844b5

Browse files
committed
async await desugaring and tests
1 parent 589446e commit cf844b5

38 files changed

+1282
-199
lines changed

src/librustc/diagnostics.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2131,5 +2131,10 @@ register_diagnostics! {
21312131
E0657, // `impl Trait` can only capture lifetimes bound at the fn level
21322132
E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax
21332133
E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders
2134-
E0697, // closures cannot be static
2134+
2135+
E0906, // closures cannot be static
2136+
2137+
E0703, // multiple different lifetimes used in arguments of `async fn`
2138+
E0704, // multiple elided lifetimes used in arguments of `async fn`
2139+
E0705, // `async` non-`move` closures with arguments are not currently supported
21352140
}

src/librustc/hir/lowering.rs

Lines changed: 520 additions & 151 deletions
Large diffs are not rendered by default.

src/librustc/hir/map/def_collector.rs

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,21 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
9999
ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
100100
return visit::walk_item(self, i);
101101
}
102+
ItemKind::Fn(_, FnHeader { asyncness: IsAsync::Async(async_node_id), .. }, ..) => {
103+
// For async functions, we need to create their inner defs inside of a
104+
// closure to match their desugared representation.
105+
let fn_def_data = DefPathData::ValueNs(i.ident.name.as_interned_str());
106+
let fn_def = self.create_def(i.id, fn_def_data, ITEM_LIKE_SPACE, i.span);
107+
return self.with_parent(fn_def, |this| {
108+
let closure_def = this.create_def(async_node_id,
109+
DefPathData::ClosureExpr,
110+
REGULAR_SPACE,
111+
i.span);
112+
this.with_parent(closure_def, |this| {
113+
visit::walk_item(this, i);
114+
})
115+
});
116+
}
102117
ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_interned_str()),
103118
ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) =>
104119
DefPathData::ValueNs(i.ident.name.as_interned_str()),
@@ -227,15 +242,32 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
227242

228243
match expr.node {
229244
ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id),
230-
ExprKind::Closure(..) => {
231-
let def = self.create_def(expr.id,
245+
ExprKind::Closure(_, asyncness, ..) => {
246+
let closure_def = self.create_def(expr.id,
232247
DefPathData::ClosureExpr,
233248
REGULAR_SPACE,
234249
expr.span);
235-
self.parent_def = Some(def);
250+
self.parent_def = Some(closure_def);
251+
252+
// Async closures desugar to closures inside of closures, so
253+
// we must create two defs.
254+
if let IsAsync::Async(async_id) = asyncness {
255+
let async_def = self.create_def(async_id,
256+
DefPathData::ClosureExpr,
257+
REGULAR_SPACE,
258+
expr.span);
259+
self.parent_def = Some(async_def);
260+
}
261+
}
262+
ExprKind::Async(_, async_id, _) => {
263+
let async_def = self.create_def(async_id,
264+
DefPathData::ClosureExpr,
265+
REGULAR_SPACE,
266+
expr.span);
267+
self.parent_def = Some(async_def);
236268
}
237269
_ => {}
238-
}
270+
};
239271

240272
visit::walk_expr(self, expr);
241273
self.parent_def = parent_def;

src/librustc/hir/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,16 @@ pub enum LifetimeName {
245245
}
246246

247247
impl LifetimeName {
248+
pub fn is_elided(self) -> bool {
249+
match self {
250+
LifetimeName::Implicit
251+
| LifetimeName::Underscore => true,
252+
LifetimeName::Fresh(_)
253+
| LifetimeName::Static
254+
| LifetimeName::Name(_) => false,
255+
}
256+
}
257+
248258
pub fn name(&self) -> Name {
249259
use self::LifetimeName::*;
250260
match *self {

src/librustc/ich/impls_syntax.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat {
409409
});
410410

411411
impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
412+
Async,
412413
DotFill,
413414
QuestionMark,
414415
ExistentialReturnType,

src/librustc_metadata/encoder.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1245,7 +1245,10 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
12451245
(has_types || tcx.codegen_fn_attrs(def_id).requests_inline()) &&
12461246
!self.metadata_output_only();
12471247
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
1248-
if needs_inline || header.constness == hir::Constness::Const || always_encode_mir {
1248+
if needs_inline
1249+
|| header.constness == hir::Constness::Const
1250+
|| always_encode_mir
1251+
{
12491252
self.encode_optimized_mir(def_id)
12501253
} else {
12511254
None

src/librustc_resolve/lib.rs

Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ use syntax::util::lev_distance::find_best_match_for_name;
5555

5656
use syntax::visit::{self, FnKind, Visitor};
5757
use syntax::attr;
58-
use syntax::ast::{Arm, BindingMode, Block, Crate, Expr, ExprKind};
58+
use syntax::ast::{Arm, IsAsync, BindingMode, Block, Crate, Expr, ExprKind, FnHeader};
5959
use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParamKind, Generics};
6060
use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
6161
use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
@@ -2054,13 +2054,54 @@ impl<'a> Resolver<'a> {
20542054
self.check_proc_macro_attrs(&item.attrs);
20552055

20562056
match item.node {
2057+
ItemKind::Fn(ref declaration,
2058+
FnHeader { asyncness: IsAsync::Async(async_closure_id), .. },
2059+
ref generics,
2060+
ref body) => {
2061+
// Async functions are desugared from `async fn foo() { .. }`
2062+
// to `fn foo() { future_from_generator(move || ... ) }`,
2063+
// so we have to visit the body inside the closure scope
2064+
self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| {
2065+
this.visit_vis(&item.vis);
2066+
this.visit_ident(item.ident);
2067+
this.visit_generics(generics);
2068+
let rib_kind = ItemRibKind;
2069+
this.ribs[ValueNS].push(Rib::new(rib_kind));
2070+
this.label_ribs.push(Rib::new(rib_kind));
2071+
let mut bindings_list = FxHashMap();
2072+
for argument in &declaration.inputs {
2073+
this.resolve_pattern(
2074+
&argument.pat, PatternSource::FnParam, &mut bindings_list);
2075+
this.visit_ty(&*argument.ty);
2076+
}
2077+
visit::walk_fn_ret_ty(this, &declaration.output);
2078+
2079+
// Now resolve the inner closure
2080+
{
2081+
let rib_kind = ClosureRibKind(async_closure_id);
2082+
this.ribs[ValueNS].push(Rib::new(rib_kind));
2083+
this.label_ribs.push(Rib::new(rib_kind));
2084+
// No need to resolve either arguments nor return type,
2085+
// as this closure has neither
2086+
2087+
// Resolve the body
2088+
this.visit_block(body);
2089+
this.label_ribs.pop();
2090+
this.ribs[ValueNS].pop();
2091+
}
2092+
this.label_ribs.pop();
2093+
this.ribs[ValueNS].pop();
2094+
2095+
walk_list!(this, visit_attribute, &item.attrs);
2096+
})
2097+
}
20572098
ItemKind::Enum(_, ref generics) |
20582099
ItemKind::Ty(_, ref generics) |
20592100
ItemKind::Struct(_, ref generics) |
20602101
ItemKind::Union(_, ref generics) |
2061-
ItemKind::Fn(.., ref generics, _) => {
2102+
ItemKind::Fn(_, _, ref generics, _) => {
20622103
self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind),
2063-
|this| visit::walk_item(this, item));
2104+
|this| visit::walk_item(this, item));
20642105
}
20652106

20662107
ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) =>
@@ -3888,6 +3929,49 @@ impl<'a> Resolver<'a> {
38883929
visit::walk_expr(self, expr);
38893930
self.current_type_ascription.pop();
38903931
}
3932+
// Resolve the body of async exprs inside the async closure to which they desugar
3933+
ExprKind::Async(_, async_closure_id, ref block) => {
3934+
let rib_kind = ClosureRibKind(async_closure_id);
3935+
self.ribs[ValueNS].push(Rib::new(rib_kind));
3936+
self.label_ribs.push(Rib::new(rib_kind));
3937+
self.visit_block(&block);
3938+
self.label_ribs.pop();
3939+
self.ribs[ValueNS].pop();
3940+
}
3941+
// `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to
3942+
// resolve the arguments within the proper scopes so that usages of them inside the
3943+
// closure are detected as upvars rather than normal closure arg usages.
3944+
ExprKind::Closure(
3945+
_, IsAsync::Async(inner_closure_id), _, ref fn_decl, ref body, _span) =>
3946+
{
3947+
let rib_kind = ClosureRibKind(expr.id);
3948+
self.ribs[ValueNS].push(Rib::new(rib_kind));
3949+
self.label_ribs.push(Rib::new(rib_kind));
3950+
// Resolve arguments:
3951+
let mut bindings_list = FxHashMap();
3952+
for argument in &fn_decl.inputs {
3953+
self.resolve_pattern(&argument.pat, PatternSource::FnParam, &mut bindings_list);
3954+
self.visit_ty(&argument.ty);
3955+
}
3956+
// No need to resolve return type-- the outer closure return type is
3957+
// FunctionRetTy::Default
3958+
3959+
// Now resolve the inner closure
3960+
{
3961+
let rib_kind = ClosureRibKind(inner_closure_id);
3962+
self.ribs[ValueNS].push(Rib::new(rib_kind));
3963+
self.label_ribs.push(Rib::new(rib_kind));
3964+
// No need to resolve arguments: the inner closure has none.
3965+
// Resolve the return type:
3966+
visit::walk_fn_ret_ty(self, &fn_decl.output);
3967+
// Resolve the body
3968+
self.visit_expr(body);
3969+
self.label_ribs.pop();
3970+
self.ribs[ValueNS].pop();
3971+
}
3972+
self.label_ribs.pop();
3973+
self.ribs[ValueNS].pop();
3974+
}
38913975
_ => {
38923976
visit::walk_expr(self, expr);
38933977
}

src/librustc_save_analysis/dump_visitor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1555,7 +1555,7 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> Visitor<'l> for DumpVisitor<'l, 'tc
15551555
}
15561556
}
15571557
}
1558-
ast::ExprKind::Closure(_, _, ref decl, ref body, _fn_decl_span) => {
1558+
ast::ExprKind::Closure(_, _, _, ref decl, ref body, _fn_decl_span) => {
15591559
let mut id = String::from("$");
15601560
id.push_str(&ex.id.to_string());
15611561

src/librustc_save_analysis/sig.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ impl Sig for ast::Item {
385385
if header.constness.node == ast::Constness::Const {
386386
text.push_str("const ");
387387
}
388-
if header.asyncness == ast::IsAsync::Async {
388+
if header.asyncness.is_async() {
389389
text.push_str("async ");
390390
}
391391
if header.unsafety == ast::Unsafety::Unsafe {
@@ -920,7 +920,7 @@ fn make_method_signature(
920920
if m.header.constness.node == ast::Constness::Const {
921921
text.push_str("const ");
922922
}
923-
if m.header.asyncness == ast::IsAsync::Async {
923+
if m.header.asyncness.is_async() {
924924
text.push_str("async ");
925925
}
926926
if m.header.unsafety == ast::Unsafety::Unsafe {

src/librustc_typeck/check/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1164,7 +1164,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
11641164
}
11651165

11661166
if let Node::NodeItem(item) = fcx.tcx.hir.get(fn_id) {
1167-
if let Item_::ItemFn(_, _, _, _, ref generics, _) = item.node {
1167+
if let Item_::ItemFn(_, _, ref generics, _) = item.node {
11681168
if !generics.params.is_empty() {
11691169
fcx.tcx.sess.span_err(
11701170
span,

src/librustdoc/html/render.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2585,7 +2585,8 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
25852585
write!(w, "{}<pre class='rust fn'>", render_spotlight_traits(it)?)?;
25862586
render_attributes(w, it)?;
25872587
write!(w,
2588-
"{vis}{constness}{asyncness}{unsafety}{abi}fn {name}{generics}{decl}{where_clause}</pre>",
2588+
"{vis}{constness}{asyncness}{unsafety}{abi}fn \
2589+
{name}{generics}{decl}{where_clause}</pre>",
25892590
vis = VisSpace(&it.visibility),
25902591
constness = ConstnessSpace(f.header.constness),
25912592
asyncness = AsyncSpace(f.header.asyncness),

src/libstd/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@
263263
#![feature(fn_traits)]
264264
#![feature(fnbox)]
265265
#![feature(futures_api)]
266+
#![feature(generator_trait)]
266267
#![feature(hashmap_internals)]
267268
#![feature(int_error_internals)]
268269
#![feature(integer_atomics)]
@@ -410,8 +411,6 @@ pub use core::ops;
410411
#[stable(feature = "rust1", since = "1.0.0")]
411412
pub use core::ptr;
412413
#[stable(feature = "rust1", since = "1.0.0")]
413-
pub use core::raw;
414-
#[stable(feature = "rust1", since = "1.0.0")]
415414
pub use core::result;
416415
#[stable(feature = "rust1", since = "1.0.0")]
417416
pub use core::option;
@@ -496,6 +495,7 @@ pub mod os;
496495
pub mod panic;
497496
pub mod path;
498497
pub mod process;
498+
pub mod raw;
499499
pub mod sync;
500500
pub mod time;
501501

src/libstd/macros.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,26 @@ macro_rules! eprintln {
213213
($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*));
214214
}
215215

216+
#[macro_export]
217+
#[unstable(feature = "await_macro", issue = "50547")]
218+
#[allow_internal_unstable]
219+
macro_rules! await {
220+
($e:expr) => { {
221+
let mut pinned = $e;
222+
let mut pinned = unsafe { ::core::mem::PinMut::new_unchecked(&mut pinned) };
223+
loop {
224+
match ::std::raw::with_get_cx(|cx|
225+
::core::future::Future::poll(pinned.reborrow(), cx))
226+
{
227+
// FIXME(cramertj) prior to stabilizing await, we have to ensure that this
228+
// can't be used to create a generator on stable via `|| await!()`.
229+
::core::task::Poll::Pending => yield,
230+
::core::task::Poll::Ready(x) => break x,
231+
}
232+
}
233+
} }
234+
}
235+
216236
/// A macro to select an event from a number of receivers.
217237
///
218238
/// This macro is used to wait for the first event to occur on a number of

0 commit comments

Comments
 (0)