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