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