]> git.lizzy.rs Git - rust.git/blob - src/librustc/hir/lowering/expr.rs
lowering: extract lower_expr_closure
[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             ) => if let IsAsync::Async { closure_id, .. } = asyncness {
270                 self.lower_expr_async_closure(capture_clause, closure_id, decl, body, fn_decl_span)
271             } else {
272                 self.lower_expr_closure(capture_clause, movability, decl, body, fn_decl_span)
273             }
274             ExprKind::Block(ref blk, opt_label) => {
275                 hir::ExprKind::Block(self.lower_block(blk,
276                                                       opt_label.is_some()),
277                                                       self.lower_label(opt_label))
278             }
279             ExprKind::Assign(ref el, ref er) => {
280                 hir::ExprKind::Assign(P(self.lower_expr(el)), P(self.lower_expr(er)))
281             }
282             ExprKind::AssignOp(op, ref el, ref er) => hir::ExprKind::AssignOp(
283                 self.lower_binop(op),
284                 P(self.lower_expr(el)),
285                 P(self.lower_expr(er)),
286             ),
287             ExprKind::Field(ref el, ident) => hir::ExprKind::Field(P(self.lower_expr(el)), ident),
288             ExprKind::Index(ref el, ref er) => {
289                 hir::ExprKind::Index(P(self.lower_expr(el)), P(self.lower_expr(er)))
290             }
291             ExprKind::Range(Some(ref e1), Some(ref e2), RangeLimits::Closed) => {
292                 self.lower_expr_range_closed(e.span, e1, e2)
293             }
294             ExprKind::Range(ref e1, ref e2, lims) => {
295                 self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims)
296             }
297             ExprKind::Path(ref qself, ref path) => {
298                 let qpath = self.lower_qpath(
299                     e.id,
300                     qself,
301                     path,
302                     ParamMode::Optional,
303                     ImplTraitContext::disallowed(),
304                 );
305                 hir::ExprKind::Path(qpath)
306             }
307             ExprKind::Break(opt_label, ref opt_expr) => {
308                 let destination = if self.is_in_loop_condition && opt_label.is_none() {
309                     hir::Destination {
310                         label: None,
311                         target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
312                     }
313                 } else {
314                     self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
315                 };
316                 hir::ExprKind::Break(
317                     destination,
318                     opt_expr.as_ref().map(|x| P(self.lower_expr(x))),
319                 )
320             }
321             ExprKind::Continue(opt_label) => {
322                 hir::ExprKind::Continue(if self.is_in_loop_condition && opt_label.is_none() {
323                     hir::Destination {
324                         label: None,
325                         target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
326                     }
327                 } else {
328                     self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
329                 })
330             }
331             ExprKind::Ret(ref e) => hir::ExprKind::Ret(e.as_ref().map(|x| P(self.lower_expr(x)))),
332             ExprKind::InlineAsm(ref asm) => self.lower_expr_asm(asm),
333             ExprKind::Struct(ref path, ref fields, ref maybe_expr) => hir::ExprKind::Struct(
334                 P(self.lower_qpath(
335                     e.id,
336                     &None,
337                     path,
338                     ParamMode::Optional,
339                     ImplTraitContext::disallowed(),
340                 )),
341                 fields.iter().map(|x| self.lower_field(x)).collect(),
342                 maybe_expr.as_ref().map(|x| P(self.lower_expr(x))),
343             ),
344             ExprKind::Paren(ref ex) => {
345                 let mut ex = self.lower_expr(ex);
346                 // Include parens in span, but only if it is a super-span.
347                 if e.span.contains(ex.span) {
348                     ex.span = e.span;
349                 }
350                 // Merge attributes into the inner expression.
351                 let mut attrs = e.attrs.clone();
352                 attrs.extend::<Vec<_>>(ex.attrs.into());
353                 ex.attrs = attrs;
354                 return ex;
355             }
356
357             ExprKind::Yield(ref opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
358
359             ExprKind::Err => hir::ExprKind::Err,
360
361             // Desugar `ExprForLoop`
362             // from: `[opt_ident]: for <pat> in <head> <body>`
363             ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => {
364                 return self.lower_expr_for(e, pat, head, body, opt_label);
365             }
366             ExprKind::Try(ref sub_expr) => self.lower_expr_try(e.span, sub_expr),
367             ExprKind::Mac(_) => panic!("Shouldn't exist here"),
368         };
369
370         hir::Expr {
371             hir_id: self.lower_node_id(e.id),
372             node: kind,
373             span: e.span,
374             attrs: e.attrs.clone(),
375         }
376     }
377
378     fn lower_expr_closure(
379         &mut self,
380         capture_clause: CaptureBy,
381         movability: Movability,
382         decl: &FnDecl,
383         body: &Expr,
384         fn_decl_span: Span,
385     ) -> hir::ExprKind {
386         // Lower outside new scope to preserve `is_in_loop_condition`.
387         let fn_decl = self.lower_fn_decl(decl, None, false, None);
388
389         self.with_new_scopes(|this| {
390             this.current_item = Some(fn_decl_span);
391             let mut generator_kind = None;
392             let body_id = this.lower_fn_body(decl, |this| {
393                 let e = this.lower_expr(body);
394                 generator_kind = this.generator_kind;
395                 e
396             });
397             let generator_option = this.generator_movability_for_fn(
398                 &decl,
399                 fn_decl_span,
400                 generator_kind,
401                 movability,
402             );
403             hir::ExprKind::Closure(
404                 this.lower_capture_clause(capture_clause),
405                 fn_decl,
406                 body_id,
407                 fn_decl_span,
408                 generator_option,
409             )
410         })
411     }
412
413     fn lower_expr_async_closure(
414         &mut self,
415         capture_clause: CaptureBy,
416         closure_id: NodeId,
417         decl: &FnDecl,
418         body: &Expr,
419         fn_decl_span: Span,
420     ) -> hir::ExprKind {
421         let outer_decl = FnDecl {
422             inputs: decl.inputs.clone(),
423             output: FunctionRetTy::Default(fn_decl_span),
424             c_variadic: false,
425         };
426         // We need to lower the declaration outside the new scope, because we
427         // have to conserve the state of being inside a loop condition for the
428         // closure argument types.
429         let fn_decl = self.lower_fn_decl(&outer_decl, None, false, None);
430
431         self.with_new_scopes(|this| {
432             // FIXME(cramertj): allow `async` non-`move` closures with arguments.
433             if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() {
434                 struct_span_err!(
435                     this.sess,
436                     fn_decl_span,
437                     E0708,
438                     "`async` non-`move` closures with arguments are not currently supported",
439                 )
440                 .help(
441                     "consider using `let` statements to manually capture \
442                     variables by reference before entering an `async move` closure"
443                 )
444                 .emit();
445             }
446
447             // Transform `async |x: u8| -> X { ... }` into
448             // `|x: u8| future_from_generator(|| -> X { ... })`.
449             let body_id = this.lower_fn_body(&outer_decl, |this| {
450                 let async_ret_ty = if let FunctionRetTy::Ty(ty) = &decl.output {
451                     Some(ty.clone())
452                 } else {
453                     None
454                 };
455                 let async_body = this.make_async_expr(
456                     capture_clause, closure_id, async_ret_ty, body.span,
457                     |this| {
458                         this.with_new_scopes(|this| this.lower_expr(body))
459                     }
460                 );
461                 this.expr(fn_decl_span, async_body, ThinVec::new())
462             });
463             hir::ExprKind::Closure(
464                 this.lower_capture_clause(capture_clause),
465                 fn_decl,
466                 body_id,
467                 fn_decl_span,
468                 None,
469             )
470         })
471     }
472
473     /// Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`.
474     fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind {
475         let id = self.next_id();
476         let e1 = self.lower_expr(e1);
477         let e2 = self.lower_expr(e2);
478         self.expr_call_std_assoc_fn(
479             id,
480             span,
481             &[sym::ops, sym::RangeInclusive],
482             "new",
483             hir_vec![e1, e2],
484         )
485     }
486
487     fn lower_expr_range(
488         &mut self,
489         span: Span,
490         e1: Option<&Expr>,
491         e2: Option<&Expr>,
492         lims: RangeLimits,
493     ) -> hir::ExprKind {
494         use syntax::ast::RangeLimits::*;
495
496         let path = match (e1, e2, lims) {
497             (None, None, HalfOpen) => sym::RangeFull,
498             (Some(..), None, HalfOpen) => sym::RangeFrom,
499             (None, Some(..), HalfOpen) => sym::RangeTo,
500             (Some(..), Some(..), HalfOpen) => sym::Range,
501             (None, Some(..), Closed) => sym::RangeToInclusive,
502             (Some(..), Some(..), Closed) => unreachable!(),
503             (_, None, Closed) => self.diagnostic()
504                 .span_fatal(span, "inclusive range with no end")
505                 .raise(),
506         };
507
508         let fields = e1.iter()
509             .map(|e| ("start", e))
510             .chain(e2.iter().map(|e| ("end", e)))
511             .map(|(s, e)| {
512                 let expr = P(self.lower_expr(&e));
513                 let ident = Ident::new(Symbol::intern(s), e.span);
514                 self.field(ident, expr, e.span)
515             })
516             .collect::<P<[hir::Field]>>();
517
518         let is_unit = fields.is_empty();
519         let struct_path = [sym::ops, path];
520         let struct_path = self.std_path(span, &struct_path, None, is_unit);
521         let struct_path = hir::QPath::Resolved(None, P(struct_path));
522
523         if is_unit {
524             hir::ExprKind::Path(struct_path)
525         } else {
526             hir::ExprKind::Struct(P(struct_path), fields, None)
527         }
528     }
529
530     fn lower_expr_asm(&mut self, asm: &InlineAsm) -> hir::ExprKind {
531         let hir_asm = hir::InlineAsm {
532             inputs: asm.inputs.iter().map(|&(ref c, _)| c.clone()).collect(),
533             outputs: asm.outputs
534                 .iter()
535                 .map(|out| hir::InlineAsmOutput {
536                     constraint: out.constraint.clone(),
537                     is_rw: out.is_rw,
538                     is_indirect: out.is_indirect,
539                     span: out.expr.span,
540                 })
541                 .collect(),
542             asm: asm.asm.clone(),
543             asm_str_style: asm.asm_str_style,
544             clobbers: asm.clobbers.clone().into(),
545             volatile: asm.volatile,
546             alignstack: asm.alignstack,
547             dialect: asm.dialect,
548             ctxt: asm.ctxt,
549         };
550
551         let outputs = asm.outputs
552             .iter()
553             .map(|out| self.lower_expr(&out.expr))
554             .collect();
555
556         let inputs = asm.inputs
557             .iter()
558             .map(|&(_, ref input)| self.lower_expr(input))
559             .collect();
560
561         hir::ExprKind::InlineAsm(P(hir_asm), outputs, inputs)
562     }
563
564     fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind {
565         match self.generator_kind {
566             Some(hir::GeneratorKind::Gen) => {},
567             Some(hir::GeneratorKind::Async) => {
568                 span_err!(
569                     self.sess,
570                     span,
571                     E0727,
572                     "`async` generators are not yet supported",
573                 );
574                 self.sess.abort_if_errors();
575             },
576             None => self.generator_kind = Some(hir::GeneratorKind::Gen),
577         }
578
579         let expr = opt_expr
580             .as_ref()
581             .map(|x| self.lower_expr(x))
582             .unwrap_or_else(|| self.expr_unit(span));
583
584         hir::ExprKind::Yield(P(expr), hir::YieldSource::Yield)
585     }
586
587     /// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into:
588     /// ```rust
589     /// {
590     ///     let result = match ::std::iter::IntoIterator::into_iter(<head>) {
591     ///         mut iter => {
592     ///             [opt_ident]: loop {
593     ///                 let mut __next;
594     ///                 match ::std::iter::Iterator::next(&mut iter) {
595     ///                     ::std::option::Option::Some(val) => __next = val,
596     ///                     ::std::option::Option::None => break
597     ///                 };
598     ///                 let <pat> = __next;
599     ///                 StmtKind::Expr(<body>);
600     ///             }
601     ///         }
602     ///     };
603     ///     result
604     /// }
605     /// ```
606     fn lower_expr_for(
607         &mut self,
608         e: &Expr,
609         pat: &Pat,
610         head: &Expr,
611         body: &Block,
612         opt_label: Option<Label>,
613     ) -> hir::Expr {
614         // expand <head>
615         let mut head = self.lower_expr(head);
616         let head_sp = head.span;
617         let desugared_span = self.mark_span_with_reason(
618             DesugaringKind::ForLoop,
619             head_sp,
620             None,
621         );
622         head.span = desugared_span;
623
624         let iter = Ident::with_empty_ctxt(sym::iter);
625
626         let next_ident = Ident::with_empty_ctxt(sym::__next);
627         let (next_pat, next_pat_hid) = self.pat_ident_binding_mode(
628             desugared_span,
629             next_ident,
630             hir::BindingAnnotation::Mutable,
631         );
632
633         // `::std::option::Option::Some(val) => __next = val`
634         let pat_arm = {
635             let val_ident = Ident::with_empty_ctxt(sym::val);
636             let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident);
637             let val_expr = P(self.expr_ident(pat.span, val_ident, val_pat_hid));
638             let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat_hid));
639             let assign = P(self.expr(
640                 pat.span,
641                 hir::ExprKind::Assign(next_expr, val_expr),
642                 ThinVec::new(),
643             ));
644             let some_pat = self.pat_some(pat.span, val_pat);
645             self.arm(hir_vec![some_pat], assign)
646         };
647
648         // `::std::option::Option::None => break`
649         let break_arm = {
650             let break_expr =
651                 self.with_loop_scope(e.id, |this| this.expr_break(e.span, ThinVec::new()));
652             let pat = self.pat_none(e.span);
653             self.arm(hir_vec![pat], break_expr)
654         };
655
656         // `mut iter`
657         let (iter_pat, iter_pat_nid) = self.pat_ident_binding_mode(
658             desugared_span,
659             iter,
660             hir::BindingAnnotation::Mutable
661         );
662
663         // `match ::std::iter::Iterator::next(&mut iter) { ... }`
664         let match_expr = {
665             let iter = P(self.expr_ident(head_sp, iter, iter_pat_nid));
666             let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter);
667             let next_path = &[sym::iter, sym::Iterator, sym::next];
668             let next_expr = P(self.expr_call_std_path(
669                 head_sp,
670                 next_path,
671                 hir_vec![ref_mut_iter],
672             ));
673             let arms = hir_vec![pat_arm, break_arm];
674
675             self.expr_match(head_sp, next_expr, arms, hir::MatchSource::ForLoopDesugar)
676         };
677         let match_stmt = self.stmt_expr(head_sp, match_expr);
678
679         let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat_hid));
680
681         // `let mut __next`
682         let next_let = self.stmt_let_pat(
683             ThinVec::new(),
684             desugared_span,
685             None,
686             next_pat,
687             hir::LocalSource::ForLoopDesugar,
688         );
689
690         // `let <pat> = __next`
691         let pat = self.lower_pat(pat);
692         let pat_let = self.stmt_let_pat(
693             ThinVec::new(),
694             head_sp,
695             Some(next_expr),
696             pat,
697             hir::LocalSource::ForLoopDesugar,
698         );
699
700         let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
701         let body_expr = self.expr_block(body_block, ThinVec::new());
702         let body_stmt = self.stmt_expr(body.span, body_expr);
703
704         let loop_block = P(self.block_all(
705             e.span,
706             hir_vec![next_let, match_stmt, pat_let, body_stmt],
707             None,
708         ));
709
710         // `[opt_ident]: loop { ... }`
711         let loop_expr = hir::ExprKind::Loop(
712             loop_block,
713             self.lower_label(opt_label),
714             hir::LoopSource::ForLoop,
715         );
716         let loop_expr = P(hir::Expr {
717             hir_id: self.lower_node_id(e.id),
718             node: loop_expr,
719             span: e.span,
720             attrs: ThinVec::new(),
721         });
722
723         // `mut iter => { ... }`
724         let iter_arm = self.arm(hir_vec![iter_pat], loop_expr);
725
726         // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
727         let into_iter_expr = {
728             let into_iter_path =
729                 &[sym::iter, sym::IntoIterator, sym::into_iter];
730             P(self.expr_call_std_path(
731                 head_sp,
732                 into_iter_path,
733                 hir_vec![head],
734             ))
735         };
736
737         let match_expr = P(self.expr_match(
738             head_sp,
739             into_iter_expr,
740             hir_vec![iter_arm],
741             hir::MatchSource::ForLoopDesugar,
742         ));
743
744         // This is effectively `{ let _result = ...; _result }`.
745         // The construct was introduced in #21984 and is necessary to make sure that
746         // temporaries in the `head` expression are dropped and do not leak to the
747         // surrounding scope of the `match` since the `match` is not a terminating scope.
748         //
749         // Also, add the attributes to the outer returned expr node.
750         self.expr_drop_temps(head_sp, match_expr, e.attrs.clone())
751     }
752
753     /// Desugar `ExprKind::Try` from: `<expr>?` into:
754     /// ```rust
755     /// match Try::into_result(<expr>) {
756     ///     Ok(val) => #[allow(unreachable_code)] val,
757     ///     Err(err) => #[allow(unreachable_code)]
758     ///                 // If there is an enclosing `try {...}`:
759     ///                 break 'catch_target Try::from_error(From::from(err)),
760     ///                 // Otherwise:
761     ///                 return Try::from_error(From::from(err)),
762     /// }
763     /// ```
764     fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind {
765         let unstable_span = self.mark_span_with_reason(
766             DesugaringKind::QuestionMark,
767             span,
768             self.allow_try_trait.clone(),
769         );
770         let try_span = self.sess.source_map().end_point(span);
771         let try_span = self.mark_span_with_reason(
772             DesugaringKind::QuestionMark,
773             try_span,
774             self.allow_try_trait.clone(),
775         );
776
777         // `Try::into_result(<expr>)`
778         let scrutinee = {
779             // expand <expr>
780             let sub_expr = self.lower_expr(sub_expr);
781
782             let path = &[sym::ops, sym::Try, sym::into_result];
783             P(self.expr_call_std_path(unstable_span, path, hir_vec![sub_expr]))
784         };
785
786         // `#[allow(unreachable_code)]`
787         let attr = {
788             // `allow(unreachable_code)`
789             let allow = {
790                 let allow_ident = Ident::new(sym::allow, span);
791                 let uc_ident = Ident::new(sym::unreachable_code, span);
792                 let uc_nested = attr::mk_nested_word_item(uc_ident);
793                 attr::mk_list_item(allow_ident, vec![uc_nested])
794             };
795             attr::mk_attr_outer(allow)
796         };
797         let attrs = vec![attr];
798
799         // `Ok(val) => #[allow(unreachable_code)] val,`
800         let ok_arm = {
801             let val_ident = Ident::with_empty_ctxt(sym::val);
802             let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident);
803             let val_expr = P(self.expr_ident_with_attrs(
804                 span,
805                 val_ident,
806                 val_pat_nid,
807                 ThinVec::from(attrs.clone()),
808             ));
809             let ok_pat = self.pat_ok(span, val_pat);
810
811             self.arm(hir_vec![ok_pat], val_expr)
812         };
813
814         // `Err(err) => #[allow(unreachable_code)]
815         //              return Try::from_error(From::from(err)),`
816         let err_arm = {
817             let err_ident = Ident::with_empty_ctxt(sym::err);
818             let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
819             let from_expr = {
820                 let from_path = &[sym::convert, sym::From, sym::from];
821                 let err_expr = self.expr_ident(try_span, err_ident, err_local_nid);
822                 self.expr_call_std_path(try_span, from_path, hir_vec![err_expr])
823             };
824             let from_err_expr =
825                 self.wrap_in_try_constructor(sym::from_error, from_expr, unstable_span);
826             let thin_attrs = ThinVec::from(attrs);
827             let catch_scope = self.catch_scopes.last().map(|x| *x);
828             let ret_expr = if let Some(catch_node) = catch_scope {
829                 let target_id = Ok(self.lower_node_id(catch_node));
830                 P(self.expr(
831                     try_span,
832                     hir::ExprKind::Break(
833                         hir::Destination {
834                             label: None,
835                             target_id,
836                         },
837                         Some(from_err_expr),
838                     ),
839                     thin_attrs,
840                 ))
841             } else {
842                 P(self.expr(try_span, hir::ExprKind::Ret(Some(from_err_expr)), thin_attrs))
843             };
844
845             let err_pat = self.pat_err(try_span, err_local);
846             self.arm(hir_vec![err_pat], ret_expr)
847         };
848
849         hir::ExprKind::Match(
850             scrutinee,
851             hir_vec![err_arm, ok_arm],
852             hir::MatchSource::TryDesugar,
853         )
854     }
855 }