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