1 use super::{LoweringContext, ParamMode, ParenthesizedGenericArgs, ImplTraitContext};
2 use crate::hir::{self, HirVec};
3 use crate::hir::ptr::P;
5 use rustc_data_structures::thin_vec::ThinVec;
8 use syntax::ptr::P as AstP;
10 use syntax::source_map::{respan, DesugaringKind, Span};
11 use syntax::symbol::{sym, Symbol};
13 impl LoweringContext<'_> {
14 fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> HirVec<hir::Expr> {
15 exprs.iter().map(|x| self.lower_expr(x)).collect()
18 pub(super) fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
19 let kind = match e.node {
20 ExprKind::Box(ref inner) => hir::ExprKind::Box(P(self.lower_expr(inner))),
21 ExprKind::Array(ref exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
22 ExprKind::Repeat(ref expr, ref count) => {
23 let expr = P(self.lower_expr(expr));
24 let count = self.lower_anon_const(count);
25 hir::ExprKind::Repeat(expr, count)
27 ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
28 ExprKind::Call(ref f, ref args) => {
29 let f = P(self.lower_expr(f));
30 hir::ExprKind::Call(f, self.lower_exprs(args))
32 ExprKind::MethodCall(ref seg, ref args) => {
33 let hir_seg = P(self.lower_path_segment(
38 ParenthesizedGenericArgs::Err,
39 ImplTraitContext::disallowed(),
42 let args = self.lower_exprs(args);
43 hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args)
45 ExprKind::Binary(binop, ref lhs, ref rhs) => {
46 let binop = self.lower_binop(binop);
47 let lhs = P(self.lower_expr(lhs));
48 let rhs = P(self.lower_expr(rhs));
49 hir::ExprKind::Binary(binop, lhs, rhs)
51 ExprKind::Unary(op, ref ohs) => {
52 let op = self.lower_unop(op);
53 let ohs = P(self.lower_expr(ohs));
54 hir::ExprKind::Unary(op, ohs)
56 ExprKind::Lit(ref l) => hir::ExprKind::Lit(respan(l.span, l.node.clone())),
57 ExprKind::Cast(ref expr, ref ty) => {
58 let expr = P(self.lower_expr(expr));
59 hir::ExprKind::Cast(expr, self.lower_ty(ty, ImplTraitContext::disallowed()))
61 ExprKind::Type(ref expr, ref ty) => {
62 let expr = P(self.lower_expr(expr));
63 hir::ExprKind::Type(expr, self.lower_ty(ty, ImplTraitContext::disallowed()))
65 ExprKind::AddrOf(m, ref ohs) => {
66 let m = self.lower_mutability(m);
67 let ohs = P(self.lower_expr(ohs));
68 hir::ExprKind::AddrOf(m, ohs)
70 ExprKind::Let(ref pats, ref scrutinee) => self.lower_expr_let(e.span, pats, scrutinee),
71 ExprKind::If(ref cond, ref then, ref else_opt) => {
72 self.lower_expr_if(e.span, cond, then, else_opt.as_deref())
74 ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| {
75 this.lower_expr_while_in_loop_scope(e.span, cond, body, opt_label)
77 ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| {
79 this.lower_block(body, false),
80 this.lower_label(opt_label),
81 hir::LoopSource::Loop,
84 ExprKind::TryBlock(ref body) => self.lower_expr_try_block(body),
85 ExprKind::Match(ref expr, ref arms) => hir::ExprKind::Match(
86 P(self.lower_expr(expr)),
87 arms.iter().map(|x| self.lower_arm(x)).collect(),
88 hir::MatchSource::Normal,
90 ExprKind::Async(capture_clause, closure_node_id, ref block) => {
91 self.make_async_expr(capture_clause, closure_node_id, None, block.span, |this| {
92 this.with_new_scopes(|this| {
93 let block = this.lower_block(block, false);
94 this.expr_block(block, ThinVec::new())
98 ExprKind::Await(ref expr) => self.lower_expr_await(e.span, expr),
100 capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span
101 ) => if let IsAsync::Async { closure_id, .. } = asyncness {
102 self.lower_expr_async_closure(capture_clause, closure_id, decl, body, fn_decl_span)
104 self.lower_expr_closure(capture_clause, movability, decl, body, fn_decl_span)
106 ExprKind::Block(ref blk, opt_label) => {
107 hir::ExprKind::Block(self.lower_block(blk,
108 opt_label.is_some()),
109 self.lower_label(opt_label))
111 ExprKind::Assign(ref el, ref er) => {
112 hir::ExprKind::Assign(P(self.lower_expr(el)), P(self.lower_expr(er)))
114 ExprKind::AssignOp(op, ref el, ref er) => hir::ExprKind::AssignOp(
115 self.lower_binop(op),
116 P(self.lower_expr(el)),
117 P(self.lower_expr(er)),
119 ExprKind::Field(ref el, ident) => hir::ExprKind::Field(P(self.lower_expr(el)), ident),
120 ExprKind::Index(ref el, ref er) => {
121 hir::ExprKind::Index(P(self.lower_expr(el)), P(self.lower_expr(er)))
123 ExprKind::Range(Some(ref e1), Some(ref e2), RangeLimits::Closed) => {
124 self.lower_expr_range_closed(e.span, e1, e2)
126 ExprKind::Range(ref e1, ref e2, lims) => {
127 self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims)
129 ExprKind::Path(ref qself, ref path) => {
130 let qpath = self.lower_qpath(
135 ImplTraitContext::disallowed(),
137 hir::ExprKind::Path(qpath)
139 ExprKind::Break(opt_label, ref opt_expr) => {
140 let destination = if self.is_in_loop_condition && opt_label.is_none() {
143 target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
146 self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
148 hir::ExprKind::Break(
150 opt_expr.as_ref().map(|x| P(self.lower_expr(x))),
153 ExprKind::Continue(opt_label) => {
154 hir::ExprKind::Continue(if self.is_in_loop_condition && opt_label.is_none() {
157 target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
160 self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
163 ExprKind::Ret(ref e) => hir::ExprKind::Ret(e.as_ref().map(|x| P(self.lower_expr(x)))),
164 ExprKind::InlineAsm(ref asm) => self.lower_expr_asm(asm),
165 ExprKind::Struct(ref path, ref fields, ref maybe_expr) => hir::ExprKind::Struct(
171 ImplTraitContext::disallowed(),
173 fields.iter().map(|x| self.lower_field(x)).collect(),
174 maybe_expr.as_ref().map(|x| P(self.lower_expr(x))),
176 ExprKind::Paren(ref ex) => {
177 let mut ex = self.lower_expr(ex);
178 // Include parens in span, but only if it is a super-span.
179 if e.span.contains(ex.span) {
182 // Merge attributes into the inner expression.
183 let mut attrs = e.attrs.clone();
184 attrs.extend::<Vec<_>>(ex.attrs.into());
189 ExprKind::Yield(ref opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
191 ExprKind::Err => hir::ExprKind::Err,
193 // Desugar `ExprForLoop`
194 // from: `[opt_ident]: for <pat> in <head> <body>`
195 ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => {
196 return self.lower_expr_for(e, pat, head, body, opt_label);
198 ExprKind::Try(ref sub_expr) => self.lower_expr_try(e.span, sub_expr),
199 ExprKind::Mac(_) => panic!("Shouldn't exist here"),
203 hir_id: self.lower_node_id(e.id),
206 attrs: e.attrs.clone(),
210 /// Emit an error and lower `ast::ExprKind::Let(pats, scrutinee)` into:
212 /// match scrutinee { pats => true, _ => false }
220 // If we got here, the `let` expression is not allowed.
222 .struct_span_err(span, "`let` expressions are not supported here")
223 .note("only supported directly in conditions of `if`- and `while`-expressions")
224 .note("as well as when nested within `&&` and parenthesis in those conditions")
227 // For better recovery, we emit:
229 // match scrutinee { pats => true, _ => false }
231 // While this doesn't fully match the user's intent, it has key advantages:
232 // 1. We can avoid using `abort_if_errors`.
233 // 2. We can typeck both `pats` and `scrutinee`.
234 // 3. `pats` is allowed to be refutable.
235 // 4. The return type of the block is `bool` which seems like what the user wanted.
236 let scrutinee = self.lower_expr(scrutinee);
238 let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
239 let expr = self.expr_bool(span, true);
240 self.arm(pats, P(expr))
243 let pats = hir_vec![self.pat_wild(span)];
244 let expr = self.expr_bool(span, false);
245 self.arm(pats, P(expr))
247 hir::ExprKind::Match(
249 vec![then_arm, else_arm].into(),
250 hir::MatchSource::Normal,
259 else_opt: Option<&Expr>,
261 // FIXME(#53667): handle lowering of && and parens.
263 // `_ => else_block` where `else_block` is `{}` if there's `None`:
264 let else_pat = self.pat_wild(span);
265 let (else_expr, contains_else_clause) = match else_opt {
266 None => (self.expr_block_empty(span), false),
267 Some(els) => (self.lower_expr(els), true),
269 let else_arm = self.arm(hir_vec![else_pat], P(else_expr));
271 // Handle then + scrutinee:
272 let then_blk = self.lower_block(then, false);
273 let then_expr = self.expr_block(then_blk, ThinVec::new());
274 let (then_pats, scrutinee, desugar) = match cond.node {
275 // `<pat> => <then>`:
276 ExprKind::Let(ref pats, ref scrutinee) => {
277 let scrutinee = self.lower_expr(scrutinee);
278 let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
279 let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause };
280 (pats, scrutinee, desugar)
285 let cond = self.lower_expr(cond);
286 let span_block = self.mark_span_with_reason(
287 DesugaringKind::CondTemporary,
291 // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
292 // to preserve drop semantics since `if cond { ... }` does not
293 // let temporaries live outside of `cond`.
294 let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new());
296 let desugar = hir::MatchSource::IfDesugar { contains_else_clause };
297 let pats = hir_vec![self.pat_bool(span, true)];
298 (pats, cond, desugar)
301 let then_arm = self.arm(then_pats, P(then_expr));
303 hir::ExprKind::Match(P(scrutinee), vec![then_arm, else_arm].into(), desugar)
306 fn lower_expr_while_in_loop_scope(
311 opt_label: Option<Label>
313 // FIXME(#53667): handle lowering of && and parens.
315 // Note that the block AND the condition are evaluated in the loop scope.
316 // This is done to allow `break` from inside the condition of the loop.
320 let else_pat = self.pat_wild(span);
321 let else_expr = self.expr_break(span, ThinVec::new());
322 self.arm(hir_vec![else_pat], else_expr)
325 // Handle then + scrutinee:
326 let then_blk = self.lower_block(body, false);
327 let then_expr = self.expr_block(then_blk, ThinVec::new());
328 let (then_pats, scrutinee, desugar, source) = match cond.node {
329 ExprKind::Let(ref pats, ref scrutinee) => {
332 // [opt_ident]: loop {
333 // match <sub_expr> {
338 let scrutinee = self.with_loop_condition_scope(|t| t.lower_expr(scrutinee));
339 let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
340 let desugar = hir::MatchSource::WhileLetDesugar;
341 (pats, scrutinee, desugar, hir::LoopSource::WhileLet)
344 // We desugar: `'label: while $cond $body` into:
348 // match DropTemps($cond) {
356 let cond = self.with_loop_condition_scope(|this| this.lower_expr(cond));
357 let span_block = self.mark_span_with_reason(
358 DesugaringKind::CondTemporary,
362 // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
363 // to preserve drop semantics since `while cond { ... }` does not
364 // let temporaries live outside of `cond`.
365 let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new());
367 let desugar = hir::MatchSource::WhileDesugar;
369 let pats = hir_vec![self.pat_bool(span, true)];
370 (pats, cond, desugar, hir::LoopSource::While)
373 let then_arm = self.arm(then_pats, P(then_expr));
375 // `match <scrutinee> { ... }`
376 let match_expr = self.expr_match(
379 hir_vec![then_arm, else_arm],
383 // `[opt_ident]: loop { ... }`
385 P(self.block_expr(P(match_expr))),
386 self.lower_label(opt_label),
391 fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind {
392 self.with_catch_scope(body.id, |this| {
393 let unstable_span = this.mark_span_with_reason(
394 DesugaringKind::TryBlock,
396 this.allow_try_trait.clone(),
398 let mut block = this.lower_block(body, true).into_inner();
399 let tail = block.expr.take().map_or_else(
400 || this.expr_unit(this.sess.source_map().end_point(unstable_span)),
401 |x: P<hir::Expr>| x.into_inner(),
403 block.expr = Some(this.wrap_in_try_constructor(sym::from_ok, tail, unstable_span));
404 hir::ExprKind::Block(P(block), None)
408 fn wrap_in_try_constructor(
414 let path = &[sym::ops, sym::Try, method];
415 let from_err = P(self.expr_std_path(unstable_span, path, None, ThinVec::new()));
416 P(self.expr_call(e.span, from_err, hir_vec![e]))
419 pub(super) fn make_async_expr(
421 capture_clause: CaptureBy,
422 closure_node_id: NodeId,
423 ret_ty: Option<AstP<Ty>>,
425 body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr,
427 let capture_clause = self.lower_capture_clause(capture_clause);
428 let output = match ret_ty {
429 Some(ty) => FunctionRetTy::Ty(ty),
430 None => FunctionRetTy::Default(span),
432 let ast_decl = FnDecl {
437 let decl = self.lower_fn_decl(&ast_decl, None, /* impl trait allowed */ false, None);
438 let body_id = self.lower_fn_body(&ast_decl, |this| {
439 this.generator_kind = Some(hir::GeneratorKind::Async);
443 // `static || -> <ret_ty> { body }`:
444 let generator_node = hir::ExprKind::Closure(
449 Some(hir::GeneratorMovability::Static)
451 let generator = hir::Expr {
452 hir_id: self.lower_node_id(closure_node_id),
453 node: generator_node,
455 attrs: ThinVec::new(),
458 // `future::from_generator`:
459 let unstable_span = self.mark_span_with_reason(
460 DesugaringKind::Async,
462 self.allow_gen_future.clone(),
464 let gen_future = self.expr_std_path(
466 &[sym::future, sym::from_generator],
471 // `future::from_generator(generator)`:
472 hir::ExprKind::Call(P(gen_future), hir_vec![generator])
475 /// Desugar `<expr>.await` into:
478 /// let mut pinned = <expr>;
480 /// match ::std::future::poll_with_tls_context(unsafe {
481 /// ::std::pin::Pin::new_unchecked(&mut pinned)
483 /// ::std::task::Poll::Ready(result) => break result,
484 /// ::std::task::Poll::Pending => {},
490 fn lower_expr_await(&mut self, await_span: Span, expr: &Expr) -> hir::ExprKind {
491 match self.generator_kind {
492 Some(hir::GeneratorKind::Async) => {},
493 Some(hir::GeneratorKind::Gen) |
495 let mut err = struct_span_err!(
499 "`await` is only allowed inside `async` functions and blocks"
501 err.span_label(await_span, "only allowed inside `async` functions and blocks");
502 if let Some(item_sp) = self.current_item {
503 err.span_label(item_sp, "this is not `async`");
508 let span = self.mark_span_with_reason(
509 DesugaringKind::Await,
513 let gen_future_span = self.mark_span_with_reason(
514 DesugaringKind::Await,
516 self.allow_gen_future.clone(),
519 // let mut pinned = <expr>;
520 let expr = P(self.lower_expr(expr));
521 let pinned_ident = Ident::with_empty_ctxt(sym::pinned);
522 let (pinned_pat, pinned_pat_hid) = self.pat_ident_binding_mode(
525 hir::BindingAnnotation::Mutable,
527 let pinned_let = self.stmt_let_pat(
532 hir::LocalSource::AwaitDesugar,
535 // ::std::future::poll_with_tls_context(unsafe {
536 // ::std::pin::Pin::new_unchecked(&mut pinned)
539 let pinned = P(self.expr_ident(span, pinned_ident, pinned_pat_hid));
540 let ref_mut_pinned = self.expr_mut_addr_of(span, pinned);
541 let pin_ty_id = self.next_id();
542 let new_unchecked_expr_kind = self.expr_call_std_assoc_fn(
545 &[sym::pin, sym::Pin],
547 hir_vec![ref_mut_pinned],
549 let new_unchecked = P(self.expr(span, new_unchecked_expr_kind, ThinVec::new()));
550 let unsafe_expr = self.expr_unsafe(new_unchecked);
551 P(self.expr_call_std_path(
553 &[sym::future, sym::poll_with_tls_context],
554 hir_vec![unsafe_expr],
558 // `::std::task::Poll::Ready(result) => break result`
559 let loop_node_id = self.sess.next_node_id();
560 let loop_hir_id = self.lower_node_id(loop_node_id);
562 let x_ident = Ident::with_empty_ctxt(sym::result);
563 let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident);
564 let x_expr = P(self.expr_ident(span, x_ident, x_pat_hid));
565 let ready_pat = self.pat_std_enum(
567 &[sym::task, sym::Poll, sym::Ready],
570 let break_x = self.with_loop_scope(loop_node_id, |this| {
571 let expr_break = hir::ExprKind::Break(
572 this.lower_loop_destination(None),
575 P(this.expr(await_span, expr_break, ThinVec::new()))
577 self.arm(hir_vec![ready_pat], break_x)
580 // `::std::task::Poll::Pending => {}`
582 let pending_pat = self.pat_std_enum(
584 &[sym::task, sym::Poll, sym::Pending],
587 let empty_block = P(self.expr_block_empty(span));
588 self.arm(hir_vec![pending_pat], empty_block)
592 let match_expr = self.expr_match(
595 hir_vec![ready_arm, pending_arm],
596 hir::MatchSource::AwaitDesugar,
598 self.stmt_expr(span, match_expr)
602 let unit = self.expr_unit(span);
603 let yield_expr = self.expr(
605 hir::ExprKind::Yield(P(unit), hir::YieldSource::Await),
608 self.stmt_expr(span, yield_expr)
611 let loop_block = P(self.block_all(
613 hir_vec![match_stmt, yield_stmt],
617 let loop_expr = P(hir::Expr {
619 node: hir::ExprKind::Loop(
622 hir::LoopSource::Loop,
625 attrs: ThinVec::new(),
628 hir::ExprKind::Block(
629 P(self.block_all(span, hir_vec![pinned_let], Some(loop_expr))),
634 fn lower_expr_closure(
636 capture_clause: CaptureBy,
637 movability: Movability,
642 // Lower outside new scope to preserve `is_in_loop_condition`.
643 let fn_decl = self.lower_fn_decl(decl, None, false, None);
645 self.with_new_scopes(|this| {
646 this.current_item = Some(fn_decl_span);
647 let mut generator_kind = None;
648 let body_id = this.lower_fn_body(decl, |this| {
649 let e = this.lower_expr(body);
650 generator_kind = this.generator_kind;
653 let generator_option = this.generator_movability_for_fn(
659 hir::ExprKind::Closure(
660 this.lower_capture_clause(capture_clause),
669 fn lower_expr_async_closure(
671 capture_clause: CaptureBy,
677 let outer_decl = FnDecl {
678 inputs: decl.inputs.clone(),
679 output: FunctionRetTy::Default(fn_decl_span),
682 // We need to lower the declaration outside the new scope, because we
683 // have to conserve the state of being inside a loop condition for the
684 // closure argument types.
685 let fn_decl = self.lower_fn_decl(&outer_decl, None, false, None);
687 self.with_new_scopes(|this| {
688 // FIXME(cramertj): allow `async` non-`move` closures with arguments.
689 if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() {
694 "`async` non-`move` closures with arguments are not currently supported",
697 "consider using `let` statements to manually capture \
698 variables by reference before entering an `async move` closure"
703 // Transform `async |x: u8| -> X { ... }` into
704 // `|x: u8| future_from_generator(|| -> X { ... })`.
705 let body_id = this.lower_fn_body(&outer_decl, |this| {
706 let async_ret_ty = if let FunctionRetTy::Ty(ty) = &decl.output {
711 let async_body = this.make_async_expr(
712 capture_clause, closure_id, async_ret_ty, body.span,
714 this.with_new_scopes(|this| this.lower_expr(body))
717 this.expr(fn_decl_span, async_body, ThinVec::new())
719 hir::ExprKind::Closure(
720 this.lower_capture_clause(capture_clause),
729 /// Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`.
730 fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind {
731 let id = self.next_id();
732 let e1 = self.lower_expr(e1);
733 let e2 = self.lower_expr(e2);
734 self.expr_call_std_assoc_fn(
737 &[sym::ops, sym::RangeInclusive],
750 use syntax::ast::RangeLimits::*;
752 let path = match (e1, e2, lims) {
753 (None, None, HalfOpen) => sym::RangeFull,
754 (Some(..), None, HalfOpen) => sym::RangeFrom,
755 (None, Some(..), HalfOpen) => sym::RangeTo,
756 (Some(..), Some(..), HalfOpen) => sym::Range,
757 (None, Some(..), Closed) => sym::RangeToInclusive,
758 (Some(..), Some(..), Closed) => unreachable!(),
759 (_, None, Closed) => self.diagnostic()
760 .span_fatal(span, "inclusive range with no end")
764 let fields = e1.iter()
765 .map(|e| ("start", e))
766 .chain(e2.iter().map(|e| ("end", e)))
768 let expr = P(self.lower_expr(&e));
769 let ident = Ident::new(Symbol::intern(s), e.span);
770 self.field(ident, expr, e.span)
772 .collect::<P<[hir::Field]>>();
774 let is_unit = fields.is_empty();
775 let struct_path = [sym::ops, path];
776 let struct_path = self.std_path(span, &struct_path, None, is_unit);
777 let struct_path = hir::QPath::Resolved(None, P(struct_path));
780 hir::ExprKind::Path(struct_path)
782 hir::ExprKind::Struct(P(struct_path), fields, None)
786 fn lower_expr_asm(&mut self, asm: &InlineAsm) -> hir::ExprKind {
787 let hir_asm = hir::InlineAsm {
788 inputs: asm.inputs.iter().map(|&(ref c, _)| c.clone()).collect(),
791 .map(|out| hir::InlineAsmOutput {
792 constraint: out.constraint.clone(),
794 is_indirect: out.is_indirect,
798 asm: asm.asm.clone(),
799 asm_str_style: asm.asm_str_style,
800 clobbers: asm.clobbers.clone().into(),
801 volatile: asm.volatile,
802 alignstack: asm.alignstack,
803 dialect: asm.dialect,
807 let outputs = asm.outputs
809 .map(|out| self.lower_expr(&out.expr))
812 let inputs = asm.inputs
814 .map(|&(_, ref input)| self.lower_expr(input))
817 hir::ExprKind::InlineAsm(P(hir_asm), outputs, inputs)
820 fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind {
821 match self.generator_kind {
822 Some(hir::GeneratorKind::Gen) => {},
823 Some(hir::GeneratorKind::Async) => {
828 "`async` generators are not yet supported",
830 self.sess.abort_if_errors();
832 None => self.generator_kind = Some(hir::GeneratorKind::Gen),
837 .map(|x| self.lower_expr(x))
838 .unwrap_or_else(|| self.expr_unit(span));
840 hir::ExprKind::Yield(P(expr), hir::YieldSource::Yield)
843 /// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into:
846 /// let result = match ::std::iter::IntoIterator::into_iter(<head>) {
848 /// [opt_ident]: loop {
850 /// match ::std::iter::Iterator::next(&mut iter) {
851 /// ::std::option::Option::Some(val) => __next = val,
852 /// ::std::option::Option::None => break
854 /// let <pat> = __next;
855 /// StmtKind::Expr(<body>);
868 opt_label: Option<Label>,
871 let mut head = self.lower_expr(head);
872 let head_sp = head.span;
873 let desugared_span = self.mark_span_with_reason(
874 DesugaringKind::ForLoop,
878 head.span = desugared_span;
880 let iter = Ident::with_empty_ctxt(sym::iter);
882 let next_ident = Ident::with_empty_ctxt(sym::__next);
883 let (next_pat, next_pat_hid) = self.pat_ident_binding_mode(
886 hir::BindingAnnotation::Mutable,
889 // `::std::option::Option::Some(val) => __next = val`
891 let val_ident = Ident::with_empty_ctxt(sym::val);
892 let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident);
893 let val_expr = P(self.expr_ident(pat.span, val_ident, val_pat_hid));
894 let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat_hid));
895 let assign = P(self.expr(
897 hir::ExprKind::Assign(next_expr, val_expr),
900 let some_pat = self.pat_some(pat.span, val_pat);
901 self.arm(hir_vec![some_pat], assign)
904 // `::std::option::Option::None => break`
907 self.with_loop_scope(e.id, |this| this.expr_break(e.span, ThinVec::new()));
908 let pat = self.pat_none(e.span);
909 self.arm(hir_vec![pat], break_expr)
913 let (iter_pat, iter_pat_nid) = self.pat_ident_binding_mode(
916 hir::BindingAnnotation::Mutable
919 // `match ::std::iter::Iterator::next(&mut iter) { ... }`
921 let iter = P(self.expr_ident(head_sp, iter, iter_pat_nid));
922 let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter);
923 let next_path = &[sym::iter, sym::Iterator, sym::next];
924 let next_expr = P(self.expr_call_std_path(
927 hir_vec![ref_mut_iter],
929 let arms = hir_vec![pat_arm, break_arm];
931 self.expr_match(head_sp, next_expr, arms, hir::MatchSource::ForLoopDesugar)
933 let match_stmt = self.stmt_expr(head_sp, match_expr);
935 let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat_hid));
938 let next_let = self.stmt_let_pat(
943 hir::LocalSource::ForLoopDesugar,
946 // `let <pat> = __next`
947 let pat = self.lower_pat(pat);
948 let pat_let = self.stmt_let_pat(
953 hir::LocalSource::ForLoopDesugar,
956 let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
957 let body_expr = self.expr_block(body_block, ThinVec::new());
958 let body_stmt = self.stmt_expr(body.span, body_expr);
960 let loop_block = P(self.block_all(
962 hir_vec![next_let, match_stmt, pat_let, body_stmt],
966 // `[opt_ident]: loop { ... }`
967 let loop_expr = hir::ExprKind::Loop(
969 self.lower_label(opt_label),
970 hir::LoopSource::ForLoop,
972 let loop_expr = P(hir::Expr {
973 hir_id: self.lower_node_id(e.id),
976 attrs: ThinVec::new(),
979 // `mut iter => { ... }`
980 let iter_arm = self.arm(hir_vec![iter_pat], loop_expr);
982 // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
983 let into_iter_expr = {
985 &[sym::iter, sym::IntoIterator, sym::into_iter];
986 P(self.expr_call_std_path(
993 let match_expr = P(self.expr_match(
997 hir::MatchSource::ForLoopDesugar,
1000 // This is effectively `{ let _result = ...; _result }`.
1001 // The construct was introduced in #21984 and is necessary to make sure that
1002 // temporaries in the `head` expression are dropped and do not leak to the
1003 // surrounding scope of the `match` since the `match` is not a terminating scope.
1005 // Also, add the attributes to the outer returned expr node.
1006 self.expr_drop_temps(head_sp, match_expr, e.attrs.clone())
1009 /// Desugar `ExprKind::Try` from: `<expr>?` into:
1011 /// match Try::into_result(<expr>) {
1012 /// Ok(val) => #[allow(unreachable_code)] val,
1013 /// Err(err) => #[allow(unreachable_code)]
1014 /// // If there is an enclosing `try {...}`:
1015 /// break 'catch_target Try::from_error(From::from(err)),
1017 /// return Try::from_error(From::from(err)),
1020 fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind {
1021 let unstable_span = self.mark_span_with_reason(
1022 DesugaringKind::QuestionMark,
1024 self.allow_try_trait.clone(),
1026 let try_span = self.sess.source_map().end_point(span);
1027 let try_span = self.mark_span_with_reason(
1028 DesugaringKind::QuestionMark,
1030 self.allow_try_trait.clone(),
1033 // `Try::into_result(<expr>)`
1036 let sub_expr = self.lower_expr(sub_expr);
1038 let path = &[sym::ops, sym::Try, sym::into_result];
1039 P(self.expr_call_std_path(unstable_span, path, hir_vec![sub_expr]))
1042 // `#[allow(unreachable_code)]`
1044 // `allow(unreachable_code)`
1046 let allow_ident = Ident::new(sym::allow, span);
1047 let uc_ident = Ident::new(sym::unreachable_code, span);
1048 let uc_nested = attr::mk_nested_word_item(uc_ident);
1049 attr::mk_list_item(allow_ident, vec![uc_nested])
1051 attr::mk_attr_outer(allow)
1053 let attrs = vec![attr];
1055 // `Ok(val) => #[allow(unreachable_code)] val,`
1057 let val_ident = Ident::with_empty_ctxt(sym::val);
1058 let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident);
1059 let val_expr = P(self.expr_ident_with_attrs(
1063 ThinVec::from(attrs.clone()),
1065 let ok_pat = self.pat_ok(span, val_pat);
1067 self.arm(hir_vec![ok_pat], val_expr)
1070 // `Err(err) => #[allow(unreachable_code)]
1071 // return Try::from_error(From::from(err)),`
1073 let err_ident = Ident::with_empty_ctxt(sym::err);
1074 let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
1076 let from_path = &[sym::convert, sym::From, sym::from];
1077 let err_expr = self.expr_ident(try_span, err_ident, err_local_nid);
1078 self.expr_call_std_path(try_span, from_path, hir_vec![err_expr])
1081 self.wrap_in_try_constructor(sym::from_error, from_expr, unstable_span);
1082 let thin_attrs = ThinVec::from(attrs);
1083 let catch_scope = self.catch_scopes.last().map(|x| *x);
1084 let ret_expr = if let Some(catch_node) = catch_scope {
1085 let target_id = Ok(self.lower_node_id(catch_node));
1088 hir::ExprKind::Break(
1093 Some(from_err_expr),
1098 P(self.expr(try_span, hir::ExprKind::Ret(Some(from_err_expr)), thin_attrs))
1101 let err_pat = self.pat_err(try_span, err_local);
1102 self.arm(hir_vec![err_pat], ret_expr)
1105 hir::ExprKind::Match(
1107 hir_vec![err_arm, ok_arm],
1108 hir::MatchSource::TryDesugar,