]> git.lizzy.rs Git - rust.git/blob - src/librustc/hir/lowering/expr.rs
lowering: extract lower_expr_range
[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                 self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims)
380             }
381             ExprKind::Path(ref qself, ref path) => {
382                 let qpath = self.lower_qpath(
383                     e.id,
384                     qself,
385                     path,
386                     ParamMode::Optional,
387                     ImplTraitContext::disallowed(),
388                 );
389                 hir::ExprKind::Path(qpath)
390             }
391             ExprKind::Break(opt_label, ref opt_expr) => {
392                 let destination = if self.is_in_loop_condition && opt_label.is_none() {
393                     hir::Destination {
394                         label: None,
395                         target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
396                     }
397                 } else {
398                     self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
399                 };
400                 hir::ExprKind::Break(
401                     destination,
402                     opt_expr.as_ref().map(|x| P(self.lower_expr(x))),
403                 )
404             }
405             ExprKind::Continue(opt_label) => {
406                 hir::ExprKind::Continue(if self.is_in_loop_condition && opt_label.is_none() {
407                     hir::Destination {
408                         label: None,
409                         target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
410                     }
411                 } else {
412                     self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
413                 })
414             }
415             ExprKind::Ret(ref e) => hir::ExprKind::Ret(e.as_ref().map(|x| P(self.lower_expr(x)))),
416             ExprKind::InlineAsm(ref asm) => self.lower_expr_asm(asm),
417             ExprKind::Struct(ref path, ref fields, ref maybe_expr) => hir::ExprKind::Struct(
418                 P(self.lower_qpath(
419                     e.id,
420                     &None,
421                     path,
422                     ParamMode::Optional,
423                     ImplTraitContext::disallowed(),
424                 )),
425                 fields.iter().map(|x| self.lower_field(x)).collect(),
426                 maybe_expr.as_ref().map(|x| P(self.lower_expr(x))),
427             ),
428             ExprKind::Paren(ref ex) => {
429                 let mut ex = self.lower_expr(ex);
430                 // Include parens in span, but only if it is a super-span.
431                 if e.span.contains(ex.span) {
432                     ex.span = e.span;
433                 }
434                 // Merge attributes into the inner expression.
435                 let mut attrs = e.attrs.clone();
436                 attrs.extend::<Vec<_>>(ex.attrs.into());
437                 ex.attrs = attrs;
438                 return ex;
439             }
440
441             ExprKind::Yield(ref opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
442
443             ExprKind::Err => hir::ExprKind::Err,
444
445             // Desugar `ExprForLoop`
446             // from: `[opt_ident]: for <pat> in <head> <body>`
447             ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => {
448                 return self.lower_expr_for(e, pat, head, body, opt_label);
449             }
450             ExprKind::Try(ref sub_expr) => self.lower_expr_try(e.span, sub_expr),
451             ExprKind::Mac(_) => panic!("Shouldn't exist here"),
452         };
453
454         hir::Expr {
455             hir_id: self.lower_node_id(e.id),
456             node: kind,
457             span: e.span,
458             attrs: e.attrs.clone(),
459         }
460     }
461
462     fn lower_expr_range(
463         &mut self,
464         span: Span,
465         e1: Option<&Expr>,
466         e2: Option<&Expr>,
467         lims: RangeLimits,
468     ) -> hir::ExprKind {
469         use syntax::ast::RangeLimits::*;
470
471         let path = match (e1, e2, lims) {
472             (None, None, HalfOpen) => sym::RangeFull,
473             (Some(..), None, HalfOpen) => sym::RangeFrom,
474             (None, Some(..), HalfOpen) => sym::RangeTo,
475             (Some(..), Some(..), HalfOpen) => sym::Range,
476             (None, Some(..), Closed) => sym::RangeToInclusive,
477             (Some(..), Some(..), Closed) => unreachable!(),
478             (_, None, Closed) => self.diagnostic()
479                 .span_fatal(span, "inclusive range with no end")
480                 .raise(),
481         };
482
483         let fields = e1.iter()
484             .map(|e| ("start", e))
485             .chain(e2.iter().map(|e| ("end", e)))
486             .map(|(s, e)| {
487                 let expr = P(self.lower_expr(&e));
488                 let ident = Ident::new(Symbol::intern(s), e.span);
489                 self.field(ident, expr, e.span)
490             })
491             .collect::<P<[hir::Field]>>();
492
493         let is_unit = fields.is_empty();
494         let struct_path = [sym::ops, path];
495         let struct_path = self.std_path(span, &struct_path, None, is_unit);
496         let struct_path = hir::QPath::Resolved(None, P(struct_path));
497
498         if is_unit {
499             hir::ExprKind::Path(struct_path)
500         } else {
501             hir::ExprKind::Struct(P(struct_path), fields, None)
502         }
503     }
504
505     fn lower_expr_asm(&mut self, asm: &InlineAsm) -> hir::ExprKind {
506         let hir_asm = hir::InlineAsm {
507             inputs: asm.inputs.iter().map(|&(ref c, _)| c.clone()).collect(),
508             outputs: asm.outputs
509                 .iter()
510                 .map(|out| hir::InlineAsmOutput {
511                     constraint: out.constraint.clone(),
512                     is_rw: out.is_rw,
513                     is_indirect: out.is_indirect,
514                     span: out.expr.span,
515                 })
516                 .collect(),
517             asm: asm.asm.clone(),
518             asm_str_style: asm.asm_str_style,
519             clobbers: asm.clobbers.clone().into(),
520             volatile: asm.volatile,
521             alignstack: asm.alignstack,
522             dialect: asm.dialect,
523             ctxt: asm.ctxt,
524         };
525
526         let outputs = asm.outputs
527             .iter()
528             .map(|out| self.lower_expr(&out.expr))
529             .collect();
530
531         let inputs = asm.inputs
532             .iter()
533             .map(|&(_, ref input)| self.lower_expr(input))
534             .collect();
535
536         hir::ExprKind::InlineAsm(P(hir_asm), outputs, inputs)
537     }
538
539     fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind {
540         match self.generator_kind {
541             Some(hir::GeneratorKind::Gen) => {},
542             Some(hir::GeneratorKind::Async) => {
543                 span_err!(
544                     self.sess,
545                     span,
546                     E0727,
547                     "`async` generators are not yet supported",
548                 );
549                 self.sess.abort_if_errors();
550             },
551             None => self.generator_kind = Some(hir::GeneratorKind::Gen),
552         }
553
554         let expr = opt_expr
555             .as_ref()
556             .map(|x| self.lower_expr(x))
557             .unwrap_or_else(|| self.expr_unit(span));
558
559         hir::ExprKind::Yield(P(expr), hir::YieldSource::Yield)
560     }
561
562     /// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into:
563     /// ```rust
564     /// {
565     ///     let result = match ::std::iter::IntoIterator::into_iter(<head>) {
566     ///         mut iter => {
567     ///             [opt_ident]: loop {
568     ///                 let mut __next;
569     ///                 match ::std::iter::Iterator::next(&mut iter) {
570     ///                     ::std::option::Option::Some(val) => __next = val,
571     ///                     ::std::option::Option::None => break
572     ///                 };
573     ///                 let <pat> = __next;
574     ///                 StmtKind::Expr(<body>);
575     ///             }
576     ///         }
577     ///     };
578     ///     result
579     /// }
580     /// ```
581     fn lower_expr_for(
582         &mut self,
583         e: &Expr,
584         pat: &Pat,
585         head: &Expr,
586         body: &Block,
587         opt_label: Option<Label>,
588     ) -> hir::Expr {
589         // expand <head>
590         let mut head = self.lower_expr(head);
591         let head_sp = head.span;
592         let desugared_span = self.mark_span_with_reason(
593             DesugaringKind::ForLoop,
594             head_sp,
595             None,
596         );
597         head.span = desugared_span;
598
599         let iter = Ident::with_empty_ctxt(sym::iter);
600
601         let next_ident = Ident::with_empty_ctxt(sym::__next);
602         let (next_pat, next_pat_hid) = self.pat_ident_binding_mode(
603             desugared_span,
604             next_ident,
605             hir::BindingAnnotation::Mutable,
606         );
607
608         // `::std::option::Option::Some(val) => __next = val`
609         let pat_arm = {
610             let val_ident = Ident::with_empty_ctxt(sym::val);
611             let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident);
612             let val_expr = P(self.expr_ident(pat.span, val_ident, val_pat_hid));
613             let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat_hid));
614             let assign = P(self.expr(
615                 pat.span,
616                 hir::ExprKind::Assign(next_expr, val_expr),
617                 ThinVec::new(),
618             ));
619             let some_pat = self.pat_some(pat.span, val_pat);
620             self.arm(hir_vec![some_pat], assign)
621         };
622
623         // `::std::option::Option::None => break`
624         let break_arm = {
625             let break_expr =
626                 self.with_loop_scope(e.id, |this| this.expr_break(e.span, ThinVec::new()));
627             let pat = self.pat_none(e.span);
628             self.arm(hir_vec![pat], break_expr)
629         };
630
631         // `mut iter`
632         let (iter_pat, iter_pat_nid) = self.pat_ident_binding_mode(
633             desugared_span,
634             iter,
635             hir::BindingAnnotation::Mutable
636         );
637
638         // `match ::std::iter::Iterator::next(&mut iter) { ... }`
639         let match_expr = {
640             let iter = P(self.expr_ident(head_sp, iter, iter_pat_nid));
641             let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter);
642             let next_path = &[sym::iter, sym::Iterator, sym::next];
643             let next_expr = P(self.expr_call_std_path(
644                 head_sp,
645                 next_path,
646                 hir_vec![ref_mut_iter],
647             ));
648             let arms = hir_vec![pat_arm, break_arm];
649
650             self.expr_match(head_sp, next_expr, arms, hir::MatchSource::ForLoopDesugar)
651         };
652         let match_stmt = self.stmt_expr(head_sp, match_expr);
653
654         let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat_hid));
655
656         // `let mut __next`
657         let next_let = self.stmt_let_pat(
658             ThinVec::new(),
659             desugared_span,
660             None,
661             next_pat,
662             hir::LocalSource::ForLoopDesugar,
663         );
664
665         // `let <pat> = __next`
666         let pat = self.lower_pat(pat);
667         let pat_let = self.stmt_let_pat(
668             ThinVec::new(),
669             head_sp,
670             Some(next_expr),
671             pat,
672             hir::LocalSource::ForLoopDesugar,
673         );
674
675         let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
676         let body_expr = self.expr_block(body_block, ThinVec::new());
677         let body_stmt = self.stmt_expr(body.span, body_expr);
678
679         let loop_block = P(self.block_all(
680             e.span,
681             hir_vec![next_let, match_stmt, pat_let, body_stmt],
682             None,
683         ));
684
685         // `[opt_ident]: loop { ... }`
686         let loop_expr = hir::ExprKind::Loop(
687             loop_block,
688             self.lower_label(opt_label),
689             hir::LoopSource::ForLoop,
690         );
691         let loop_expr = P(hir::Expr {
692             hir_id: self.lower_node_id(e.id),
693             node: loop_expr,
694             span: e.span,
695             attrs: ThinVec::new(),
696         });
697
698         // `mut iter => { ... }`
699         let iter_arm = self.arm(hir_vec![iter_pat], loop_expr);
700
701         // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
702         let into_iter_expr = {
703             let into_iter_path =
704                 &[sym::iter, sym::IntoIterator, sym::into_iter];
705             P(self.expr_call_std_path(
706                 head_sp,
707                 into_iter_path,
708                 hir_vec![head],
709             ))
710         };
711
712         let match_expr = P(self.expr_match(
713             head_sp,
714             into_iter_expr,
715             hir_vec![iter_arm],
716             hir::MatchSource::ForLoopDesugar,
717         ));
718
719         // This is effectively `{ let _result = ...; _result }`.
720         // The construct was introduced in #21984 and is necessary to make sure that
721         // temporaries in the `head` expression are dropped and do not leak to the
722         // surrounding scope of the `match` since the `match` is not a terminating scope.
723         //
724         // Also, add the attributes to the outer returned expr node.
725         self.expr_drop_temps(head_sp, match_expr, e.attrs.clone())
726     }
727
728     /// Desugar `ExprKind::Try` from: `<expr>?` into:
729     /// ```rust
730     /// match Try::into_result(<expr>) {
731     ///     Ok(val) => #[allow(unreachable_code)] val,
732     ///     Err(err) => #[allow(unreachable_code)]
733     ///                 // If there is an enclosing `try {...}`:
734     ///                 break 'catch_target Try::from_error(From::from(err)),
735     ///                 // Otherwise:
736     ///                 return Try::from_error(From::from(err)),
737     /// }
738     /// ```
739     fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind {
740         let unstable_span = self.mark_span_with_reason(
741             DesugaringKind::QuestionMark,
742             span,
743             self.allow_try_trait.clone(),
744         );
745         let try_span = self.sess.source_map().end_point(span);
746         let try_span = self.mark_span_with_reason(
747             DesugaringKind::QuestionMark,
748             try_span,
749             self.allow_try_trait.clone(),
750         );
751
752         // `Try::into_result(<expr>)`
753         let scrutinee = {
754             // expand <expr>
755             let sub_expr = self.lower_expr(sub_expr);
756
757             let path = &[sym::ops, sym::Try, sym::into_result];
758             P(self.expr_call_std_path(unstable_span, path, hir_vec![sub_expr]))
759         };
760
761         // `#[allow(unreachable_code)]`
762         let attr = {
763             // `allow(unreachable_code)`
764             let allow = {
765                 let allow_ident = Ident::new(sym::allow, span);
766                 let uc_ident = Ident::new(sym::unreachable_code, span);
767                 let uc_nested = attr::mk_nested_word_item(uc_ident);
768                 attr::mk_list_item(allow_ident, vec![uc_nested])
769             };
770             attr::mk_attr_outer(allow)
771         };
772         let attrs = vec![attr];
773
774         // `Ok(val) => #[allow(unreachable_code)] val,`
775         let ok_arm = {
776             let val_ident = Ident::with_empty_ctxt(sym::val);
777             let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident);
778             let val_expr = P(self.expr_ident_with_attrs(
779                 span,
780                 val_ident,
781                 val_pat_nid,
782                 ThinVec::from(attrs.clone()),
783             ));
784             let ok_pat = self.pat_ok(span, val_pat);
785
786             self.arm(hir_vec![ok_pat], val_expr)
787         };
788
789         // `Err(err) => #[allow(unreachable_code)]
790         //              return Try::from_error(From::from(err)),`
791         let err_arm = {
792             let err_ident = Ident::with_empty_ctxt(sym::err);
793             let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
794             let from_expr = {
795                 let from_path = &[sym::convert, sym::From, sym::from];
796                 let err_expr = self.expr_ident(try_span, err_ident, err_local_nid);
797                 self.expr_call_std_path(try_span, from_path, hir_vec![err_expr])
798             };
799             let from_err_expr =
800                 self.wrap_in_try_constructor(sym::from_error, from_expr, unstable_span);
801             let thin_attrs = ThinVec::from(attrs);
802             let catch_scope = self.catch_scopes.last().map(|x| *x);
803             let ret_expr = if let Some(catch_node) = catch_scope {
804                 let target_id = Ok(self.lower_node_id(catch_node));
805                 P(self.expr(
806                     try_span,
807                     hir::ExprKind::Break(
808                         hir::Destination {
809                             label: None,
810                             target_id,
811                         },
812                         Some(from_err_expr),
813                     ),
814                     thin_attrs,
815                 ))
816             } else {
817                 P(self.expr(try_span, hir::ExprKind::Ret(Some(from_err_expr)), thin_attrs))
818             };
819
820             let err_pat = self.pat_err(try_span, err_local);
821             self.arm(hir_vec![err_pat], ret_expr)
822         };
823
824         hir::ExprKind::Match(
825             scrutinee,
826             hir_vec![err_arm, ok_arm],
827             hir::MatchSource::TryDesugar,
828         )
829     }
830 }