]> git.lizzy.rs Git - rust.git/blob - src/librustc/hir/lowering/expr.rs
lowering: extract lower_expr_yield
[rust.git] / src / librustc / hir / lowering / expr.rs
1 use super::{LoweringContext, ParamMode, ParenthesizedGenericArgs, ImplTraitContext};
2 use crate::hir::{self, HirVec};
3 use crate::hir::ptr::P;
4
5 use rustc_data_structures::thin_vec::ThinVec;
6
7 use syntax::attr;
8 use syntax::ptr::P as AstP;
9 use syntax::ast::*;
10 use syntax::source_map::{respan, DesugaringKind, Span};
11 use syntax::symbol::{sym, Symbol};
12
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()
16     }
17
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)
26             }
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))
31             }
32             ExprKind::MethodCall(ref seg, ref args) => {
33                 let hir_seg = P(self.lower_path_segment(
34                     e.span,
35                     seg,
36                     ParamMode::Optional,
37                     0,
38                     ParenthesizedGenericArgs::Err,
39                     ImplTraitContext::disallowed(),
40                     None,
41                 ));
42                 let args = self.lower_exprs(args);
43                 hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args)
44             }
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)
50             }
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)
55             }
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()))
60             }
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()))
64             }
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)
69             }
70             ExprKind::Let(ref pats, ref scrutinee) => {
71                 // If we got here, the `let` expression is not allowed.
72                 self.sess
73                     .struct_span_err(e.span, "`let` expressions are not supported here")
74                     .note("only supported directly in conditions of `if`- and `while`-expressions")
75                     .note("as well as when nested within `&&` and parenthesis in those conditions")
76                     .emit();
77
78                 // For better recovery, we emit:
79                 // ```
80                 // match scrutinee { pats => true, _ => false }
81                 // ```
82                 // While this doesn't fully match the user's intent, it has key advantages:
83                 // 1. We can avoid using `abort_if_errors`.
84                 // 2. We can typeck both `pats` and `scrutinee`.
85                 // 3. `pats` is allowed to be refutable.
86                 // 4. The return type of the block is `bool` which seems like what the user wanted.
87                 let scrutinee = self.lower_expr(scrutinee);
88                 let then_arm = {
89                     let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
90                     let expr = self.expr_bool(e.span, true);
91                     self.arm(pats, P(expr))
92                 };
93                 let else_arm = {
94                     let pats = hir_vec![self.pat_wild(e.span)];
95                     let expr = self.expr_bool(e.span, false);
96                     self.arm(pats, P(expr))
97                 };
98                 hir::ExprKind::Match(
99                     P(scrutinee),
100                     vec![then_arm, else_arm].into(),
101                     hir::MatchSource::Normal,
102                 )
103             }
104             // FIXME(#53667): handle lowering of && and parens.
105             ExprKind::If(ref cond, ref then, ref else_opt) => {
106                 // `_ => else_block` where `else_block` is `{}` if there's `None`:
107                 let else_pat = self.pat_wild(e.span);
108                 let (else_expr, contains_else_clause) = match else_opt {
109                     None => (self.expr_block_empty(e.span), false),
110                     Some(els) => (self.lower_expr(els), true),
111                 };
112                 let else_arm = self.arm(hir_vec![else_pat], P(else_expr));
113
114                 // Handle then + scrutinee:
115                 let then_blk = self.lower_block(then, false);
116                 let then_expr = self.expr_block(then_blk, ThinVec::new());
117                 let (then_pats, scrutinee, desugar) = match cond.node {
118                     // `<pat> => <then>`:
119                     ExprKind::Let(ref pats, ref scrutinee) => {
120                         let scrutinee = self.lower_expr(scrutinee);
121                         let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
122                         let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause };
123                         (pats, scrutinee, desugar)
124                     }
125                     // `true => <then>`:
126                     _ => {
127                         // Lower condition:
128                         let cond = self.lower_expr(cond);
129                         let span_block = self.mark_span_with_reason(
130                             DesugaringKind::CondTemporary, cond.span, None
131                         );
132                         // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
133                         // to preserve drop semantics since `if cond { ... }` does not
134                         // let temporaries live outside of `cond`.
135                         let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new());
136
137                         let desugar = hir::MatchSource::IfDesugar { contains_else_clause };
138                         let pats = hir_vec![self.pat_bool(e.span, true)];
139                         (pats, cond, desugar)
140                     }
141                 };
142                 let then_arm = self.arm(then_pats, P(then_expr));
143
144                 hir::ExprKind::Match(P(scrutinee), vec![then_arm, else_arm].into(), desugar)
145             }
146             // FIXME(#53667): handle lowering of && and parens.
147             ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| {
148                 // Note that the block AND the condition are evaluated in the loop scope.
149                 // This is done to allow `break` from inside the condition of the loop.
150
151                 // `_ => break`:
152                 let else_arm = {
153                     let else_pat = this.pat_wild(e.span);
154                     let else_expr = this.expr_break(e.span, ThinVec::new());
155                     this.arm(hir_vec![else_pat], else_expr)
156                 };
157
158                 // Handle then + scrutinee:
159                 let then_blk = this.lower_block(body, false);
160                 let then_expr = this.expr_block(then_blk, ThinVec::new());
161                 let (then_pats, scrutinee, desugar, source) = match cond.node {
162                     ExprKind::Let(ref pats, ref scrutinee) => {
163                         // to:
164                         //
165                         //   [opt_ident]: loop {
166                         //     match <sub_expr> {
167                         //       <pat> => <body>,
168                         //       _ => break
169                         //     }
170                         //   }
171                         let scrutinee = this.with_loop_condition_scope(|t| t.lower_expr(scrutinee));
172                         let pats = pats.iter().map(|pat| this.lower_pat(pat)).collect();
173                         let desugar = hir::MatchSource::WhileLetDesugar;
174                         (pats, scrutinee, desugar, hir::LoopSource::WhileLet)
175                     }
176                     _ => {
177                         // We desugar: `'label: while $cond $body` into:
178                         //
179                         // ```
180                         // 'label: loop {
181                         //     match DropTemps($cond) {
182                         //         true => $body,
183                         //         _ => break,
184                         //     }
185                         // }
186                         // ```
187
188                         // Lower condition:
189                         let cond = this.with_loop_condition_scope(|this| this.lower_expr(cond));
190                         let span_block = this.mark_span_with_reason(
191                             DesugaringKind::CondTemporary, cond.span, None
192                         );
193                         // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
194                         // to preserve drop semantics since `while cond { ... }` does not
195                         // let temporaries live outside of `cond`.
196                         let cond = this.expr_drop_temps(span_block, P(cond), ThinVec::new());
197
198                         let desugar = hir::MatchSource::WhileDesugar;
199                         // `true => <then>`:
200                         let pats = hir_vec![this.pat_bool(e.span, true)];
201                         (pats, cond, desugar, hir::LoopSource::While)
202                     }
203                 };
204                 let then_arm = this.arm(then_pats, P(then_expr));
205
206                 // `match <scrutinee> { ... }`
207                 let match_expr = this.expr_match(
208                     scrutinee.span,
209                     P(scrutinee),
210                     hir_vec![then_arm, else_arm],
211                     desugar,
212                 );
213
214                 // `[opt_ident]: loop { ... }`
215                 hir::ExprKind::Loop(
216                     P(this.block_expr(P(match_expr))),
217                     this.lower_label(opt_label),
218                     source
219                 )
220             }),
221             ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| {
222                 hir::ExprKind::Loop(
223                     this.lower_block(body, false),
224                     this.lower_label(opt_label),
225                     hir::LoopSource::Loop,
226                 )
227             }),
228             ExprKind::TryBlock(ref body) => {
229                 self.with_catch_scope(body.id, |this| {
230                     let unstable_span = this.mark_span_with_reason(
231                         DesugaringKind::TryBlock,
232                         body.span,
233                         this.allow_try_trait.clone(),
234                     );
235                     let mut block = this.lower_block(body, true).into_inner();
236                     let tail = block.expr.take().map_or_else(
237                         || {
238                             let span = this.sess.source_map().end_point(unstable_span);
239                             hir::Expr {
240                                 span,
241                                 node: hir::ExprKind::Tup(hir_vec![]),
242                                 attrs: ThinVec::new(),
243                                 hir_id: this.next_id(),
244                             }
245                         },
246                         |x: P<hir::Expr>| x.into_inner(),
247                     );
248                     block.expr = Some(this.wrap_in_try_constructor(
249                         sym::from_ok, tail, unstable_span));
250                     hir::ExprKind::Block(P(block), None)
251                 })
252             }
253             ExprKind::Match(ref expr, ref arms) => hir::ExprKind::Match(
254                 P(self.lower_expr(expr)),
255                 arms.iter().map(|x| self.lower_arm(x)).collect(),
256                 hir::MatchSource::Normal,
257             ),
258             ExprKind::Async(capture_clause, closure_node_id, ref block) => {
259                 self.make_async_expr(capture_clause, closure_node_id, None, block.span, |this| {
260                     this.with_new_scopes(|this| {
261                         let block = this.lower_block(block, false);
262                         this.expr_block(block, ThinVec::new())
263                     })
264                 })
265             }
266             ExprKind::Await(ref expr) => self.lower_await(e.span, expr),
267             ExprKind::Closure(
268                 capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span
269             ) => {
270                 if let IsAsync::Async { closure_id, .. } = asyncness {
271                     let outer_decl = FnDecl {
272                         inputs: decl.inputs.clone(),
273                         output: FunctionRetTy::Default(fn_decl_span),
274                         c_variadic: false,
275                     };
276                     // We need to lower the declaration outside the new scope, because we
277                     // have to conserve the state of being inside a loop condition for the
278                     // closure argument types.
279                     let fn_decl = self.lower_fn_decl(&outer_decl, None, false, None);
280
281                     self.with_new_scopes(|this| {
282                         // FIXME(cramertj): allow `async` non-`move` closures with arguments.
283                         if capture_clause == CaptureBy::Ref &&
284                             !decl.inputs.is_empty()
285                         {
286                             struct_span_err!(
287                                 this.sess,
288                                 fn_decl_span,
289                                 E0708,
290                                 "`async` non-`move` closures with arguments \
291                                 are not currently supported",
292                             )
293                                 .help("consider using `let` statements to manually capture \
294                                        variables by reference before entering an \
295                                        `async move` closure")
296                                 .emit();
297                         }
298
299                         // Transform `async |x: u8| -> X { ... }` into
300                         // `|x: u8| future_from_generator(|| -> X { ... })`.
301                         let body_id = this.lower_fn_body(&outer_decl, |this| {
302                             let async_ret_ty = if let FunctionRetTy::Ty(ty) = &decl.output {
303                                 Some(ty.clone())
304                             } else { None };
305                             let async_body = this.make_async_expr(
306                                 capture_clause, closure_id, async_ret_ty, body.span,
307                                 |this| {
308                                     this.with_new_scopes(|this| this.lower_expr(body))
309                                 });
310                             this.expr(fn_decl_span, async_body, ThinVec::new())
311                         });
312                         hir::ExprKind::Closure(
313                             this.lower_capture_clause(capture_clause),
314                             fn_decl,
315                             body_id,
316                             fn_decl_span,
317                             None,
318                         )
319                     })
320                 } else {
321                     // Lower outside new scope to preserve `is_in_loop_condition`.
322                     let fn_decl = self.lower_fn_decl(decl, None, false, None);
323
324                     self.with_new_scopes(|this| {
325                         this.current_item = Some(fn_decl_span);
326                         let mut generator_kind = None;
327                         let body_id = this.lower_fn_body(decl, |this| {
328                             let e = this.lower_expr(body);
329                             generator_kind = this.generator_kind;
330                             e
331                         });
332                         let generator_option = this.generator_movability_for_fn(
333                             &decl,
334                             fn_decl_span,
335                             generator_kind,
336                             movability,
337                         );
338                         hir::ExprKind::Closure(
339                             this.lower_capture_clause(capture_clause),
340                             fn_decl,
341                             body_id,
342                             fn_decl_span,
343                             generator_option,
344                         )
345                     })
346                 }
347             }
348             ExprKind::Block(ref blk, opt_label) => {
349                 hir::ExprKind::Block(self.lower_block(blk,
350                                                       opt_label.is_some()),
351                                                       self.lower_label(opt_label))
352             }
353             ExprKind::Assign(ref el, ref er) => {
354                 hir::ExprKind::Assign(P(self.lower_expr(el)), P(self.lower_expr(er)))
355             }
356             ExprKind::AssignOp(op, ref el, ref er) => hir::ExprKind::AssignOp(
357                 self.lower_binop(op),
358                 P(self.lower_expr(el)),
359                 P(self.lower_expr(er)),
360             ),
361             ExprKind::Field(ref el, ident) => hir::ExprKind::Field(P(self.lower_expr(el)), ident),
362             ExprKind::Index(ref el, ref er) => {
363                 hir::ExprKind::Index(P(self.lower_expr(el)), P(self.lower_expr(er)))
364             }
365             // Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`.
366             ExprKind::Range(Some(ref e1), Some(ref e2), RangeLimits::Closed) => {
367                 let id = self.next_id();
368                 let e1 = self.lower_expr(e1);
369                 let e2 = self.lower_expr(e2);
370                 self.expr_call_std_assoc_fn(
371                     id,
372                     e.span,
373                     &[sym::ops, sym::RangeInclusive],
374                     "new",
375                     hir_vec![e1, e2],
376                 )
377             }
378             ExprKind::Range(ref e1, ref e2, lims) => {
379                 use syntax::ast::RangeLimits::*;
380
381                 let path = match (e1, e2, lims) {
382                     (&None, &None, HalfOpen) => sym::RangeFull,
383                     (&Some(..), &None, HalfOpen) => sym::RangeFrom,
384                     (&None, &Some(..), HalfOpen) => sym::RangeTo,
385                     (&Some(..), &Some(..), HalfOpen) => sym::Range,
386                     (&None, &Some(..), Closed) => sym::RangeToInclusive,
387                     (&Some(..), &Some(..), Closed) => unreachable!(),
388                     (_, &None, Closed) => self.diagnostic()
389                         .span_fatal(e.span, "inclusive range with no end")
390                         .raise(),
391                 };
392
393                 let fields = e1.iter()
394                     .map(|e| ("start", e))
395                     .chain(e2.iter().map(|e| ("end", e)))
396                     .map(|(s, e)| {
397                         let expr = P(self.lower_expr(&e));
398                         let ident = Ident::new(Symbol::intern(s), e.span);
399                         self.field(ident, expr, e.span)
400                     })
401                     .collect::<P<[hir::Field]>>();
402
403                 let is_unit = fields.is_empty();
404                 let struct_path = [sym::ops, path];
405                 let struct_path = self.std_path(e.span, &struct_path, None, is_unit);
406                 let struct_path = hir::QPath::Resolved(None, P(struct_path));
407
408                 return hir::Expr {
409                     hir_id: self.lower_node_id(e.id),
410                     node: if is_unit {
411                         hir::ExprKind::Path(struct_path)
412                     } else {
413                         hir::ExprKind::Struct(P(struct_path), fields, None)
414                     },
415                     span: e.span,
416                     attrs: e.attrs.clone(),
417                 };
418             }
419             ExprKind::Path(ref qself, ref path) => {
420                 let qpath = self.lower_qpath(
421                     e.id,
422                     qself,
423                     path,
424                     ParamMode::Optional,
425                     ImplTraitContext::disallowed(),
426                 );
427                 hir::ExprKind::Path(qpath)
428             }
429             ExprKind::Break(opt_label, ref opt_expr) => {
430                 let destination = if self.is_in_loop_condition && opt_label.is_none() {
431                     hir::Destination {
432                         label: None,
433                         target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
434                     }
435                 } else {
436                     self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
437                 };
438                 hir::ExprKind::Break(
439                     destination,
440                     opt_expr.as_ref().map(|x| P(self.lower_expr(x))),
441                 )
442             }
443             ExprKind::Continue(opt_label) => {
444                 hir::ExprKind::Continue(if self.is_in_loop_condition && opt_label.is_none() {
445                     hir::Destination {
446                         label: None,
447                         target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
448                     }
449                 } else {
450                     self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
451                 })
452             }
453             ExprKind::Ret(ref e) => hir::ExprKind::Ret(e.as_ref().map(|x| P(self.lower_expr(x)))),
454             ExprKind::InlineAsm(ref asm) => {
455                 let hir_asm = hir::InlineAsm {
456                     inputs: asm.inputs.iter().map(|&(ref c, _)| c.clone()).collect(),
457                     outputs: asm.outputs
458                         .iter()
459                         .map(|out| hir::InlineAsmOutput {
460                             constraint: out.constraint.clone(),
461                             is_rw: out.is_rw,
462                             is_indirect: out.is_indirect,
463                             span: out.expr.span,
464                         })
465                         .collect(),
466                     asm: asm.asm.clone(),
467                     asm_str_style: asm.asm_str_style,
468                     clobbers: asm.clobbers.clone().into(),
469                     volatile: asm.volatile,
470                     alignstack: asm.alignstack,
471                     dialect: asm.dialect,
472                     ctxt: asm.ctxt,
473                 };
474                 let outputs = asm.outputs
475                     .iter()
476                     .map(|out| self.lower_expr(&out.expr))
477                     .collect();
478                 let inputs = asm.inputs
479                     .iter()
480                     .map(|&(_, ref input)| self.lower_expr(input))
481                     .collect();
482                 hir::ExprKind::InlineAsm(P(hir_asm), outputs, inputs)
483             }
484             ExprKind::Struct(ref path, ref fields, ref maybe_expr) => hir::ExprKind::Struct(
485                 P(self.lower_qpath(
486                     e.id,
487                     &None,
488                     path,
489                     ParamMode::Optional,
490                     ImplTraitContext::disallowed(),
491                 )),
492                 fields.iter().map(|x| self.lower_field(x)).collect(),
493                 maybe_expr.as_ref().map(|x| P(self.lower_expr(x))),
494             ),
495             ExprKind::Paren(ref ex) => {
496                 let mut ex = self.lower_expr(ex);
497                 // Include parens in span, but only if it is a super-span.
498                 if e.span.contains(ex.span) {
499                     ex.span = e.span;
500                 }
501                 // Merge attributes into the inner expression.
502                 let mut attrs = e.attrs.clone();
503                 attrs.extend::<Vec<_>>(ex.attrs.into());
504                 ex.attrs = attrs;
505                 return ex;
506             }
507
508             ExprKind::Yield(ref opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
509
510             ExprKind::Err => hir::ExprKind::Err,
511
512             // Desugar `ExprForLoop`
513             // from: `[opt_ident]: for <pat> in <head> <body>`
514             ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => {
515                 return self.lower_expr_for(e, pat, head, body, opt_label);
516             }
517             ExprKind::Try(ref sub_expr) => self.lower_expr_try(e.span, sub_expr),
518             ExprKind::Mac(_) => panic!("Shouldn't exist here"),
519         };
520
521         hir::Expr {
522             hir_id: self.lower_node_id(e.id),
523             node: kind,
524             span: e.span,
525             attrs: e.attrs.clone(),
526         }
527     }
528
529     fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind {
530         match self.generator_kind {
531             Some(hir::GeneratorKind::Gen) => {},
532             Some(hir::GeneratorKind::Async) => {
533                 span_err!(
534                     self.sess,
535                     span,
536                     E0727,
537                     "`async` generators are not yet supported",
538                 );
539                 self.sess.abort_if_errors();
540             },
541             None => self.generator_kind = Some(hir::GeneratorKind::Gen),
542         }
543
544         let expr = opt_expr
545             .as_ref()
546             .map(|x| self.lower_expr(x))
547             .unwrap_or_else(|| self.expr_unit(span));
548
549         hir::ExprKind::Yield(P(expr), hir::YieldSource::Yield)
550     }
551
552     /// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into:
553     /// ```rust
554     /// {
555     ///     let result = match ::std::iter::IntoIterator::into_iter(<head>) {
556     ///         mut iter => {
557     ///             [opt_ident]: loop {
558     ///                 let mut __next;
559     ///                 match ::std::iter::Iterator::next(&mut iter) {
560     ///                     ::std::option::Option::Some(val) => __next = val,
561     ///                     ::std::option::Option::None => break
562     ///                 };
563     ///                 let <pat> = __next;
564     ///                 StmtKind::Expr(<body>);
565     ///             }
566     ///         }
567     ///     };
568     ///     result
569     /// }
570     /// ```
571     fn lower_expr_for(
572         &mut self,
573         e: &Expr,
574         pat: &Pat,
575         head: &Expr,
576         body: &Block,
577         opt_label: Option<Label>,
578     ) -> hir::Expr {
579         // expand <head>
580         let mut head = self.lower_expr(head);
581         let head_sp = head.span;
582         let desugared_span = self.mark_span_with_reason(
583             DesugaringKind::ForLoop,
584             head_sp,
585             None,
586         );
587         head.span = desugared_span;
588
589         let iter = Ident::with_empty_ctxt(sym::iter);
590
591         let next_ident = Ident::with_empty_ctxt(sym::__next);
592         let (next_pat, next_pat_hid) = self.pat_ident_binding_mode(
593             desugared_span,
594             next_ident,
595             hir::BindingAnnotation::Mutable,
596         );
597
598         // `::std::option::Option::Some(val) => __next = val`
599         let pat_arm = {
600             let val_ident = Ident::with_empty_ctxt(sym::val);
601             let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident);
602             let val_expr = P(self.expr_ident(pat.span, val_ident, val_pat_hid));
603             let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat_hid));
604             let assign = P(self.expr(
605                 pat.span,
606                 hir::ExprKind::Assign(next_expr, val_expr),
607                 ThinVec::new(),
608             ));
609             let some_pat = self.pat_some(pat.span, val_pat);
610             self.arm(hir_vec![some_pat], assign)
611         };
612
613         // `::std::option::Option::None => break`
614         let break_arm = {
615             let break_expr =
616                 self.with_loop_scope(e.id, |this| this.expr_break(e.span, ThinVec::new()));
617             let pat = self.pat_none(e.span);
618             self.arm(hir_vec![pat], break_expr)
619         };
620
621         // `mut iter`
622         let (iter_pat, iter_pat_nid) = self.pat_ident_binding_mode(
623             desugared_span,
624             iter,
625             hir::BindingAnnotation::Mutable
626         );
627
628         // `match ::std::iter::Iterator::next(&mut iter) { ... }`
629         let match_expr = {
630             let iter = P(self.expr_ident(head_sp, iter, iter_pat_nid));
631             let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter);
632             let next_path = &[sym::iter, sym::Iterator, sym::next];
633             let next_expr = P(self.expr_call_std_path(
634                 head_sp,
635                 next_path,
636                 hir_vec![ref_mut_iter],
637             ));
638             let arms = hir_vec![pat_arm, break_arm];
639
640             self.expr_match(head_sp, next_expr, arms, hir::MatchSource::ForLoopDesugar)
641         };
642         let match_stmt = self.stmt_expr(head_sp, match_expr);
643
644         let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat_hid));
645
646         // `let mut __next`
647         let next_let = self.stmt_let_pat(
648             ThinVec::new(),
649             desugared_span,
650             None,
651             next_pat,
652             hir::LocalSource::ForLoopDesugar,
653         );
654
655         // `let <pat> = __next`
656         let pat = self.lower_pat(pat);
657         let pat_let = self.stmt_let_pat(
658             ThinVec::new(),
659             head_sp,
660             Some(next_expr),
661             pat,
662             hir::LocalSource::ForLoopDesugar,
663         );
664
665         let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
666         let body_expr = self.expr_block(body_block, ThinVec::new());
667         let body_stmt = self.stmt_expr(body.span, body_expr);
668
669         let loop_block = P(self.block_all(
670             e.span,
671             hir_vec![next_let, match_stmt, pat_let, body_stmt],
672             None,
673         ));
674
675         // `[opt_ident]: loop { ... }`
676         let loop_expr = hir::ExprKind::Loop(
677             loop_block,
678             self.lower_label(opt_label),
679             hir::LoopSource::ForLoop,
680         );
681         let loop_expr = P(hir::Expr {
682             hir_id: self.lower_node_id(e.id),
683             node: loop_expr,
684             span: e.span,
685             attrs: ThinVec::new(),
686         });
687
688         // `mut iter => { ... }`
689         let iter_arm = self.arm(hir_vec![iter_pat], loop_expr);
690
691         // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
692         let into_iter_expr = {
693             let into_iter_path =
694                 &[sym::iter, sym::IntoIterator, sym::into_iter];
695             P(self.expr_call_std_path(
696                 head_sp,
697                 into_iter_path,
698                 hir_vec![head],
699             ))
700         };
701
702         let match_expr = P(self.expr_match(
703             head_sp,
704             into_iter_expr,
705             hir_vec![iter_arm],
706             hir::MatchSource::ForLoopDesugar,
707         ));
708
709         // This is effectively `{ let _result = ...; _result }`.
710         // The construct was introduced in #21984 and is necessary to make sure that
711         // temporaries in the `head` expression are dropped and do not leak to the
712         // surrounding scope of the `match` since the `match` is not a terminating scope.
713         //
714         // Also, add the attributes to the outer returned expr node.
715         self.expr_drop_temps(head_sp, match_expr, e.attrs.clone())
716     }
717
718     /// Desugar `ExprKind::Try` from: `<expr>?` into:
719     /// ```rust
720     /// match Try::into_result(<expr>) {
721     ///     Ok(val) => #[allow(unreachable_code)] val,
722     ///     Err(err) => #[allow(unreachable_code)]
723     ///                 // If there is an enclosing `try {...}`:
724     ///                 break 'catch_target Try::from_error(From::from(err)),
725     ///                 // Otherwise:
726     ///                 return Try::from_error(From::from(err)),
727     /// }
728     /// ```
729     fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind {
730         let unstable_span = self.mark_span_with_reason(
731             DesugaringKind::QuestionMark,
732             span,
733             self.allow_try_trait.clone(),
734         );
735         let try_span = self.sess.source_map().end_point(span);
736         let try_span = self.mark_span_with_reason(
737             DesugaringKind::QuestionMark,
738             try_span,
739             self.allow_try_trait.clone(),
740         );
741
742         // `Try::into_result(<expr>)`
743         let scrutinee = {
744             // expand <expr>
745             let sub_expr = self.lower_expr(sub_expr);
746
747             let path = &[sym::ops, sym::Try, sym::into_result];
748             P(self.expr_call_std_path(unstable_span, path, hir_vec![sub_expr]))
749         };
750
751         // `#[allow(unreachable_code)]`
752         let attr = {
753             // `allow(unreachable_code)`
754             let allow = {
755                 let allow_ident = Ident::new(sym::allow, span);
756                 let uc_ident = Ident::new(sym::unreachable_code, span);
757                 let uc_nested = attr::mk_nested_word_item(uc_ident);
758                 attr::mk_list_item(allow_ident, vec![uc_nested])
759             };
760             attr::mk_attr_outer(allow)
761         };
762         let attrs = vec![attr];
763
764         // `Ok(val) => #[allow(unreachable_code)] val,`
765         let ok_arm = {
766             let val_ident = Ident::with_empty_ctxt(sym::val);
767             let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident);
768             let val_expr = P(self.expr_ident_with_attrs(
769                 span,
770                 val_ident,
771                 val_pat_nid,
772                 ThinVec::from(attrs.clone()),
773             ));
774             let ok_pat = self.pat_ok(span, val_pat);
775
776             self.arm(hir_vec![ok_pat], val_expr)
777         };
778
779         // `Err(err) => #[allow(unreachable_code)]
780         //              return Try::from_error(From::from(err)),`
781         let err_arm = {
782             let err_ident = Ident::with_empty_ctxt(sym::err);
783             let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
784             let from_expr = {
785                 let from_path = &[sym::convert, sym::From, sym::from];
786                 let err_expr = self.expr_ident(try_span, err_ident, err_local_nid);
787                 self.expr_call_std_path(try_span, from_path, hir_vec![err_expr])
788             };
789             let from_err_expr =
790                 self.wrap_in_try_constructor(sym::from_error, from_expr, unstable_span);
791             let thin_attrs = ThinVec::from(attrs);
792             let catch_scope = self.catch_scopes.last().map(|x| *x);
793             let ret_expr = if let Some(catch_node) = catch_scope {
794                 let target_id = Ok(self.lower_node_id(catch_node));
795                 P(self.expr(
796                     try_span,
797                     hir::ExprKind::Break(
798                         hir::Destination {
799                             label: None,
800                             target_id,
801                         },
802                         Some(from_err_expr),
803                     ),
804                     thin_attrs,
805                 ))
806             } else {
807                 P(self.expr(try_span, hir::ExprKind::Ret(Some(from_err_expr)), thin_attrs))
808             };
809
810             let err_pat = self.pat_err(try_span, err_local);
811             self.arm(hir_vec![err_pat], ret_expr)
812         };
813
814         hir::ExprKind::Match(
815             scrutinee,
816             hir_vec![err_arm, ok_arm],
817             hir::MatchSource::TryDesugar,
818         )
819     }
820 }