| use super::{LoweringContext, ParamMode, ParenthesizedGenericArgs, ImplTraitContext}; |
| use crate::hir::{self, HirVec}; |
| use crate::hir::def::Res; |
| use crate::hir::ptr::P; |
| |
| use rustc_data_structures::thin_vec::ThinVec; |
| |
| use syntax::attr; |
| use syntax::ptr::P as AstP; |
| use syntax::ast::*; |
| use syntax::source_map::{respan, DesugaringKind, Span, Spanned}; |
| use syntax::symbol::{sym, Symbol}; |
| |
| impl LoweringContext<'_> { |
| fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> HirVec<hir::Expr> { |
| exprs.iter().map(|x| self.lower_expr(x)).collect() |
| } |
| |
| pub(super) fn lower_expr(&mut self, e: &Expr) -> hir::Expr { |
| let kind = match e.node { |
| ExprKind::Box(ref inner) => hir::ExprKind::Box(P(self.lower_expr(inner))), |
| ExprKind::Array(ref exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), |
| ExprKind::Repeat(ref expr, ref count) => { |
| let expr = P(self.lower_expr(expr)); |
| let count = self.lower_anon_const(count); |
| hir::ExprKind::Repeat(expr, count) |
| } |
| ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)), |
| ExprKind::Call(ref f, ref args) => { |
| let f = P(self.lower_expr(f)); |
| hir::ExprKind::Call(f, self.lower_exprs(args)) |
| } |
| ExprKind::MethodCall(ref seg, ref args) => { |
| let hir_seg = P(self.lower_path_segment( |
| e.span, |
| seg, |
| ParamMode::Optional, |
| 0, |
| ParenthesizedGenericArgs::Err, |
| ImplTraitContext::disallowed(), |
| None, |
| )); |
| let args = self.lower_exprs(args); |
| hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args) |
| } |
| ExprKind::Binary(binop, ref lhs, ref rhs) => { |
| let binop = self.lower_binop(binop); |
| let lhs = P(self.lower_expr(lhs)); |
| let rhs = P(self.lower_expr(rhs)); |
| hir::ExprKind::Binary(binop, lhs, rhs) |
| } |
| ExprKind::Unary(op, ref ohs) => { |
| let op = self.lower_unop(op); |
| let ohs = P(self.lower_expr(ohs)); |
| hir::ExprKind::Unary(op, ohs) |
| } |
| ExprKind::Lit(ref l) => hir::ExprKind::Lit(respan(l.span, l.node.clone())), |
| ExprKind::Cast(ref expr, ref ty) => { |
| let expr = P(self.lower_expr(expr)); |
| hir::ExprKind::Cast(expr, self.lower_ty(ty, ImplTraitContext::disallowed())) |
| } |
| ExprKind::Type(ref expr, ref ty) => { |
| let expr = P(self.lower_expr(expr)); |
| hir::ExprKind::Type(expr, self.lower_ty(ty, ImplTraitContext::disallowed())) |
| } |
| ExprKind::AddrOf(m, ref ohs) => { |
| let m = self.lower_mutability(m); |
| let ohs = P(self.lower_expr(ohs)); |
| hir::ExprKind::AddrOf(m, ohs) |
| } |
| ExprKind::Let(ref pat, ref scrutinee) => self.lower_expr_let(e.span, pat, scrutinee), |
| ExprKind::If(ref cond, ref then, ref else_opt) => { |
| self.lower_expr_if(e.span, cond, then, else_opt.as_deref()) |
| } |
| ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| { |
| this.lower_expr_while_in_loop_scope(e.span, cond, body, opt_label) |
| }), |
| ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| { |
| hir::ExprKind::Loop( |
| this.lower_block(body, false), |
| this.lower_label(opt_label), |
| hir::LoopSource::Loop, |
| ) |
| }), |
| ExprKind::TryBlock(ref body) => self.lower_expr_try_block(body), |
| ExprKind::Match(ref expr, ref arms) => hir::ExprKind::Match( |
| P(self.lower_expr(expr)), |
| arms.iter().map(|x| self.lower_arm(x)).collect(), |
| hir::MatchSource::Normal, |
| ), |
| ExprKind::Async(capture_clause, closure_node_id, ref block) => { |
| self.make_async_expr(capture_clause, closure_node_id, None, block.span, |this| { |
| this.with_new_scopes(|this| this.lower_block_expr(block)) |
| }) |
| } |
| ExprKind::Await(ref expr) => self.lower_expr_await(e.span, expr), |
| ExprKind::Closure( |
| capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span |
| ) => if let IsAsync::Async { closure_id, .. } = asyncness { |
| self.lower_expr_async_closure(capture_clause, closure_id, decl, body, fn_decl_span) |
| } else { |
| self.lower_expr_closure(capture_clause, movability, decl, body, fn_decl_span) |
| } |
| ExprKind::Block(ref blk, opt_label) => { |
| hir::ExprKind::Block(self.lower_block(blk, |
| opt_label.is_some()), |
| self.lower_label(opt_label)) |
| } |
| ExprKind::Assign(ref el, ref er) => { |
| hir::ExprKind::Assign(P(self.lower_expr(el)), P(self.lower_expr(er))) |
| } |
| ExprKind::AssignOp(op, ref el, ref er) => hir::ExprKind::AssignOp( |
| self.lower_binop(op), |
| P(self.lower_expr(el)), |
| P(self.lower_expr(er)), |
| ), |
| ExprKind::Field(ref el, ident) => hir::ExprKind::Field(P(self.lower_expr(el)), ident), |
| ExprKind::Index(ref el, ref er) => { |
| hir::ExprKind::Index(P(self.lower_expr(el)), P(self.lower_expr(er))) |
| } |
| ExprKind::Range(Some(ref e1), Some(ref e2), RangeLimits::Closed) => { |
| self.lower_expr_range_closed(e.span, e1, e2) |
| } |
| ExprKind::Range(ref e1, ref e2, lims) => { |
| self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims) |
| } |
| ExprKind::Path(ref qself, ref path) => { |
| let qpath = self.lower_qpath( |
| e.id, |
| qself, |
| path, |
| ParamMode::Optional, |
| ImplTraitContext::disallowed(), |
| ); |
| hir::ExprKind::Path(qpath) |
| } |
| ExprKind::Break(opt_label, ref opt_expr) => { |
| hir::ExprKind::Break( |
| self.lower_jump_destination(e.id, opt_label), |
| opt_expr.as_ref().map(|x| P(self.lower_expr(x))), |
| ) |
| } |
| ExprKind::Continue(opt_label) => { |
| hir::ExprKind::Continue(self.lower_jump_destination(e.id, opt_label)) |
| } |
| ExprKind::Ret(ref e) => hir::ExprKind::Ret(e.as_ref().map(|x| P(self.lower_expr(x)))), |
| ExprKind::InlineAsm(ref asm) => self.lower_expr_asm(asm), |
| ExprKind::Struct(ref path, ref fields, ref maybe_expr) => hir::ExprKind::Struct( |
| P(self.lower_qpath( |
| e.id, |
| &None, |
| path, |
| ParamMode::Optional, |
| ImplTraitContext::disallowed(), |
| )), |
| fields.iter().map(|x| self.lower_field(x)).collect(), |
| maybe_expr.as_ref().map(|x| P(self.lower_expr(x))), |
| ), |
| ExprKind::Paren(ref ex) => { |
| let mut ex = self.lower_expr(ex); |
| // Include parens in span, but only if it is a super-span. |
| if e.span.contains(ex.span) { |
| ex.span = e.span; |
| } |
| // Merge attributes into the inner expression. |
| let mut attrs = e.attrs.clone(); |
| attrs.extend::<Vec<_>>(ex.attrs.into()); |
| ex.attrs = attrs; |
| return ex; |
| } |
| |
| ExprKind::Yield(ref opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()), |
| |
| ExprKind::Err => hir::ExprKind::Err, |
| |
| // Desugar `ExprForLoop` |
| // from: `[opt_ident]: for <pat> in <head> <body>` |
| ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => { |
| return self.lower_expr_for(e, pat, head, body, opt_label); |
| } |
| ExprKind::Try(ref sub_expr) => self.lower_expr_try(e.span, sub_expr), |
| ExprKind::Mac(_) => panic!("Shouldn't exist here"), |
| }; |
| |
| hir::Expr { |
| hir_id: self.lower_node_id(e.id), |
| node: kind, |
| span: e.span, |
| attrs: e.attrs.clone(), |
| } |
| } |
| |
| fn lower_unop(&mut self, u: UnOp) -> hir::UnOp { |
| match u { |
| UnOp::Deref => hir::UnDeref, |
| UnOp::Not => hir::UnNot, |
| UnOp::Neg => hir::UnNeg, |
| } |
| } |
| |
| fn lower_binop(&mut self, b: BinOp) -> hir::BinOp { |
| Spanned { |
| node: match b.node { |
| BinOpKind::Add => hir::BinOpKind::Add, |
| BinOpKind::Sub => hir::BinOpKind::Sub, |
| BinOpKind::Mul => hir::BinOpKind::Mul, |
| BinOpKind::Div => hir::BinOpKind::Div, |
| BinOpKind::Rem => hir::BinOpKind::Rem, |
| BinOpKind::And => hir::BinOpKind::And, |
| BinOpKind::Or => hir::BinOpKind::Or, |
| BinOpKind::BitXor => hir::BinOpKind::BitXor, |
| BinOpKind::BitAnd => hir::BinOpKind::BitAnd, |
| BinOpKind::BitOr => hir::BinOpKind::BitOr, |
| BinOpKind::Shl => hir::BinOpKind::Shl, |
| BinOpKind::Shr => hir::BinOpKind::Shr, |
| BinOpKind::Eq => hir::BinOpKind::Eq, |
| BinOpKind::Lt => hir::BinOpKind::Lt, |
| BinOpKind::Le => hir::BinOpKind::Le, |
| BinOpKind::Ne => hir::BinOpKind::Ne, |
| BinOpKind::Ge => hir::BinOpKind::Ge, |
| BinOpKind::Gt => hir::BinOpKind::Gt, |
| }, |
| span: b.span, |
| } |
| } |
| |
| /// Emit an error and lower `ast::ExprKind::Let(pat, scrutinee)` into: |
| /// ```rust |
| /// match scrutinee { pats => true, _ => false } |
| /// ``` |
| fn lower_expr_let(&mut self, span: Span, pat: &Pat, scrutinee: &Expr) -> hir::ExprKind { |
| // If we got here, the `let` expression is not allowed. |
| self.sess |
| .struct_span_err(span, "`let` expressions are not supported here") |
| .note("only supported directly in conditions of `if`- and `while`-expressions") |
| .note("as well as when nested within `&&` and parenthesis in those conditions") |
| .emit(); |
| |
| // For better recovery, we emit: |
| // ``` |
| // match scrutinee { pat => true, _ => false } |
| // ``` |
| // While this doesn't fully match the user's intent, it has key advantages: |
| // 1. We can avoid using `abort_if_errors`. |
| // 2. We can typeck both `pat` and `scrutinee`. |
| // 3. `pat` is allowed to be refutable. |
| // 4. The return type of the block is `bool` which seems like what the user wanted. |
| let scrutinee = self.lower_expr(scrutinee); |
| let then_arm = { |
| let pat = self.lower_pat_top_hack(pat); |
| let expr = self.expr_bool(span, true); |
| self.arm(pat, P(expr)) |
| }; |
| let else_arm = { |
| let pat = self.pat_wild(span); |
| let expr = self.expr_bool(span, false); |
| self.arm(hir_vec![pat], P(expr)) |
| }; |
| hir::ExprKind::Match( |
| P(scrutinee), |
| vec![then_arm, else_arm].into(), |
| hir::MatchSource::Normal, |
| ) |
| } |
| |
| fn lower_expr_if( |
| &mut self, |
| span: Span, |
| cond: &Expr, |
| then: &Block, |
| else_opt: Option<&Expr>, |
| ) -> hir::ExprKind { |
| // FIXME(#53667): handle lowering of && and parens. |
| |
| // `_ => else_block` where `else_block` is `{}` if there's `None`: |
| let else_pat = self.pat_wild(span); |
| let (else_expr, contains_else_clause) = match else_opt { |
| None => (self.expr_block_empty(span), false), |
| Some(els) => (self.lower_expr(els), true), |
| }; |
| let else_arm = self.arm(hir_vec![else_pat], P(else_expr)); |
| |
| // Handle then + scrutinee: |
| let then_expr = self.lower_block_expr(then); |
| let (then_pat, scrutinee, desugar) = match cond.node { |
| // `<pat> => <then>`: |
| ExprKind::Let(ref pat, ref scrutinee) => { |
| let scrutinee = self.lower_expr(scrutinee); |
| let pat = self.lower_pat_top_hack(pat); |
| (pat, scrutinee, hir::MatchSource::IfLetDesugar { contains_else_clause }) |
| } |
| // `true => <then>`: |
| _ => { |
| // Lower condition: |
| let cond = self.lower_expr(cond); |
| let span_block = self.mark_span_with_reason( |
| DesugaringKind::CondTemporary, |
| cond.span, |
| None |
| ); |
| // Wrap in a construct equivalent to `{ let _t = $cond; _t }` |
| // to preserve drop semantics since `if cond { ... }` does not |
| // let temporaries live outside of `cond`. |
| let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new()); |
| let pat = self.pat_bool(span, true); |
| (hir_vec![pat], cond, hir::MatchSource::IfDesugar { contains_else_clause }) |
| } |
| }; |
| let then_arm = self.arm(then_pat, P(then_expr)); |
| |
| hir::ExprKind::Match(P(scrutinee), vec![then_arm, else_arm].into(), desugar) |
| } |
| |
| fn lower_expr_while_in_loop_scope( |
| &mut self, |
| span: Span, |
| cond: &Expr, |
| body: &Block, |
| opt_label: Option<Label> |
| ) -> hir::ExprKind { |
| // FIXME(#53667): handle lowering of && and parens. |
| |
| // Note that the block AND the condition are evaluated in the loop scope. |
| // This is done to allow `break` from inside the condition of the loop. |
| |
| // `_ => break`: |
| let else_arm = { |
| let else_pat = self.pat_wild(span); |
| let else_expr = self.expr_break(span, ThinVec::new()); |
| self.arm(hir_vec![else_pat], else_expr) |
| }; |
| |
| // Handle then + scrutinee: |
| let then_expr = self.lower_block_expr(body); |
| let (then_pat, scrutinee, desugar, source) = match cond.node { |
| ExprKind::Let(ref pat, ref scrutinee) => { |
| // to: |
| // |
| // [opt_ident]: loop { |
| // match <sub_expr> { |
| // <pat> => <body>, |
| // _ => break |
| // } |
| // } |
| let scrutinee = self.with_loop_condition_scope(|t| t.lower_expr(scrutinee)); |
| let pat = self.lower_pat_top_hack(pat); |
| (pat, scrutinee, hir::MatchSource::WhileLetDesugar, hir::LoopSource::WhileLet) |
| } |
| _ => { |
| // We desugar: `'label: while $cond $body` into: |
| // |
| // ``` |
| // 'label: loop { |
| // match drop-temps { $cond } { |
| // true => $body, |
| // _ => break, |
| // } |
| // } |
| // ``` |
| |
| // Lower condition: |
| let cond = self.with_loop_condition_scope(|this| this.lower_expr(cond)); |
| let span_block = self.mark_span_with_reason( |
| DesugaringKind::CondTemporary, |
| cond.span, |
| None, |
| ); |
| // Wrap in a construct equivalent to `{ let _t = $cond; _t }` |
| // to preserve drop semantics since `while cond { ... }` does not |
| // let temporaries live outside of `cond`. |
| let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new()); |
| // `true => <then>`: |
| let pat = self.pat_bool(span, true); |
| (hir_vec![pat], cond, hir::MatchSource::WhileDesugar, hir::LoopSource::While) |
| } |
| }; |
| let then_arm = self.arm(then_pat, P(then_expr)); |
| |
| // `match <scrutinee> { ... }` |
| let match_expr = self.expr_match( |
| scrutinee.span, |
| P(scrutinee), |
| hir_vec![then_arm, else_arm], |
| desugar, |
| ); |
| |
| // `[opt_ident]: loop { ... }` |
| hir::ExprKind::Loop( |
| P(self.block_expr(P(match_expr))), |
| self.lower_label(opt_label), |
| source |
| ) |
| } |
| |
| fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind { |
| self.with_catch_scope(body.id, |this| { |
| let unstable_span = this.mark_span_with_reason( |
| DesugaringKind::TryBlock, |
| body.span, |
| this.allow_try_trait.clone(), |
| ); |
| let mut block = this.lower_block(body, true).into_inner(); |
| let tail = block.expr.take().map_or_else( |
| || this.expr_unit(this.sess.source_map().end_point(unstable_span)), |
| |x: P<hir::Expr>| x.into_inner(), |
| ); |
| block.expr = Some(this.wrap_in_try_constructor(sym::from_ok, tail, unstable_span)); |
| hir::ExprKind::Block(P(block), None) |
| }) |
| } |
| |
| fn wrap_in_try_constructor( |
| &mut self, |
| method: Symbol, |
| e: hir::Expr, |
| unstable_span: Span, |
| ) -> P<hir::Expr> { |
| let path = &[sym::ops, sym::Try, method]; |
| let from_err = P(self.expr_std_path(unstable_span, path, None, ThinVec::new())); |
| P(self.expr_call(e.span, from_err, hir_vec![e])) |
| } |
| |
| fn lower_arm(&mut self, arm: &Arm) -> hir::Arm { |
| hir::Arm { |
| hir_id: self.next_id(), |
| attrs: self.lower_attrs(&arm.attrs), |
| pats: self.lower_pat_top_hack(&arm.pat), |
| guard: match arm.guard { |
| Some(ref x) => Some(hir::Guard::If(P(self.lower_expr(x)))), |
| _ => None, |
| }, |
| body: P(self.lower_expr(&arm.body)), |
| span: arm.span, |
| } |
| } |
| |
| /// HACK(or_patterns; Centril | dlrobertson): For now we don't push down top level or-patterns |
| /// `p | q` into `hir::PatKind::Or(...)` as post-lowering bits of the compiler are not ready |
| /// to deal with it. This should by fixed by pushing it down to HIR and then HAIR. |
| fn lower_pat_top_hack(&mut self, pat: &Pat) -> HirVec<P<hir::Pat>> { |
| match pat.node { |
| PatKind::Or(ref ps) => ps.iter().map(|x| self.lower_pat(x)).collect(), |
| _ => hir_vec![self.lower_pat(pat)], |
| } |
| } |
| |
| pub(super) fn make_async_expr( |
| &mut self, |
| capture_clause: CaptureBy, |
| closure_node_id: NodeId, |
| ret_ty: Option<AstP<Ty>>, |
| span: Span, |
| body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr, |
| ) -> hir::ExprKind { |
| let capture_clause = self.lower_capture_clause(capture_clause); |
| let output = match ret_ty { |
| Some(ty) => FunctionRetTy::Ty(ty), |
| None => FunctionRetTy::Default(span), |
| }; |
| let ast_decl = FnDecl { |
| inputs: vec![], |
| output, |
| c_variadic: false |
| }; |
| let decl = self.lower_fn_decl(&ast_decl, None, /* impl trait allowed */ false, None); |
| let body_id = self.lower_fn_body(&ast_decl, |this| { |
| this.generator_kind = Some(hir::GeneratorKind::Async); |
| body(this) |
| }); |
| |
| // `static || -> <ret_ty> { body }`: |
| let generator_node = hir::ExprKind::Closure( |
| capture_clause, |
| decl, |
| body_id, |
| span, |
| Some(hir::GeneratorMovability::Static) |
| ); |
| let generator = hir::Expr { |
| hir_id: self.lower_node_id(closure_node_id), |
| node: generator_node, |
| span, |
| attrs: ThinVec::new(), |
| }; |
| |
| // `future::from_generator`: |
| let unstable_span = self.mark_span_with_reason( |
| DesugaringKind::Async, |
| span, |
| self.allow_gen_future.clone(), |
| ); |
| let gen_future = self.expr_std_path( |
| unstable_span, |
| &[sym::future, sym::from_generator], |
| None, |
| ThinVec::new() |
| ); |
| |
| // `future::from_generator(generator)`: |
| hir::ExprKind::Call(P(gen_future), hir_vec![generator]) |
| } |
| |
| /// Desugar `<expr>.await` into: |
| /// ```rust |
| /// match <expr> { |
| /// mut pinned => loop { |
| /// match ::std::future::poll_with_tls_context(unsafe { |
| /// <::std::pin::Pin>::new_unchecked(&mut pinned) |
| /// }) { |
| /// ::std::task::Poll::Ready(result) => break result, |
| /// ::std::task::Poll::Pending => {} |
| /// } |
| /// yield (); |
| /// } |
| /// } |
| /// ``` |
| fn lower_expr_await(&mut self, await_span: Span, expr: &Expr) -> hir::ExprKind { |
| match self.generator_kind { |
| Some(hir::GeneratorKind::Async) => {}, |
| Some(hir::GeneratorKind::Gen) | |
| None => { |
| let mut err = struct_span_err!( |
| self.sess, |
| await_span, |
| E0728, |
| "`await` is only allowed inside `async` functions and blocks" |
| ); |
| err.span_label(await_span, "only allowed inside `async` functions and blocks"); |
| if let Some(item_sp) = self.current_item { |
| err.span_label(item_sp, "this is not `async`"); |
| } |
| err.emit(); |
| } |
| } |
| let span = self.mark_span_with_reason( |
| DesugaringKind::Await, |
| await_span, |
| None, |
| ); |
| let gen_future_span = self.mark_span_with_reason( |
| DesugaringKind::Await, |
| await_span, |
| self.allow_gen_future.clone(), |
| ); |
| |
| let pinned_ident = Ident::with_dummy_span(sym::pinned); |
| let (pinned_pat, pinned_pat_hid) = self.pat_ident_binding_mode( |
| span, |
| pinned_ident, |
| hir::BindingAnnotation::Mutable, |
| ); |
| |
| // ::std::future::poll_with_tls_context(unsafe { |
| // ::std::pin::Pin::new_unchecked(&mut pinned) |
| // })` |
| let poll_expr = { |
| let pinned = P(self.expr_ident(span, pinned_ident, pinned_pat_hid)); |
| let ref_mut_pinned = self.expr_mut_addr_of(span, pinned); |
| let pin_ty_id = self.next_id(); |
| let new_unchecked_expr_kind = self.expr_call_std_assoc_fn( |
| pin_ty_id, |
| span, |
| &[sym::pin, sym::Pin], |
| "new_unchecked", |
| hir_vec![ref_mut_pinned], |
| ); |
| let new_unchecked = P(self.expr(span, new_unchecked_expr_kind, ThinVec::new())); |
| let unsafe_expr = self.expr_unsafe(new_unchecked); |
| P(self.expr_call_std_path( |
| gen_future_span, |
| &[sym::future, sym::poll_with_tls_context], |
| hir_vec![unsafe_expr], |
| )) |
| }; |
| |
| // `::std::task::Poll::Ready(result) => break result` |
| let loop_node_id = self.sess.next_node_id(); |
| let loop_hir_id = self.lower_node_id(loop_node_id); |
| let ready_arm = { |
| let x_ident = Ident::with_dummy_span(sym::result); |
| let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident); |
| let x_expr = P(self.expr_ident(span, x_ident, x_pat_hid)); |
| let ready_pat = self.pat_std_enum( |
| span, |
| &[sym::task, sym::Poll, sym::Ready], |
| hir_vec![x_pat], |
| ); |
| let break_x = self.with_loop_scope(loop_node_id, |this| { |
| let expr_break = hir::ExprKind::Break( |
| this.lower_loop_destination(None), |
| Some(x_expr), |
| ); |
| P(this.expr(await_span, expr_break, ThinVec::new())) |
| }); |
| self.arm(hir_vec![ready_pat], break_x) |
| }; |
| |
| // `::std::task::Poll::Pending => {}` |
| let pending_arm = { |
| let pending_pat = self.pat_std_enum( |
| span, |
| &[sym::task, sym::Poll, sym::Pending], |
| hir_vec![], |
| ); |
| let empty_block = P(self.expr_block_empty(span)); |
| self.arm(hir_vec![pending_pat], empty_block) |
| }; |
| |
| let inner_match_stmt = { |
| let match_expr = self.expr_match( |
| span, |
| poll_expr, |
| hir_vec![ready_arm, pending_arm], |
| hir::MatchSource::AwaitDesugar, |
| ); |
| self.stmt_expr(span, match_expr) |
| }; |
| |
| let yield_stmt = { |
| let unit = self.expr_unit(span); |
| let yield_expr = self.expr( |
| span, |
| hir::ExprKind::Yield(P(unit), hir::YieldSource::Await), |
| ThinVec::new(), |
| ); |
| self.stmt_expr(span, yield_expr) |
| }; |
| |
| let loop_block = P(self.block_all( |
| span, |
| hir_vec![inner_match_stmt, yield_stmt], |
| None, |
| )); |
| |
| // loop { .. } |
| let loop_expr = P(hir::Expr { |
| hir_id: loop_hir_id, |
| node: hir::ExprKind::Loop( |
| loop_block, |
| None, |
| hir::LoopSource::Loop, |
| ), |
| span, |
| attrs: ThinVec::new(), |
| }); |
| |
| // mut pinned => loop { ... } |
| let pinned_arm = self.arm(hir_vec![pinned_pat], loop_expr); |
| |
| // match <expr> { |
| // mut pinned => loop { .. } |
| // } |
| let expr = P(self.lower_expr(expr)); |
| hir::ExprKind::Match(expr, hir_vec![pinned_arm], hir::MatchSource::AwaitDesugar) |
| } |
| |
| fn lower_expr_closure( |
| &mut self, |
| capture_clause: CaptureBy, |
| movability: Movability, |
| decl: &FnDecl, |
| body: &Expr, |
| fn_decl_span: Span, |
| ) -> hir::ExprKind { |
| // Lower outside new scope to preserve `is_in_loop_condition`. |
| let fn_decl = self.lower_fn_decl(decl, None, false, None); |
| |
| self.with_new_scopes(|this| { |
| let prev = this.current_item; |
| this.current_item = Some(fn_decl_span); |
| let mut generator_kind = None; |
| let body_id = this.lower_fn_body(decl, |this| { |
| let e = this.lower_expr(body); |
| generator_kind = this.generator_kind; |
| e |
| }); |
| let generator_option = this.generator_movability_for_fn( |
| &decl, |
| fn_decl_span, |
| generator_kind, |
| movability, |
| ); |
| let capture_clause = this.lower_capture_clause(capture_clause); |
| this.current_item = prev; |
| hir::ExprKind::Closure( |
| capture_clause, |
| fn_decl, |
| body_id, |
| fn_decl_span, |
| generator_option, |
| ) |
| }) |
| } |
| |
| fn lower_capture_clause(&mut self, c: CaptureBy) -> hir::CaptureClause { |
| match c { |
| CaptureBy::Value => hir::CaptureByValue, |
| CaptureBy::Ref => hir::CaptureByRef, |
| } |
| } |
| |
| fn generator_movability_for_fn( |
| &mut self, |
| decl: &FnDecl, |
| fn_decl_span: Span, |
| generator_kind: Option<hir::GeneratorKind>, |
| movability: Movability, |
| ) -> Option<hir::GeneratorMovability> { |
| match generator_kind { |
| Some(hir::GeneratorKind::Gen) => { |
| if !decl.inputs.is_empty() { |
| span_err!( |
| self.sess, |
| fn_decl_span, |
| E0628, |
| "generators cannot have explicit parameters" |
| ); |
| self.sess.abort_if_errors(); |
| } |
| Some(match movability { |
| Movability::Movable => hir::GeneratorMovability::Movable, |
| Movability::Static => hir::GeneratorMovability::Static, |
| }) |
| }, |
| Some(hir::GeneratorKind::Async) => { |
| bug!("non-`async` closure body turned `async` during lowering"); |
| }, |
| None => { |
| if movability == Movability::Static { |
| span_err!( |
| self.sess, |
| fn_decl_span, |
| E0697, |
| "closures cannot be static" |
| ); |
| } |
| None |
| }, |
| } |
| } |
| |
| fn lower_expr_async_closure( |
| &mut self, |
| capture_clause: CaptureBy, |
| closure_id: NodeId, |
| decl: &FnDecl, |
| body: &Expr, |
| fn_decl_span: Span, |
| ) -> hir::ExprKind { |
| let outer_decl = FnDecl { |
| inputs: decl.inputs.clone(), |
| output: FunctionRetTy::Default(fn_decl_span), |
| c_variadic: false, |
| }; |
| // We need to lower the declaration outside the new scope, because we |
| // have to conserve the state of being inside a loop condition for the |
| // closure argument types. |
| let fn_decl = self.lower_fn_decl(&outer_decl, None, false, None); |
| |
| self.with_new_scopes(|this| { |
| // FIXME(cramertj): allow `async` non-`move` closures with arguments. |
| if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() { |
| struct_span_err!( |
| this.sess, |
| fn_decl_span, |
| E0708, |
| "`async` non-`move` closures with parameters are not currently supported", |
| ) |
| .help( |
| "consider using `let` statements to manually capture \ |
| variables by reference before entering an `async move` closure" |
| ) |
| .emit(); |
| } |
| |
| // Transform `async |x: u8| -> X { ... }` into |
| // `|x: u8| future_from_generator(|| -> X { ... })`. |
| let body_id = this.lower_fn_body(&outer_decl, |this| { |
| let async_ret_ty = if let FunctionRetTy::Ty(ty) = &decl.output { |
| Some(ty.clone()) |
| } else { |
| None |
| }; |
| let async_body = this.make_async_expr( |
| capture_clause, closure_id, async_ret_ty, body.span, |
| |this| { |
| this.with_new_scopes(|this| this.lower_expr(body)) |
| } |
| ); |
| this.expr(fn_decl_span, async_body, ThinVec::new()) |
| }); |
| hir::ExprKind::Closure( |
| this.lower_capture_clause(capture_clause), |
| fn_decl, |
| body_id, |
| fn_decl_span, |
| None, |
| ) |
| }) |
| } |
| |
| /// Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`. |
| fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind { |
| let id = self.next_id(); |
| let e1 = self.lower_expr(e1); |
| let e2 = self.lower_expr(e2); |
| self.expr_call_std_assoc_fn( |
| id, |
| span, |
| &[sym::ops, sym::RangeInclusive], |
| "new", |
| hir_vec![e1, e2], |
| ) |
| } |
| |
| fn lower_expr_range( |
| &mut self, |
| span: Span, |
| e1: Option<&Expr>, |
| e2: Option<&Expr>, |
| lims: RangeLimits, |
| ) -> hir::ExprKind { |
| use syntax::ast::RangeLimits::*; |
| |
| let path = match (e1, e2, lims) { |
| (None, None, HalfOpen) => sym::RangeFull, |
| (Some(..), None, HalfOpen) => sym::RangeFrom, |
| (None, Some(..), HalfOpen) => sym::RangeTo, |
| (Some(..), Some(..), HalfOpen) => sym::Range, |
| (None, Some(..), Closed) => sym::RangeToInclusive, |
| (Some(..), Some(..), Closed) => unreachable!(), |
| (_, None, Closed) => self.diagnostic() |
| .span_fatal(span, "inclusive range with no end") |
| .raise(), |
| }; |
| |
| let fields = e1.iter() |
| .map(|e| ("start", e)) |
| .chain(e2.iter().map(|e| ("end", e))) |
| .map(|(s, e)| { |
| let expr = P(self.lower_expr(&e)); |
| let ident = Ident::new(Symbol::intern(s), e.span); |
| self.field(ident, expr, e.span) |
| }) |
| .collect::<P<[hir::Field]>>(); |
| |
| let is_unit = fields.is_empty(); |
| let struct_path = [sym::ops, path]; |
| let struct_path = self.std_path(span, &struct_path, None, is_unit); |
| let struct_path = hir::QPath::Resolved(None, P(struct_path)); |
| |
| if is_unit { |
| hir::ExprKind::Path(struct_path) |
| } else { |
| hir::ExprKind::Struct(P(struct_path), fields, None) |
| } |
| } |
| |
| fn lower_label(&mut self, label: Option<Label>) -> Option<hir::Label> { |
| label.map(|label| hir::Label { |
| ident: label.ident, |
| }) |
| } |
| |
| fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination { |
| let target_id = match destination { |
| Some((id, _)) => { |
| if let Some(loop_id) = self.resolver.get_label_res(id) { |
| Ok(self.lower_node_id(loop_id)) |
| } else { |
| Err(hir::LoopIdError::UnresolvedLabel) |
| } |
| } |
| None => { |
| self.loop_scopes |
| .last() |
| .cloned() |
| .map(|id| Ok(self.lower_node_id(id))) |
| .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)) |
| .into() |
| } |
| }; |
| hir::Destination { |
| label: self.lower_label(destination.map(|(_, label)| label)), |
| target_id, |
| } |
| } |
| |
| fn lower_jump_destination(&mut self, id: NodeId, opt_label: Option<Label>) -> hir::Destination { |
| if self.is_in_loop_condition && opt_label.is_none() { |
| hir::Destination { |
| label: None, |
| target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(), |
| } |
| } else { |
| self.lower_loop_destination(opt_label.map(|label| (id, label))) |
| } |
| } |
| |
| fn with_catch_scope<T, F>(&mut self, catch_id: NodeId, f: F) -> T |
| where |
| F: FnOnce(&mut LoweringContext<'_>) -> T, |
| { |
| let len = self.catch_scopes.len(); |
| self.catch_scopes.push(catch_id); |
| |
| let result = f(self); |
| assert_eq!( |
| len + 1, |
| self.catch_scopes.len(), |
| "catch scopes should be added and removed in stack order" |
| ); |
| |
| self.catch_scopes.pop().unwrap(); |
| |
| result |
| } |
| |
| fn with_loop_scope<T, F>(&mut self, loop_id: NodeId, f: F) -> T |
| where |
| F: FnOnce(&mut LoweringContext<'_>) -> T, |
| { |
| // We're no longer in the base loop's condition; we're in another loop. |
| let was_in_loop_condition = self.is_in_loop_condition; |
| self.is_in_loop_condition = false; |
| |
| let len = self.loop_scopes.len(); |
| self.loop_scopes.push(loop_id); |
| |
| let result = f(self); |
| assert_eq!( |
| len + 1, |
| self.loop_scopes.len(), |
| "loop scopes should be added and removed in stack order" |
| ); |
| |
| self.loop_scopes.pop().unwrap(); |
| |
| self.is_in_loop_condition = was_in_loop_condition; |
| |
| result |
| } |
| |
| fn with_loop_condition_scope<T, F>(&mut self, f: F) -> T |
| where |
| F: FnOnce(&mut LoweringContext<'_>) -> T, |
| { |
| let was_in_loop_condition = self.is_in_loop_condition; |
| self.is_in_loop_condition = true; |
| |
| let result = f(self); |
| |
| self.is_in_loop_condition = was_in_loop_condition; |
| |
| result |
| } |
| |
| fn lower_expr_asm(&mut self, asm: &InlineAsm) -> hir::ExprKind { |
| let hir_asm = hir::InlineAsm { |
| inputs: asm.inputs.iter().map(|&(ref c, _)| c.clone()).collect(), |
| outputs: asm.outputs |
| .iter() |
| .map(|out| hir::InlineAsmOutput { |
| constraint: out.constraint.clone(), |
| is_rw: out.is_rw, |
| is_indirect: out.is_indirect, |
| span: out.expr.span, |
| }) |
| .collect(), |
| asm: asm.asm.clone(), |
| asm_str_style: asm.asm_str_style, |
| clobbers: asm.clobbers.clone().into(), |
| volatile: asm.volatile, |
| alignstack: asm.alignstack, |
| dialect: asm.dialect, |
| }; |
| |
| let outputs = asm.outputs |
| .iter() |
| .map(|out| self.lower_expr(&out.expr)) |
| .collect(); |
| |
| let inputs = asm.inputs |
| .iter() |
| .map(|&(_, ref input)| self.lower_expr(input)) |
| .collect(); |
| |
| hir::ExprKind::InlineAsm(P(hir_asm), outputs, inputs) |
| } |
| |
| fn lower_field(&mut self, f: &Field) -> hir::Field { |
| hir::Field { |
| hir_id: self.next_id(), |
| ident: f.ident, |
| expr: P(self.lower_expr(&f.expr)), |
| span: f.span, |
| is_shorthand: f.is_shorthand, |
| } |
| } |
| |
| fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind { |
| match self.generator_kind { |
| Some(hir::GeneratorKind::Gen) => {}, |
| Some(hir::GeneratorKind::Async) => { |
| span_err!( |
| self.sess, |
| span, |
| E0727, |
| "`async` generators are not yet supported", |
| ); |
| self.sess.abort_if_errors(); |
| }, |
| None => self.generator_kind = Some(hir::GeneratorKind::Gen), |
| } |
| |
| let expr = opt_expr |
| .as_ref() |
| .map(|x| self.lower_expr(x)) |
| .unwrap_or_else(|| self.expr_unit(span)); |
| |
| hir::ExprKind::Yield(P(expr), hir::YieldSource::Yield) |
| } |
| |
| /// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into: |
| /// ```rust |
| /// { |
| /// let result = match ::std::iter::IntoIterator::into_iter(<head>) { |
| /// mut iter => { |
| /// [opt_ident]: loop { |
| /// let mut __next; |
| /// match ::std::iter::Iterator::next(&mut iter) { |
| /// ::std::option::Option::Some(val) => __next = val, |
| /// ::std::option::Option::None => break |
| /// }; |
| /// let <pat> = __next; |
| /// StmtKind::Expr(<body>); |
| /// } |
| /// } |
| /// }; |
| /// result |
| /// } |
| /// ``` |
| fn lower_expr_for( |
| &mut self, |
| e: &Expr, |
| pat: &Pat, |
| head: &Expr, |
| body: &Block, |
| opt_label: Option<Label>, |
| ) -> hir::Expr { |
| // expand <head> |
| let mut head = self.lower_expr(head); |
| let head_sp = head.span; |
| let desugared_span = self.mark_span_with_reason( |
| DesugaringKind::ForLoop, |
| head_sp, |
| None, |
| ); |
| head.span = desugared_span; |
| |
| let iter = Ident::with_dummy_span(sym::iter); |
| |
| let next_ident = Ident::with_dummy_span(sym::__next); |
| let (next_pat, next_pat_hid) = self.pat_ident_binding_mode( |
| desugared_span, |
| next_ident, |
| hir::BindingAnnotation::Mutable, |
| ); |
| |
| // `::std::option::Option::Some(val) => __next = val` |
| let pat_arm = { |
| let val_ident = Ident::with_dummy_span(sym::val); |
| let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident); |
| let val_expr = P(self.expr_ident(pat.span, val_ident, val_pat_hid)); |
| let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat_hid)); |
| let assign = P(self.expr( |
| pat.span, |
| hir::ExprKind::Assign(next_expr, val_expr), |
| ThinVec::new(), |
| )); |
| let some_pat = self.pat_some(pat.span, val_pat); |
| self.arm(hir_vec![some_pat], assign) |
| }; |
| |
| // `::std::option::Option::None => break` |
| let break_arm = { |
| let break_expr = |
| self.with_loop_scope(e.id, |this| this.expr_break(e.span, ThinVec::new())); |
| let pat = self.pat_none(e.span); |
| self.arm(hir_vec![pat], break_expr) |
| }; |
| |
| // `mut iter` |
| let (iter_pat, iter_pat_nid) = self.pat_ident_binding_mode( |
| desugared_span, |
| iter, |
| hir::BindingAnnotation::Mutable |
| ); |
| |
| // `match ::std::iter::Iterator::next(&mut iter) { ... }` |
| let match_expr = { |
| let iter = P(self.expr_ident(head_sp, iter, iter_pat_nid)); |
| let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter); |
| let next_path = &[sym::iter, sym::Iterator, sym::next]; |
| let next_expr = P(self.expr_call_std_path( |
| head_sp, |
| next_path, |
| hir_vec![ref_mut_iter], |
| )); |
| let arms = hir_vec![pat_arm, break_arm]; |
| |
| self.expr_match(head_sp, next_expr, arms, hir::MatchSource::ForLoopDesugar) |
| }; |
| let match_stmt = self.stmt_expr(head_sp, match_expr); |
| |
| let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat_hid)); |
| |
| // `let mut __next` |
| let next_let = self.stmt_let_pat( |
| ThinVec::new(), |
| desugared_span, |
| None, |
| next_pat, |
| hir::LocalSource::ForLoopDesugar, |
| ); |
| |
| // `let <pat> = __next` |
| let pat = self.lower_pat(pat); |
| let pat_let = self.stmt_let_pat( |
| ThinVec::new(), |
| head_sp, |
| Some(next_expr), |
| pat, |
| hir::LocalSource::ForLoopDesugar, |
| ); |
| |
| let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false)); |
| let body_expr = self.expr_block(body_block, ThinVec::new()); |
| let body_stmt = self.stmt_expr(body.span, body_expr); |
| |
| let loop_block = P(self.block_all( |
| e.span, |
| hir_vec![next_let, match_stmt, pat_let, body_stmt], |
| None, |
| )); |
| |
| // `[opt_ident]: loop { ... }` |
| let loop_expr = hir::ExprKind::Loop( |
| loop_block, |
| self.lower_label(opt_label), |
| hir::LoopSource::ForLoop, |
| ); |
| let loop_expr = P(hir::Expr { |
| hir_id: self.lower_node_id(e.id), |
| node: loop_expr, |
| span: e.span, |
| attrs: ThinVec::new(), |
| }); |
| |
| // `mut iter => { ... }` |
| let iter_arm = self.arm(hir_vec![iter_pat], loop_expr); |
| |
| // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }` |
| let into_iter_expr = { |
| let into_iter_path = |
| &[sym::iter, sym::IntoIterator, sym::into_iter]; |
| P(self.expr_call_std_path( |
| head_sp, |
| into_iter_path, |
| hir_vec![head], |
| )) |
| }; |
| |
| let match_expr = P(self.expr_match( |
| head_sp, |
| into_iter_expr, |
| hir_vec![iter_arm], |
| hir::MatchSource::ForLoopDesugar, |
| )); |
| |
| // This is effectively `{ let _result = ...; _result }`. |
| // The construct was introduced in #21984 and is necessary to make sure that |
| // temporaries in the `head` expression are dropped and do not leak to the |
| // surrounding scope of the `match` since the `match` is not a terminating scope. |
| // |
| // Also, add the attributes to the outer returned expr node. |
| self.expr_drop_temps(head_sp, match_expr, e.attrs.clone()) |
| } |
| |
| /// Desugar `ExprKind::Try` from: `<expr>?` into: |
| /// ```rust |
| /// match Try::into_result(<expr>) { |
| /// Ok(val) => #[allow(unreachable_code)] val, |
| /// Err(err) => #[allow(unreachable_code)] |
| /// // If there is an enclosing `try {...}`: |
| /// break 'catch_target Try::from_error(From::from(err)), |
| /// // Otherwise: |
| /// return Try::from_error(From::from(err)), |
| /// } |
| /// ``` |
| fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind { |
| let unstable_span = self.mark_span_with_reason( |
| DesugaringKind::QuestionMark, |
| span, |
| self.allow_try_trait.clone(), |
| ); |
| let try_span = self.sess.source_map().end_point(span); |
| let try_span = self.mark_span_with_reason( |
| DesugaringKind::QuestionMark, |
| try_span, |
| self.allow_try_trait.clone(), |
| ); |
| |
| // `Try::into_result(<expr>)` |
| let scrutinee = { |
| // expand <expr> |
| let sub_expr = self.lower_expr(sub_expr); |
| |
| let path = &[sym::ops, sym::Try, sym::into_result]; |
| P(self.expr_call_std_path(unstable_span, path, hir_vec![sub_expr])) |
| }; |
| |
| // `#[allow(unreachable_code)]` |
| let attr = { |
| // `allow(unreachable_code)` |
| let allow = { |
| let allow_ident = Ident::new(sym::allow, span); |
| let uc_ident = Ident::new(sym::unreachable_code, span); |
| let uc_nested = attr::mk_nested_word_item(uc_ident); |
| attr::mk_list_item(allow_ident, vec![uc_nested]) |
| }; |
| attr::mk_attr_outer(allow) |
| }; |
| let attrs = vec![attr]; |
| |
| // `Ok(val) => #[allow(unreachable_code)] val,` |
| let ok_arm = { |
| let val_ident = Ident::with_dummy_span(sym::val); |
| let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident); |
| let val_expr = P(self.expr_ident_with_attrs( |
| span, |
| val_ident, |
| val_pat_nid, |
| ThinVec::from(attrs.clone()), |
| )); |
| let ok_pat = self.pat_ok(span, val_pat); |
| self.arm(hir_vec![ok_pat], val_expr) |
| }; |
| |
| // `Err(err) => #[allow(unreachable_code)] |
| // return Try::from_error(From::from(err)),` |
| let err_arm = { |
| let err_ident = Ident::with_dummy_span(sym::err); |
| let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident); |
| let from_expr = { |
| let from_path = &[sym::convert, sym::From, sym::from]; |
| let err_expr = self.expr_ident(try_span, err_ident, err_local_nid); |
| self.expr_call_std_path(try_span, from_path, hir_vec![err_expr]) |
| }; |
| let from_err_expr = |
| self.wrap_in_try_constructor(sym::from_error, from_expr, unstable_span); |
| let thin_attrs = ThinVec::from(attrs); |
| let catch_scope = self.catch_scopes.last().map(|x| *x); |
| let ret_expr = if let Some(catch_node) = catch_scope { |
| let target_id = Ok(self.lower_node_id(catch_node)); |
| P(self.expr( |
| try_span, |
| hir::ExprKind::Break( |
| hir::Destination { |
| label: None, |
| target_id, |
| }, |
| Some(from_err_expr), |
| ), |
| thin_attrs, |
| )) |
| } else { |
| P(self.expr(try_span, hir::ExprKind::Ret(Some(from_err_expr)), thin_attrs)) |
| }; |
| |
| let err_pat = self.pat_err(try_span, err_local); |
| self.arm(hir_vec![err_pat], ret_expr) |
| }; |
| |
| hir::ExprKind::Match( |
| scrutinee, |
| hir_vec![err_arm, ok_arm], |
| hir::MatchSource::TryDesugar, |
| ) |
| } |
| |
| // ========================================================================= |
| // Helper methods for building HIR. |
| // ========================================================================= |
| |
| /// Constructs a `true` or `false` literal expression. |
| pub(super) fn expr_bool(&mut self, span: Span, val: bool) -> hir::Expr { |
| let lit = Spanned { span, node: LitKind::Bool(val) }; |
| self.expr(span, hir::ExprKind::Lit(lit), ThinVec::new()) |
| } |
| |
| /// Wrap the given `expr` in a terminating scope using `hir::ExprKind::DropTemps`. |
| /// |
| /// In terms of drop order, it has the same effect as wrapping `expr` in |
| /// `{ let _t = $expr; _t }` but should provide better compile-time performance. |
| /// |
| /// The drop order can be important in e.g. `if expr { .. }`. |
| pub(super) fn expr_drop_temps( |
| &mut self, |
| span: Span, |
| expr: P<hir::Expr>, |
| attrs: ThinVec<Attribute> |
| ) -> hir::Expr { |
| self.expr(span, hir::ExprKind::DropTemps(expr), attrs) |
| } |
| |
| fn expr_match( |
| &mut self, |
| span: Span, |
| arg: P<hir::Expr>, |
| arms: hir::HirVec<hir::Arm>, |
| source: hir::MatchSource, |
| ) -> hir::Expr { |
| self.expr(span, hir::ExprKind::Match(arg, arms, source), ThinVec::new()) |
| } |
| |
| fn expr_break(&mut self, span: Span, attrs: ThinVec<Attribute>) -> P<hir::Expr> { |
| let expr_break = hir::ExprKind::Break(self.lower_loop_destination(None), None); |
| P(self.expr(span, expr_break, attrs)) |
| } |
| |
| fn expr_mut_addr_of(&mut self, span: Span, e: P<hir::Expr>) -> hir::Expr { |
| self.expr(span, hir::ExprKind::AddrOf(hir::MutMutable, e), ThinVec::new()) |
| } |
| |
| fn expr_unit(&mut self, sp: Span) -> hir::Expr { |
| self.expr_tuple(sp, hir_vec![]) |
| } |
| |
| fn expr_tuple(&mut self, sp: Span, exprs: hir::HirVec<hir::Expr>) -> hir::Expr { |
| self.expr(sp, hir::ExprKind::Tup(exprs), ThinVec::new()) |
| } |
| |
| fn expr_call( |
| &mut self, |
| span: Span, |
| e: P<hir::Expr>, |
| args: hir::HirVec<hir::Expr>, |
| ) -> hir::Expr { |
| self.expr(span, hir::ExprKind::Call(e, args), ThinVec::new()) |
| } |
| |
| // Note: associated functions must use `expr_call_std_path`. |
| fn expr_call_std_path( |
| &mut self, |
| span: Span, |
| path_components: &[Symbol], |
| args: hir::HirVec<hir::Expr>, |
| ) -> hir::Expr { |
| let path = P(self.expr_std_path(span, path_components, None, ThinVec::new())); |
| self.expr_call(span, path, args) |
| } |
| |
| // Create an expression calling an associated function of an std type. |
| // |
| // Associated functions cannot be resolved through the normal `std_path` function, |
| // as they are resolved differently and so cannot use `expr_call_std_path`. |
| // |
| // This function accepts the path component (`ty_path_components`) separately from |
| // the name of the associated function (`assoc_fn_name`) in order to facilitate |
| // separate resolution of the type and creation of a path referring to its associated |
| // function. |
| fn expr_call_std_assoc_fn( |
| &mut self, |
| ty_path_id: hir::HirId, |
| span: Span, |
| ty_path_components: &[Symbol], |
| assoc_fn_name: &str, |
| args: hir::HirVec<hir::Expr>, |
| ) -> hir::ExprKind { |
| let ty_path = P(self.std_path(span, ty_path_components, None, false)); |
| let ty = P(self.ty_path(ty_path_id, span, hir::QPath::Resolved(None, ty_path))); |
| let fn_seg = P(hir::PathSegment::from_ident(Ident::from_str(assoc_fn_name))); |
| let fn_path = hir::QPath::TypeRelative(ty, fn_seg); |
| let fn_expr = P(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new())); |
| hir::ExprKind::Call(fn_expr, args) |
| } |
| |
| fn expr_std_path( |
| &mut self, |
| span: Span, |
| components: &[Symbol], |
| params: Option<P<hir::GenericArgs>>, |
| attrs: ThinVec<Attribute>, |
| ) -> hir::Expr { |
| let path = self.std_path(span, components, params, true); |
| self.expr( |
| span, |
| hir::ExprKind::Path(hir::QPath::Resolved(None, P(path))), |
| attrs, |
| ) |
| } |
| |
| pub(super) fn expr_ident(&mut self, sp: Span, ident: Ident, binding: hir::HirId) -> hir::Expr { |
| self.expr_ident_with_attrs(sp, ident, binding, ThinVec::new()) |
| } |
| |
| fn expr_ident_with_attrs( |
| &mut self, |
| span: Span, |
| ident: Ident, |
| binding: hir::HirId, |
| attrs: ThinVec<Attribute>, |
| ) -> hir::Expr { |
| let expr_path = hir::ExprKind::Path(hir::QPath::Resolved( |
| None, |
| P(hir::Path { |
| span, |
| res: Res::Local(binding), |
| segments: hir_vec![hir::PathSegment::from_ident(ident)], |
| }), |
| )); |
| |
| self.expr(span, expr_path, attrs) |
| } |
| |
| fn expr_unsafe(&mut self, expr: P<hir::Expr>) -> hir::Expr { |
| let hir_id = self.next_id(); |
| let span = expr.span; |
| self.expr( |
| span, |
| hir::ExprKind::Block(P(hir::Block { |
| stmts: hir_vec![], |
| expr: Some(expr), |
| hir_id, |
| rules: hir::UnsafeBlock(hir::CompilerGenerated), |
| span, |
| targeted_by_break: false, |
| }), None), |
| ThinVec::new(), |
| ) |
| } |
| |
| fn expr_block_empty(&mut self, span: Span) -> hir::Expr { |
| let blk = self.block_all(span, hir_vec![], None); |
| self.expr_block(P(blk), ThinVec::new()) |
| } |
| |
| pub(super) fn expr_block(&mut self, b: P<hir::Block>, attrs: ThinVec<Attribute>) -> hir::Expr { |
| self.expr(b.span, hir::ExprKind::Block(b, None), attrs) |
| } |
| |
| pub(super) fn expr( |
| &mut self, |
| span: Span, |
| node: hir::ExprKind, |
| attrs: ThinVec<Attribute> |
| ) -> hir::Expr { |
| hir::Expr { |
| hir_id: self.next_id(), |
| node, |
| span, |
| attrs, |
| } |
| } |
| |
| fn field(&mut self, ident: Ident, expr: P<hir::Expr>, span: Span) -> hir::Field { |
| hir::Field { |
| hir_id: self.next_id(), |
| ident, |
| span, |
| expr, |
| is_shorthand: false, |
| } |
| } |
| |
| /// HACK(or_patterns; Centril | dlrobertson): For now we don't push down top level or-patterns |
| /// `p | q` into `hir::PatKind::Or(...)` as post-lowering bits of the compiler are not ready |
| /// to deal with it. This should by fixed by pushing it down to HIR and then HAIR. |
| fn arm(&mut self, pats: HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm { |
| hir::Arm { |
| hir_id: self.next_id(), |
| attrs: hir_vec![], |
| pats, |
| guard: None, |
| span: expr.span, |
| body: expr, |
| } |
| } |
| } |