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