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};
+use syntax::source_map::{respan, DesugaringKind, Span, Spanned};
use syntax::symbol::{sym, Symbol};
impl LoweringContext<'_> {
let ohs = P(self.lower_expr(ohs));
hir::ExprKind::AddrOf(m, ohs)
}
- ExprKind::Let(ref pats, ref scrutinee) => {
- // If we got here, the `let` expression is not allowed.
- self.sess
- .struct_span_err(e.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 { pats => 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 `pats` and `scrutinee`.
- // 3. `pats` 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 pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
- let expr = self.expr_bool(e.span, true);
- self.arm(pats, P(expr))
- };
- let else_arm = {
- let pats = hir_vec![self.pat_wild(e.span)];
- let expr = self.expr_bool(e.span, false);
- self.arm(pats, P(expr))
- };
- hir::ExprKind::Match(
- P(scrutinee),
- vec![then_arm, else_arm].into(),
- hir::MatchSource::Normal,
- )
- }
- // FIXME(#53667): handle lowering of && and parens.
+ ExprKind::Let(ref pats, ref scrutinee) => self.lower_expr_let(e.span, pats, scrutinee),
ExprKind::If(ref cond, ref then, ref else_opt) => {
- // `_ => else_block` where `else_block` is `{}` if there's `None`:
- let else_pat = self.pat_wild(e.span);
- let (else_expr, contains_else_clause) = match else_opt {
- None => (self.expr_block_empty(e.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_blk = self.lower_block(then, false);
- let then_expr = self.expr_block(then_blk, ThinVec::new());
- let (then_pats, scrutinee, desugar) = match cond.node {
- // `<pat> => <then>`:
- ExprKind::Let(ref pats, ref scrutinee) => {
- let scrutinee = self.lower_expr(scrutinee);
- let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
- let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause };
- (pats, scrutinee, desugar)
- }
- // `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 desugar = hir::MatchSource::IfDesugar { contains_else_clause };
- let pats = hir_vec![self.pat_bool(e.span, true)];
- (pats, cond, desugar)
- }
- };
- let then_arm = self.arm(then_pats, P(then_expr));
-
- hir::ExprKind::Match(P(scrutinee), vec![then_arm, else_arm].into(), desugar)
+ self.lower_expr_if(e.span, cond, then, else_opt.as_deref())
}
- // FIXME(#53667): handle lowering of && and parens.
ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| {
- // 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 = this.pat_wild(e.span);
- let else_expr = this.expr_break(e.span, ThinVec::new());
- this.arm(hir_vec![else_pat], else_expr)
- };
-
- // Handle then + scrutinee:
- let then_blk = this.lower_block(body, false);
- let then_expr = this.expr_block(then_blk, ThinVec::new());
- let (then_pats, scrutinee, desugar, source) = match cond.node {
- ExprKind::Let(ref pats, ref scrutinee) => {
- // to:
- //
- // [opt_ident]: loop {
- // match <sub_expr> {
- // <pat> => <body>,
- // _ => break
- // }
- // }
- let scrutinee = this.with_loop_condition_scope(|t| t.lower_expr(scrutinee));
- let pats = pats.iter().map(|pat| this.lower_pat(pat)).collect();
- let desugar = hir::MatchSource::WhileLetDesugar;
- (pats, scrutinee, desugar, hir::LoopSource::WhileLet)
- }
- _ => {
- // We desugar: `'label: while $cond $body` into:
- //
- // ```
- // 'label: loop {
- // match DropTemps($cond) {
- // true => $body,
- // _ => break,
- // }
- // }
- // ```
-
- // Lower condition:
- let cond = this.with_loop_condition_scope(|this| this.lower_expr(cond));
- let span_block = this.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 = this.expr_drop_temps(span_block, P(cond), ThinVec::new());
-
- let desugar = hir::MatchSource::WhileDesugar;
- // `true => <then>`:
- let pats = hir_vec![this.pat_bool(e.span, true)];
- (pats, cond, desugar, hir::LoopSource::While)
- }
- };
- let then_arm = this.arm(then_pats, P(then_expr));
-
- // `match <scrutinee> { ... }`
- let match_expr = this.expr_match(
- scrutinee.span,
- P(scrutinee),
- hir_vec![then_arm, else_arm],
- desugar,
- );
-
- // `[opt_ident]: loop { ... }`
- hir::ExprKind::Loop(
- P(this.block_expr(P(match_expr))),
- this.lower_label(opt_label),
- source
- )
+ 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(
hir::ExprKind::Path(qpath)
}
ExprKind::Break(opt_label, ref opt_expr) => {
- let 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| (e.id, label)))
- };
hir::ExprKind::Break(
- destination,
+ 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(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| (e.id, 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),
}
}
+ 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(pats, scrutinee)` into:
+ /// ```rust
+ /// match scrutinee { pats => true, _ => false }
+ /// ```
+ fn lower_expr_let(
+ &mut self,
+ span: Span,
+ pats: &[AstP<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 { pats => 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 `pats` and `scrutinee`.
+ // 3. `pats` 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 pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
+ let expr = self.expr_bool(span, true);
+ self.arm(pats, P(expr))
+ };
+ let else_arm = {
+ let pats = hir_vec![self.pat_wild(span)];
+ let expr = self.expr_bool(span, false);
+ self.arm(pats, 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_blk = self.lower_block(then, false);
+ let then_expr = self.expr_block(then_blk, ThinVec::new());
+ let (then_pats, scrutinee, desugar) = match cond.node {
+ // `<pat> => <then>`:
+ ExprKind::Let(ref pats, ref scrutinee) => {
+ let scrutinee = self.lower_expr(scrutinee);
+ let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
+ let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause };
+ (pats, scrutinee, desugar)
+ }
+ // `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 desugar = hir::MatchSource::IfDesugar { contains_else_clause };
+ let pats = hir_vec![self.pat_bool(span, true)];
+ (pats, cond, desugar)
+ }
+ };
+ let then_arm = self.arm(then_pats, 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_blk = self.lower_block(body, false);
+ let then_expr = self.expr_block(then_blk, ThinVec::new());
+ let (then_pats, scrutinee, desugar, source) = match cond.node {
+ ExprKind::Let(ref pats, 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 pats = pats.iter().map(|pat| self.lower_pat(pat)).collect();
+ let desugar = hir::MatchSource::WhileLetDesugar;
+ (pats, scrutinee, desugar, hir::LoopSource::WhileLet)
+ }
+ _ => {
+ // We desugar: `'label: while $cond $body` into:
+ //
+ // ```
+ // 'label: loop {
+ // match DropTemps($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());
+
+ let desugar = hir::MatchSource::WhileDesugar;
+ // `true => <then>`:
+ let pats = hir_vec![self.pat_bool(span, true)];
+ (pats, cond, desugar, hir::LoopSource::While)
+ }
+ };
+ let then_arm = self.arm(then_pats, 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(
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: arm.pats.iter().map(|x| self.lower_pat(x)).collect(),
+ 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,
+ }
+ }
+
+ 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
/// {
// let mut pinned = <expr>;
let expr = P(self.lower_expr(expr));
- let pinned_ident = Ident::with_empty_ctxt(sym::pinned);
+ let pinned_ident = Ident::with_dummy_span(sym::pinned);
let (pinned_pat, pinned_pat_hid) = self.pat_ident_binding_mode(
span,
pinned_ident,
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_empty_ctxt(sym::result);
+ 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(
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| {
generator_kind,
movability,
);
+ let capture_clause = this.lower_capture_clause(capture_clause);
+ this.current_item = prev;
hir::ExprKind::Closure(
- this.lower_capture_clause(capture_clause),
+ capture_clause,
fn_decl,
body_id,
fn_decl_span,
})
}
+ 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 arguments"
+ );
+ 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,
}
}
+ 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(),
volatile: asm.volatile,
alignstack: asm.alignstack,
dialect: asm.dialect,
- ctxt: asm.ctxt,
};
let outputs = asm.outputs
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) => {},
);
head.span = desugared_span;
- let iter = Ident::with_empty_ctxt(sym::iter);
+ let iter = Ident::with_dummy_span(sym::iter);
- let next_ident = Ident::with_empty_ctxt(sym::__next);
+ let next_ident = Ident::with_dummy_span(sym::__next);
let (next_pat, next_pat_hid) = self.pat_ident_binding_mode(
desugared_span,
next_ident,
// `::std::option::Option::Some(val) => __next = val`
let pat_arm = {
- let val_ident = Ident::with_empty_ctxt(sym::val);
+ 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));
// `Ok(val) => #[allow(unreachable_code)] val,`
let ok_arm = {
- let val_ident = Ident::with_empty_ctxt(sym::val);
+ 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,
// `Err(err) => #[allow(unreachable_code)]
// return Try::from_error(From::from(err)),`
let err_arm = {
- let err_ident = Ident::with_empty_ctxt(sym::err);
+ 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];
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 { .. }`.
+ 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,
+ }
+ }
+
+ fn arm(&mut self, pats: hir::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,
+ }
+ }
}