use crate::build::ForGuard::OutsideGuard;
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
use crate::thir::*;
-use rustc_hir as hir;
use rustc_middle::mir::*;
use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN;
use rustc_session::lint::Level;
&mut self,
destination: Place<'tcx>,
block: BasicBlock,
- ast_block: &'tcx hir::Block<'tcx>,
+ ast_block: &Block<'tcx>,
source_info: SourceInfo,
) -> BlockAnd<()> {
let Block {
expr,
targeted_by_break,
safety_mode,
- } = self.hir.mirror(ast_block);
+ } = ast_block;
self.in_opt_scope(opt_destruction_scope.map(|de| (de, source_info)), move |this| {
- this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
- if targeted_by_break {
- this.in_breakable_scope(None, destination, span, |this| {
+ this.in_scope((*region_scope, source_info), LintLevel::Inherited, move |this| {
+ if *targeted_by_break {
+ this.in_breakable_scope(None, destination, *span, |this| {
Some(this.ast_block_stmts(
destination,
block,
- span,
- stmts,
- expr,
- safety_mode,
+ *span,
+ &stmts,
+ expr.as_deref(),
+ *safety_mode,
))
})
} else {
- this.ast_block_stmts(destination, block, span, stmts, expr, safety_mode)
+ this.ast_block_stmts(
+ destination,
+ block,
+ *span,
+ &stmts,
+ expr.as_deref(),
+ *safety_mode,
+ )
}
})
})
destination: Place<'tcx>,
mut block: BasicBlock,
span: Span,
- stmts: Vec<StmtRef<'tcx>>,
- expr: Option<ExprRef<'tcx>>,
+ stmts: &[Stmt<'tcx>],
+ expr: Option<&Expr<'tcx>>,
safety_mode: BlockSafety,
) -> BlockAnd<()> {
let this = self;
this.update_source_scope_for_safety_mode(span, safety_mode);
let source_info = this.source_info(span);
- for stmt in stmts {
- let Stmt { kind, opt_destruction_scope } = this.hir.mirror(stmt);
+ for Stmt { kind, opt_destruction_scope } in stmts {
match kind {
StmtKind::Expr { scope, expr } => {
this.block_context.push(BlockFrame::Statement { ignores_expr_result: true });
block = this.in_opt_scope(
opt_destruction_scope.map(|de| (de, source_info)),
|this| {
- let si = (scope, source_info);
+ let si = (*scope, source_info);
this.in_scope(si, LintLevel::Inherited, |this| {
- let expr = this.hir.mirror(expr);
- this.stmt_expr(block, expr, Some(scope))
+ this.stmt_expr(block, &expr, Some(*scope))
})
}
)
this.block_context.push(BlockFrame::Statement { ignores_expr_result });
// Enter the remainder scope, i.e., the bindings' destruction scope.
- this.push_scope((remainder_scope, source_info));
+ this.push_scope((*remainder_scope, source_info));
let_scope_stack.push(remainder_scope);
// Declare the bindings, which may create a source scope.
// Evaluate the initializer, if present.
if let Some(init) = initializer {
- let initializer_span = init.span();
+ let initializer_span = init.span;
unpack!(
block = this.in_opt_scope(
opt_destruction_scope.map(|de| (de, source_info)),
|this| {
- let scope = (init_scope, source_info);
- this.in_scope(scope, lint_level, |this| {
+ let scope = (*init_scope, source_info);
+ this.in_scope(scope, *lint_level, |this| {
this.declare_bindings(
visibility_scope,
remainder_span,
ArmHasGuard(false),
Some((None, initializer_span)),
);
- this.expr_into_pattern(block, pattern, init)
+ this.expr_into_pattern(block, pattern.clone(), &init)
})
}
)
);
} else {
- let scope = (init_scope, source_info);
- unpack!(this.in_scope(scope, lint_level, |this| {
+ let scope = (*init_scope, source_info);
+ unpack!(this.in_scope(scope, *lint_level, |this| {
this.declare_bindings(
visibility_scope,
remainder_span,
if let Some(expr) = expr {
let tail_result_is_ignored =
destination_ty.is_unit() || this.block_context.currently_ignores_tail_results();
- let span = match expr {
- ExprRef::Thir(expr) => expr.span,
- ExprRef::Mirror(ref expr) => expr.span,
- };
- this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored, span });
+ this.block_context
+ .push(BlockFrame::TailExpr { tail_result_is_ignored, span: expr.span });
- unpack!(block = this.into(destination, block, expr));
+ unpack!(block = this.expr_into_dest(destination, block, expr));
let popped = this.block_context.pop();
assert!(popped.map_or(false, |bf| bf.is_tail_expr()));
// Finally, we pop all the let scopes before exiting out from the scope of block
// itself.
for scope in let_scope_stack.into_iter().rev() {
- unpack!(block = this.pop_scope((scope, source_info), block));
+ unpack!(block = this.pop_scope((*scope, source_info), block));
}
// Restore the original source scope.
this.source_scope = outer_source_scope;
impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Compile `expr`, yielding a compile-time constant. Assumes that
/// `expr` is a valid compile-time constant!
- crate fn as_constant<M>(&mut self, expr: M) -> Constant<'tcx>
- where
- M: Mirror<'tcx, Output = Expr<'tcx>>,
- {
- let expr = self.hir.mirror(expr);
- self.expr_as_constant(expr)
- }
-
- fn expr_as_constant(&mut self, expr: Expr<'tcx>) -> Constant<'tcx> {
+ crate fn as_constant(&mut self, expr: &Expr<'tcx>) -> Constant<'tcx> {
let this = self;
let Expr { ty, temp_lifetime: _, span, kind } = expr;
match kind {
- ExprKind::Scope { region_scope: _, lint_level: _, value } => this.as_constant(value),
+ ExprKind::Scope { region_scope: _, lint_level: _, value } => this.as_constant(&value),
ExprKind::Literal { literal, user_ty, const_id: _ } => {
let user_ty = user_ty.map(|user_ty| {
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
- span,
+ span: *span,
user_ty,
inferred_ty: ty,
})
});
- assert_eq!(literal.ty, ty);
- Constant { span, user_ty, literal }
+ assert_eq!(literal.ty, *ty);
+ Constant { span: *span, user_ty, literal }
+ }
+ ExprKind::StaticRef { literal, .. } => Constant { span: *span, user_ty: None, literal },
+ ExprKind::ConstBlock { value } => {
+ Constant { span: *span, user_ty: None, literal: value }
}
- ExprKind::StaticRef { literal, .. } => Constant { span, user_ty: None, literal },
- ExprKind::ConstBlock { value } => Constant { span, user_ty: None, literal: value },
- _ => span_bug!(span, "expression is not a valid constant {:?}", kind),
+ _ => span_bug!(*span, "expression is not a valid constant {:?}", kind),
}
}
}
/// after the current enclosing `ExprKind::Scope` has ended, so
/// please do *not* return it from functions to avoid bad
/// miscompiles.
- crate fn as_local_operand<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Operand<'tcx>>
- where
- M: Mirror<'tcx, Output = Expr<'tcx>>,
- {
+ crate fn as_local_operand(
+ &mut self,
+ block: BasicBlock,
+ expr: &Expr<'tcx>,
+ ) -> BlockAnd<Operand<'tcx>> {
let local_scope = self.local_scope();
self.as_operand(block, Some(local_scope), expr)
}
/// value to the stack.
///
/// See #68034 for more details.
- crate fn as_local_call_operand<M>(
+ crate fn as_local_call_operand(
&mut self,
block: BasicBlock,
- expr: M,
- ) -> BlockAnd<Operand<'tcx>>
- where
- M: Mirror<'tcx, Output = Expr<'tcx>>,
- {
+ expr: &Expr<'tcx>,
+ ) -> BlockAnd<Operand<'tcx>> {
let local_scope = self.local_scope();
self.as_call_operand(block, Some(local_scope), expr)
}
/// this time.
///
/// The operand is known to be live until the end of `scope`.
- crate fn as_operand<M>(
- &mut self,
- block: BasicBlock,
- scope: Option<region::Scope>,
- expr: M,
- ) -> BlockAnd<Operand<'tcx>>
- where
- M: Mirror<'tcx, Output = Expr<'tcx>>,
- {
- let expr = self.hir.mirror(expr);
- self.expr_as_operand(block, scope, expr)
- }
-
+ ///
/// Like `as_local_call_operand`, except that the argument will
/// not be valid once `scope` ends.
- fn as_call_operand<M>(
- &mut self,
- block: BasicBlock,
- scope: Option<region::Scope>,
- expr: M,
- ) -> BlockAnd<Operand<'tcx>>
- where
- M: Mirror<'tcx, Output = Expr<'tcx>>,
- {
- let expr = self.hir.mirror(expr);
- self.expr_as_call_operand(block, scope, expr)
- }
-
- fn expr_as_operand(
+ crate fn as_operand(
&mut self,
mut block: BasicBlock,
scope: Option<region::Scope>,
- expr: Expr<'tcx>,
+ expr: &Expr<'tcx>,
) -> BlockAnd<Operand<'tcx>> {
- debug!("expr_as_operand(block={:?}, expr={:?})", block, expr);
+ debug!("as_operand(block={:?}, expr={:?})", block, expr);
let this = self;
- if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
+ if let ExprKind::Scope { region_scope, lint_level, value } = &expr.kind {
let source_info = this.source_info(expr.span);
- let region_scope = (region_scope, source_info);
+ let region_scope = (*region_scope, source_info);
return this
- .in_scope(region_scope, lint_level, |this| this.as_operand(block, scope, value));
+ .in_scope(region_scope, *lint_level, |this| this.as_operand(block, scope, &value));
}
let category = Category::of(&expr.kind).unwrap();
- debug!("expr_as_operand: category={:?} for={:?}", category, expr.kind);
+ debug!("as_operand: category={:?} for={:?}", category, expr.kind);
match category {
Category::Constant => {
let constant = this.as_constant(expr);
}
}
- fn expr_as_call_operand(
+ crate fn as_call_operand(
&mut self,
mut block: BasicBlock,
scope: Option<region::Scope>,
- expr: Expr<'tcx>,
+ expr: &Expr<'tcx>,
) -> BlockAnd<Operand<'tcx>> {
- debug!("expr_as_call_operand(block={:?}, expr={:?})", block, expr);
+ debug!("as_call_operand(block={:?}, expr={:?})", block, expr);
let this = self;
- if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
+ if let ExprKind::Scope { region_scope, lint_level, value } = &expr.kind {
let source_info = this.source_info(expr.span);
- let region_scope = (region_scope, source_info);
- return this.in_scope(region_scope, lint_level, |this| {
- this.as_call_operand(block, scope, value)
+ let region_scope = (*region_scope, source_info);
+ return this.in_scope(region_scope, *lint_level, |this| {
+ this.as_call_operand(block, scope, &value)
});
}
// As described above, detect the case where we are passing a value of unsized
// type, and that value is coming from the deref of a box.
if let ExprKind::Deref { ref arg } = expr.kind {
- let arg = this.hir.mirror(arg.clone());
-
// Generate let tmp0 = arg0
let operand = unpack!(block = this.as_temp(block, scope, arg, Mutability::Mut));
}
}
- this.expr_as_operand(block, scope, expr)
+ this.as_operand(block, scope, expr)
}
}
/// Extra care is needed if any user code is allowed to run between calling
/// this method and using it, as is the case for `match` and index
/// expressions.
- crate fn as_place<M>(&mut self, mut block: BasicBlock, expr: M) -> BlockAnd<Place<'tcx>>
- where
- M: Mirror<'tcx, Output = Expr<'tcx>>,
- {
+ crate fn as_place(
+ &mut self,
+ mut block: BasicBlock,
+ expr: &Expr<'tcx>,
+ ) -> BlockAnd<Place<'tcx>> {
let place_builder = unpack!(block = self.as_place_builder(block, expr));
block.and(place_builder.into_place(self.hir.tcx(), self.hir.typeck_results()))
}
/// This is used when constructing a compound `Place`, so that we can avoid creating
/// intermediate `Place` values until we know the full set of projections.
- crate fn as_place_builder<M>(
+ crate fn as_place_builder(
&mut self,
block: BasicBlock,
- expr: M,
- ) -> BlockAnd<PlaceBuilder<'tcx>>
- where
- M: Mirror<'tcx, Output = Expr<'tcx>>,
- {
- let expr = self.hir.mirror(expr);
+ expr: &Expr<'tcx>,
+ ) -> BlockAnd<PlaceBuilder<'tcx>> {
self.expr_as_place(block, expr, Mutability::Mut, None)
}
/// place. The place itself may or may not be mutable:
/// * If this expr is a place expr like a.b, then we will return that place.
/// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
- crate fn as_read_only_place<M>(
+ crate fn as_read_only_place(
&mut self,
mut block: BasicBlock,
- expr: M,
- ) -> BlockAnd<Place<'tcx>>
- where
- M: Mirror<'tcx, Output = Expr<'tcx>>,
- {
+ expr: &Expr<'tcx>,
+ ) -> BlockAnd<Place<'tcx>> {
let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
block.and(place_builder.into_place(self.hir.tcx(), self.hir.typeck_results()))
}
/// place. The place itself may or may not be mutable:
/// * If this expr is a place expr like a.b, then we will return that place.
/// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
- fn as_read_only_place_builder<M>(
+ fn as_read_only_place_builder(
&mut self,
block: BasicBlock,
- expr: M,
- ) -> BlockAnd<PlaceBuilder<'tcx>>
- where
- M: Mirror<'tcx, Output = Expr<'tcx>>,
- {
- let expr = self.hir.mirror(expr);
+ expr: &Expr<'tcx>,
+ ) -> BlockAnd<PlaceBuilder<'tcx>> {
self.expr_as_place(block, expr, Mutability::Not, None)
}
fn expr_as_place(
&mut self,
mut block: BasicBlock,
- expr: Expr<'tcx>,
+ expr: &Expr<'tcx>,
mutability: Mutability,
fake_borrow_temps: Option<&mut Vec<Local>>,
) -> BlockAnd<PlaceBuilder<'tcx>> {
let this = self;
let expr_span = expr.span;
let source_info = this.source_info(expr_span);
- match expr.kind {
+ match &expr.kind {
ExprKind::Scope { region_scope, lint_level, value } => {
- this.in_scope((region_scope, source_info), lint_level, |this| {
- let value = this.hir.mirror(value);
- this.expr_as_place(block, value, mutability, fake_borrow_temps)
+ this.in_scope((*region_scope, source_info), *lint_level, |this| {
+ this.expr_as_place(block, &value, mutability, fake_borrow_temps)
})
}
ExprKind::Field { lhs, name } => {
- let lhs = this.hir.mirror(lhs);
- let place_builder =
- unpack!(block = this.expr_as_place(block, lhs, mutability, fake_borrow_temps,));
- block.and(place_builder.field(name, expr.ty))
+ let place_builder = unpack!(
+ block = this.expr_as_place(block, &lhs, mutability, fake_borrow_temps,)
+ );
+ block.and(place_builder.field(*name, expr.ty))
}
ExprKind::Deref { arg } => {
- let arg = this.hir.mirror(arg);
- let place_builder =
- unpack!(block = this.expr_as_place(block, arg, mutability, fake_borrow_temps,));
+ let place_builder = unpack!(
+ block = this.expr_as_place(block, &arg, mutability, fake_borrow_temps,)
+ );
block.and(place_builder.deref())
}
ExprKind::Index { lhs, index } => this.lower_index_expression(
block,
- lhs,
- index,
+ &lhs,
+ &index,
mutability,
fake_borrow_temps,
expr.temp_lifetime,
source_info,
),
ExprKind::UpvarRef { closure_def_id, var_hir_id } => {
- let upvar_id = ty::UpvarId::new(var_hir_id, closure_def_id.expect_local());
+ let upvar_id = ty::UpvarId::new(*var_hir_id, closure_def_id.expect_local());
this.lower_captured_upvar(block, upvar_id)
}
ExprKind::VarRef { id } => {
- let place_builder = if this.is_bound_var_in_guard(id) {
- let index = this.var_local_id(id, RefWithinGuard);
+ let place_builder = if this.is_bound_var_in_guard(*id) {
+ let index = this.var_local_id(*id, RefWithinGuard);
PlaceBuilder::from(index).deref()
} else {
- let index = this.var_local_id(id, OutsideGuard);
+ let index = this.var_local_id(*id, OutsideGuard);
PlaceBuilder::from(index)
};
block.and(place_builder)
}
ExprKind::PlaceTypeAscription { source, user_ty } => {
- let source = this.hir.mirror(source);
let place_builder = unpack!(
- block = this.expr_as_place(block, source, mutability, fake_borrow_temps,)
+ block = this.expr_as_place(block, &source, mutability, fake_borrow_temps,)
);
if let Some(user_ty) = user_ty {
let annotation_index =
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
span: source_info.span,
- user_ty,
+ user_ty: *user_ty,
inferred_ty: expr.ty,
});
block.and(place_builder)
}
ExprKind::ValueTypeAscription { source, user_ty } => {
- let source = this.hir.mirror(source);
let temp =
- unpack!(block = this.as_temp(block, source.temp_lifetime, source, mutability));
+ unpack!(block = this.as_temp(block, source.temp_lifetime, &source, mutability));
if let Some(user_ty) = user_ty {
let annotation_index =
this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
span: source_info.span,
- user_ty,
+ user_ty: *user_ty,
inferred_ty: expr.ty,
});
this.cfg.push(
fn lower_index_expression(
&mut self,
mut block: BasicBlock,
- base: ExprRef<'tcx>,
- index: ExprRef<'tcx>,
+ base: &Expr<'tcx>,
+ index: &Expr<'tcx>,
mutability: Mutability,
fake_borrow_temps: Option<&mut Vec<Local>>,
temp_lifetime: Option<region::Scope>,
expr_span: Span,
source_info: SourceInfo,
) -> BlockAnd<PlaceBuilder<'tcx>> {
- let lhs = self.hir.mirror(base);
-
let base_fake_borrow_temps = &mut Vec::new();
let is_outermost_index = fake_borrow_temps.is_none();
let fake_borrow_temps = fake_borrow_temps.unwrap_or(base_fake_borrow_temps);
let mut base_place =
- unpack!(block = self.expr_as_place(block, lhs, mutability, Some(fake_borrow_temps),));
+ unpack!(block = self.expr_as_place(block, base, mutability, Some(fake_borrow_temps),));
// Making this a *fresh* temporary means we do not have to worry about
// the index changing later: Nothing will ever change this temporary.
/// The operand returned from this function will *not be valid* after
/// an ExprKind::Scope is passed, so please do *not* return it from
/// functions to avoid bad miscompiles.
- crate fn as_local_rvalue<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Rvalue<'tcx>>
- where
- M: Mirror<'tcx, Output = Expr<'tcx>>,
- {
+ crate fn as_local_rvalue(
+ &mut self,
+ block: BasicBlock,
+ expr: &Expr<'tcx>,
+ ) -> BlockAnd<Rvalue<'tcx>> {
let local_scope = self.local_scope();
self.as_rvalue(block, Some(local_scope), expr)
}
/// Compile `expr`, yielding an rvalue.
- fn as_rvalue<M>(
- &mut self,
- block: BasicBlock,
- scope: Option<region::Scope>,
- expr: M,
- ) -> BlockAnd<Rvalue<'tcx>>
- where
- M: Mirror<'tcx, Output = Expr<'tcx>>,
- {
- let expr = self.hir.mirror(expr);
- self.expr_as_rvalue(block, scope, expr)
- }
-
- fn expr_as_rvalue(
+ crate fn as_rvalue(
&mut self,
mut block: BasicBlock,
scope: Option<region::Scope>,
- expr: Expr<'tcx>,
+ expr: &Expr<'tcx>,
) -> BlockAnd<Rvalue<'tcx>> {
debug!("expr_as_rvalue(block={:?}, scope={:?}, expr={:?})", block, scope, expr);
let expr_span = expr.span;
let source_info = this.source_info(expr_span);
- match expr.kind {
- ExprKind::ThreadLocalRef(did) => block.and(Rvalue::ThreadLocalRef(did)),
+ match &expr.kind {
+ ExprKind::ThreadLocalRef(did) => block.and(Rvalue::ThreadLocalRef(*did)),
ExprKind::Scope { region_scope, lint_level, value } => {
- let region_scope = (region_scope, source_info);
- this.in_scope(region_scope, lint_level, |this| this.as_rvalue(block, scope, value))
+ let region_scope = (*region_scope, source_info);
+ this.in_scope(region_scope, *lint_level, |this| {
+ this.as_rvalue(block, scope, &value)
+ })
}
ExprKind::Repeat { value, count } => {
- let value_operand = unpack!(block = this.as_operand(block, scope, value));
+ let value_operand = unpack!(block = this.as_operand(block, scope, &value));
block.and(Rvalue::Repeat(value_operand, count))
}
ExprKind::Binary { op, lhs, rhs } => {
- let lhs = unpack!(block = this.as_operand(block, scope, lhs));
- let rhs = unpack!(block = this.as_operand(block, scope, rhs));
- this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs)
+ let lhs = unpack!(block = this.as_operand(block, scope, &lhs));
+ let rhs = unpack!(block = this.as_operand(block, scope, &rhs));
+ this.build_binary_op(block, *op, expr_span, expr.ty, lhs, rhs)
}
ExprKind::Unary { op, arg } => {
- let arg = unpack!(block = this.as_operand(block, scope, arg));
+ let arg = unpack!(block = this.as_operand(block, scope, &arg));
// Check for -MIN on signed integers
- if this.hir.check_overflow() && op == UnOp::Neg && expr.ty.is_signed() {
+ if this.hir.check_overflow() && *op == UnOp::Neg && expr.ty.is_signed() {
let bool_ty = this.hir.bool_ty();
let minval = this.minval_literal(expr_span, expr.ty);
expr_span,
);
}
- block.and(Rvalue::UnaryOp(op, arg))
+ block.and(Rvalue::UnaryOp(*op, arg))
}
ExprKind::Box { value } => {
- let value = this.hir.mirror(value);
// The `Box<T>` temporary created here is not a part of the HIR,
// and therefore is not considered during generator auto-trait
// determination. See the comment about `box` at `yield_in_scope`.
// initialize the box contents:
unpack!(
- block =
- this.into(this.hir.tcx().mk_place_deref(Place::from(result)), block, value)
+ block = this.expr_into_dest(
+ this.hir.tcx().mk_place_deref(Place::from(result)),
+ block,
+ &value
+ )
);
block.and(Rvalue::Use(Operand::Move(Place::from(result))))
}
ExprKind::Cast { source } => {
- let source = unpack!(block = this.as_operand(block, scope, source));
+ let source = unpack!(block = this.as_operand(block, scope, &source));
block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
}
ExprKind::Pointer { cast, source } => {
- let source = unpack!(block = this.as_operand(block, scope, source));
- block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty))
+ let source = unpack!(block = this.as_operand(block, scope, &source));
+ block.and(Rvalue::Cast(CastKind::Pointer(*cast), source, expr.ty))
}
ExprKind::Array { fields } => {
// (*) We would (maybe) be closer to codegen if we
let el_ty = expr.ty.sequence_element_type(this.hir.tcx());
let fields: Vec<_> = fields
.into_iter()
- .map(|f| unpack!(block = this.as_operand(block, scope, f)))
+ .map(|f| unpack!(block = this.as_operand(block, scope, &f)))
.collect();
block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields))
// first process the set of fields
let fields: Vec<_> = fields
.into_iter()
- .map(|f| unpack!(block = this.as_operand(block, scope, f)))
+ .map(|f| unpack!(block = this.as_operand(block, scope, &f)))
.collect();
block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
let operands: Vec<_> = upvars
.into_iter()
.map(|upvar| {
- let upvar = this.hir.mirror(upvar);
match Category::of(&upvar.kind) {
// Use as_place to avoid creating a temporary when
// moving a variable into a closure, so that
// This occurs when capturing by copy/move, while
// by reference captures use as_operand
Some(Category::Place) => {
- let place = unpack!(block = this.as_place(block, upvar));
+ let place = unpack!(block = this.as_place(block, &upvar));
this.consume_by_copy_or_move(place)
}
_ => {
// borrow captures when capturing an immutable
// variable. This is sound because the mutation
// that caused the capture will cause an error.
- match upvar.kind {
+ match &upvar.kind {
ExprKind::Borrow {
borrow_kind:
BorrowKind::Mut { allow_two_phase_borrow: false },
arg,
} => unpack!(
block = this.limit_capture_mutability(
- upvar.span, upvar.ty, scope, block, arg,
+ upvar.span, upvar.ty, scope, block, &arg,
)
),
- _ => unpack!(block = this.as_operand(block, scope, upvar)),
+ _ => unpack!(block = this.as_operand(block, scope, &upvar)),
}
}
}
// We implicitly set the discriminant to 0. See
// librustc_mir/transform/deaggregator.rs for details.
let movability = movability.unwrap();
- box AggregateKind::Generator(closure_id, substs, movability)
+ box AggregateKind::Generator(*closure_id, substs, movability)
}
- UpvarSubsts::Closure(substs) => box AggregateKind::Closure(closure_id, substs),
+ UpvarSubsts::Closure(substs) => box AggregateKind::Closure(*closure_id, substs),
};
block.and(Rvalue::Aggregate(result, operands))
}
upvar_ty: Ty<'tcx>,
temp_lifetime: Option<region::Scope>,
mut block: BasicBlock,
- arg: ExprRef<'tcx>,
+ arg: &Expr<'tcx>,
) -> BlockAnd<Operand<'tcx>> {
let this = self;
use crate::build::{BlockAnd, BlockAndExtension, Builder};
use crate::thir::*;
use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_hir as hir;
use rustc_middle::middle::region;
use rustc_middle::mir::*;
impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Compile `expr` into a fresh temporary. This is used when building
/// up rvalues so as to freeze the value that will be consumed.
- crate fn as_temp<M>(
+ crate fn as_temp(
&mut self,
block: BasicBlock,
temp_lifetime: Option<region::Scope>,
- expr: M,
+ expr: &Expr<'tcx>,
mutability: Mutability,
- ) -> BlockAnd<Local>
- where
- M: Mirror<'tcx, Output = Expr<'tcx>>,
- {
- let expr = self.hir.mirror(expr);
- //
+ ) -> BlockAnd<Local> {
// this is the only place in mir building that we need to truly need to worry about
// infinite recursion. Everything else does recurse, too, but it always gets broken up
// at some point by inserting an intermediate temporary
- ensure_sufficient_stack(|| self.expr_as_temp(block, temp_lifetime, expr, mutability))
+ ensure_sufficient_stack(|| self.as_temp_inner(block, temp_lifetime, expr, mutability))
}
- fn expr_as_temp(
+ fn as_temp_inner(
&mut self,
mut block: BasicBlock,
temp_lifetime: Option<region::Scope>,
- expr: Expr<'tcx>,
+ expr: &Expr<'tcx>,
mutability: Mutability,
) -> BlockAnd<Local> {
debug!(
- "expr_as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})",
+ "as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})",
block, temp_lifetime, expr, mutability
);
let this = self;
let expr_span = expr.span;
let source_info = this.source_info(expr_span);
- if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
- return this.in_scope((region_scope, source_info), lint_level, |this| {
+ if let ExprKind::Scope { region_scope, lint_level, value } = &expr.kind {
+ return this.in_scope((*region_scope, source_info), *lint_level, |this| {
this.as_temp(block, temp_lifetime, value, mutability)
});
}
// Don't bother with StorageLive and Dead for these temporaries,
// they are never assigned.
ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } => (),
- ExprKind::Block { body: hir::Block { expr: None, targeted_by_break: false, .. } }
+ ExprKind::Block { body: Block { expr: None, targeted_by_break: false, .. } }
if expr_ty.is_never() => {}
_ => {
this.cfg
}
}
- unpack!(block = this.into(temp_place, block, expr));
+ unpack!(block = this.expr_into_dest(temp_place, block, expr));
if let Some(temp_lifetime) = temp_lifetime {
this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value);
impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Compile `expr`, storing the result into `destination`, which
/// is assumed to be uninitialized.
- crate fn into_expr(
+ crate fn expr_into_dest(
&mut self,
destination: Place<'tcx>,
mut block: BasicBlock,
- expr: Expr<'tcx>,
+ expr: &Expr<'tcx>,
) -> BlockAnd<()> {
- debug!("into_expr(destination={:?}, block={:?}, expr={:?})", destination, block, expr);
+ debug!("expr_into_dest(destination={:?}, block={:?}, expr={:?})", destination, block, expr);
// since we frequently have to reference `self` from within a
// closure, where `self` would be shadowed, it's easier to
this.block_context.push(BlockFrame::SubExpr);
}
- let block_and = match expr.kind {
+ let block_and = match &expr.kind {
ExprKind::Scope { region_scope, lint_level, value } => {
- let region_scope = (region_scope, source_info);
+ let region_scope = (*region_scope, source_info);
ensure_sufficient_stack(|| {
- this.in_scope(region_scope, lint_level, |this| {
- this.into(destination, block, value)
+ this.in_scope(region_scope, *lint_level, |this| {
+ this.expr_into_dest(destination, block, &value)
})
})
}
ExprKind::Block { body: ast_block } => {
- this.ast_block(destination, block, ast_block, source_info)
+ this.ast_block(destination, block, &ast_block, source_info)
}
ExprKind::Match { scrutinee, arms } => {
- this.match_expr(destination, expr_span, block, scrutinee, arms)
+ this.match_expr(destination, expr_span, block, &scrutinee, &arms)
}
ExprKind::If { cond, then, else_opt } => {
let place = unpack!(
- block = this.as_temp(block, Some(this.local_scope()), cond, Mutability::Mut)
+ block = this.as_temp(block, Some(this.local_scope()), &cond, Mutability::Mut)
);
let operand = Operand::Move(Place::from(place));
let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block);
this.cfg.terminate(block, source_info, term);
- unpack!(then_block = this.into(destination, then_block, then));
+ unpack!(then_block = this.expr_into_dest(destination, then_block, &then));
else_block = if let Some(else_opt) = else_opt {
- unpack!(this.into(destination, else_block, else_opt))
+ unpack!(this.expr_into_dest(destination, else_block, &else_opt))
} else {
// Body of the `if` expression without an `else` clause must return `()`, thus
// we implicitly generate a `else {}` if it is not specified.
join_block.unit()
}
ExprKind::NeverToAny { source } => {
- let source = this.hir.mirror(source);
let is_call =
matches!(source.kind, ExprKind::Call { .. } | ExprKind::InlineAsm { .. });
// (#66975) Source could be a const of type `!`, so has to
// exist in the generated MIR.
unpack!(
- block = this.as_temp(block, Some(this.local_scope()), source, Mutability::Mut,)
+ block =
+ this.as_temp(block, Some(this.local_scope()), &source, Mutability::Mut,)
);
// This is an optimization. If the expression was a call then we already have an
this.cfg.start_new_block(),
);
- let lhs = unpack!(block = this.as_local_operand(block, lhs));
+ let lhs = unpack!(block = this.as_local_operand(block, &lhs));
let blocks = match op {
LogicalOp::And => (else_block, false_block),
LogicalOp::Or => (true_block, else_block),
let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1);
this.cfg.terminate(block, source_info, term);
- let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs));
+ let rhs = unpack!(else_block = this.as_local_operand(else_block, &rhs));
let term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block);
this.cfg.terminate(else_block, source_info, term);
// introduce a unit temporary as the destination for the loop body.
let tmp = this.get_unit_temp();
// Execute the body, branching back to the test.
- let body_block_end = unpack!(this.into(tmp, body_block, body));
+ let body_block_end = unpack!(this.expr_into_dest(tmp, body_block, &body));
this.cfg.goto(body_block_end, source_info, loop_block);
// Loops are only exited by `break` expressions.
})
}
ExprKind::Call { ty: _, fun, args, from_hir_call, fn_span } => {
- let fun = unpack!(block = this.as_local_operand(block, fun));
+ let fun = unpack!(block = this.as_local_operand(block, &fun));
let args: Vec<_> = args
.into_iter()
- .map(|arg| unpack!(block = this.as_local_call_operand(block, arg)))
+ .map(|arg| unpack!(block = this.as_local_call_operand(block, &arg)))
.collect();
let success = this.cfg.start_new_block();
this.record_operands_moved(&args);
- debug!("into_expr: fn_span={:?}", fn_span);
+ debug!("expr_into_dest: fn_span={:?}", fn_span);
this.cfg.terminate(
block,
} else {
Some((destination, success))
},
- from_hir_call,
- fn_span,
+ from_hir_call: *from_hir_call,
+ fn_span: *fn_span,
},
);
this.diverge_from(block);
success.unit()
}
- ExprKind::Use { source } => this.into(destination, block, source),
+ ExprKind::Use { source } => this.expr_into_dest(destination, block, &source),
ExprKind::Borrow { arg, borrow_kind } => {
// We don't do this in `as_rvalue` because we use `as_place`
// for borrow expressions, so we cannot create an `RValue` that
// by this method anyway, so this shouldn't cause too many
// unnecessary temporaries.
let arg_place = match borrow_kind {
- BorrowKind::Shared => unpack!(block = this.as_read_only_place(block, arg)),
- _ => unpack!(block = this.as_place(block, arg)),
+ BorrowKind::Shared => unpack!(block = this.as_read_only_place(block, &arg)),
+ _ => unpack!(block = this.as_place(block, &arg)),
};
let borrow =
- Rvalue::Ref(this.hir.tcx().lifetimes.re_erased, borrow_kind, arg_place);
+ Rvalue::Ref(this.hir.tcx().lifetimes.re_erased, *borrow_kind, arg_place);
this.cfg.push_assign(block, source_info, destination, borrow);
block.unit()
}
ExprKind::AddressOf { mutability, arg } => {
let place = match mutability {
- hir::Mutability::Not => this.as_read_only_place(block, arg),
- hir::Mutability::Mut => this.as_place(block, arg),
+ hir::Mutability::Not => this.as_read_only_place(block, &arg),
+ hir::Mutability::Mut => this.as_place(block, &arg),
};
- let address_of = Rvalue::AddressOf(mutability, unpack!(block = place));
+ let address_of = Rvalue::AddressOf(*mutability, unpack!(block = place));
this.cfg.push_assign(block, source_info, destination, address_of);
block.unit()
}
// (evaluating them in order given by user)
let fields_map: FxHashMap<_, _> = fields
.into_iter()
- .map(|f| (f.name, unpack!(block = this.as_operand(block, Some(scope), f.expr))))
+ .map(|f| {
+ (f.name, unpack!(block = this.as_operand(block, Some(scope), &f.expr)))
+ })
.collect();
- let field_names = this.hir.all_fields(adt_def, variant_index);
+ let field_names = this.hir.all_fields(adt_def, *variant_index);
let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base {
- let place_builder = unpack!(block = this.as_place_builder(block, base));
+ let place_builder = unpack!(block = this.as_place_builder(block, &base));
// MIR does not natively support FRU, so for each
// base-supplied field, generate an operand that
});
let adt = box AggregateKind::Adt(
adt_def,
- variant_index,
+ *variant_index,
substs,
user_ty,
active_field_index,
.into_iter()
.map(|op| match op {
thir::InlineAsmOperand::In { reg, expr } => mir::InlineAsmOperand::In {
- reg,
- value: unpack!(block = this.as_local_operand(block, expr)),
+ reg: *reg,
+ value: unpack!(block = this.as_local_operand(block, &expr)),
},
thir::InlineAsmOperand::Out { reg, late, expr } => {
mir::InlineAsmOperand::Out {
- reg,
- late,
- place: expr.map(|expr| unpack!(block = this.as_place(block, expr))),
+ reg: *reg,
+ late: *late,
+ place: expr
+ .as_ref()
+ .map(|expr| unpack!(block = this.as_place(block, expr))),
}
}
thir::InlineAsmOperand::InOut { reg, late, expr } => {
- let place = unpack!(block = this.as_place(block, expr));
+ let place = unpack!(block = this.as_place(block, &expr));
mir::InlineAsmOperand::InOut {
- reg,
- late,
+ reg: *reg,
+ late: *late,
// This works because asm operands must be Copy
in_value: Operand::Copy(place),
out_place: Some(place),
}
thir::InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => {
mir::InlineAsmOperand::InOut {
- reg,
- late,
- in_value: unpack!(block = this.as_local_operand(block, in_expr)),
- out_place: out_expr.map(|out_expr| {
+ reg: *reg,
+ late: *late,
+ in_value: unpack!(block = this.as_local_operand(block, &in_expr)),
+ out_place: out_expr.as_ref().map(|out_expr| {
unpack!(block = this.as_place(block, out_expr))
}),
}
}
thir::InlineAsmOperand::Const { expr } => mir::InlineAsmOperand::Const {
- value: unpack!(block = this.as_local_operand(block, expr)),
+ value: unpack!(block = this.as_local_operand(block, &expr)),
},
thir::InlineAsmOperand::SymFn { expr } => {
- mir::InlineAsmOperand::SymFn { value: box this.as_constant(expr) }
+ mir::InlineAsmOperand::SymFn { value: box this.as_constant(&expr) }
}
thir::InlineAsmOperand::SymStatic { def_id } => {
- mir::InlineAsmOperand::SymStatic { def_id }
+ mir::InlineAsmOperand::SymStatic { def_id: *def_id }
}
})
.collect();
TerminatorKind::InlineAsm {
template,
operands,
- options,
+ options: *options,
line_spans,
destination: if options.contains(InlineAsmOptions::NORETURN) {
None
ExprKind::Yield { value } => {
let scope = this.local_scope();
- let value = unpack!(block = this.as_operand(block, Some(scope), value));
+ let value = unpack!(block = this.as_operand(block, Some(scope), &value));
let resume = this.cfg.start_new_block();
this.cfg.terminate(
block,
//! a type that is not `Copy`, then using any of these functions will
//! "move" the value out of its current home (if any).
//!
-//! - `into` -- writes the value into a specific location, which
+//! - `expr_into_dest` -- writes the value into a specific location, which
//! should be uninitialized
//! - `as_operand` -- evaluates the value and yields an `Operand`,
//! suitable for use as an argument to an `Rvalue`
crate fn stmt_expr(
&mut self,
mut block: BasicBlock,
- expr: Expr<'tcx>,
+ expr: &Expr<'tcx>,
statement_scope: Option<region::Scope>,
) -> BlockAnd<()> {
let this = self;
// Handle a number of expressions that don't need a destination at all. This
// avoids needing a mountain of temporary `()` variables.
let expr2 = expr.clone();
- match expr.kind {
+ match &expr.kind {
ExprKind::Scope { region_scope, lint_level, value } => {
- let value = this.hir.mirror(value);
- this.in_scope((region_scope, source_info), lint_level, |this| {
- this.stmt_expr(block, value, statement_scope)
+ this.in_scope((*region_scope, source_info), *lint_level, |this| {
+ this.stmt_expr(block, &value, statement_scope)
})
}
ExprKind::Assign { lhs, rhs } => {
- let lhs = this.hir.mirror(lhs);
- let rhs = this.hir.mirror(rhs);
let lhs_span = lhs.span;
// Note: we evaluate assignments right-to-left. This
// Generate better code for things that don't need to be
// dropped.
if this.hir.needs_drop(lhs.ty) {
- let rhs = unpack!(block = this.as_local_operand(block, rhs));
- let lhs = unpack!(block = this.as_place(block, lhs));
+ let rhs = unpack!(block = this.as_local_operand(block, &rhs));
+ let lhs = unpack!(block = this.as_place(block, &lhs));
unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs));
} else {
- let rhs = unpack!(block = this.as_local_rvalue(block, rhs));
- let lhs = unpack!(block = this.as_place(block, lhs));
+ let rhs = unpack!(block = this.as_local_rvalue(block, &rhs));
+ let lhs = unpack!(block = this.as_place(block, &lhs));
this.cfg.push_assign(block, source_info, lhs, rhs);
}
// only affects weird things like `x += {x += 1; x}`
// -- is that equal to `x + (x + 1)` or `2*(x+1)`?
- let lhs = this.hir.mirror(lhs);
let lhs_ty = lhs.ty;
debug!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr2);
this.block_context.push(BlockFrame::SubExpr);
// As above, RTL.
- let rhs = unpack!(block = this.as_local_operand(block, rhs));
- let lhs = unpack!(block = this.as_place(block, lhs));
+ let rhs = unpack!(block = this.as_local_operand(block, &rhs));
+ let lhs = unpack!(block = this.as_place(block, &lhs));
// we don't have to drop prior contents or anything
// because AssignOp is only legal for Copy types
// (overloaded ops should be desugared into a call).
let result = unpack!(
- block =
- this.build_binary_op(block, op, expr_span, lhs_ty, Operand::Copy(lhs), rhs)
+ block = this.build_binary_op(
+ block,
+ *op,
+ expr_span,
+ lhs_ty,
+ Operand::Copy(lhs),
+ rhs
+ )
);
this.cfg.push_assign(block, source_info, lhs, result);
block.unit()
}
ExprKind::Continue { label } => {
- this.break_scope(block, None, BreakableTarget::Continue(label), source_info)
- }
- ExprKind::Break { label, value } => {
- this.break_scope(block, value, BreakableTarget::Break(label), source_info)
+ this.break_scope(block, None, BreakableTarget::Continue(*label), source_info)
}
+ ExprKind::Break { label, value } => this.break_scope(
+ block,
+ value.as_deref(),
+ BreakableTarget::Break(*label),
+ source_info,
+ ),
ExprKind::Return { value } => {
- this.break_scope(block, value, BreakableTarget::Return, source_info)
+ this.break_scope(block, value.as_deref(), BreakableTarget::Return, source_info)
}
ExprKind::LlvmInlineAsm { asm, outputs, inputs } => {
debug!("stmt_expr LlvmInlineAsm block_context.push(SubExpr) : {:?}", expr2);
this.block_context.push(BlockFrame::SubExpr);
let outputs = outputs
.into_iter()
- .map(|output| unpack!(block = this.as_place(block, output)))
+ .map(|output| unpack!(block = this.as_place(block, &output)))
.collect::<Vec<_>>()
.into_boxed_slice();
let inputs = inputs
.into_iter()
.map(|input| {
- (input.span(), unpack!(block = this.as_local_operand(block, input)))
+ (input.span, unpack!(block = this.as_local_operand(block, &input)))
})
.collect::<Vec<_>>()
.into_boxed_slice();
Statement {
source_info,
kind: StatementKind::LlvmInlineAsm(box LlvmInlineAsm {
- asm: asm.clone(),
+ asm: (*asm).clone(),
outputs,
inputs,
}),
// it is usually better to focus on `the_value` rather
// than the entirety of block(s) surrounding it.
let adjusted_span = (|| {
- if let ExprKind::Block { body } = expr.kind {
+ if let ExprKind::Block { body } = &expr.kind {
if let Some(tail_expr) = &body.expr {
- let mut expr = tail_expr;
- while let rustc_hir::ExprKind::Block(subblock, _label) = &expr.kind {
+ let mut expr = &*tail_expr;
+ while let ExprKind::Block { body: subblock } = &expr.kind {
if let Some(subtail_expr) = &subblock.expr {
expr = subtail_expr
} else {
+++ /dev/null
-//! In general, there are a number of things for which it's convenient
-//! to just call `builder.into` and have it emit its result into a
-//! given location. This is basically for expressions or things that can be
-//! wrapped up as expressions (e.g., blocks). To make this ergonomic, we use this
-//! latter `EvalInto` trait.
-
-use crate::build::{BlockAnd, Builder};
-use crate::thir::*;
-use rustc_middle::mir::*;
-
-pub(in crate::build) trait EvalInto<'tcx> {
- fn eval_into(
- self,
- builder: &mut Builder<'_, 'tcx>,
- destination: Place<'tcx>,
- block: BasicBlock,
- ) -> BlockAnd<()>;
-}
-
-impl<'a, 'tcx> Builder<'a, 'tcx> {
- crate fn into<E>(
- &mut self,
- destination: Place<'tcx>,
- block: BasicBlock,
- expr: E,
- ) -> BlockAnd<()>
- where
- E: EvalInto<'tcx>,
- {
- expr.eval_into(self, destination, block)
- }
-}
-
-impl<'tcx> EvalInto<'tcx> for ExprRef<'tcx> {
- fn eval_into(
- self,
- builder: &mut Builder<'_, 'tcx>,
- destination: Place<'tcx>,
- block: BasicBlock,
- ) -> BlockAnd<()> {
- let expr = builder.hir.mirror(self);
- builder.into_expr(destination, block, expr)
- }
-}
-
-impl<'tcx> EvalInto<'tcx> for Expr<'tcx> {
- fn eval_into(
- self,
- builder: &mut Builder<'_, 'tcx>,
- destination: Place<'tcx>,
- block: BasicBlock,
- ) -> BlockAnd<()> {
- builder.into_expr(destination, block, self)
- }
-}
destination: Place<'tcx>,
span: Span,
mut block: BasicBlock,
- scrutinee: ExprRef<'tcx>,
- arms: Vec<Arm<'tcx>>,
+ scrutinee: &Expr<'tcx>,
+ arms: &[Arm<'tcx>],
) -> BlockAnd<()> {
- let scrutinee_span = scrutinee.span();
+ let scrutinee_span = scrutinee.span;
let scrutinee_place =
unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span,));
fn lower_scrutinee(
&mut self,
mut block: BasicBlock,
- scrutinee: ExprRef<'tcx>,
+ scrutinee: &Expr<'tcx>,
scrutinee_span: Span,
) -> BlockAnd<Place<'tcx>> {
let scrutinee_place = unpack!(block = self.as_place(block, scrutinee));
let arm_source_info = self.source_info(arm.span);
let arm_scope = (arm.scope, arm_source_info);
self.in_scope(arm_scope, arm.lint_level, |this| {
- let body = this.hir.mirror(arm.body.clone());
let scope = this.declare_bindings(
None,
arm.span,
this.source_scope = source_scope;
}
- this.into(destination, arm_block, body)
+ this.expr_into_dest(destination, arm_block, &arm.body)
})
})
.collect();
&mut self,
mut block: BasicBlock,
irrefutable_pat: Pat<'tcx>,
- initializer: ExprRef<'tcx>,
+ initializer: &Expr<'tcx>,
) -> BlockAnd<()> {
match *irrefutable_pat.kind {
// Optimize the case of `let x = ...` to write directly into `x`
PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => {
let place =
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
- unpack!(block = self.into(place, block, initializer));
+ unpack!(block = self.expr_into_dest(place, block, initializer));
// Inject a fake read, see comments on `FakeReadCause::ForLet`.
let source_info = self.source_info(irrefutable_pat.span);
} => {
let place =
self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
- unpack!(block = self.into(place, block, initializer));
+ unpack!(block = self.expr_into_dest(place, block, initializer));
// Inject a fake read, see comments on `FakeReadCause::ForLet`.
let pattern_source_info = self.source_info(irrefutable_pat.span);
let (guard_span, (post_guard_block, otherwise_post_guard_block)) = match guard {
Guard::If(e) => {
- let e = self.hir.mirror(e.clone());
let source_info = self.source_info(e.span);
(e.span, self.test_bool(block, e, source_info))
}
Guard::IfLet(pat, scrutinee) => {
- let scrutinee_span = scrutinee.span();
- let scrutinee_place = unpack!(
- block = self.lower_scrutinee(block, scrutinee.clone(), scrutinee_span)
- );
+ let scrutinee_span = scrutinee.span;
+ let scrutinee_place =
+ unpack!(block = self.lower_scrutinee(block, &scrutinee, scrutinee_span));
let mut guard_candidate = Candidate::new(scrutinee_place, &pat, false);
let wildcard = Pat::wildcard_from_ty(pat.ty);
let mut otherwise_candidate = Candidate::new(scrutinee_place, &wildcard, false);
pat.span.to(arm_span.unwrap()),
pat,
ArmHasGuard(false),
- Some((Some(&scrutinee_place), scrutinee.span())),
+ Some((Some(&scrutinee_place), scrutinee.span)),
);
let post_guard_block = self.bind_pattern(
self.source_info(pat.span),
guard_candidate,
None,
&fake_borrow_temps,
- scrutinee.span(),
+ scrutinee.span,
None,
None,
);
let mut block = START_BLOCK;
let ast_expr = &tcx.hir().body(body_id).value;
- let expr = builder.hir.mirror(ast_expr);
- unpack!(block = builder.into_expr(Place::return_place(), block, expr));
+ let expr = builder.hir.mirror_expr(ast_expr);
+ unpack!(block = builder.expr_into_dest(Place::return_place(), block, &expr));
let source_info = builder.source_info(span);
builder.cfg.terminate(block, source_info, TerminatorKind::Return);
self.source_scope = source_scope;
}
- let body = self.hir.mirror(ast_body);
- self.into(Place::return_place(), block, body)
+ let body = self.hir.mirror_expr(ast_body);
+ self.expr_into_dest(Place::return_place(), block, &body)
}
fn set_correct_source_scope_for_arg(
mod block;
mod cfg;
mod expr;
-mod into;
mod matches;
mod misc;
mod scope;
*/
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
-use crate::thir::{Expr, ExprRef, LintLevel};
+use crate::thir::{Expr, LintLevel};
use rustc_data_structures::fx::FxHashMap;
use rustc_index::vec::IndexVec;
use rustc_middle::middle::region;
crate fn break_scope(
&mut self,
mut block: BasicBlock,
- value: Option<ExprRef<'tcx>>,
+ value: Option<&Expr<'tcx>>,
target: BreakableTarget,
source_info: SourceInfo,
) -> BlockAnd<()> {
if let Some(value) = value {
debug!("stmt_expr Break val block_context.push(SubExpr)");
self.block_context.push(BlockFrame::SubExpr);
- unpack!(block = self.into(destination, block, value));
+ unpack!(block = self.expr_into_dest(destination, block, value));
self.block_context.pop();
} else {
self.cfg.push_assign_unit(block, source_info, destination, self.hir.tcx())
crate fn test_bool(
&mut self,
mut block: BasicBlock,
- condition: Expr<'tcx>,
+ condition: &Expr<'tcx>,
source_info: SourceInfo,
) -> (BasicBlock, BasicBlock) {
let cond = unpack!(block = self.as_local_operand(block, condition));
-use crate::thir::cx::to_ref::ToRef;
use crate::thir::cx::Cx;
use crate::thir::{self, *};
use rustc_index::vec::Idx;
-impl<'tcx> Mirror<'tcx> for &'tcx hir::Block<'tcx> {
- type Output = Block<'tcx>;
-
- fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Block<'tcx> {
+impl<'a, 'tcx> Cx<'a, 'tcx> {
+ crate fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block<'tcx> {
// We have to eagerly lower the "spine" of the statements
// in order to get the lexical scoping correctly.
- let stmts = mirror_stmts(cx, self.hir_id.local_id, &*self.stmts);
+ let stmts = self.mirror_stmts(block.hir_id.local_id, &*block.stmts);
let opt_destruction_scope =
- cx.region_scope_tree.opt_destruction_scope(self.hir_id.local_id);
+ self.region_scope_tree.opt_destruction_scope(block.hir_id.local_id);
Block {
- targeted_by_break: self.targeted_by_break,
- region_scope: region::Scope { id: self.hir_id.local_id, data: region::ScopeData::Node },
+ targeted_by_break: block.targeted_by_break,
+ region_scope: region::Scope {
+ id: block.hir_id.local_id,
+ data: region::ScopeData::Node,
+ },
opt_destruction_scope,
- span: self.span,
+ span: block.span,
stmts,
- expr: self.expr.to_ref(),
- safety_mode: match self.rules {
+ expr: block.expr.as_ref().map(|expr| self.mirror_expr_boxed(expr)),
+ safety_mode: match block.rules {
hir::BlockCheckMode::DefaultBlock => BlockSafety::Safe,
- hir::BlockCheckMode::UnsafeBlock(..) => BlockSafety::ExplicitUnsafe(self.hir_id),
+ hir::BlockCheckMode::UnsafeBlock(..) => BlockSafety::ExplicitUnsafe(block.hir_id),
hir::BlockCheckMode::PushUnsafeBlock(..) => BlockSafety::PushUnsafe,
hir::BlockCheckMode::PopUnsafeBlock(..) => BlockSafety::PopUnsafe,
},
}
}
-}
-fn mirror_stmts<'a, 'tcx>(
- cx: &mut Cx<'a, 'tcx>,
- block_id: hir::ItemLocalId,
- stmts: &'tcx [hir::Stmt<'tcx>],
-) -> Vec<StmtRef<'tcx>> {
- let mut result = vec![];
- for (index, stmt) in stmts.iter().enumerate() {
- let hir_id = stmt.hir_id;
- let opt_dxn_ext = cx.region_scope_tree.opt_destruction_scope(hir_id.local_id);
- match stmt.kind {
- hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => {
- result.push(StmtRef::Mirror(Box::new(Stmt {
- kind: StmtKind::Expr {
- scope: region::Scope { id: hir_id.local_id, data: region::ScopeData::Node },
- expr: expr.to_ref(),
- },
- opt_destruction_scope: opt_dxn_ext,
- })))
- }
- hir::StmtKind::Item(..) => {
- // ignore for purposes of the MIR
- }
- hir::StmtKind::Local(ref local) => {
- let remainder_scope = region::Scope {
- id: block_id,
- data: region::ScopeData::Remainder(region::FirstStatementIndex::new(index)),
- };
+ fn mirror_stmts(
+ &mut self,
+ block_id: hir::ItemLocalId,
+ stmts: &'tcx [hir::Stmt<'tcx>],
+ ) -> Vec<Stmt<'tcx>> {
+ let mut result = vec![];
+ for (index, stmt) in stmts.iter().enumerate() {
+ let hir_id = stmt.hir_id;
+ let opt_dxn_ext = self.region_scope_tree.opt_destruction_scope(hir_id.local_id);
+ match stmt.kind {
+ hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => {
+ result.push(Stmt {
+ kind: StmtKind::Expr {
+ scope: region::Scope {
+ id: hir_id.local_id,
+ data: region::ScopeData::Node,
+ },
+ expr: self.mirror_expr_boxed(expr),
+ },
+ opt_destruction_scope: opt_dxn_ext,
+ })
+ }
+ hir::StmtKind::Item(..) => {
+ // ignore for purposes of the MIR
+ }
+ hir::StmtKind::Local(ref local) => {
+ let remainder_scope = region::Scope {
+ id: block_id,
+ data: region::ScopeData::Remainder(region::FirstStatementIndex::new(index)),
+ };
- let mut pattern = cx.pattern_from_hir(&local.pat);
+ let mut pattern = self.pattern_from_hir(&local.pat);
- if let Some(ty) = &local.ty {
- if let Some(&user_ty) = cx.typeck_results.user_provided_types().get(ty.hir_id) {
- debug!("mirror_stmts: user_ty={:?}", user_ty);
- pattern = Pat {
- ty: pattern.ty,
- span: pattern.span,
- kind: Box::new(PatKind::AscribeUserType {
- ascription: thir::pattern::Ascription {
- user_ty: PatTyProj::from_user_type(user_ty),
- user_ty_span: ty.span,
- variance: ty::Variance::Covariant,
- },
- subpattern: pattern,
- }),
- };
+ if let Some(ty) = &local.ty {
+ if let Some(&user_ty) =
+ self.typeck_results.user_provided_types().get(ty.hir_id)
+ {
+ debug!("mirror_stmts: user_ty={:?}", user_ty);
+ pattern = Pat {
+ ty: pattern.ty,
+ span: pattern.span,
+ kind: Box::new(PatKind::AscribeUserType {
+ ascription: thir::pattern::Ascription {
+ user_ty: PatTyProj::from_user_type(user_ty),
+ user_ty_span: ty.span,
+ variance: ty::Variance::Covariant,
+ },
+ subpattern: pattern,
+ }),
+ };
+ }
}
- }
- result.push(StmtRef::Mirror(Box::new(Stmt {
- kind: StmtKind::Let {
- remainder_scope,
- init_scope: region::Scope {
- id: hir_id.local_id,
- data: region::ScopeData::Node,
+ result.push(Stmt {
+ kind: StmtKind::Let {
+ remainder_scope,
+ init_scope: region::Scope {
+ id: hir_id.local_id,
+ data: region::ScopeData::Node,
+ },
+ pattern,
+ initializer: local.init.map(|init| self.mirror_expr_boxed(init)),
+ lint_level: LintLevel::Explicit(local.hir_id),
},
- pattern,
- initializer: local.init.to_ref(),
- lint_level: LintLevel::Explicit(local.hir_id),
- },
- opt_destruction_scope: opt_dxn_ext,
- })));
+ opt_destruction_scope: opt_dxn_ext,
+ });
+ }
}
}
+ result
}
- result
-}
-
-crate fn to_expr_ref<'a, 'tcx>(
- cx: &mut Cx<'a, 'tcx>,
- block: &'tcx hir::Block<'tcx>,
-) -> ExprRef<'tcx> {
- let block_ty = cx.typeck_results().node_type(block.hir_id);
- let temp_lifetime = cx.region_scope_tree.temporary_scope(block.hir_id.local_id);
- let expr = Expr {
- ty: block_ty,
- temp_lifetime,
- span: block.span,
- kind: ExprKind::Block { body: block },
- };
- expr.to_ref()
}
-use crate::thir::cx::block;
-use crate::thir::cx::to_ref::ToRef;
use crate::thir::cx::Cx;
use crate::thir::util::UserAnnotatedTyHelpers;
use crate::thir::*;
use rustc_middle::ty::{self, AdtKind, Ty};
use rustc_span::Span;
-impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr<'tcx> {
- type Output = Expr<'tcx>;
+impl<'a, 'tcx> Cx<'a, 'tcx> {
+ crate fn mirror_expr(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> {
+ let temp_lifetime = self.region_scope_tree.temporary_scope(hir_expr.hir_id.local_id);
+ let expr_scope =
+ region::Scope { id: hir_expr.hir_id.local_id, data: region::ScopeData::Node };
- fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Expr<'tcx> {
- let temp_lifetime = cx.region_scope_tree.temporary_scope(self.hir_id.local_id);
- let expr_scope = region::Scope { id: self.hir_id.local_id, data: region::ScopeData::Node };
+ debug!("Expr::make_mirror(): id={}, span={:?}", hir_expr.hir_id, hir_expr.span);
- debug!("Expr::make_mirror(): id={}, span={:?}", self.hir_id, self.span);
-
- let mut expr = make_mirror_unadjusted(cx, self);
+ let mut expr = self.make_mirror_unadjusted(hir_expr);
// Now apply adjustments, if any.
- for adjustment in cx.typeck_results().expr_adjustments(self) {
+ for adjustment in self.typeck_results().expr_adjustments(hir_expr) {
debug!("make_mirror: expr={:?} applying adjustment={:?}", expr, adjustment);
- expr = apply_adjustment(cx, self, expr, adjustment);
+ expr = self.apply_adjustment(hir_expr, expr, adjustment);
}
// Next, wrap this up in the expr's scope.
expr = Expr {
temp_lifetime,
ty: expr.ty,
- span: self.span,
+ span: hir_expr.span,
kind: ExprKind::Scope {
region_scope: expr_scope,
- value: expr.to_ref(),
- lint_level: LintLevel::Explicit(self.hir_id),
+ value: Box::new(expr),
+ lint_level: LintLevel::Explicit(hir_expr.hir_id),
},
};
// Finally, create a destruction scope, if any.
- if let Some(region_scope) = cx.region_scope_tree.opt_destruction_scope(self.hir_id.local_id)
+ if let Some(region_scope) =
+ self.region_scope_tree.opt_destruction_scope(hir_expr.hir_id.local_id)
{
expr = Expr {
temp_lifetime,
ty: expr.ty,
- span: self.span,
+ span: hir_expr.span,
kind: ExprKind::Scope {
region_scope,
- value: expr.to_ref(),
+ value: Box::new(expr),
lint_level: LintLevel::Inherited,
},
};
// OK, all done!
expr
}
-}
-
-fn apply_adjustment<'a, 'tcx>(
- cx: &mut Cx<'a, 'tcx>,
- hir_expr: &'tcx hir::Expr<'tcx>,
- mut expr: Expr<'tcx>,
- adjustment: &Adjustment<'tcx>,
-) -> Expr<'tcx> {
- let Expr { temp_lifetime, mut span, .. } = expr;
-
- // Adjust the span from the block, to the last expression of the
- // block. This is a better span when returning a mutable reference
- // with too short a lifetime. The error message will use the span
- // from the assignment to the return place, which should only point
- // at the returned value, not the entire function body.
- //
- // fn return_short_lived<'a>(x: &'a mut i32) -> &'static mut i32 {
- // x
- // // ^ error message points at this expression.
- // }
- let mut adjust_span = |expr: &mut Expr<'tcx>| {
- if let ExprKind::Block { body } = expr.kind {
- if let Some(ref last_expr) = body.expr {
- span = last_expr.span;
- expr.span = span;
- }
- }
- };
- let kind = match adjustment.kind {
- Adjust::Pointer(PointerCast::Unsize) => {
- adjust_span(&mut expr);
- ExprKind::Pointer { cast: PointerCast::Unsize, source: expr.to_ref() }
- }
- Adjust::Pointer(cast) => ExprKind::Pointer { cast, source: expr.to_ref() },
- Adjust::NeverToAny => ExprKind::NeverToAny { source: expr.to_ref() },
- Adjust::Deref(None) => {
- adjust_span(&mut expr);
- ExprKind::Deref { arg: expr.to_ref() }
- }
- Adjust::Deref(Some(deref)) => {
- // We don't need to do call adjust_span here since
- // deref coercions always start with a built-in deref.
- let call = deref.method_call(cx.tcx(), expr.ty);
-
- expr = Expr {
- temp_lifetime,
- ty: cx.tcx.mk_ref(deref.region, ty::TypeAndMut { ty: expr.ty, mutbl: deref.mutbl }),
- span,
- kind: ExprKind::Borrow {
- borrow_kind: deref.mutbl.to_borrow_kind(),
- arg: expr.to_ref(),
- },
- };
+ crate fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> Vec<Expr<'tcx>> {
+ exprs.iter().map(|expr| self.mirror_expr(expr)).collect()
+ }
- overloaded_place(
- cx,
- hir_expr,
- adjustment.target,
- Some(call),
- vec![expr.to_ref()],
- deref.span,
- )
- }
- Adjust::Borrow(AutoBorrow::Ref(_, m)) => {
- ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), arg: expr.to_ref() }
- }
- Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => {
- ExprKind::AddressOf { mutability, arg: expr.to_ref() }
- }
- };
+ crate fn mirror_expr_boxed(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Box<Expr<'tcx>> {
+ Box::new(self.mirror_expr(expr))
+ }
- Expr { temp_lifetime, ty: adjustment.target, span, kind }
-}
+ fn apply_adjustment(
+ &mut self,
+ hir_expr: &'tcx hir::Expr<'tcx>,
+ mut expr: Expr<'tcx>,
+ adjustment: &Adjustment<'tcx>,
+ ) -> Expr<'tcx> {
+ let Expr { temp_lifetime, mut span, .. } = expr;
+
+ // Adjust the span from the block, to the last expression of the
+ // block. This is a better span when returning a mutable reference
+ // with too short a lifetime. The error message will use the span
+ // from the assignment to the return place, which should only point
+ // at the returned value, not the entire function body.
+ //
+ // fn return_short_lived<'a>(x: &'a mut i32) -> &'static mut i32 {
+ // x
+ // // ^ error message points at this expression.
+ // }
+ let mut adjust_span = |expr: &mut Expr<'tcx>| {
+ if let ExprKind::Block { body } = &expr.kind {
+ if let Some(ref last_expr) = body.expr {
+ span = last_expr.span;
+ expr.span = span;
+ }
+ }
+ };
-fn make_mirror_unadjusted<'a, 'tcx>(
- cx: &mut Cx<'a, 'tcx>,
- expr: &'tcx hir::Expr<'tcx>,
-) -> Expr<'tcx> {
- let expr_ty = cx.typeck_results().expr_ty(expr);
- let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
-
- let kind = match expr.kind {
- // Here comes the interesting stuff:
- hir::ExprKind::MethodCall(_, method_span, ref args, fn_span) => {
- // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
- let expr = method_callee(cx, expr, method_span, None);
- let args = args.iter().map(|e| e.to_ref()).collect();
- ExprKind::Call { ty: expr.ty, fun: expr.to_ref(), args, from_hir_call: true, fn_span }
- }
+ let kind = match adjustment.kind {
+ Adjust::Pointer(PointerCast::Unsize) => {
+ adjust_span(&mut expr);
+ ExprKind::Pointer { cast: PointerCast::Unsize, source: Box::new(expr) }
+ }
+ Adjust::Pointer(cast) => ExprKind::Pointer { cast, source: Box::new(expr) },
+ Adjust::NeverToAny => ExprKind::NeverToAny { source: Box::new(expr) },
+ Adjust::Deref(None) => {
+ adjust_span(&mut expr);
+ ExprKind::Deref { arg: Box::new(expr) }
+ }
+ Adjust::Deref(Some(deref)) => {
+ // We don't need to do call adjust_span here since
+ // deref coercions always start with a built-in deref.
+ let call = deref.method_call(self.tcx(), expr.ty);
- hir::ExprKind::Call(ref fun, ref args) => {
- if cx.typeck_results().is_method_call(expr) {
- // The callee is something implementing Fn, FnMut, or FnOnce.
- // Find the actual method implementation being called and
- // build the appropriate UFCS call expression with the
- // callee-object as expr parameter.
+ expr = Expr {
+ temp_lifetime,
+ ty: self
+ .tcx
+ .mk_ref(deref.region, ty::TypeAndMut { ty: expr.ty, mutbl: deref.mutbl }),
+ span,
+ kind: ExprKind::Borrow {
+ borrow_kind: deref.mutbl.to_borrow_kind(),
+ arg: Box::new(expr),
+ },
+ };
- // rewrite f(u, v) into FnOnce::call_once(f, (u, v))
+ self.overloaded_place(
+ hir_expr,
+ adjustment.target,
+ Some(call),
+ vec![expr],
+ deref.span,
+ )
+ }
+ Adjust::Borrow(AutoBorrow::Ref(_, m)) => {
+ ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), arg: Box::new(expr) }
+ }
+ Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => {
+ ExprKind::AddressOf { mutability, arg: Box::new(expr) }
+ }
+ };
- let method = method_callee(cx, expr, fun.span, None);
+ Expr { temp_lifetime, ty: adjustment.target, span, kind }
+ }
- let arg_tys = args.iter().map(|e| cx.typeck_results().expr_ty_adjusted(e));
- let tupled_args = Expr {
- ty: cx.tcx.mk_tup(arg_tys),
- temp_lifetime,
- span: expr.span,
- kind: ExprKind::Tuple { fields: args.iter().map(ToRef::to_ref).collect() },
- };
+ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> {
+ let expr_ty = self.typeck_results().expr_ty(expr);
+ let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+ let kind = match expr.kind {
+ // Here comes the interesting stuff:
+ hir::ExprKind::MethodCall(_, method_span, ref args, fn_span) => {
+ // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
+ let expr = self.method_callee(expr, method_span, None);
+ let args = self.mirror_exprs(args);
ExprKind::Call {
- ty: method.ty,
- fun: method.to_ref(),
- args: vec![fun.to_ref(), tupled_args.to_ref()],
+ ty: expr.ty,
+ fun: Box::new(expr),
+ args,
from_hir_call: true,
- fn_span: expr.span,
+ fn_span,
}
- } else {
- let adt_data =
- if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = fun.kind {
- // Tuple-like ADTs are represented as ExprKind::Call. We convert them here.
- expr_ty.ty_adt_def().and_then(|adt_def| match path.res {
- Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_id) => {
- Some((adt_def, adt_def.variant_index_with_ctor_id(ctor_id)))
- }
- Res::SelfCtor(..) => Some((adt_def, VariantIdx::new(0))),
- _ => None,
- })
- } else {
- None
+ }
+
+ hir::ExprKind::Call(ref fun, ref args) => {
+ if self.typeck_results().is_method_call(expr) {
+ // The callee is something implementing Fn, FnMut, or FnOnce.
+ // Find the actual method implementation being called and
+ // build the appropriate UFCS call expression with the
+ // callee-object as expr parameter.
+
+ // rewrite f(u, v) into FnOnce::call_once(f, (u, v))
+
+ let method = self.method_callee(expr, fun.span, None);
+
+ let arg_tys = args.iter().map(|e| self.typeck_results().expr_ty_adjusted(e));
+ let tupled_args = Expr {
+ ty: self.tcx.mk_tup(arg_tys),
+ temp_lifetime,
+ span: expr.span,
+ kind: ExprKind::Tuple { fields: self.mirror_exprs(args) },
};
- if let Some((adt_def, index)) = adt_data {
- let substs = cx.typeck_results().node_substs(fun.hir_id);
- let user_provided_types = cx.typeck_results().user_provided_types();
- let user_ty = user_provided_types.get(fun.hir_id).copied().map(|mut u_ty| {
- if let UserType::TypeOf(ref mut did, _) = &mut u_ty.value {
- *did = adt_def.did;
- }
- u_ty
- });
- debug!("make_mirror_unadjusted: (call) user_ty={:?}", user_ty);
-
- let field_refs = args
- .iter()
- .enumerate()
- .map(|(idx, e)| FieldExprRef { name: Field::new(idx), expr: e.to_ref() })
- .collect();
- ExprKind::Adt {
- adt_def,
- substs,
- variant_index: index,
- fields: field_refs,
- user_ty,
- base: None,
- }
- } else {
+
ExprKind::Call {
- ty: cx.typeck_results().node_type(fun.hir_id),
- fun: fun.to_ref(),
- args: args.to_ref(),
+ ty: method.ty,
+ fun: Box::new(method),
+ args: vec![self.mirror_expr(fun), tupled_args],
from_hir_call: true,
fn_span: expr.span,
}
+ } else {
+ let adt_data =
+ if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = fun.kind {
+ // Tuple-like ADTs are represented as ExprKind::Call. We convert them here.
+ expr_ty.ty_adt_def().and_then(|adt_def| match path.res {
+ Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_id) => {
+ Some((adt_def, adt_def.variant_index_with_ctor_id(ctor_id)))
+ }
+ Res::SelfCtor(..) => Some((adt_def, VariantIdx::new(0))),
+ _ => None,
+ })
+ } else {
+ None
+ };
+ if let Some((adt_def, index)) = adt_data {
+ let substs = self.typeck_results().node_substs(fun.hir_id);
+ let user_provided_types = self.typeck_results().user_provided_types();
+ let user_ty =
+ user_provided_types.get(fun.hir_id).copied().map(|mut u_ty| {
+ if let UserType::TypeOf(ref mut did, _) = &mut u_ty.value {
+ *did = adt_def.did;
+ }
+ u_ty
+ });
+ debug!("make_mirror_unadjusted: (call) user_ty={:?}", user_ty);
+
+ let field_refs = args
+ .iter()
+ .enumerate()
+ .map(|(idx, e)| FieldExpr {
+ name: Field::new(idx),
+ expr: self.mirror_expr(e),
+ })
+ .collect();
+ ExprKind::Adt {
+ adt_def,
+ substs,
+ variant_index: index,
+ fields: field_refs,
+ user_ty,
+ base: None,
+ }
+ } else {
+ ExprKind::Call {
+ ty: self.typeck_results().node_type(fun.hir_id),
+ fun: self.mirror_expr_boxed(fun),
+ args: self.mirror_exprs(args),
+ from_hir_call: true,
+ fn_span: expr.span,
+ }
+ }
}
}
- }
- hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, ref arg) => {
- ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg: arg.to_ref() }
- }
+ hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, ref arg) => ExprKind::Borrow {
+ borrow_kind: mutbl.to_borrow_kind(),
+ arg: self.mirror_expr_boxed(arg),
+ },
- hir::ExprKind::AddrOf(hir::BorrowKind::Raw, mutability, ref arg) => {
- ExprKind::AddressOf { mutability, arg: arg.to_ref() }
- }
+ hir::ExprKind::AddrOf(hir::BorrowKind::Raw, mutability, ref arg) => {
+ ExprKind::AddressOf { mutability, arg: self.mirror_expr_boxed(arg) }
+ }
- hir::ExprKind::Block(ref blk, _) => ExprKind::Block { body: &blk },
+ hir::ExprKind::Block(ref blk, _) => ExprKind::Block { body: self.mirror_block(blk) },
- hir::ExprKind::Assign(ref lhs, ref rhs, _) => {
- ExprKind::Assign { lhs: lhs.to_ref(), rhs: rhs.to_ref() }
- }
+ hir::ExprKind::Assign(ref lhs, ref rhs, _) => ExprKind::Assign {
+ lhs: self.mirror_expr_boxed(lhs),
+ rhs: self.mirror_expr_boxed(rhs),
+ },
- hir::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
- if cx.typeck_results().is_method_call(expr) {
- overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()])
- } else {
- ExprKind::AssignOp { op: bin_op(op.node), lhs: lhs.to_ref(), rhs: rhs.to_ref() }
+ hir::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
+ if self.typeck_results().is_method_call(expr) {
+ let lhs = self.mirror_expr(lhs);
+ let rhs = self.mirror_expr(rhs);
+ self.overloaded_operator(expr, vec![lhs, rhs])
+ } else {
+ ExprKind::AssignOp {
+ op: bin_op(op.node),
+ lhs: self.mirror_expr_boxed(lhs),
+ rhs: self.mirror_expr_boxed(rhs),
+ }
+ }
}
- }
- hir::ExprKind::Lit(ref lit) => ExprKind::Literal {
- literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false),
- user_ty: None,
- const_id: None,
- },
-
- hir::ExprKind::Binary(op, ref lhs, ref rhs) => {
- if cx.typeck_results().is_method_call(expr) {
- overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()])
- } else {
- // FIXME overflow
- match (op.node, cx.constness) {
- (hir::BinOpKind::And, _) => ExprKind::LogicalOp {
- op: LogicalOp::And,
- lhs: lhs.to_ref(),
- rhs: rhs.to_ref(),
- },
- (hir::BinOpKind::Or, _) => ExprKind::LogicalOp {
- op: LogicalOp::Or,
- lhs: lhs.to_ref(),
- rhs: rhs.to_ref(),
- },
+ hir::ExprKind::Lit(ref lit) => ExprKind::Literal {
+ literal: self.const_eval_literal(&lit.node, expr_ty, lit.span, false),
+ user_ty: None,
+ const_id: None,
+ },
- _ => {
- let op = bin_op(op.node);
- ExprKind::Binary { op, lhs: lhs.to_ref(), rhs: rhs.to_ref() }
+ hir::ExprKind::Binary(op, ref lhs, ref rhs) => {
+ if self.typeck_results().is_method_call(expr) {
+ let lhs = self.mirror_expr(lhs);
+ let rhs = self.mirror_expr(rhs);
+ self.overloaded_operator(expr, vec![lhs, rhs])
+ } else {
+ // FIXME overflow
+ match (op.node, self.constness) {
+ (hir::BinOpKind::And, _) => ExprKind::LogicalOp {
+ op: LogicalOp::And,
+ lhs: self.mirror_expr_boxed(lhs),
+ rhs: self.mirror_expr_boxed(rhs),
+ },
+ (hir::BinOpKind::Or, _) => ExprKind::LogicalOp {
+ op: LogicalOp::Or,
+ lhs: self.mirror_expr_boxed(lhs),
+ rhs: self.mirror_expr_boxed(rhs),
+ },
+
+ _ => {
+ let op = bin_op(op.node);
+ ExprKind::Binary {
+ op,
+ lhs: self.mirror_expr_boxed(lhs),
+ rhs: self.mirror_expr_boxed(rhs),
+ }
+ }
}
}
}
- }
- hir::ExprKind::Index(ref lhs, ref index) => {
- if cx.typeck_results().is_method_call(expr) {
- overloaded_place(
- cx,
- expr,
- expr_ty,
- None,
- vec![lhs.to_ref(), index.to_ref()],
- expr.span,
- )
- } else {
- ExprKind::Index { lhs: lhs.to_ref(), index: index.to_ref() }
+ hir::ExprKind::Index(ref lhs, ref index) => {
+ if self.typeck_results().is_method_call(expr) {
+ let lhs = self.mirror_expr(lhs);
+ let index = self.mirror_expr(index);
+ self.overloaded_place(expr, expr_ty, None, vec![lhs, index], expr.span)
+ } else {
+ ExprKind::Index {
+ lhs: self.mirror_expr_boxed(lhs),
+ index: self.mirror_expr_boxed(index),
+ }
+ }
}
- }
- hir::ExprKind::Unary(hir::UnOp::Deref, ref arg) => {
- if cx.typeck_results().is_method_call(expr) {
- overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()], expr.span)
- } else {
- ExprKind::Deref { arg: arg.to_ref() }
+ hir::ExprKind::Unary(hir::UnOp::Deref, ref arg) => {
+ if self.typeck_results().is_method_call(expr) {
+ let arg = self.mirror_expr(arg);
+ self.overloaded_place(expr, expr_ty, None, vec![arg], expr.span)
+ } else {
+ ExprKind::Deref { arg: self.mirror_expr_boxed(arg) }
+ }
}
- }
- hir::ExprKind::Unary(hir::UnOp::Not, ref arg) => {
- if cx.typeck_results().is_method_call(expr) {
- overloaded_operator(cx, expr, vec![arg.to_ref()])
- } else {
- ExprKind::Unary { op: UnOp::Not, arg: arg.to_ref() }
+ hir::ExprKind::Unary(hir::UnOp::Not, ref arg) => {
+ if self.typeck_results().is_method_call(expr) {
+ let arg = self.mirror_expr(arg);
+ self.overloaded_operator(expr, vec![arg])
+ } else {
+ ExprKind::Unary { op: UnOp::Not, arg: self.mirror_expr_boxed(arg) }
+ }
}
- }
- hir::ExprKind::Unary(hir::UnOp::Neg, ref arg) => {
- if cx.typeck_results().is_method_call(expr) {
- overloaded_operator(cx, expr, vec![arg.to_ref()])
- } else if let hir::ExprKind::Lit(ref lit) = arg.kind {
- ExprKind::Literal {
- literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true),
- user_ty: None,
- const_id: None,
+ hir::ExprKind::Unary(hir::UnOp::Neg, ref arg) => {
+ if self.typeck_results().is_method_call(expr) {
+ let arg = self.mirror_expr(arg);
+ self.overloaded_operator(expr, vec![arg])
+ } else if let hir::ExprKind::Lit(ref lit) = arg.kind {
+ ExprKind::Literal {
+ literal: self.const_eval_literal(&lit.node, expr_ty, lit.span, true),
+ user_ty: None,
+ const_id: None,
+ }
+ } else {
+ ExprKind::Unary { op: UnOp::Neg, arg: self.mirror_expr_boxed(arg) }
}
- } else {
- ExprKind::Unary { op: UnOp::Neg, arg: arg.to_ref() }
}
- }
- hir::ExprKind::Struct(ref qpath, ref fields, ref base) => match expr_ty.kind() {
- ty::Adt(adt, substs) => match adt.adt_kind() {
- AdtKind::Struct | AdtKind::Union => {
- let user_provided_types = cx.typeck_results().user_provided_types();
- let user_ty = user_provided_types.get(expr.hir_id).copied();
- debug!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty);
- ExprKind::Adt {
- adt_def: adt,
- variant_index: VariantIdx::new(0),
- substs,
- user_ty,
- fields: field_refs(cx, fields),
- base: base.as_ref().map(|base| FruInfo {
- base: base.to_ref(),
- field_types: cx.typeck_results().fru_field_types()[expr.hir_id].clone(),
- }),
+ hir::ExprKind::Struct(ref qpath, ref fields, ref base) => match expr_ty.kind() {
+ ty::Adt(adt, substs) => match adt.adt_kind() {
+ AdtKind::Struct | AdtKind::Union => {
+ let user_provided_types = self.typeck_results().user_provided_types();
+ let user_ty = user_provided_types.get(expr.hir_id).copied();
+ debug!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty);
+ ExprKind::Adt {
+ adt_def: adt,
+ variant_index: VariantIdx::new(0),
+ substs,
+ user_ty,
+ fields: self.field_refs(fields),
+ base: base.as_ref().map(|base| FruInfo {
+ base: self.mirror_expr_boxed(base),
+ field_types: self.typeck_results().fru_field_types()[expr.hir_id]
+ .clone(),
+ }),
+ }
}
- }
- AdtKind::Enum => {
- let res = cx.typeck_results().qpath_res(qpath, expr.hir_id);
- match res {
- Res::Def(DefKind::Variant, variant_id) => {
- assert!(base.is_none());
-
- let index = adt.variant_index_with_id(variant_id);
- let user_provided_types = cx.typeck_results().user_provided_types();
- let user_ty = user_provided_types.get(expr.hir_id).copied();
- debug!("make_mirror_unadjusted: (variant) user_ty={:?}", user_ty);
- ExprKind::Adt {
- adt_def: adt,
- variant_index: index,
- substs,
- user_ty,
- fields: field_refs(cx, fields),
- base: None,
+ AdtKind::Enum => {
+ let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
+ match res {
+ Res::Def(DefKind::Variant, variant_id) => {
+ assert!(base.is_none());
+
+ let index = adt.variant_index_with_id(variant_id);
+ let user_provided_types =
+ self.typeck_results().user_provided_types();
+ let user_ty = user_provided_types.get(expr.hir_id).copied();
+ debug!("make_mirror_unadjusted: (variant) user_ty={:?}", user_ty);
+ ExprKind::Adt {
+ adt_def: adt,
+ variant_index: index,
+ substs,
+ user_ty,
+ fields: self.field_refs(fields),
+ base: None,
+ }
+ }
+ _ => {
+ span_bug!(expr.span, "unexpected res: {:?}", res);
}
- }
- _ => {
- span_bug!(expr.span, "unexpected res: {:?}", res);
}
}
- }
- },
- _ => {
- span_bug!(expr.span, "unexpected type for struct literal: {:?}", expr_ty);
- }
- },
-
- hir::ExprKind::Closure(..) => {
- let closure_ty = cx.typeck_results().expr_ty(expr);
- let (def_id, substs, movability) = match *closure_ty.kind() {
- ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs), None),
- ty::Generator(def_id, substs, movability) => {
- (def_id, UpvarSubsts::Generator(substs), Some(movability))
- }
+ },
_ => {
- span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty);
+ span_bug!(expr.span, "unexpected type for struct literal: {:?}", expr_ty);
}
- };
+ },
- let upvars = cx
- .typeck_results()
- .closure_min_captures_flattened(def_id)
- .zip(substs.upvar_tys())
- .map(|(captured_place, ty)| capture_upvar(cx, expr, captured_place, ty))
- .collect();
- ExprKind::Closure { closure_id: def_id, substs, upvars, movability }
- }
+ hir::ExprKind::Closure(..) => {
+ let closure_ty = self.typeck_results().expr_ty(expr);
+ let (def_id, substs, movability) = match *closure_ty.kind() {
+ ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs), None),
+ ty::Generator(def_id, substs, movability) => {
+ (def_id, UpvarSubsts::Generator(substs), Some(movability))
+ }
+ _ => {
+ span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty);
+ }
+ };
- hir::ExprKind::Path(ref qpath) => {
- let res = cx.typeck_results().qpath_res(qpath, expr.hir_id);
- convert_path_expr(cx, expr, res)
- }
+ let upvars = self
+ .typeck_results()
+ .closure_min_captures_flattened(def_id)
+ .zip(substs.upvar_tys())
+ .map(|(captured_place, ty)| self.capture_upvar(expr, captured_place, ty))
+ .collect();
+ ExprKind::Closure { closure_id: def_id, substs, upvars, movability }
+ }
- hir::ExprKind::InlineAsm(ref asm) => ExprKind::InlineAsm {
- template: asm.template,
- operands: asm
- .operands
- .iter()
- .map(|(op, _op_sp)| {
- match *op {
- hir::InlineAsmOperand::In { reg, ref expr } => {
- InlineAsmOperand::In { reg, expr: expr.to_ref() }
- }
- hir::InlineAsmOperand::Out { reg, late, ref expr } => {
- InlineAsmOperand::Out {
+ hir::ExprKind::Path(ref qpath) => {
+ let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
+ self.convert_path_expr(expr, res)
+ }
+
+ hir::ExprKind::InlineAsm(ref asm) => ExprKind::InlineAsm {
+ template: asm.template,
+ operands: asm
+ .operands
+ .iter()
+ .map(|(op, _op_sp)| {
+ match *op {
+ hir::InlineAsmOperand::In { reg, ref expr } => {
+ InlineAsmOperand::In { reg, expr: self.mirror_expr(expr) }
+ }
+ hir::InlineAsmOperand::Out { reg, late, ref expr } => {
+ InlineAsmOperand::Out {
+ reg,
+ late,
+ expr: expr.as_ref().map(|expr| self.mirror_expr(expr)),
+ }
+ }
+ hir::InlineAsmOperand::InOut { reg, late, ref expr } => {
+ InlineAsmOperand::InOut { reg, late, expr: self.mirror_expr(expr) }
+ }
+ hir::InlineAsmOperand::SplitInOut {
reg,
late,
- expr: expr.as_ref().map(|expr| expr.to_ref()),
+ ref in_expr,
+ ref out_expr,
+ } => InlineAsmOperand::SplitInOut {
+ reg,
+ late,
+ in_expr: self.mirror_expr(in_expr),
+ out_expr: out_expr.as_ref().map(|expr| self.mirror_expr(expr)),
+ },
+ hir::InlineAsmOperand::Const { ref expr } => {
+ InlineAsmOperand::Const { expr: self.mirror_expr(expr) }
}
- }
- hir::InlineAsmOperand::InOut { reg, late, ref expr } => {
- InlineAsmOperand::InOut { reg, late, expr: expr.to_ref() }
- }
- hir::InlineAsmOperand::SplitInOut {
- reg,
- late,
- ref in_expr,
- ref out_expr,
- } => InlineAsmOperand::SplitInOut {
- reg,
- late,
- in_expr: in_expr.to_ref(),
- out_expr: out_expr.as_ref().map(|expr| expr.to_ref()),
- },
- hir::InlineAsmOperand::Const { ref expr } => {
- InlineAsmOperand::Const { expr: expr.to_ref() }
- }
- hir::InlineAsmOperand::Sym { ref expr } => {
- let qpath = match expr.kind {
- hir::ExprKind::Path(ref qpath) => qpath,
- _ => span_bug!(
- expr.span,
- "asm `sym` operand should be a path, found {:?}",
- expr.kind
- ),
- };
- let temp_lifetime =
- cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
- let res = cx.typeck_results().qpath_res(qpath, expr.hir_id);
- let ty;
- match res {
- Res::Def(DefKind::Fn, _) | Res::Def(DefKind::AssocFn, _) => {
- ty = cx.typeck_results().node_type(expr.hir_id);
- let user_ty = user_substs_applied_to_res(cx, expr.hir_id, res);
- InlineAsmOperand::SymFn {
- expr: Expr {
- ty,
- temp_lifetime,
- span: expr.span,
- kind: ExprKind::Literal {
- literal: ty::Const::zero_sized(cx.tcx, ty),
- user_ty,
- const_id: None,
+ hir::InlineAsmOperand::Sym { ref expr } => {
+ let qpath = match expr.kind {
+ hir::ExprKind::Path(ref qpath) => qpath,
+ _ => span_bug!(
+ expr.span,
+ "asm `sym` operand should be a path, found {:?}",
+ expr.kind
+ ),
+ };
+ let temp_lifetime =
+ self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+ let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
+ let ty;
+ match res {
+ Res::Def(DefKind::Fn, _) | Res::Def(DefKind::AssocFn, _) => {
+ ty = self.typeck_results().node_type(expr.hir_id);
+ let user_ty =
+ self.user_substs_applied_to_res(expr.hir_id, res);
+ InlineAsmOperand::SymFn {
+ expr: Expr {
+ ty,
+ temp_lifetime,
+ span: expr.span,
+ kind: ExprKind::Literal {
+ literal: ty::Const::zero_sized(self.tcx, ty),
+ user_ty,
+ const_id: None,
+ },
},
}
- .to_ref(),
}
- }
- Res::Def(DefKind::Static, def_id) => {
- InlineAsmOperand::SymStatic { def_id }
- }
+ Res::Def(DefKind::Static, def_id) => {
+ InlineAsmOperand::SymStatic { def_id }
+ }
- _ => {
- cx.tcx.sess.span_err(
- expr.span,
- "asm `sym` operand must point to a fn or static",
- );
-
- // Not a real fn, but we're not reaching codegen anyways...
- ty = cx.tcx.ty_error();
- InlineAsmOperand::SymFn {
- expr: Expr {
- ty,
- temp_lifetime,
- span: expr.span,
- kind: ExprKind::Literal {
- literal: ty::Const::zero_sized(cx.tcx, ty),
- user_ty: None,
- const_id: None,
+ _ => {
+ self.tcx.sess.span_err(
+ expr.span,
+ "asm `sym` operand must point to a fn or static",
+ );
+
+ // Not a real fn, but we're not reaching codegen anyways...
+ ty = self.tcx.ty_error();
+ InlineAsmOperand::SymFn {
+ expr: Expr {
+ ty,
+ temp_lifetime,
+ span: expr.span,
+ kind: ExprKind::Literal {
+ literal: ty::Const::zero_sized(self.tcx, ty),
+ user_ty: None,
+ const_id: None,
+ },
},
}
- .to_ref(),
}
}
}
}
- }
- })
- .collect(),
- options: asm.options,
- line_spans: asm.line_spans,
- },
-
- hir::ExprKind::LlvmInlineAsm(ref asm) => ExprKind::LlvmInlineAsm {
- asm: &asm.inner,
- outputs: asm.outputs_exprs.to_ref(),
- inputs: asm.inputs_exprs.to_ref(),
- },
-
- hir::ExprKind::ConstBlock(ref anon_const) => {
- let anon_const_def_id = cx.tcx.hir().local_def_id(anon_const.hir_id);
- let value = ty::Const::from_anon_const(cx.tcx, anon_const_def_id);
-
- ExprKind::ConstBlock { value }
- }
- // Now comes the rote stuff:
- hir::ExprKind::Repeat(ref v, ref count) => {
- let count_def_id = cx.tcx.hir().local_def_id(count.hir_id);
- let count = ty::Const::from_anon_const(cx.tcx, count_def_id);
+ })
+ .collect(),
+ options: asm.options,
+ line_spans: asm.line_spans,
+ },
- ExprKind::Repeat { value: v.to_ref(), count }
- }
- hir::ExprKind::Ret(ref v) => ExprKind::Return { value: v.to_ref() },
- hir::ExprKind::Break(dest, ref value) => match dest.target_id {
- Ok(target_id) => ExprKind::Break {
- label: region::Scope { id: target_id.local_id, data: region::ScopeData::Node },
- value: value.to_ref(),
+ hir::ExprKind::LlvmInlineAsm(ref asm) => ExprKind::LlvmInlineAsm {
+ asm: &asm.inner,
+ outputs: self.mirror_exprs(asm.outputs_exprs),
+ inputs: self.mirror_exprs(asm.inputs_exprs),
+ },
+
+ hir::ExprKind::ConstBlock(ref anon_const) => {
+ let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
+ let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
+
+ ExprKind::ConstBlock { value }
+ }
+ // Now comes the rote stuff:
+ hir::ExprKind::Repeat(ref v, ref count) => {
+ let count_def_id = self.tcx.hir().local_def_id(count.hir_id);
+ let count = ty::Const::from_anon_const(self.tcx, count_def_id);
+
+ ExprKind::Repeat { value: self.mirror_expr_boxed(v), count }
+ }
+ hir::ExprKind::Ret(ref v) => {
+ ExprKind::Return { value: v.as_ref().map(|v| self.mirror_expr_boxed(v)) }
+ }
+ hir::ExprKind::Break(dest, ref value) => match dest.target_id {
+ Ok(target_id) => ExprKind::Break {
+ label: region::Scope { id: target_id.local_id, data: region::ScopeData::Node },
+ value: value.as_ref().map(|value| self.mirror_expr_boxed(value)),
+ },
+ Err(err) => bug!("invalid loop id for break: {}", err),
+ },
+ hir::ExprKind::Continue(dest) => match dest.target_id {
+ Ok(loop_id) => ExprKind::Continue {
+ label: region::Scope { id: loop_id.local_id, data: region::ScopeData::Node },
+ },
+ Err(err) => bug!("invalid loop id for continue: {}", err),
},
- Err(err) => bug!("invalid loop id for break: {}", err),
- },
- hir::ExprKind::Continue(dest) => match dest.target_id {
- Ok(loop_id) => ExprKind::Continue {
- label: region::Scope { id: loop_id.local_id, data: region::ScopeData::Node },
+ hir::ExprKind::If(cond, then, else_opt) => ExprKind::If {
+ cond: self.mirror_expr_boxed(cond),
+ then: self.mirror_expr_boxed(then),
+ else_opt: else_opt.map(|el| self.mirror_expr_boxed(el)),
},
- Err(err) => bug!("invalid loop id for continue: {}", err),
- },
- hir::ExprKind::If(cond, then, else_opt) => ExprKind::If {
- cond: cond.to_ref(),
- then: then.to_ref(),
- else_opt: else_opt.map(|el| el.to_ref()),
- },
- hir::ExprKind::Match(ref discr, ref arms, _) => ExprKind::Match {
- scrutinee: discr.to_ref(),
- arms: arms.iter().map(|a| convert_arm(cx, a)).collect(),
- },
- hir::ExprKind::Loop(ref body, ..) => ExprKind::Loop { body: block::to_expr_ref(cx, body) },
- hir::ExprKind::Field(ref source, ..) => ExprKind::Field {
- lhs: source.to_ref(),
- name: Field::new(cx.tcx.field_index(expr.hir_id, cx.typeck_results)),
- },
- hir::ExprKind::Cast(ref source, ref cast_ty) => {
- // Check for a user-given type annotation on this `cast`
- let user_provided_types = cx.typeck_results.user_provided_types();
- let user_ty = user_provided_types.get(cast_ty.hir_id);
-
- debug!(
- "cast({:?}) has ty w/ hir_id {:?} and user provided ty {:?}",
- expr, cast_ty.hir_id, user_ty,
- );
-
- // Check to see if this cast is a "coercion cast", where the cast is actually done
- // using a coercion (or is a no-op).
- let cast = if cx.typeck_results().is_coercion_cast(source.hir_id) {
- // Convert the lexpr to a vexpr.
- ExprKind::Use { source: source.to_ref() }
- } else if cx.typeck_results().expr_ty(source).is_region_ptr() {
- // Special cased so that we can type check that the element
- // type of the source matches the pointed to type of the
- // destination.
- ExprKind::Pointer { source: source.to_ref(), cast: PointerCast::ArrayToPointer }
- } else {
- // check whether this is casting an enum variant discriminant
- // to prevent cycles, we refer to the discriminant initializer
- // which is always an integer and thus doesn't need to know the
- // enum's layout (or its tag type) to compute it during const eval
- // Example:
- // enum Foo {
- // A,
- // B = A as isize + 4,
- // }
- // The correct solution would be to add symbolic computations to miri,
- // so we wouldn't have to compute and store the actual value
- let var = if let hir::ExprKind::Path(ref qpath) = source.kind {
- let res = cx.typeck_results().qpath_res(qpath, source.hir_id);
- cx.typeck_results().node_type(source.hir_id).ty_adt_def().and_then(|adt_def| {
- match res {
- Res::Def(
- DefKind::Ctor(CtorOf::Variant, CtorKind::Const),
- variant_ctor_id,
- ) => {
- let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id);
- let (d, o) = adt_def.discriminant_def_for_variant(idx);
- use rustc_middle::ty::util::IntTypeExt;
- let ty = adt_def.repr.discr_type();
- let ty = ty.to_ty(cx.tcx());
- Some((d, o, ty))
- }
- _ => None,
- }
- })
+ hir::ExprKind::Match(ref discr, ref arms, _) => ExprKind::Match {
+ scrutinee: self.mirror_expr_boxed(discr),
+ arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
+ },
+ hir::ExprKind::Loop(ref body, ..) => {
+ let block_ty = self.typeck_results().node_type(body.hir_id);
+ let temp_lifetime = self.region_scope_tree.temporary_scope(body.hir_id.local_id);
+ let block = self.mirror_block(body);
+ let body = Box::new(Expr {
+ ty: block_ty,
+ temp_lifetime,
+ span: block.span,
+ kind: ExprKind::Block { body: block },
+ });
+ ExprKind::Loop { body }
+ }
+ hir::ExprKind::Field(ref source, ..) => ExprKind::Field {
+ lhs: self.mirror_expr_boxed(source),
+ name: Field::new(self.tcx.field_index(expr.hir_id, self.typeck_results)),
+ },
+ hir::ExprKind::Cast(ref source, ref cast_ty) => {
+ // Check for a user-given type annotation on this `cast`
+ let user_provided_types = self.typeck_results.user_provided_types();
+ let user_ty = user_provided_types.get(cast_ty.hir_id);
+
+ debug!(
+ "cast({:?}) has ty w/ hir_id {:?} and user provided ty {:?}",
+ expr, cast_ty.hir_id, user_ty,
+ );
+
+ // Check to see if this cast is a "coercion cast", where the cast is actually done
+ // using a coercion (or is a no-op).
+ let cast = if self.typeck_results().is_coercion_cast(source.hir_id) {
+ // Convert the lexpr to a vexpr.
+ ExprKind::Use { source: self.mirror_expr_boxed(source) }
+ } else if self.typeck_results().expr_ty(source).is_region_ptr() {
+ // Special cased so that we can type check that the element
+ // type of the source matches the pointed to type of the
+ // destination.
+ ExprKind::Pointer {
+ source: self.mirror_expr_boxed(source),
+ cast: PointerCast::ArrayToPointer,
+ }
} else {
- None
- };
+ // check whether this is casting an enum variant discriminant
+ // to prevent cycles, we refer to the discriminant initializer
+ // which is always an integer and thus doesn't need to know the
+ // enum's layout (or its tag type) to compute it during const eval
+ // Example:
+ // enum Foo {
+ // A,
+ // B = A as isize + 4,
+ // }
+ // The correct solution would be to add symbolic computations to miri,
+ // so we wouldn't have to compute and store the actual value
+ let var = if let hir::ExprKind::Path(ref qpath) = source.kind {
+ let res = self.typeck_results().qpath_res(qpath, source.hir_id);
+ self.typeck_results().node_type(source.hir_id).ty_adt_def().and_then(
+ |adt_def| match res {
+ Res::Def(
+ DefKind::Ctor(CtorOf::Variant, CtorKind::Const),
+ variant_ctor_id,
+ ) => {
+ let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id);
+ let (d, o) = adt_def.discriminant_def_for_variant(idx);
+ use rustc_middle::ty::util::IntTypeExt;
+ let ty = adt_def.repr.discr_type();
+ let ty = ty.to_ty(self.tcx());
+ Some((d, o, ty))
+ }
+ _ => None,
+ },
+ )
+ } else {
+ None
+ };
- let source = if let Some((did, offset, var_ty)) = var {
- let mk_const = |literal| {
- Expr {
+ let source = if let Some((did, offset, var_ty)) = var {
+ let mk_const = |literal| Expr {
temp_lifetime,
ty: var_ty,
span: expr.span,
kind: ExprKind::Literal { literal, user_ty: None, const_id: None },
+ };
+ let offset = mk_const(ty::Const::from_bits(
+ self.tcx,
+ offset as u128,
+ self.param_env.and(var_ty),
+ ));
+ match did {
+ Some(did) => {
+ // in case we are offsetting from a computed discriminant
+ // and not the beginning of discriminants (which is always `0`)
+ let substs = InternalSubsts::identity_for_item(self.tcx(), did);
+ let lhs = mk_const(self.tcx().mk_const(ty::Const {
+ val: ty::ConstKind::Unevaluated(
+ ty::WithOptConstParam::unknown(did),
+ substs,
+ None,
+ ),
+ ty: var_ty,
+ }));
+ let bin = ExprKind::Binary {
+ op: BinOp::Add,
+ lhs: Box::new(lhs),
+ rhs: Box::new(offset),
+ };
+ Expr { temp_lifetime, ty: var_ty, span: expr.span, kind: bin }
+ }
+ None => offset,
}
- .to_ref()
+ } else {
+ self.mirror_expr(source)
};
- let offset = mk_const(ty::Const::from_bits(
- cx.tcx,
- offset as u128,
- cx.param_env.and(var_ty),
- ));
- match did {
- Some(did) => {
- // in case we are offsetting from a computed discriminant
- // and not the beginning of discriminants (which is always `0`)
- let substs = InternalSubsts::identity_for_item(cx.tcx(), did);
- let lhs = mk_const(cx.tcx().mk_const(ty::Const {
- val: ty::ConstKind::Unevaluated(
- ty::WithOptConstParam::unknown(did),
- substs,
- None,
- ),
- ty: var_ty,
- }));
- let bin = ExprKind::Binary { op: BinOp::Add, lhs, rhs: offset };
- Expr { temp_lifetime, ty: var_ty, span: expr.span, kind: bin }.to_ref()
- }
- None => offset,
- }
- } else {
- source.to_ref()
- };
- ExprKind::Cast { source }
- };
+ ExprKind::Cast { source: Box::new(source) }
+ };
- if let Some(user_ty) = user_ty {
- // NOTE: Creating a new Expr and wrapping a Cast inside of it may be
- // inefficient, revisit this when performance becomes an issue.
- let cast_expr = Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind: cast };
- debug!("make_mirror_unadjusted: (cast) user_ty={:?}", user_ty);
+ if let Some(user_ty) = user_ty {
+ // NOTE: Creating a new Expr and wrapping a Cast inside of it may be
+ // inefficient, revisit this when performance becomes an issue.
+ let cast_expr =
+ Box::new(Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind: cast });
+ debug!("make_mirror_unadjusted: (cast) user_ty={:?}", user_ty);
- ExprKind::ValueTypeAscription {
- source: cast_expr.to_ref(),
- user_ty: Some(*user_ty),
+ ExprKind::ValueTypeAscription { source: cast_expr, user_ty: Some(*user_ty) }
+ } else {
+ cast
}
- } else {
- cast
}
- }
- hir::ExprKind::Type(ref source, ref ty) => {
- let user_provided_types = cx.typeck_results.user_provided_types();
- let user_ty = user_provided_types.get(ty.hir_id).copied();
- debug!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty);
- if source.is_syntactic_place_expr() {
- ExprKind::PlaceTypeAscription { source: source.to_ref(), user_ty }
- } else {
- ExprKind::ValueTypeAscription { source: source.to_ref(), user_ty }
+ hir::ExprKind::Type(ref source, ref ty) => {
+ let user_provided_types = self.typeck_results.user_provided_types();
+ let user_ty = user_provided_types.get(ty.hir_id).copied();
+ debug!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty);
+ let mirrored = self.mirror_expr_boxed(source);
+ if source.is_syntactic_place_expr() {
+ ExprKind::PlaceTypeAscription { source: mirrored, user_ty }
+ } else {
+ ExprKind::ValueTypeAscription { source: mirrored, user_ty }
+ }
+ }
+ hir::ExprKind::DropTemps(ref source) => {
+ ExprKind::Use { source: self.mirror_expr_boxed(source) }
+ }
+ hir::ExprKind::Box(ref value) => ExprKind::Box { value: self.mirror_expr_boxed(value) },
+ hir::ExprKind::Array(ref fields) => ExprKind::Array {
+ fields: fields.iter().map(|field| self.mirror_expr(field)).collect(),
+ },
+ hir::ExprKind::Tup(ref fields) => ExprKind::Tuple {
+ fields: fields.iter().map(|field| self.mirror_expr(field)).collect(),
+ },
+
+ hir::ExprKind::Yield(ref v, _) => ExprKind::Yield { value: self.mirror_expr_boxed(v) },
+ hir::ExprKind::Err => unreachable!(),
+ };
+
+ Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind }
+ }
+
+ fn user_substs_applied_to_res(
+ &mut self,
+ hir_id: hir::HirId,
+ res: Res,
+ ) -> Option<ty::CanonicalUserType<'tcx>> {
+ debug!("user_substs_applied_to_res: res={:?}", res);
+ let user_provided_type = match res {
+ // A reference to something callable -- e.g., a fn, method, or
+ // a tuple-struct or tuple-variant. This has the type of a
+ // `Fn` but with the user-given substitutions.
+ Res::Def(DefKind::Fn, _)
+ | Res::Def(DefKind::AssocFn, _)
+ | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
+ | Res::Def(DefKind::Const, _)
+ | Res::Def(DefKind::AssocConst, _) => {
+ self.typeck_results().user_provided_types().get(hir_id).copied()
+ }
+
+ // A unit struct/variant which is used as a value (e.g.,
+ // `None`). This has the type of the enum/struct that defines
+ // this variant -- but with the substitutions given by the
+ // user.
+ Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => {
+ self.user_substs_applied_to_ty_of_hir_id(hir_id)
+ }
+
+ // `Self` is used in expression as a tuple struct constructor or an unit struct constructor
+ Res::SelfCtor(_) => self.user_substs_applied_to_ty_of_hir_id(hir_id),
+
+ _ => bug!("user_substs_applied_to_res: unexpected res {:?} at {:?}", res, hir_id),
+ };
+ debug!("user_substs_applied_to_res: user_provided_type={:?}", user_provided_type);
+ user_provided_type
+ }
+
+ fn method_callee(
+ &mut self,
+ expr: &hir::Expr<'_>,
+ span: Span,
+ overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
+ ) -> Expr<'tcx> {
+ let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+ let (def_id, substs, user_ty) = match overloaded_callee {
+ Some((def_id, substs)) => (def_id, substs, None),
+ None => {
+ let (kind, def_id) =
+ self.typeck_results().type_dependent_def(expr.hir_id).unwrap_or_else(|| {
+ span_bug!(expr.span, "no type-dependent def for method callee")
+ });
+ let user_ty = self.user_substs_applied_to_res(expr.hir_id, Res::Def(kind, def_id));
+ debug!("method_callee: user_ty={:?}", user_ty);
+ (def_id, self.typeck_results().node_substs(expr.hir_id), user_ty)
}
+ };
+ let ty = self.tcx().mk_fn_def(def_id, substs);
+ Expr {
+ temp_lifetime,
+ ty,
+ span,
+ kind: ExprKind::Literal {
+ literal: ty::Const::zero_sized(self.tcx(), ty),
+ user_ty,
+ const_id: None,
+ },
+ }
+ }
+
+ fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> Arm<'tcx> {
+ Arm {
+ pattern: self.pattern_from_hir(&arm.pat),
+ guard: arm.guard.as_ref().map(|g| match g {
+ hir::Guard::If(ref e) => Guard::If(self.mirror_expr_boxed(e)),
+ hir::Guard::IfLet(ref pat, ref e) => {
+ Guard::IfLet(self.pattern_from_hir(pat), self.mirror_expr_boxed(e))
+ }
+ }),
+ body: self.mirror_expr(arm.body),
+ lint_level: LintLevel::Explicit(arm.hir_id),
+ scope: region::Scope { id: arm.hir_id.local_id, data: region::ScopeData::Node },
+ span: arm.span,
}
- hir::ExprKind::DropTemps(ref source) => ExprKind::Use { source: source.to_ref() },
- hir::ExprKind::Box(ref value) => ExprKind::Box { value: value.to_ref() },
- hir::ExprKind::Array(ref fields) => ExprKind::Array { fields: fields.to_ref() },
- hir::ExprKind::Tup(ref fields) => ExprKind::Tuple { fields: fields.to_ref() },
+ }
- hir::ExprKind::Yield(ref v, _) => ExprKind::Yield { value: v.to_ref() },
- hir::ExprKind::Err => unreachable!(),
- };
+ fn convert_path_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, res: Res) -> ExprKind<'tcx> {
+ let substs = self.typeck_results().node_substs(expr.hir_id);
+ match res {
+ // A regular function, constructor function or a constant.
+ Res::Def(DefKind::Fn, _)
+ | Res::Def(DefKind::AssocFn, _)
+ | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
+ | Res::SelfCtor(..) => {
+ let user_ty = self.user_substs_applied_to_res(expr.hir_id, res);
+ debug!("convert_path_expr: user_ty={:?}", user_ty);
+ ExprKind::Literal {
+ literal: ty::Const::zero_sized(
+ self.tcx,
+ self.typeck_results().node_type(expr.hir_id),
+ ),
+ user_ty,
+ const_id: None,
+ }
+ }
- Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind }
-}
+ Res::Def(DefKind::ConstParam, def_id) => {
+ let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+ let item_id = self.tcx.hir().get_parent_node(hir_id);
+ let item_def_id = self.tcx.hir().local_def_id(item_id);
+ let generics = self.tcx.generics_of(item_def_id);
+ let index = generics.param_def_id_to_index[&def_id];
+ let name = self.tcx.hir().name(hir_id);
+ let val = ty::ConstKind::Param(ty::ParamConst::new(index, name));
+ ExprKind::Literal {
+ literal: self.tcx.mk_const(ty::Const {
+ val,
+ ty: self.typeck_results().node_type(expr.hir_id),
+ }),
+ user_ty: None,
+ const_id: Some(def_id),
+ }
+ }
+
+ Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => {
+ let user_ty = self.user_substs_applied_to_res(expr.hir_id, res);
+ debug!("convert_path_expr: (const) user_ty={:?}", user_ty);
+ ExprKind::Literal {
+ literal: self.tcx.mk_const(ty::Const {
+ val: ty::ConstKind::Unevaluated(
+ ty::WithOptConstParam::unknown(def_id),
+ substs,
+ None,
+ ),
+ ty: self.typeck_results().node_type(expr.hir_id),
+ }),
+ user_ty,
+ const_id: Some(def_id),
+ }
+ }
+
+ Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id) => {
+ let user_provided_types = self.typeck_results.user_provided_types();
+ let user_provided_type = user_provided_types.get(expr.hir_id).copied();
+ debug!("convert_path_expr: user_provided_type={:?}", user_provided_type);
+ let ty = self.typeck_results().node_type(expr.hir_id);
+ match ty.kind() {
+ // A unit struct/variant which is used as a value.
+ // We return a completely different ExprKind here to account for this special case.
+ ty::Adt(adt_def, substs) => ExprKind::Adt {
+ adt_def,
+ variant_index: adt_def.variant_index_with_ctor_id(def_id),
+ substs,
+ user_ty: user_provided_type,
+ fields: vec![],
+ base: None,
+ },
+ _ => bug!("unexpected ty: {:?}", ty),
+ }
+ }
+
+ // We encode uses of statics as a `*&STATIC` where the `&STATIC` part is
+ // a constant reference (or constant raw pointer for `static mut`) in MIR
+ Res::Def(DefKind::Static, id) => {
+ let ty = self.tcx.static_ptr_ty(id);
+ let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+ let kind = if self.tcx.is_thread_local_static(id) {
+ ExprKind::ThreadLocalRef(id)
+ } else {
+ let ptr = self.tcx.create_static_alloc(id);
+ ExprKind::StaticRef {
+ literal: ty::Const::from_scalar(self.tcx, Scalar::Ptr(ptr.into()), ty),
+ def_id: id,
+ }
+ };
+ ExprKind::Deref { arg: Box::new(Expr { ty, temp_lifetime, span: expr.span, kind }) }
+ }
+
+ Res::Local(var_hir_id) => self.convert_var(var_hir_id),
-fn user_substs_applied_to_res<'tcx>(
- cx: &mut Cx<'_, 'tcx>,
- hir_id: hir::HirId,
- res: Res,
-) -> Option<ty::CanonicalUserType<'tcx>> {
- debug!("user_substs_applied_to_res: res={:?}", res);
- let user_provided_type = match res {
- // A reference to something callable -- e.g., a fn, method, or
- // a tuple-struct or tuple-variant. This has the type of a
- // `Fn` but with the user-given substitutions.
- Res::Def(DefKind::Fn, _)
- | Res::Def(DefKind::AssocFn, _)
- | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
- | Res::Def(DefKind::Const, _)
- | Res::Def(DefKind::AssocConst, _) => {
- cx.typeck_results().user_provided_types().get(hir_id).copied()
+ _ => span_bug!(expr.span, "res `{:?}` not yet implemented", res),
}
+ }
- // A unit struct/variant which is used as a value (e.g.,
- // `None`). This has the type of the enum/struct that defines
- // this variant -- but with the substitutions given by the
- // user.
- Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => {
- cx.user_substs_applied_to_ty_of_hir_id(hir_id)
+ fn convert_var(&mut self, var_hir_id: hir::HirId) -> ExprKind<'tcx> {
+ // We want upvars here not captures.
+ // Captures will be handled in MIR.
+ let is_upvar = self
+ .tcx
+ .upvars_mentioned(self.body_owner)
+ .map_or(false, |upvars| upvars.contains_key(&var_hir_id));
+
+ debug!(
+ "convert_var({:?}): is_upvar={}, body_owner={:?}",
+ var_hir_id, is_upvar, self.body_owner
+ );
+
+ if is_upvar {
+ ExprKind::UpvarRef { closure_def_id: self.body_owner, var_hir_id }
+ } else {
+ ExprKind::VarRef { id: var_hir_id }
}
+ }
- // `Self` is used in expression as a tuple struct constructor or an unit struct constructor
- Res::SelfCtor(_) => cx.user_substs_applied_to_ty_of_hir_id(hir_id),
+ fn overloaded_operator(
+ &mut self,
+ expr: &'tcx hir::Expr<'tcx>,
+ args: Vec<Expr<'tcx>>,
+ ) -> ExprKind<'tcx> {
+ let fun = Box::new(self.method_callee(expr, expr.span, None));
+ ExprKind::Call { ty: fun.ty, fun, args, from_hir_call: false, fn_span: expr.span }
+ }
- _ => bug!("user_substs_applied_to_res: unexpected res {:?} at {:?}", res, hir_id),
- };
- debug!("user_substs_applied_to_res: user_provided_type={:?}", user_provided_type);
- user_provided_type
-}
+ fn overloaded_place(
+ &mut self,
+ expr: &'tcx hir::Expr<'tcx>,
+ place_ty: Ty<'tcx>,
+ overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
+ args: Vec<Expr<'tcx>>,
+ span: Span,
+ ) -> ExprKind<'tcx> {
+ // For an overloaded *x or x[y] expression of type T, the method
+ // call returns an &T and we must add the deref so that the types
+ // line up (this is because `*x` and `x[y]` represent places):
+
+ // Reconstruct the output assuming it's a reference with the
+ // same region and mutability as the receiver. This holds for
+ // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
+ let (region, mutbl) = match *args[0].ty.kind() {
+ ty::Ref(region, _, mutbl) => (region, mutbl),
+ _ => span_bug!(span, "overloaded_place: receiver is not a reference"),
+ };
+ let ref_ty = self.tcx.mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl });
+
+ // construct the complete expression `foo()` for the overloaded call,
+ // which will yield the &T type
+ let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+ let fun = Box::new(self.method_callee(expr, span, overloaded_callee));
+ let ref_expr = Box::new(Expr {
+ temp_lifetime,
+ ty: ref_ty,
+ span,
+ kind: ExprKind::Call { ty: fun.ty, fun, args, from_hir_call: false, fn_span: span },
+ });
+
+ // construct and return a deref wrapper `*foo()`
+ ExprKind::Deref { arg: ref_expr }
+ }
+
+ fn capture_upvar(
+ &mut self,
+ closure_expr: &'tcx hir::Expr<'tcx>,
+ captured_place: &'a ty::CapturedPlace<'tcx>,
+ upvar_ty: Ty<'tcx>,
+ ) -> Expr<'tcx> {
+ let upvar_capture = captured_place.info.capture_kind;
+ let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
+ let var_ty = captured_place.place.base_ty;
+
+ // The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path
+ // as it's seen for use within the closure and not at the time of closure creation.
+ //
+ // That is we see expect to see it start from a captured upvar and not something that is local
+ // to the closure's parent.
+ let var_hir_id = match captured_place.place.base {
+ HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
+ base => bug!("Expected an upvar, found {:?}", base),
+ };
+
+ let mut captured_place_expr = Expr {
+ temp_lifetime,
+ ty: var_ty,
+ span: closure_expr.span,
+ kind: self.convert_var(var_hir_id),
+ };
+
+ for proj in captured_place.place.projections.iter() {
+ let kind = match proj.kind {
+ HirProjectionKind::Deref => ExprKind::Deref { arg: Box::new(captured_place_expr) },
+ HirProjectionKind::Field(field, ..) => {
+ // Variant index will always be 0, because for multi-variant
+ // enums, we capture the enum entirely.
+ ExprKind::Field {
+ lhs: Box::new(captured_place_expr),
+ name: Field::new(field as usize),
+ }
+ }
+ HirProjectionKind::Index | HirProjectionKind::Subslice => {
+ // We don't capture these projections, so we can ignore them here
+ continue;
+ }
+ };
-fn method_callee<'a, 'tcx>(
- cx: &mut Cx<'a, 'tcx>,
- expr: &hir::Expr<'_>,
- span: Span,
- overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
-) -> Expr<'tcx> {
- let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
- let (def_id, substs, user_ty) = match overloaded_callee {
- Some((def_id, substs)) => (def_id, substs, None),
- None => {
- let (kind, def_id) = cx
- .typeck_results()
- .type_dependent_def(expr.hir_id)
- .unwrap_or_else(|| span_bug!(expr.span, "no type-dependent def for method callee"));
- let user_ty = user_substs_applied_to_res(cx, expr.hir_id, Res::Def(kind, def_id));
- debug!("method_callee: user_ty={:?}", user_ty);
- (def_id, cx.typeck_results().node_substs(expr.hir_id), user_ty)
+ captured_place_expr =
+ Expr { temp_lifetime, ty: proj.ty, span: closure_expr.span, kind };
+ }
+
+ match upvar_capture {
+ ty::UpvarCapture::ByValue(_) => captured_place_expr,
+ ty::UpvarCapture::ByRef(upvar_borrow) => {
+ let borrow_kind = match upvar_borrow.kind {
+ ty::BorrowKind::ImmBorrow => BorrowKind::Shared,
+ ty::BorrowKind::UniqueImmBorrow => BorrowKind::Unique,
+ ty::BorrowKind::MutBorrow => BorrowKind::Mut { allow_two_phase_borrow: false },
+ };
+ Expr {
+ temp_lifetime,
+ ty: upvar_ty,
+ span: closure_expr.span,
+ kind: ExprKind::Borrow { borrow_kind, arg: Box::new(captured_place_expr) },
+ }
+ }
}
- };
- let ty = cx.tcx().mk_fn_def(def_id, substs);
- Expr {
- temp_lifetime,
- ty,
- span,
- kind: ExprKind::Literal {
- literal: ty::Const::zero_sized(cx.tcx(), ty),
- user_ty,
- const_id: None,
- },
+ }
+
+ /// Converts a list of named fields (i.e., for struct-like struct/enum ADTs) into FieldExpr.
+ fn field_refs(&mut self, fields: &'tcx [hir::Field<'tcx>]) -> Vec<FieldExpr<'tcx>> {
+ fields
+ .iter()
+ .map(|field| FieldExpr {
+ name: Field::new(self.tcx.field_index(field.hir_id, self.typeck_results)),
+ expr: self.mirror_expr(field.expr),
+ })
+ .collect()
}
}
}
}
-fn convert_arm<'tcx>(cx: &mut Cx<'_, 'tcx>, arm: &'tcx hir::Arm<'tcx>) -> Arm<'tcx> {
- Arm {
- pattern: cx.pattern_from_hir(&arm.pat),
- guard: arm.guard.as_ref().map(|g| match g {
- hir::Guard::If(ref e) => Guard::If(e.to_ref()),
- hir::Guard::IfLet(ref pat, ref e) => Guard::IfLet(cx.pattern_from_hir(pat), e.to_ref()),
- }),
- body: arm.body.to_ref(),
- lint_level: LintLevel::Explicit(arm.hir_id),
- scope: region::Scope { id: arm.hir_id.local_id, data: region::ScopeData::Node },
- span: arm.span,
- }
-}
-
-fn convert_path_expr<'a, 'tcx>(
- cx: &mut Cx<'a, 'tcx>,
- expr: &'tcx hir::Expr<'tcx>,
- res: Res,
-) -> ExprKind<'tcx> {
- let substs = cx.typeck_results().node_substs(expr.hir_id);
- match res {
- // A regular function, constructor function or a constant.
- Res::Def(DefKind::Fn, _)
- | Res::Def(DefKind::AssocFn, _)
- | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _)
- | Res::SelfCtor(..) => {
- let user_ty = user_substs_applied_to_res(cx, expr.hir_id, res);
- debug!("convert_path_expr: user_ty={:?}", user_ty);
- ExprKind::Literal {
- literal: ty::Const::zero_sized(cx.tcx, cx.typeck_results().node_type(expr.hir_id)),
- user_ty,
- const_id: None,
- }
- }
-
- Res::Def(DefKind::ConstParam, def_id) => {
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
- let item_id = cx.tcx.hir().get_parent_node(hir_id);
- let item_def_id = cx.tcx.hir().local_def_id(item_id);
- let generics = cx.tcx.generics_of(item_def_id);
- let index = generics.param_def_id_to_index[&def_id];
- let name = cx.tcx.hir().name(hir_id);
- let val = ty::ConstKind::Param(ty::ParamConst::new(index, name));
- ExprKind::Literal {
- literal: cx
- .tcx
- .mk_const(ty::Const { val, ty: cx.typeck_results().node_type(expr.hir_id) }),
- user_ty: None,
- const_id: Some(def_id),
- }
- }
-
- Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => {
- let user_ty = user_substs_applied_to_res(cx, expr.hir_id, res);
- debug!("convert_path_expr: (const) user_ty={:?}", user_ty);
- ExprKind::Literal {
- literal: cx.tcx.mk_const(ty::Const {
- val: ty::ConstKind::Unevaluated(
- ty::WithOptConstParam::unknown(def_id),
- substs,
- None,
- ),
- ty: cx.typeck_results().node_type(expr.hir_id),
- }),
- user_ty,
- const_id: Some(def_id),
- }
- }
-
- Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id) => {
- let user_provided_types = cx.typeck_results.user_provided_types();
- let user_provided_type = user_provided_types.get(expr.hir_id).copied();
- debug!("convert_path_expr: user_provided_type={:?}", user_provided_type);
- let ty = cx.typeck_results().node_type(expr.hir_id);
- match ty.kind() {
- // A unit struct/variant which is used as a value.
- // We return a completely different ExprKind here to account for this special case.
- ty::Adt(adt_def, substs) => ExprKind::Adt {
- adt_def,
- variant_index: adt_def.variant_index_with_ctor_id(def_id),
- substs,
- user_ty: user_provided_type,
- fields: vec![],
- base: None,
- },
- _ => bug!("unexpected ty: {:?}", ty),
- }
- }
-
- // We encode uses of statics as a `*&STATIC` where the `&STATIC` part is
- // a constant reference (or constant raw pointer for `static mut`) in MIR
- Res::Def(DefKind::Static, id) => {
- let ty = cx.tcx.static_ptr_ty(id);
- let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
- let kind = if cx.tcx.is_thread_local_static(id) {
- ExprKind::ThreadLocalRef(id)
- } else {
- let ptr = cx.tcx.create_static_alloc(id);
- ExprKind::StaticRef {
- literal: ty::Const::from_scalar(cx.tcx, Scalar::Ptr(ptr.into()), ty),
- def_id: id,
- }
- };
- ExprKind::Deref { arg: Expr { ty, temp_lifetime, span: expr.span, kind }.to_ref() }
- }
-
- Res::Local(var_hir_id) => convert_var(cx, var_hir_id),
-
- _ => span_bug!(expr.span, "res `{:?}` not yet implemented", res),
- }
-}
-
-fn convert_var<'tcx>(cx: &mut Cx<'_, 'tcx>, var_hir_id: hir::HirId) -> ExprKind<'tcx> {
- // We want upvars here not captures.
- // Captures will be handled in MIR.
- let is_upvar = cx
- .tcx
- .upvars_mentioned(cx.body_owner)
- .map_or(false, |upvars| upvars.contains_key(&var_hir_id));
-
- debug!("convert_var({:?}): is_upvar={}, body_owner={:?}", var_hir_id, is_upvar, cx.body_owner);
-
- if is_upvar {
- ExprKind::UpvarRef { closure_def_id: cx.body_owner, var_hir_id }
- } else {
- ExprKind::VarRef { id: var_hir_id }
- }
-}
-
fn bin_op(op: hir::BinOpKind) -> BinOp {
match op {
hir::BinOpKind::Add => BinOp::Add,
_ => bug!("no equivalent for ast binop {:?}", op),
}
}
-
-fn overloaded_operator<'a, 'tcx>(
- cx: &mut Cx<'a, 'tcx>,
- expr: &'tcx hir::Expr<'tcx>,
- args: Vec<ExprRef<'tcx>>,
-) -> ExprKind<'tcx> {
- let fun = method_callee(cx, expr, expr.span, None);
- ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), args, from_hir_call: false, fn_span: expr.span }
-}
-
-fn overloaded_place<'a, 'tcx>(
- cx: &mut Cx<'a, 'tcx>,
- expr: &'tcx hir::Expr<'tcx>,
- place_ty: Ty<'tcx>,
- overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
- args: Vec<ExprRef<'tcx>>,
- span: Span,
-) -> ExprKind<'tcx> {
- // For an overloaded *x or x[y] expression of type T, the method
- // call returns an &T and we must add the deref so that the types
- // line up (this is because `*x` and `x[y]` represent places):
-
- let recv_ty = match args[0] {
- ExprRef::Thir(e) => cx.typeck_results().expr_ty_adjusted(e),
- ExprRef::Mirror(ref e) => e.ty,
- };
-
- // Reconstruct the output assuming it's a reference with the
- // same region and mutability as the receiver. This holds for
- // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
- let (region, mutbl) = match *recv_ty.kind() {
- ty::Ref(region, _, mutbl) => (region, mutbl),
- _ => span_bug!(span, "overloaded_place: receiver is not a reference"),
- };
- let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl });
-
- // construct the complete expression `foo()` for the overloaded call,
- // which will yield the &T type
- let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
- let fun = method_callee(cx, expr, span, overloaded_callee);
- let ref_expr = Expr {
- temp_lifetime,
- ty: ref_ty,
- span,
- kind: ExprKind::Call {
- ty: fun.ty,
- fun: fun.to_ref(),
- args,
- from_hir_call: false,
- fn_span: span,
- },
- };
-
- // construct and return a deref wrapper `*foo()`
- ExprKind::Deref { arg: ref_expr.to_ref() }
-}
-
-fn capture_upvar<'a, 'tcx>(
- cx: &mut Cx<'_, 'tcx>,
- closure_expr: &'tcx hir::Expr<'tcx>,
- captured_place: &'a ty::CapturedPlace<'tcx>,
- upvar_ty: Ty<'tcx>,
-) -> ExprRef<'tcx> {
- let upvar_capture = captured_place.info.capture_kind;
- let temp_lifetime = cx.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
- let var_ty = captured_place.place.base_ty;
-
- // The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path
- // as it's seen for use within the closure and not at the time of closure creation.
- //
- // That is we see expect to see it start from a captured upvar and not something that is local
- // to the closure's parent.
- let var_hir_id = match captured_place.place.base {
- HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
- base => bug!("Expected an upvar, found {:?}", base),
- };
-
- let mut captured_place_expr = Expr {
- temp_lifetime,
- ty: var_ty,
- span: closure_expr.span,
- kind: convert_var(cx, var_hir_id),
- };
-
- for proj in captured_place.place.projections.iter() {
- let kind = match proj.kind {
- HirProjectionKind::Deref => ExprKind::Deref { arg: captured_place_expr.to_ref() },
- HirProjectionKind::Field(field, ..) => {
- // Variant index will always be 0, because for multi-variant
- // enums, we capture the enum entirely.
- ExprKind::Field {
- lhs: captured_place_expr.to_ref(),
- name: Field::new(field as usize),
- }
- }
- HirProjectionKind::Index | HirProjectionKind::Subslice => {
- // We don't capture these projections, so we can ignore them here
- continue;
- }
- };
-
- captured_place_expr = Expr { temp_lifetime, ty: proj.ty, span: closure_expr.span, kind };
- }
-
- match upvar_capture {
- ty::UpvarCapture::ByValue(_) => captured_place_expr.to_ref(),
- ty::UpvarCapture::ByRef(upvar_borrow) => {
- let borrow_kind = match upvar_borrow.kind {
- ty::BorrowKind::ImmBorrow => BorrowKind::Shared,
- ty::BorrowKind::UniqueImmBorrow => BorrowKind::Unique,
- ty::BorrowKind::MutBorrow => BorrowKind::Mut { allow_two_phase_borrow: false },
- };
- Expr {
- temp_lifetime,
- ty: upvar_ty,
- span: closure_expr.span,
- kind: ExprKind::Borrow { borrow_kind, arg: captured_place_expr.to_ref() },
- }
- .to_ref()
- }
- }
-}
-
-/// Converts a list of named fields (i.e., for struct-like struct/enum ADTs) into FieldExprRef.
-fn field_refs<'a, 'tcx>(
- cx: &mut Cx<'a, 'tcx>,
- fields: &'tcx [hir::Field<'tcx>],
-) -> Vec<FieldExprRef<'tcx>> {
- fields
- .iter()
- .map(|field| FieldExprRef {
- name: Field::new(cx.tcx.field_index(field.hir_id, cx.typeck_results)),
- expr: field.expr.to_ref(),
- })
- .collect()
-}
}
impl<'a, 'tcx> Cx<'a, 'tcx> {
- /// Normalizes `ast` into the appropriate "mirror" type.
- crate fn mirror<M: Mirror<'tcx>>(&mut self, ast: M) -> M::Output {
- ast.make_mirror(self)
- }
-
crate fn usize_ty(&mut self) -> Ty<'tcx> {
self.tcx.types.usize
}
mod block;
mod expr;
-mod to_ref;
+++ /dev/null
-use crate::thir::*;
-
-use rustc_hir as hir;
-
-crate trait ToRef {
- type Output;
- fn to_ref(self) -> Self::Output;
-}
-
-impl<'tcx> ToRef for &'tcx hir::Expr<'tcx> {
- type Output = ExprRef<'tcx>;
-
- fn to_ref(self) -> ExprRef<'tcx> {
- ExprRef::Thir(self)
- }
-}
-
-impl<'tcx> ToRef for &'tcx &'tcx hir::Expr<'tcx> {
- type Output = ExprRef<'tcx>;
-
- fn to_ref(self) -> ExprRef<'tcx> {
- ExprRef::Thir(&**self)
- }
-}
-
-impl<'tcx> ToRef for Expr<'tcx> {
- type Output = ExprRef<'tcx>;
-
- fn to_ref(self) -> ExprRef<'tcx> {
- ExprRef::Mirror(Box::new(self))
- }
-}
-
-impl<'tcx, T, U> ToRef for &'tcx Option<T>
-where
- &'tcx T: ToRef<Output = U>,
-{
- type Output = Option<U>;
-
- fn to_ref(self) -> Option<U> {
- self.as_ref().map(|expr| expr.to_ref())
- }
-}
-
-impl<'tcx, T, U> ToRef for &'tcx Vec<T>
-where
- &'tcx T: ToRef<Output = U>,
-{
- type Output = Vec<U>;
-
- fn to_ref(self) -> Vec<U> {
- self.iter().map(|expr| expr.to_ref()).collect()
- }
-}
-
-impl<'tcx, T, U> ToRef for &'tcx [T]
-where
- &'tcx T: ToRef<Output = U>,
-{
- type Output = Vec<U>;
-
- fn to_ref(self) -> Vec<U> {
- self.iter().map(|expr| expr.to_ref()).collect()
- }
-}
//! unit-tested and separated from the Rust source and compiler data
//! structures.
-use self::cx::Cx;
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
crate region_scope: region::Scope,
crate opt_destruction_scope: Option<region::Scope>,
crate span: Span,
- crate stmts: Vec<StmtRef<'tcx>>,
- crate expr: Option<ExprRef<'tcx>>,
+ crate stmts: Vec<Stmt<'tcx>>,
+ crate expr: Option<Box<Expr<'tcx>>>,
crate safety_mode: BlockSafety,
}
PopUnsafe,
}
-#[derive(Clone, Debug)]
-crate enum StmtRef<'tcx> {
- Mirror(Box<Stmt<'tcx>>),
-}
-
#[derive(Clone, Debug)]
crate struct Stmt<'tcx> {
crate kind: StmtKind<'tcx>,
scope: region::Scope,
/// expression being evaluated in this statement
- expr: ExprRef<'tcx>,
+ expr: Box<Expr<'tcx>>,
},
Let {
pattern: Pat<'tcx>,
/// let pat: ty = <INIT> ...
- initializer: Option<ExprRef<'tcx>>,
+ initializer: Option<Box<Expr<'tcx>>>,
/// the lint level for this let-statement
lint_level: LintLevel,
// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Expr<'_>, 168);
+rustc_data_structures::static_assert_size!(Expr<'_>, 160);
/// The Thir trait implementor lowers their expressions (`&'tcx H::Expr`)
/// into instances of this `Expr` enum. This lowering can be done
/// basically as lazily or as eagerly as desired: every recursive
-/// reference to an expression in this enum is an `ExprRef<'tcx>`, which
+/// reference to an expression in this enum is an `Box<Expr<'tcx>>`, which
/// may in turn be another instance of this enum (boxed), or else an
/// unlowered `&'tcx H::Expr`. Note that instances of `Expr` are very
/// short-lived. They are created by `Thir::to_expr`, analyzed and
Scope {
region_scope: region::Scope,
lint_level: LintLevel,
- value: ExprRef<'tcx>,
+ value: Box<Expr<'tcx>>,
},
Box {
- value: ExprRef<'tcx>,
+ value: Box<Expr<'tcx>>,
},
If {
- cond: ExprRef<'tcx>,
- then: ExprRef<'tcx>,
- else_opt: Option<ExprRef<'tcx>>,
+ cond: Box<Expr<'tcx>>,
+ then: Box<Expr<'tcx>>,
+ else_opt: Option<Box<Expr<'tcx>>>,
},
Call {
ty: Ty<'tcx>,
- fun: ExprRef<'tcx>,
- args: Vec<ExprRef<'tcx>>,
- // Whether this is from a call in HIR, rather than from an overloaded
- // operator. True for overloaded function call.
+ fun: Box<Expr<'tcx>>,
+ args: Vec<Expr<'tcx>>,
+ /// Whether this is from a call in HIR, rather than from an overloaded
+ /// operator. `true` for overloaded function call.
from_hir_call: bool,
/// This `Span` is the span of the function, without the dot and receiver
/// (e.g. `foo(a, b)` in `x.foo(a, b)`
fn_span: Span,
},
Deref {
- arg: ExprRef<'tcx>,
+ arg: Box<Expr<'tcx>>,
}, // NOT overloaded!
Binary {
op: BinOp,
- lhs: ExprRef<'tcx>,
- rhs: ExprRef<'tcx>,
+ lhs: Box<Expr<'tcx>>,
+ rhs: Box<Expr<'tcx>>,
}, // NOT overloaded!
LogicalOp {
op: LogicalOp,
- lhs: ExprRef<'tcx>,
- rhs: ExprRef<'tcx>,
+ lhs: Box<Expr<'tcx>>,
+ rhs: Box<Expr<'tcx>>,
}, // NOT overloaded!
// LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands.
Unary {
op: UnOp,
- arg: ExprRef<'tcx>,
+ arg: Box<Expr<'tcx>>,
}, // NOT overloaded!
Cast {
- source: ExprRef<'tcx>,
+ source: Box<Expr<'tcx>>,
},
Use {
- source: ExprRef<'tcx>,
+ source: Box<Expr<'tcx>>,
}, // Use a lexpr to get a vexpr.
NeverToAny {
- source: ExprRef<'tcx>,
+ source: Box<Expr<'tcx>>,
},
Pointer {
cast: PointerCast,
- source: ExprRef<'tcx>,
+ source: Box<Expr<'tcx>>,
},
Loop {
- body: ExprRef<'tcx>,
+ body: Box<Expr<'tcx>>,
},
Match {
- scrutinee: ExprRef<'tcx>,
+ scrutinee: Box<Expr<'tcx>>,
arms: Vec<Arm<'tcx>>,
},
Block {
- body: &'tcx hir::Block<'tcx>,
+ body: Block<'tcx>,
},
Assign {
- lhs: ExprRef<'tcx>,
- rhs: ExprRef<'tcx>,
+ lhs: Box<Expr<'tcx>>,
+ rhs: Box<Expr<'tcx>>,
},
AssignOp {
op: BinOp,
- lhs: ExprRef<'tcx>,
- rhs: ExprRef<'tcx>,
+ lhs: Box<Expr<'tcx>>,
+ rhs: Box<Expr<'tcx>>,
},
Field {
- lhs: ExprRef<'tcx>,
+ lhs: Box<Expr<'tcx>>,
name: Field,
},
Index {
- lhs: ExprRef<'tcx>,
- index: ExprRef<'tcx>,
+ lhs: Box<Expr<'tcx>>,
+ index: Box<Expr<'tcx>>,
},
VarRef {
id: hir::HirId,
},
Borrow {
borrow_kind: BorrowKind,
- arg: ExprRef<'tcx>,
+ arg: Box<Expr<'tcx>>,
},
/// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
AddressOf {
mutability: hir::Mutability,
- arg: ExprRef<'tcx>,
+ arg: Box<Expr<'tcx>>,
},
Break {
label: region::Scope,
- value: Option<ExprRef<'tcx>>,
+ value: Option<Box<Expr<'tcx>>>,
},
Continue {
label: region::Scope,
},
Return {
- value: Option<ExprRef<'tcx>>,
+ value: Option<Box<Expr<'tcx>>>,
},
ConstBlock {
value: &'tcx Const<'tcx>,
},
Repeat {
- value: ExprRef<'tcx>,
+ value: Box<Expr<'tcx>>,
count: &'tcx Const<'tcx>,
},
Array {
- fields: Vec<ExprRef<'tcx>>,
+ fields: Vec<Expr<'tcx>>,
},
Tuple {
- fields: Vec<ExprRef<'tcx>>,
+ fields: Vec<Expr<'tcx>>,
},
Adt {
adt_def: &'tcx AdtDef,
/// Bar::<T> { ... }`.
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
- fields: Vec<FieldExprRef<'tcx>>,
+ fields: Vec<FieldExpr<'tcx>>,
base: Option<FruInfo<'tcx>>,
},
PlaceTypeAscription {
- source: ExprRef<'tcx>,
+ source: Box<Expr<'tcx>>,
/// Type that the user gave to this expression
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
},
ValueTypeAscription {
- source: ExprRef<'tcx>,
+ source: Box<Expr<'tcx>>,
/// Type that the user gave to this expression
user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
},
Closure {
closure_id: DefId,
substs: UpvarSubsts<'tcx>,
- upvars: Vec<ExprRef<'tcx>>,
+ upvars: Vec<Expr<'tcx>>,
movability: Option<hir::Movability>,
},
Literal {
ThreadLocalRef(DefId),
LlvmInlineAsm {
asm: &'tcx hir::LlvmInlineAsmInner,
- outputs: Vec<ExprRef<'tcx>>,
- inputs: Vec<ExprRef<'tcx>>,
+ outputs: Vec<Expr<'tcx>>,
+ inputs: Vec<Expr<'tcx>>,
},
Yield {
- value: ExprRef<'tcx>,
+ value: Box<Expr<'tcx>>,
},
}
#[derive(Clone, Debug)]
-crate enum ExprRef<'tcx> {
- Thir(&'tcx hir::Expr<'tcx>),
- Mirror(Box<Expr<'tcx>>),
-}
-
-#[derive(Clone, Debug)]
-crate struct FieldExprRef<'tcx> {
+crate struct FieldExpr<'tcx> {
crate name: Field,
- crate expr: ExprRef<'tcx>,
+ crate expr: Expr<'tcx>,
}
#[derive(Clone, Debug)]
crate struct FruInfo<'tcx> {
- crate base: ExprRef<'tcx>,
+ crate base: Box<Expr<'tcx>>,
crate field_types: Vec<Ty<'tcx>>,
}
crate struct Arm<'tcx> {
crate pattern: Pat<'tcx>,
crate guard: Option<Guard<'tcx>>,
- crate body: ExprRef<'tcx>,
+ crate body: Expr<'tcx>,
crate lint_level: LintLevel,
crate scope: region::Scope,
crate span: Span,
#[derive(Clone, Debug)]
crate enum Guard<'tcx> {
- If(ExprRef<'tcx>),
- IfLet(Pat<'tcx>, ExprRef<'tcx>),
+ If(Box<Expr<'tcx>>),
+ IfLet(Pat<'tcx>, Box<Expr<'tcx>>),
}
#[derive(Copy, Clone, Debug)]
Or,
}
-impl<'tcx> ExprRef<'tcx> {
- crate fn span(&self) -> Span {
- match self {
- ExprRef::Thir(expr) => expr.span,
- ExprRef::Mirror(expr) => expr.span,
- }
- }
-}
-
#[derive(Clone, Debug)]
crate enum InlineAsmOperand<'tcx> {
In {
reg: InlineAsmRegOrRegClass,
- expr: ExprRef<'tcx>,
+ expr: Expr<'tcx>,
},
Out {
reg: InlineAsmRegOrRegClass,
late: bool,
- expr: Option<ExprRef<'tcx>>,
+ expr: Option<Expr<'tcx>>,
},
InOut {
reg: InlineAsmRegOrRegClass,
late: bool,
- expr: ExprRef<'tcx>,
+ expr: Expr<'tcx>,
},
SplitInOut {
reg: InlineAsmRegOrRegClass,
late: bool,
- in_expr: ExprRef<'tcx>,
- out_expr: Option<ExprRef<'tcx>>,
+ in_expr: Expr<'tcx>,
+ out_expr: Option<Expr<'tcx>>,
},
Const {
- expr: ExprRef<'tcx>,
+ expr: Expr<'tcx>,
},
SymFn {
- expr: ExprRef<'tcx>,
+ expr: Expr<'tcx>,
},
SymStatic {
def_id: DefId,
},
}
-
-///////////////////////////////////////////////////////////////////////////
-// The Mirror trait
-
-/// "Mirroring" is the process of converting from a HIR type into one
-/// of the THIR types defined in this file. This is basically a "on
-/// the fly" desugaring step that hides a lot of the messiness in the
-/// tcx. For example, the mirror of a `&'tcx hir::Expr` is an
-/// `Expr<'tcx>`.
-///
-/// Mirroring is gradual: when you mirror an outer expression like `e1
-/// + e2`, the references to the inner expressions `e1` and `e2` are
-/// `ExprRef<'tcx>` instances, and they may or may not be eagerly
-/// mirrored. This allows a single AST node from the compiler to
-/// expand into one or more Thir nodes, which lets the Thir nodes be
-/// simpler.
-crate trait Mirror<'tcx> {
- type Output;
-
- fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Self::Output;
-}
-
-impl<'tcx> Mirror<'tcx> for Expr<'tcx> {
- type Output = Expr<'tcx>;
-
- fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Expr<'tcx> {
- self
- }
-}
-
-impl<'tcx> Mirror<'tcx> for ExprRef<'tcx> {
- type Output = Expr<'tcx>;
-
- fn make_mirror(self, hir: &mut Cx<'_, 'tcx>) -> Expr<'tcx> {
- match self {
- ExprRef::Thir(h) => h.make_mirror(hir),
- ExprRef::Mirror(m) => *m,
- }
- }
-}
-
-impl<'tcx> Mirror<'tcx> for Stmt<'tcx> {
- type Output = Stmt<'tcx>;
-
- fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Stmt<'tcx> {
- self
- }
-}
-
-impl<'tcx> Mirror<'tcx> for StmtRef<'tcx> {
- type Output = Stmt<'tcx>;
-
- fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Stmt<'tcx> {
- match self {
- StmtRef::Mirror(m) => *m,
- }
- }
-}
-
-impl<'tcx> Mirror<'tcx> for Block<'tcx> {
- type Output = Block<'tcx>;
-
- fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Block<'tcx> {
- self
- }
-}