]> git.lizzy.rs Git - rust.git/blob - src/librustc/hir/lowering/expr.rs
lowering: move lower_expr -> expr.rs
[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};
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) => {
509                 match self.generator_kind {
510                     Some(hir::GeneratorKind::Gen) => {},
511                     Some(hir::GeneratorKind::Async) => {
512                         span_err!(
513                             self.sess,
514                             e.span,
515                             E0727,
516                             "`async` generators are not yet supported",
517                         );
518                         self.sess.abort_if_errors();
519                     },
520                     None => {
521                         self.generator_kind = Some(hir::GeneratorKind::Gen);
522                     }
523                 }
524                 let expr = opt_expr
525                     .as_ref()
526                     .map(|x| self.lower_expr(x))
527                     .unwrap_or_else(|| self.expr_unit(e.span));
528                 hir::ExprKind::Yield(P(expr), hir::YieldSource::Yield)
529             }
530
531             ExprKind::Err => hir::ExprKind::Err,
532
533             // Desugar `ExprForLoop`
534             // from: `[opt_ident]: for <pat> in <head> <body>`
535             ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => {
536                 // to:
537                 //
538                 //   {
539                 //     let result = match ::std::iter::IntoIterator::into_iter(<head>) {
540                 //       mut iter => {
541                 //         [opt_ident]: loop {
542                 //           let mut __next;
543                 //           match ::std::iter::Iterator::next(&mut iter) {
544                 //             ::std::option::Option::Some(val) => __next = val,
545                 //             ::std::option::Option::None => break
546                 //           };
547                 //           let <pat> = __next;
548                 //           StmtKind::Expr(<body>);
549                 //         }
550                 //       }
551                 //     };
552                 //     result
553                 //   }
554
555                 // expand <head>
556                 let mut head = self.lower_expr(head);
557                 let head_sp = head.span;
558                 let desugared_span = self.mark_span_with_reason(
559                     DesugaringKind::ForLoop,
560                     head_sp,
561                     None,
562                 );
563                 head.span = desugared_span;
564
565                 let iter = Ident::with_empty_ctxt(sym::iter);
566
567                 let next_ident = Ident::with_empty_ctxt(sym::__next);
568                 let (next_pat, next_pat_hid) = self.pat_ident_binding_mode(
569                     desugared_span,
570                     next_ident,
571                     hir::BindingAnnotation::Mutable,
572                 );
573
574                 // `::std::option::Option::Some(val) => __next = val`
575                 let pat_arm = {
576                     let val_ident = Ident::with_empty_ctxt(sym::val);
577                     let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident);
578                     let val_expr = P(self.expr_ident(pat.span, val_ident, val_pat_hid));
579                     let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat_hid));
580                     let assign = P(self.expr(
581                         pat.span,
582                         hir::ExprKind::Assign(next_expr, val_expr),
583                         ThinVec::new(),
584                     ));
585                     let some_pat = self.pat_some(pat.span, val_pat);
586                     self.arm(hir_vec![some_pat], assign)
587                 };
588
589                 // `::std::option::Option::None => break`
590                 let break_arm = {
591                     let break_expr =
592                         self.with_loop_scope(e.id, |this| this.expr_break(e.span, ThinVec::new()));
593                     let pat = self.pat_none(e.span);
594                     self.arm(hir_vec![pat], break_expr)
595                 };
596
597                 // `mut iter`
598                 let (iter_pat, iter_pat_nid) = self.pat_ident_binding_mode(
599                     desugared_span,
600                     iter,
601                     hir::BindingAnnotation::Mutable
602                 );
603
604                 // `match ::std::iter::Iterator::next(&mut iter) { ... }`
605                 let match_expr = {
606                     let iter = P(self.expr_ident(head_sp, iter, iter_pat_nid));
607                     let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter);
608                     let next_path = &[sym::iter, sym::Iterator, sym::next];
609                     let next_expr = P(self.expr_call_std_path(
610                         head_sp,
611                         next_path,
612                         hir_vec![ref_mut_iter],
613                     ));
614                     let arms = hir_vec![pat_arm, break_arm];
615
616                     self.expr_match(head_sp, next_expr, arms, hir::MatchSource::ForLoopDesugar)
617                 };
618                 let match_stmt = self.stmt_expr(head_sp, match_expr);
619
620                 let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat_hid));
621
622                 // `let mut __next`
623                 let next_let = self.stmt_let_pat(
624                     ThinVec::new(),
625                     desugared_span,
626                     None,
627                     next_pat,
628                     hir::LocalSource::ForLoopDesugar,
629                 );
630
631                 // `let <pat> = __next`
632                 let pat = self.lower_pat(pat);
633                 let pat_let = self.stmt_let_pat(
634                     ThinVec::new(),
635                     head_sp,
636                     Some(next_expr),
637                     pat,
638                     hir::LocalSource::ForLoopDesugar,
639                 );
640
641                 let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
642                 let body_expr = self.expr_block(body_block, ThinVec::new());
643                 let body_stmt = self.stmt_expr(body.span, body_expr);
644
645                 let loop_block = P(self.block_all(
646                     e.span,
647                     hir_vec![next_let, match_stmt, pat_let, body_stmt],
648                     None,
649                 ));
650
651                 // `[opt_ident]: loop { ... }`
652                 let loop_expr = hir::ExprKind::Loop(
653                     loop_block,
654                     self.lower_label(opt_label),
655                     hir::LoopSource::ForLoop,
656                 );
657                 let loop_expr = P(hir::Expr {
658                     hir_id: self.lower_node_id(e.id),
659                     node: loop_expr,
660                     span: e.span,
661                     attrs: ThinVec::new(),
662                 });
663
664                 // `mut iter => { ... }`
665                 let iter_arm = self.arm(hir_vec![iter_pat], loop_expr);
666
667                 // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
668                 let into_iter_expr = {
669                     let into_iter_path =
670                         &[sym::iter, sym::IntoIterator, sym::into_iter];
671                     P(self.expr_call_std_path(
672                         head_sp,
673                         into_iter_path,
674                         hir_vec![head],
675                     ))
676                 };
677
678                 let match_expr = P(self.expr_match(
679                     head_sp,
680                     into_iter_expr,
681                     hir_vec![iter_arm],
682                     hir::MatchSource::ForLoopDesugar,
683                 ));
684
685                 // This is effectively `{ let _result = ...; _result }`.
686                 // The construct was introduced in #21984 and is necessary to make sure that
687                 // temporaries in the `head` expression are dropped and do not leak to the
688                 // surrounding scope of the `match` since the `match` is not a terminating scope.
689                 //
690                 // Also, add the attributes to the outer returned expr node.
691                 return self.expr_drop_temps(head_sp, match_expr, e.attrs.clone())
692             }
693
694             // Desugar `ExprKind::Try`
695             // from: `<expr>?`
696             ExprKind::Try(ref sub_expr) => {
697                 // into:
698                 //
699                 // match Try::into_result(<expr>) {
700                 //     Ok(val) => #[allow(unreachable_code)] val,
701                 //     Err(err) => #[allow(unreachable_code)]
702                 //                 // If there is an enclosing `catch {...}`
703                 //                 break 'catch_target Try::from_error(From::from(err)),
704                 //                 // Otherwise
705                 //                 return Try::from_error(From::from(err)),
706                 // }
707
708                 let unstable_span = self.mark_span_with_reason(
709                     DesugaringKind::QuestionMark,
710                     e.span,
711                     self.allow_try_trait.clone(),
712                 );
713                 let try_span = self.sess.source_map().end_point(e.span);
714                 let try_span = self.mark_span_with_reason(
715                     DesugaringKind::QuestionMark,
716                     try_span,
717                     self.allow_try_trait.clone(),
718                 );
719
720                 // `Try::into_result(<expr>)`
721                 let discr = {
722                     // expand <expr>
723                     let sub_expr = self.lower_expr(sub_expr);
724
725                     let path = &[sym::ops, sym::Try, sym::into_result];
726                     P(self.expr_call_std_path(
727                         unstable_span,
728                         path,
729                         hir_vec![sub_expr],
730                     ))
731                 };
732
733                 // `#[allow(unreachable_code)]`
734                 let attr = {
735                     // `allow(unreachable_code)`
736                     let allow = {
737                         let allow_ident = Ident::new(sym::allow, e.span);
738                         let uc_ident = Ident::new(sym::unreachable_code, e.span);
739                         let uc_nested = attr::mk_nested_word_item(uc_ident);
740                         attr::mk_list_item(allow_ident, vec![uc_nested])
741                     };
742                     attr::mk_attr_outer(allow)
743                 };
744                 let attrs = vec![attr];
745
746                 // `Ok(val) => #[allow(unreachable_code)] val,`
747                 let ok_arm = {
748                     let val_ident = Ident::with_empty_ctxt(sym::val);
749                     let (val_pat, val_pat_nid) = self.pat_ident(e.span, val_ident);
750                     let val_expr = P(self.expr_ident_with_attrs(
751                         e.span,
752                         val_ident,
753                         val_pat_nid,
754                         ThinVec::from(attrs.clone()),
755                     ));
756                     let ok_pat = self.pat_ok(e.span, val_pat);
757
758                     self.arm(hir_vec![ok_pat], val_expr)
759                 };
760
761                 // `Err(err) => #[allow(unreachable_code)]
762                 //              return Try::from_error(From::from(err)),`
763                 let err_arm = {
764                     let err_ident = Ident::with_empty_ctxt(sym::err);
765                     let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
766                     let from_expr = {
767                         let from_path = &[sym::convert, sym::From, sym::from];
768                         let err_expr = self.expr_ident(try_span, err_ident, err_local_nid);
769                         self.expr_call_std_path(try_span, from_path, hir_vec![err_expr])
770                     };
771                     let from_err_expr =
772                         self.wrap_in_try_constructor(sym::from_error, from_expr, unstable_span);
773                     let thin_attrs = ThinVec::from(attrs);
774                     let catch_scope = self.catch_scopes.last().map(|x| *x);
775                     let ret_expr = if let Some(catch_node) = catch_scope {
776                         let target_id = Ok(self.lower_node_id(catch_node));
777                         P(self.expr(
778                             try_span,
779                             hir::ExprKind::Break(
780                                 hir::Destination {
781                                     label: None,
782                                     target_id,
783                                 },
784                                 Some(from_err_expr),
785                             ),
786                             thin_attrs,
787                         ))
788                     } else {
789                         P(self.expr(try_span, hir::ExprKind::Ret(Some(from_err_expr)), thin_attrs))
790                     };
791
792                     let err_pat = self.pat_err(try_span, err_local);
793                     self.arm(hir_vec![err_pat], ret_expr)
794                 };
795
796                 hir::ExprKind::Match(
797                     discr,
798                     hir_vec![err_arm, ok_arm],
799                     hir::MatchSource::TryDesugar,
800                 )
801             }
802
803             ExprKind::Mac(_) => panic!("Shouldn't exist here"),
804         };
805
806         hir::Expr {
807             hir_id: self.lower_node_id(e.id),
808             node: kind,
809             span: e.span,
810             attrs: e.attrs.clone(),
811         }
812     }
813 }