Skip to content

Commit 6cf70ca

Browse files
author
Without Boats
committed
Lower async items to generators.
1 parent b793cf8 commit 6cf70ca

File tree

7 files changed

+83
-9
lines changed

7 files changed

+83
-9
lines changed

src/librustc/hir/lowering.rs

+68-7
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,50 @@ impl<'a> LoweringContext<'a> {
825825
result
826826
}
827827

828+
// Takes the body of an async function/closure, or an async block, and
829+
// lowers it to a generator wrapped in a ::std::raw::GenFuture adapter.
830+
//
831+
// This makes it evaluate to a Future.
832+
//
833+
// For example, this:
834+
// async { ... }
835+
// Becomes:
836+
//
837+
// ::std::raw::GenFuture(|| { ... })
838+
//
839+
// TODO: Visit body and make sure it contains no bare `yield` statements.
840+
fn make_async_expr(&mut self, body: hir::Expr) -> hir::Expr {
841+
let span = body.span;
842+
843+
// Construct a generator around body
844+
let generator = {
845+
let decl = P(hir::FnDecl {
846+
inputs: hir_vec![],
847+
output: hir::DefaultReturn(span),
848+
variadic: false,
849+
has_implicit_self: false,
850+
});
851+
let body_id = {
852+
let prev = mem::replace(&mut self.is_generator, true);
853+
let r = self.record_body(body, None);
854+
self.is_generator = prev;
855+
r
856+
};
857+
let LoweredNodeId { node_id, hir_id } = self.next_id();
858+
hir::Expr {
859+
id: node_id,
860+
node: hir::ExprClosure(hir::CaptureByValue, decl, body_id, span,
861+
Some(hir::GeneratorMovability::Static)),
862+
attrs: ThinVec::new(),
863+
span, hir_id,
864+
}
865+
};
866+
867+
let gen_future = self.expr_std_path(span, &["raw", "GenFuture"], ThinVec::new());
868+
self.expr_call(span, P(gen_future), hir_vec![generator])
869+
}
870+
871+
828872
fn lower_body<F>(&mut self, decl: Option<&FnDecl>, f: F) -> hir::BodyId
829873
where
830874
F: FnOnce(&mut LoweringContext) -> hir::Expr,
@@ -2313,7 +2357,10 @@ impl<'a> LoweringContext<'a> {
23132357
self.with_new_scopes(|this| {
23142358
let body_id = this.lower_body(Some(decl), |this| {
23152359
let body = this.lower_block(body, false);
2316-
this.expr_block(body, ThinVec::new())
2360+
let expr = this.expr_block(body, ThinVec::new());
2361+
if header.asyncness == IsAsync::Async {
2362+
this.make_async_expr(expr)
2363+
} else { expr }
23172364
});
23182365
let fn_ret_transform: &FnRetTransform = match header.asyncness {
23192366
IsAsync::Async => &AsyncFunctionRet,
@@ -2608,7 +2655,10 @@ impl<'a> LoweringContext<'a> {
26082655
TraitItemKind::Method(ref sig, Some(ref body)) => {
26092656
let body_id = this.lower_body(Some(&sig.decl), |this| {
26102657
let body = this.lower_block(body, false);
2611-
this.expr_block(body, ThinVec::new())
2658+
let expr = this.expr_block(body, ThinVec::new());
2659+
if sig.header.asyncness == IsAsync::Async {
2660+
this.make_async_expr(expr)
2661+
} else { expr }
26122662
});
26132663

26142664
this.add_in_band_defs(
@@ -2691,7 +2741,10 @@ impl<'a> LoweringContext<'a> {
26912741
ImplItemKind::Method(ref sig, ref body) => {
26922742
let body_id = this.lower_body(Some(&sig.decl), |this| {
26932743
let body = this.lower_block(body, false);
2694-
this.expr_block(body, ThinVec::new())
2744+
let e = this.expr_block(body, ThinVec::new());
2745+
if sig.header.asyncness == IsAsync::Async {
2746+
this.make_async_expr(e)
2747+
} else { e }
26952748
});
26962749
let impl_trait_return_allow = !this.is_in_trait_impl;
26972750

@@ -3203,7 +3256,9 @@ impl<'a> LoweringContext<'a> {
32033256
let body_id = this.lower_body(Some(decl), |this| {
32043257
let e = this.lower_expr(body);
32053258
is_generator = this.is_generator;
3206-
e
3259+
if asyncness == IsAsync::Async {
3260+
this.make_async_expr(e)
3261+
} else { e }
32073262
});
32083263
let generator_option = if is_generator {
32093264
if !decl.inputs.is_empty() {
@@ -3245,9 +3300,15 @@ impl<'a> LoweringContext<'a> {
32453300
})
32463301
}
32473302
ExprKind::Block(ref blk, opt_label) => {
3248-
hir::ExprBlock(self.lower_block(blk,
3249-
opt_label.is_some()),
3250-
self.lower_label(opt_label))
3303+
let blk = self.lower_block(blk,
3304+
opt_label.is_some());
3305+
let opt_label = self.lower_label(opt_label);
3306+
hir::ExprBlock(blk, opt_label)
3307+
}
3308+
ExprKind::Async(ref blk) => {
3309+
let blk = self.lower_block(blk, false);
3310+
let expr = self.expr(blk.span, hir::ExprBlock(blk, None), ThinVec::new());
3311+
return self.make_async_expr(expr);
32513312
}
32523313
ExprKind::Assign(ref el, ref er) => {
32533314
hir::ExprAssign(P(self.lower_expr(el)), P(self.lower_expr(er)))

src/libsyntax/ast.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -947,7 +947,7 @@ impl Expr {
947947
/// Whether this expression would be valid somewhere that expects a value, for example, an `if`
948948
/// condition.
949949
pub fn returns(&self) -> bool {
950-
if let ExprKind::Block(ref block, _) = self.node {
950+
if let ExprKind::Block(ref block, ..) = self.node {
951951
match block.stmts.last().map(|last_stmt| &last_stmt.node) {
952952
// implicit return
953953
Some(&StmtKind::Expr(_)) => true,
@@ -1027,6 +1027,7 @@ impl Expr {
10271027
ExprKind::Match(..) => ExprPrecedence::Match,
10281028
ExprKind::Closure(..) => ExprPrecedence::Closure,
10291029
ExprKind::Block(..) => ExprPrecedence::Block,
1030+
ExprKind::Async(..) => ExprPrecedence::Async,
10301031
ExprKind::Catch(..) => ExprPrecedence::Catch,
10311032
ExprKind::Assign(..) => ExprPrecedence::Assign,
10321033
ExprKind::AssignOp(..) => ExprPrecedence::AssignOp,
@@ -1138,6 +1139,8 @@ pub enum ExprKind {
11381139
Block(P<Block>, Option<Label>),
11391140
/// A catch block (`catch { ... }`)
11401141
Catch(P<Block>),
1142+
/// An async block
1143+
Async(P<Block>),
11411144

11421145
/// An assignment (`a = foo()`)
11431146
Assign(P<Expr>, P<Expr>),

src/libsyntax/feature_gate.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1700,7 +1700,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
17001700
"multiple patterns in `if let` and `while let` are unstable");
17011701
}
17021702
}
1703-
ast::ExprKind::Block(_, opt_label) => {
1703+
ast::ExprKind::Block(.., opt_label) => {
17041704
if let Some(label) = opt_label {
17051705
gate_feature_post!(&self, label_break_value, label.ident.span,
17061706
"labels on blocks are unstable");

src/libsyntax/fold.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1349,6 +1349,7 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
13491349
ExprKind::Yield(ex) => ExprKind::Yield(ex.map(|x| folder.fold_expr(x))),
13501350
ExprKind::Try(ex) => ExprKind::Try(folder.fold_expr(ex)),
13511351
ExprKind::Catch(body) => ExprKind::Catch(folder.fold_block(body)),
1352+
ExprKind::Async(body) => ExprKind::Async(folder.fold_block(body)),
13521353
},
13531354
id: folder.new_id(id),
13541355
span: folder.new_span(span),

src/libsyntax/print/pprust.rs

+4
Original file line numberDiff line numberDiff line change
@@ -2173,6 +2173,10 @@ impl<'a> State<'a> {
21732173
// empty box to satisfy the close.
21742174
self.ibox(0)?;
21752175
}
2176+
ast::ExprKind::Async(ref blk) => {
2177+
self.print_asyncness(ast::IsAsync::Async)?;
2178+
self.print_block_with_attrs(blk, attrs)?;
2179+
}
21762180
ast::ExprKind::Block(ref blk, opt_label) => {
21772181
if let Some(label) = opt_label {
21782182
self.print_ident(label.ident)?;

src/libsyntax/util/parser.rs

+2
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ pub enum ExprPrecedence {
271271
Match,
272272
Block,
273273
Catch,
274+
Async,
274275
Struct,
275276
}
276277

@@ -340,6 +341,7 @@ impl ExprPrecedence {
340341
ExprPrecedence::Match |
341342
ExprPrecedence::Block |
342343
ExprPrecedence::Catch |
344+
ExprPrecedence::Async |
343345
ExprPrecedence::Struct => PREC_PAREN,
344346
}
345347
}

src/libsyntax/visit.rs

+3
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
800800
ExprKind::Catch(ref body) => {
801801
visitor.visit_block(body)
802802
}
803+
ExprKind::Async(ref body) => {
804+
visitor.visit_block(body)
805+
}
803806
}
804807

805808
visitor.visit_expr_post(expression)

0 commit comments

Comments
 (0)