1
Fork 0

lowering: move lower_await -> expr.rs

This commit is contained in:
Mazdak Farrokhzad 2019-08-10 15:01:38 +02:00
parent 548e3090c2
commit e450dcaf8e
2 changed files with 160 additions and 163 deletions

View file

@ -5125,168 +5125,6 @@ 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(result) => break result,
// ::std::task::Poll::Pending => {},
// }
// yield ();
// }
// }
match self.generator_kind {
Some(hir::GeneratorKind::Async) => {},
Some(hir::GeneratorKind::Gen) |
None => {
let mut err = struct_span_err!(
self.sess,
await_span,
E0728,
"`await` is only allowed inside `async` functions and blocks"
);
err.span_label(await_span, "only allowed inside `async` functions and blocks");
if let Some(item_sp) = self.current_item {
err.span_label(item_sp, "this is not `async`");
}
err.emit();
}
}
let span = self.mark_span_with_reason(
DesugaringKind::Await,
await_span,
None,
);
let gen_future_span = self.mark_span_with_reason(
DesugaringKind::Await,
await_span,
self.allow_gen_future.clone(),
);
// let mut pinned = <expr>;
let expr = P(self.lower_expr(expr));
let pinned_ident = Ident::with_empty_ctxt(sym::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(
ThinVec::new(),
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,
&[sym::pin, sym::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,
&[sym::future, sym::poll_with_tls_context],
hir_vec![unsafe_expr],
))
};
// `::std::task::Poll::Ready(result) => break result`
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 = Ident::with_empty_ctxt(sym::result);
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,
&[sym::task, sym::Poll, sym::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,
&[sym::task, sym::Poll, sym::Pending],
hir_vec![],
);
let empty_block = P(self.expr_block_empty(span));
self.arm(hir_vec![pending_pat], empty_block)
};
let match_stmt = {
let match_expr = self.expr_match(
span,
poll_expr,
hir_vec![ready_arm, pending_arm],
hir::MatchSource::AwaitDesugar,
);
self.stmt_expr(span, match_expr)
};
let yield_stmt = {
let unit = self.expr_unit(span);
let yield_expr = self.expr(
span,
hir::ExprKind::Yield(P(unit), hir::YieldSource::Await),
ThinVec::new(),
);
self.stmt_expr(span, yield_expr)
};
let loop_block = P(self.block_all(
span,
hir_vec![match_stmt, yield_stmt],
None,
));
let loop_expr = P(hir::Expr {
hir_id: loop_hir_id,
node: hir::ExprKind::Loop(
loop_block,
None,
hir::LoopSource::Loop,
),
span,
attrs: ThinVec::new(),
});
hir::ExprKind::Block(
P(self.block_all(span, hir_vec![pinned_let], Some(loop_expr))),
None,
)
}
}
fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body>) -> Vec<hir::BodyId> {

View file

@ -263,7 +263,7 @@ impl LoweringContext<'_> {
})
})
}
ExprKind::Await(ref expr) => self.lower_await(e.span, expr),
ExprKind::Await(ref expr) => self.lower_expr_await(e.span, expr),
ExprKind::Closure(
capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span
) => if let IsAsync::Async { closure_id, .. } = asyncness {
@ -375,6 +375,165 @@ impl LoweringContext<'_> {
}
}
/// Desugar `<expr>.await` into:
/// ```rust
/// {
/// let mut pinned = <expr>;
/// loop {
/// match ::std::future::poll_with_tls_context(unsafe {
/// ::std::pin::Pin::new_unchecked(&mut pinned)
/// }) {
/// ::std::task::Poll::Ready(result) => break result,
/// ::std::task::Poll::Pending => {},
/// }
/// yield ();
/// }
/// }
/// ```
fn lower_expr_await(&mut self, await_span: Span, expr: &Expr) -> hir::ExprKind {
match self.generator_kind {
Some(hir::GeneratorKind::Async) => {},
Some(hir::GeneratorKind::Gen) |
None => {
let mut err = struct_span_err!(
self.sess,
await_span,
E0728,
"`await` is only allowed inside `async` functions and blocks"
);
err.span_label(await_span, "only allowed inside `async` functions and blocks");
if let Some(item_sp) = self.current_item {
err.span_label(item_sp, "this is not `async`");
}
err.emit();
}
}
let span = self.mark_span_with_reason(
DesugaringKind::Await,
await_span,
None,
);
let gen_future_span = self.mark_span_with_reason(
DesugaringKind::Await,
await_span,
self.allow_gen_future.clone(),
);
// let mut pinned = <expr>;
let expr = P(self.lower_expr(expr));
let pinned_ident = Ident::with_empty_ctxt(sym::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(
ThinVec::new(),
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,
&[sym::pin, sym::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,
&[sym::future, sym::poll_with_tls_context],
hir_vec![unsafe_expr],
))
};
// `::std::task::Poll::Ready(result) => break result`
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 = Ident::with_empty_ctxt(sym::result);
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,
&[sym::task, sym::Poll, sym::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,
&[sym::task, sym::Poll, sym::Pending],
hir_vec![],
);
let empty_block = P(self.expr_block_empty(span));
self.arm(hir_vec![pending_pat], empty_block)
};
let match_stmt = {
let match_expr = self.expr_match(
span,
poll_expr,
hir_vec![ready_arm, pending_arm],
hir::MatchSource::AwaitDesugar,
);
self.stmt_expr(span, match_expr)
};
let yield_stmt = {
let unit = self.expr_unit(span);
let yield_expr = self.expr(
span,
hir::ExprKind::Yield(P(unit), hir::YieldSource::Await),
ThinVec::new(),
);
self.stmt_expr(span, yield_expr)
};
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 lower_expr_closure(
&mut self,
capture_clause: CaptureBy,