diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index d5f72e6f22d..808c6e3ff64 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -2,7 +2,6 @@ use crate::build::matches::ArmHasGuard; 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; @@ -13,7 +12,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, destination: Place<'tcx>, block: BasicBlock, - ast_block: &'tcx hir::Block<'tcx>, + ast_block: &Block<'_, 'tcx>, source_info: SourceInfo, ) -> BlockAnd<()> { let Block { @@ -24,7 +23,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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 { @@ -50,8 +49,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination: Place<'tcx>, mut block: BasicBlock, span: Span, - stmts: Vec>, - expr: Option>, + stmts: &[Stmt<'_, 'tcx>], + expr: Option<&Expr<'_, 'tcx>>, safety_mode: BlockSafety, ) -> BlockAnd<()> { let this = self; @@ -79,10 +78,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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 } => { + &StmtKind::Expr { scope, expr } => { this.block_context.push(BlockFrame::Statement { ignores_expr_result: true }); unpack!( block = this.in_opt_scope( @@ -90,7 +88,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { |this| { 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)) }) } @@ -102,45 +99,44 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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. - let remainder_span = - remainder_scope.span(this.hir.tcx(), &this.hir.region_scope_tree); + let remainder_span = remainder_scope.span(this.tcx, this.region_scope_tree); let visibility_scope = Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None)); // 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, - &pattern, + pattern, 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, - &pattern, + pattern, ArmHasGuard(false), None, ); @@ -171,18 +167,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Then, the block may have an optional trailing expression which is a “return” value // of the block, which is stored into `destination`. - let tcx = this.hir.tcx(); + let tcx = this.tcx; let destination_ty = destination.ty(&this.local_decls, tcx).ty; 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())); @@ -194,13 +187,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if destination_ty.is_unit() { // We only want to assign an implicit `()` as the return value of the block if the // block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.) - this.cfg.push_assign_unit(block, source_info, destination, this.hir.tcx()); + this.cfg.push_assign_unit(block, source_info, destination, this.tcx); } } // 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; @@ -220,7 +213,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Safety::Safe => {} // no longer treat `unsafe fn`s as `unsafe` contexts (see RFC #2585) Safety::FnUnsafe - if self.hir.tcx().lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, hir_id).0 + if self.tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, hir_id).0 != Level::Allow => {} _ => return, } diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 3a36ad590c5..727aedb0ef8 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -8,17 +8,9 @@ use rustc_middle::ty::CanonicalUserTypeAnnotation; 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(&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; + let Expr { ty, temp_lifetime: _, span, ref kind } = *expr; match kind { ExprKind::Scope { region_scope: _, lint_level: _, value } => this.as_constant(value), ExprKind::Literal { literal, user_ty, const_id: _ } => { @@ -33,7 +25,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Constant { span, user_ty, literal } } ExprKind::StaticRef { literal, .. } => Constant { span, user_ty: None, literal }, - ExprKind::ConstBlock { value } => Constant { span, user_ty: None, literal: value }, + ExprKind::ConstBlock { value } => { + Constant { span: span, user_ty: None, literal: value } + } _ => span_bug!(span, "expression is not a valid constant {:?}", kind), } } diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs index 60f8d8c8a9f..c393878e0b9 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -14,10 +14,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// 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(&mut self, block: BasicBlock, expr: M) -> BlockAnd> - where - M: Mirror<'tcx, Output = Expr<'tcx>>, - { + crate fn as_local_operand( + &mut self, + block: BasicBlock, + expr: &Expr<'_, 'tcx>, + ) -> BlockAnd> { let local_scope = self.local_scope(); self.as_operand(block, Some(local_scope), expr) } @@ -70,14 +71,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// value to the stack. /// /// See #68034 for more details. - crate fn as_local_call_operand( + crate fn as_local_call_operand( &mut self, block: BasicBlock, - expr: M, - ) -> BlockAnd> - where - M: Mirror<'tcx, Output = Expr<'tcx>>, - { + expr: &Expr<'_, 'tcx>, + ) -> BlockAnd> { let local_scope = self.local_scope(); self.as_call_operand(block, Some(local_scope), expr) } @@ -88,41 +86,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// this time. /// /// The operand is known to be live until the end of `scope`. - crate fn as_operand( - &mut self, - block: BasicBlock, - scope: Option, - expr: M, - ) -> BlockAnd> - 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( - &mut self, - block: BasicBlock, - scope: Option, - expr: M, - ) -> BlockAnd> - 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, - expr: Expr<'tcx>, + expr: &Expr<'_, 'tcx>, ) -> BlockAnd> { - 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 { @@ -133,7 +106,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } 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); @@ -146,13 +119,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - fn expr_as_call_operand( + crate fn as_call_operand( &mut self, mut block: BasicBlock, scope: Option, - expr: Expr<'tcx>, + expr: &Expr<'_, 'tcx>, ) -> BlockAnd> { - 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 { @@ -163,12 +136,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }); } - let tcx = this.hir.tcx(); + let tcx = this.tcx; if tcx.features().unsized_fn_params { let ty = expr.ty; let span = expr.span; - let param_env = this.hir.param_env; + let param_env = this.param_env; if !ty.is_sized(tcx.at(span), param_env) { // !sized means !copy, so this is an unsized move @@ -176,9 +149,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // 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()); - + if let ExprKind::Deref { arg } = expr.kind { // Generate let tmp0 = arg0 let operand = unpack!(block = this.as_temp(block, scope, arg, Mutability::Mut)); @@ -193,6 +164,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - this.expr_as_operand(block, scope, expr) + this.as_operand(block, scope, expr) } } diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 89143e24447..532c725c823 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -347,25 +347,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// 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(&mut self, mut block: BasicBlock, expr: M) -> BlockAnd> - where - M: Mirror<'tcx, Output = Expr<'tcx>>, - { + crate fn as_place( + &mut self, + mut block: BasicBlock, + expr: &Expr<'_, 'tcx>, + ) -> BlockAnd> { let place_builder = unpack!(block = self.as_place_builder(block, expr)); - block.and(place_builder.into_place(self.hir.tcx(), self.hir.typeck_results())) + block.and(place_builder.into_place(self.tcx, self.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( + crate fn as_place_builder( &mut self, block: BasicBlock, - expr: M, - ) -> BlockAnd> - where - M: Mirror<'tcx, Output = Expr<'tcx>>, - { - let expr = self.hir.mirror(expr); + expr: &Expr<'_, 'tcx>, + ) -> BlockAnd> { self.expr_as_place(block, expr, Mutability::Mut, None) } @@ -374,16 +371,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// 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( + crate fn as_read_only_place( &mut self, mut block: BasicBlock, - expr: M, - ) -> BlockAnd> - where - M: Mirror<'tcx, Output = Expr<'tcx>>, - { + expr: &Expr<'_, 'tcx>, + ) -> BlockAnd> { 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())) + block.and(place_builder.into_place(self.tcx, self.typeck_results)) } /// This is used when constructing a compound `Place`, so that we can avoid creating @@ -392,22 +386,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// 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( + fn as_read_only_place_builder( &mut self, block: BasicBlock, - expr: M, - ) -> BlockAnd> - where - M: Mirror<'tcx, Output = Expr<'tcx>>, - { - let expr = self.hir.mirror(expr); + expr: &Expr<'_, 'tcx>, + ) -> BlockAnd> { 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>, ) -> BlockAnd> { @@ -419,18 +409,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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) }) } 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)) } ExprKind::Deref { arg } => { - let arg = this.hir.mirror(arg); let place_builder = unpack!(block = this.expr_as_place(block, arg, mutability, fake_borrow_temps,)); block.and(place_builder.deref()) @@ -462,7 +449,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } 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,) ); @@ -474,8 +460,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { inferred_ty: expr.ty, }); - let place = - place_builder.clone().into_place(this.hir.tcx(), this.hir.typeck_results()); + let place = place_builder.clone().into_place(this.tcx, this.typeck_results); this.cfg.push( block, Statement { @@ -493,7 +478,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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)); if let Some(user_ty) = user_ty { @@ -570,12 +554,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { upvar_id: ty::UpvarId, ) -> BlockAnd> { let closure_ty = self - .hir - .typeck_results() - .node_type(self.hir.tcx().hir().local_def_id_to_hir_id(upvar_id.closure_expr_id)); + .typeck_results + .node_type(self.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id)); let closure_kind = if let ty::Closure(_, closure_substs) = closure_ty.kind() { - self.hir.infcx().closure_kind(closure_substs).unwrap() + self.infcx.closure_kind(closure_substs).unwrap() } else { // Generators are considered FnOnce. ty::ClosureKind::FnOnce @@ -599,22 +582,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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>, temp_lifetime: Option, expr_span: Span, source_info: SourceInfo, ) -> BlockAnd> { - 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. @@ -623,7 +604,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = self.bounds_check( block, - base_place.clone().into_place(self.hir.tcx(), self.hir.typeck_results()), + base_place.clone().into_place(self.tcx, self.typeck_results), idx, expr_span, source_info, @@ -632,8 +613,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if is_outermost_index { self.read_fake_borrows(block, fake_borrow_temps, source_info) } else { - base_place = - base_place.expect_upvars_resolved(self.hir.tcx(), self.hir.typeck_results()); + base_place = base_place.expect_upvars_resolved(self.tcx, self.typeck_results); self.add_fake_borrows_of_base( &base_place, block, @@ -654,8 +634,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr_span: Span, source_info: SourceInfo, ) -> BasicBlock { - let usize_ty = self.hir.usize_ty(); - let bool_ty = self.hir.bool_ty(); + let usize_ty = self.tcx.types.usize; + let bool_ty = self.tcx.types.bool; // bounds check: let len = self.temp(usize_ty, expr_span); let lt = self.temp(bool_ty, expr_span); @@ -685,7 +665,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr_span: Span, source_info: SourceInfo, ) { - let tcx = self.hir.tcx(); + let tcx = self.tcx; let local = match base_place.base { PlaceBase::Local(local) => local, PlaceBase::Upvar { .. } => bug!("Expected PlacseBase::Local found Upvar"), diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index fd696f99706..d73e5eef70c 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -19,33 +19,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// 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(&mut self, block: BasicBlock, expr: M) -> BlockAnd> - where - M: Mirror<'tcx, Output = Expr<'tcx>>, - { + crate fn as_local_rvalue( + &mut self, + block: BasicBlock, + expr: &Expr<'_, 'tcx>, + ) -> BlockAnd> { let local_scope = self.local_scope(); self.as_rvalue(block, Some(local_scope), expr) } /// Compile `expr`, yielding an rvalue. - fn as_rvalue( - &mut self, - block: BasicBlock, - scope: Option, - expr: M, - ) -> BlockAnd> - 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, - expr: Expr<'tcx>, + expr: &Expr<'_, 'tcx>, ) -> BlockAnd> { debug!("expr_as_rvalue(block={:?}, scope={:?}, expr={:?})", block, scope, expr); @@ -71,8 +59,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::Unary { op, 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() { - let bool_ty = this.hir.bool_ty(); + if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() { + let bool_ty = this.tcx.types.bool; let minval = this.minval_literal(expr_span, expr.ty); let is_min = this.temp(bool_ty, expr_span); @@ -95,7 +83,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(Rvalue::UnaryOp(op, arg)) } ExprKind::Box { value } => { - let value = this.hir.mirror(value); // The `Box` 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`. @@ -115,8 +102,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // 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.tcx.mk_place_deref(Place::from(result)), + block, + value + ) ); block.and(Rvalue::Use(Operand::Move(Place::from(result)))) } @@ -156,7 +146,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // to the same MIR as `let x = ();`. // first process the set of fields - let el_ty = expr.ty.sequence_element_type(this.hir.tcx()); + let el_ty = expr.ty.sequence_element_type(this.tcx); let fields: Vec<_> = fields .into_iter() .map(|f| unpack!(block = this.as_operand(block, scope, f))) @@ -179,7 +169,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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 @@ -230,7 +219,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(Rvalue::Use(Operand::Constant(box Constant { span: expr_span, user_ty: None, - literal: ty::Const::zero_sized(this.hir.tcx(), this.hir.tcx().types.unit), + literal: ty::Const::zero_sized(this.tcx, this.tcx.types.unit), }))) } ExprKind::Yield { .. } @@ -282,9 +271,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { rhs: Operand<'tcx>, ) -> BlockAnd> { let source_info = self.source_info(span); - let bool_ty = self.hir.bool_ty(); - if self.hir.check_overflow() && op.is_checkable() && ty.is_integral() { - let result_tup = self.hir.tcx().intern_tup(&[ty, bool_ty]); + let bool_ty = self.tcx.types.bool; + if self.check_overflow && op.is_checkable() && ty.is_integral() { + let result_tup = self.tcx.intern_tup(&[ty, bool_ty]); let result_value = self.temp(result_tup, span); self.cfg.push_assign( @@ -296,7 +285,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let val_fld = Field::new(0); let of_fld = Field::new(1); - let tcx = self.hir.tcx(); + let tcx = self.tcx; let val = tcx.mk_place_field(result_value, val_fld, ty); let of = tcx.mk_place_field(result_value, of_fld, bool_ty); @@ -377,7 +366,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { upvar_ty: Ty<'tcx>, temp_lifetime: Option, mut block: BasicBlock, - arg: ExprRef<'tcx>, + arg: &Expr<'_, 'tcx>, ) -> BlockAnd> { let this = self; @@ -398,7 +387,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // is same as that of the capture in the parent closure. PlaceBase::Upvar { .. } => { let enclosing_upvars_resolved = - arg_place_builder.clone().into_place(this.hir.tcx(), this.hir.typeck_results()); + arg_place_builder.clone().into_place(this.tcx, this.typeck_results); match enclosing_upvars_resolved.as_ref() { PlaceRef { @@ -435,13 +424,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false }, }; - let arg_place = arg_place_builder.into_place(this.hir.tcx(), this.hir.typeck_results()); + let arg_place = arg_place_builder.into_place(this.tcx, this.typeck_results); this.cfg.push_assign( block, source_info, Place::from(temp), - Rvalue::Ref(this.hir.tcx().lifetimes.re_erased, borrow_kind, arg_place), + Rvalue::Ref(this.tcx.lifetimes.re_erased, borrow_kind, arg_place), ); // See the comment in `expr_as_temp` and on the `rvalue_scopes` field for why @@ -456,9 +445,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Helper to get a `-1` value of the appropriate type fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { let param_ty = ty::ParamEnv::empty().and(ty); - let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits(); + let bits = self.tcx.layout_of(param_ty).unwrap().size.bits(); let n = (!0u128) >> (128 - bits); - let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty); + let literal = ty::Const::from_bits(self.tcx, n, param_ty); self.literal_operand(span, literal) } @@ -467,9 +456,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { assert!(ty.is_signed()); let param_ty = ty::ParamEnv::empty().and(ty); - let bits = self.hir.tcx().layout_of(param_ty).unwrap().size.bits(); + let bits = self.tcx.layout_of(param_ty).unwrap().size.bits(); let n = 1 << (bits - 1); - let literal = ty::Const::from_bits(self.hir.tcx(), n, param_ty); + let literal = ty::Const::from_bits(self.tcx, n, param_ty); self.literal_operand(span, literal) } diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index 9984b527ffd..98b910ab21c 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -4,40 +4,34 @@ use crate::build::scope::DropKind; 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( + crate fn as_temp( &mut self, block: BasicBlock, temp_lifetime: Option, - expr: M, + expr: &Expr<'_, 'tcx>, mutability: Mutability, - ) -> BlockAnd - where - M: Mirror<'tcx, Output = Expr<'tcx>>, - { - let expr = self.hir.mirror(expr); - // + ) -> BlockAnd { // 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, - expr: Expr<'tcx>, + expr: &Expr<'_, 'tcx>, mutability: Mutability, ) -> BlockAnd { debug!( - "expr_as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})", + "as_temp(block={:?}, temp_lifetime={:?}, expr={:?}, mutability={:?})", block, temp_lifetime, expr, mutability ); let this = self; @@ -65,13 +59,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } match expr.kind { ExprKind::StaticRef { def_id, .. } => { - assert!(!this.hir.tcx().is_thread_local_static(def_id)); + assert!(!this.tcx.is_thread_local_static(def_id)); local_decl.internal = true; local_decl.local_info = Some(box LocalInfo::StaticRef { def_id, is_thread_local: false }); } ExprKind::ThreadLocalRef(def_id) => { - assert!(this.hir.tcx().is_thread_local_static(def_id)); + assert!(this.tcx.is_thread_local_static(def_id)); local_decl.internal = true; local_decl.local_info = Some(box LocalInfo::StaticRef { def_id, is_thread_local: true }); @@ -89,7 +83,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // 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 @@ -114,7 +108,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - 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); diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs index 9320b5810e3..0cadfa2f0a1 100644 --- a/compiler/rustc_mir_build/src/build/expr/category.rs +++ b/compiler/rustc_mir_build/src/build/expr/category.rs @@ -31,7 +31,7 @@ crate enum RvalueFunc { /// Determines the category for a given expression. Note that scope /// and paren expressions have no category. impl Category { - crate fn of(ek: &ExprKind<'_>) -> Option { + crate fn of(ek: &ExprKind<'_, '_>) -> Option { match *ek { ExprKind::Scope { .. } => None, diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 235fe14cbf9..47f75825fb6 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -7,19 +7,20 @@ use rustc_ast::InlineAsmOptions; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; +use rustc_index::vec::Idx; use rustc_middle::mir::*; -use rustc_middle::ty::CanonicalUserTypeAnnotation; +use rustc_middle::ty::{self, CanonicalUserTypeAnnotation}; 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 @@ -40,11 +41,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let region_scope = (region_scope, source_info); ensure_sufficient_stack(|| { this.in_scope(region_scope, lint_level, |this| { - this.into(destination, block, value) + this.expr_into_dest(destination, block, value) }) }) } - ExprKind::Block { body: ast_block } => { + ExprKind::Block { body: ref ast_block } => { this.ast_block(destination, block, ast_block, source_info) } ExprKind::Match { scrutinee, arms } => { @@ -58,17 +59,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut then_block = this.cfg.start_new_block(); let mut else_block = this.cfg.start_new_block(); - let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block); + let term = TerminatorKind::if_(this.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. let correct_si = this.source_info(expr_span.shrink_to_hi()); - this.cfg.push_assign_unit(else_block, correct_si, destination, this.hir.tcx()); + this.cfg.push_assign_unit(else_block, correct_si, destination, this.tcx); else_block }; @@ -87,7 +88,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { join_block.unit() } ExprKind::NeverToAny { source } => { - let source = this.hir.mirror(source); let is_call = matches!(source.kind, ExprKind::Call { .. } | ExprKind::InlineAsm { .. }); @@ -132,25 +132,33 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { LogicalOp::And => (else_block, false_block), LogicalOp::Or => (true_block, else_block), }; - let term = TerminatorKind::if_(this.hir.tcx(), lhs, blocks.0, blocks.1); + let term = TerminatorKind::if_(this.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 term = TerminatorKind::if_(this.hir.tcx(), rhs, true_block, false_block); + let term = TerminatorKind::if_(this.tcx, rhs, true_block, false_block); this.cfg.terminate(else_block, source_info, term); this.cfg.push_assign_constant( true_block, source_info, destination, - Constant { span: expr_span, user_ty: None, literal: this.hir.true_literal() }, + Constant { + span: expr_span, + user_ty: None, + literal: ty::Const::from_bool(this.tcx, true), + }, ); this.cfg.push_assign_constant( false_block, source_info, destination, - Constant { span: expr_span, user_ty: None, literal: this.hir.false_literal() }, + Constant { + span: expr_span, + user_ty: None, + literal: ty::Const::from_bool(this.tcx, false), + }, ); // Link up both branches: @@ -188,7 +196,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // 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. @@ -206,7 +214,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.record_operands_moved(&args); - debug!("into_expr: fn_span={:?}", fn_span); + debug!("expr_into_dest: fn_span={:?}", fn_span); this.cfg.terminate( block, @@ -230,7 +238,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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 @@ -241,8 +249,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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); + let borrow = Rvalue::Ref(this.tcx.lifetimes.re_erased, borrow_kind, arg_place); this.cfg.push_assign(block, source_info, destination, borrow); block.unit() } @@ -255,7 +262,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.cfg.push_assign(block, source_info, destination, address_of); block.unit() } - ExprKind::Adt { adt_def, variant_index, substs, user_ty, fields, base } => { + ExprKind::Adt { adt_def, variant_index, substs, user_ty, fields, ref base } => { // See the notes for `ExprKind::Array` in `as_rvalue` and for // `ExprKind::Borrow` above. let is_union = adt_def.is_union(); @@ -270,7 +277,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .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: Vec<_> = + (0..adt_def.variants[variant_index].fields.len()).map(Field::new).collect(); let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base { let place_builder = unpack!(block = this.as_place_builder(block, base)); @@ -288,7 +296,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.consume_by_copy_or_move( place_builder .field(n, ty) - .into_place(this.hir.tcx(), this.hir.typeck_results()), + .into_place(this.tcx, this.typeck_results), ) } }) @@ -325,7 +333,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { use rustc_middle::mir; let operands = operands .into_iter() - .map(|op| match op { + .map(|op| match *op { thir::InlineAsmOperand::In { reg, expr } => mir::InlineAsmOperand::In { reg, value: unpack!(block = this.as_local_operand(block, expr)), @@ -334,7 +342,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mir::InlineAsmOperand::Out { reg, late, - place: expr.map(|expr| unpack!(block = this.as_place(block, expr))), + place: expr + .as_ref() + .map(|expr| unpack!(block = this.as_place(block, expr))), } } thir::InlineAsmOperand::InOut { reg, late, expr } => { @@ -352,7 +362,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { reg, late, in_value: unpack!(block = this.as_local_operand(block, in_expr)), - out_place: out_expr.map(|out_expr| { + out_place: out_expr.as_ref().map(|out_expr| { unpack!(block = this.as_place(block, out_expr)) }), } @@ -394,7 +404,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::AssignOp { .. } | ExprKind::LlvmInlineAsm { .. } => { unpack!(block = this.stmt_expr(block, expr, None)); - this.cfg.push_assign_unit(block, source_info, destination, this.hir.tcx()); + this.cfg.push_assign_unit(block, source_info, destination, this.tcx); block.unit() } diff --git a/compiler/rustc_mir_build/src/build/expr/mod.rs b/compiler/rustc_mir_build/src/build/expr/mod.rs index ac8c7e725e1..07338928eb8 100644 --- a/compiler/rustc_mir_build/src/build/expr/mod.rs +++ b/compiler/rustc_mir_build/src/build/expr/mod.rs @@ -9,7 +9,7 @@ //! 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` diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs index f117689d940..f01315fc5db 100644 --- a/compiler/rustc_mir_build/src/build/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs @@ -13,7 +13,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn stmt_expr( &mut self, mut block: BasicBlock, - expr: Expr<'tcx>, + expr: &Expr<'_, 'tcx>, statement_scope: Option, ) -> BlockAnd<()> { let this = self; @@ -21,29 +21,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let source_info = this.source_info(expr.span); // 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 { 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) }) } 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 // is better for borrowck interaction with overloaded // operators like x[j] = x[i]. - debug!("stmt_expr Assign block_context.push(SubExpr) : {:?}", expr2); + debug!("stmt_expr Assign block_context.push(SubExpr) : {:?}", expr); this.block_context.push(BlockFrame::SubExpr); // Generate better code for things that don't need to be // dropped. - if this.hir.needs_drop(lhs.ty) { + if lhs.ty.needs_drop(this.tcx, this.param_env) { 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)); @@ -65,10 +61,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // 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); + debug!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr); this.block_context.push(BlockFrame::SubExpr); // As above, RTL. @@ -90,24 +85,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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) - } + 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); + debug!("stmt_expr LlvmInlineAsm block_context.push(SubExpr) : {:?}", expr); 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::>() .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::>() .into_boxed_slice(); @@ -140,15 +138,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // 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 { - if let Some(subtail_expr) = &subblock.expr { - expr = subtail_expr - } else { - break; - } + let mut expr = &*tail_expr; + while let ExprKind::Block { + body: Block { expr: Some(nested_expr), .. }, + } + | ExprKind::Scope { value: nested_expr, .. } = &expr.kind + { + expr = nested_expr; } this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored: true, diff --git a/compiler/rustc_mir_build/src/build/into.rs b/compiler/rustc_mir_build/src/build/into.rs deleted file mode 100644 index 7264e495b84..00000000000 --- a/compiler/rustc_mir_build/src/build/into.rs +++ /dev/null @@ -1,55 +0,0 @@ -//! 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( - &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) - } -} diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index fde007ec011..6c31528be73 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -89,10 +89,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination: Place<'tcx>, span: Span, mut block: BasicBlock, - scrutinee: ExprRef<'tcx>, - arms: Vec>, + 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,)); @@ -119,7 +119,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn lower_scrutinee( &mut self, mut block: BasicBlock, - scrutinee: ExprRef<'tcx>, + scrutinee: &Expr<'_, 'tcx>, scrutinee_span: Span, ) -> BlockAnd> { let scrutinee_place = unpack!(block = self.as_place(block, scrutinee)); @@ -149,8 +149,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn create_match_candidates<'pat>( &mut self, scrutinee: Place<'tcx>, - arms: &'pat [Arm<'tcx>], - ) -> Vec<(&'pat Arm<'tcx>, Candidate<'pat, 'tcx>)> { + arms: &'pat [Arm<'pat, 'tcx>], + ) -> Vec<(&'pat Arm<'pat, 'tcx>, Candidate<'pat, 'tcx>)> { // Assemble a list of candidates: there is one candidate per pattern, // which means there may be more than one candidate *per arm*. arms.iter() @@ -224,7 +224,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination: Place<'tcx>, scrutinee_place: Place<'tcx>, scrutinee_span: Span, - arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>, + arm_candidates: Vec<(&'_ Arm<'_, 'tcx>, Candidate<'_, 'tcx>)>, outer_source_info: SourceInfo, fake_borrow_temps: Vec<(Place<'tcx>, Local)>, ) -> BlockAnd<()> { @@ -236,7 +236,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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, @@ -259,7 +258,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.source_scope = source_scope; } - this.into(destination, arm_block, body) + this.expr_into_dest(destination, arm_block, &arm.body) }) }) .collect(); @@ -286,7 +285,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, outer_source_info: SourceInfo, candidate: Candidate<'_, 'tcx>, - guard: Option<&Guard<'tcx>>, + guard: Option<&Guard<'_, 'tcx>>, fake_borrow_temps: &Vec<(Place<'tcx>, Local)>, scrutinee_span: Span, arm_span: Option, @@ -362,14 +361,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &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); @@ -404,7 +403,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } => { 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); @@ -414,7 +413,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let ty_source_info = self.source_info(user_ty_span); let user_ty = pat_ascription_ty.user_ty( &mut self.canonical_user_type_annotations, - place.ty(&self.local_decls, self.hir.tcx()).ty, + place.ty(&self.local_decls, self.tcx).ty, ty_source_info.span, ); self.cfg.push( @@ -556,7 +555,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let local_id = self.var_local_id(var, for_guard); let source_info = self.source_info(span); self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) }); - let region_scope = self.hir.region_scope_tree.var_scope(var.local_id); + let region_scope = self.region_scope_tree.var_scope(var.local_id); if schedule_drop { self.schedule_drop(span, region_scope, local_id, DropKind::Storage); } @@ -565,7 +564,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn schedule_drop_for_binding(&mut self, var: HirId, span: Span, for_guard: ForGuard) { let local_id = self.var_local_id(var, for_guard); - let region_scope = self.hir.region_scope_tree.var_scope(var.local_id); + let region_scope = self.region_scope_tree.var_scope(var.local_id); self.schedule_drop(span, region_scope, local_id, DropKind::Value); } @@ -1071,7 +1070,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fake_borrows.insert(Place { local: source.local, - projection: self.hir.tcx().intern_place_elems(proj_base), + projection: self.tcx.intern_place_elems(proj_base), }); } } @@ -1550,7 +1549,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fake_borrows: &'b FxHashSet>, temp_span: Span, ) -> Vec<(Place<'tcx>, Local)> { - let tcx = self.hir.tcx(); + let tcx = self.tcx; debug!("add_fake_borrows fake_borrows = {:?}", fake_borrows); @@ -1613,7 +1612,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, candidate: Candidate<'pat, 'tcx>, parent_bindings: &[(Vec>, Vec>)], - guard: Option<&Guard<'tcx>>, + guard: Option<&Guard<'_, 'tcx>>, fake_borrows: &Vec<(Place<'tcx>, Local)>, scrutinee_span: Span, arm_span: Option, @@ -1727,7 +1726,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // * So we eagerly create the reference for the arm and then take a // reference to that. if let Some(guard) = guard { - let tcx = self.hir.tcx(); + let tcx = self.tcx; let bindings = parent_bindings .iter() .flat_map(|(bindings, _)| bindings) @@ -1749,15 +1748,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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); @@ -1772,14 +1769,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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, ); @@ -1888,7 +1885,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let user_ty = ascription.user_ty.clone().user_ty( &mut self.canonical_user_type_annotations, - ascription.source.ty(&self.local_decls, self.hir.tcx()).ty, + ascription.source.ty(&self.local_decls, self.tcx).ty, source_info.span, ); self.cfg.push( @@ -1917,7 +1914,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Assign each of the bindings. Since we are binding for a // guard expression, this will never trigger moves out of the // candidate. - let re_erased = self.hir.tcx().lifetimes.re_erased; + let re_erased = self.tcx.lifetimes.re_erased; for binding in bindings { debug!("bind_matched_candidate_for_guard(binding={:?})", binding); let source_info = self.source_info(binding.span); @@ -1966,7 +1963,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { { debug!("bind_matched_candidate_for_arm_body(block={:?})", block); - let re_erased = self.hir.tcx().lifetimes.re_erased; + let re_erased = self.tcx.lifetimes.re_erased; // Assign each of the bindings. This may trigger moves out of the candidate. for binding in bindings { let source_info = self.source_info(binding.span); @@ -2015,7 +2012,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { var_id, name, mode, var_ty, visibility_scope, source_info ); - let tcx = self.hir.tcx(); + let tcx = self.tcx; let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope }; let binding_mode = match mode { BindingMode::ByValue => ty::BindingMode::BindByValue(mutability), diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index ddfaeafc07c..9931cdf3b9e 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -147,7 +147,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match_pair: MatchPair<'pat, 'tcx>, candidate: &mut Candidate<'pat, 'tcx>, ) -> Result<(), MatchPair<'pat, 'tcx>> { - let tcx = self.hir.tcx(); + let tcx = self.tcx; match *match_pair.pattern.kind { PatKind::AscribeUserType { ref subpattern, @@ -251,13 +251,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Variant { adt_def, substs, variant_index, ref subpatterns } => { let irrefutable = adt_def.variants.iter_enumerated().all(|(i, v)| { i == variant_index || { - self.hir.tcx().features().exhaustive_patterns + self.tcx.features().exhaustive_patterns && !v .uninhabited_from( - self.hir.tcx(), + self.tcx, substs, adt_def.adt_kind(), - self.hir.param_env, + self.param_env, ) .is_empty() } diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index c428ed817b1..48abaa8d35f 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -13,9 +13,11 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_hir::{LangItem, RangeEnd}; use rustc_index::bit_set::BitSet; use rustc_middle::mir::*; +use rustc_middle::ty::subst::{GenericArg, Subst}; use rustc_middle::ty::util::IntTypeExt; -use rustc_middle::ty::{self, adjustment::PointerCast, Ty}; -use rustc_span::symbol::sym; +use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt}; +use rustc_span::def_id::DefId; +use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::VariantIdx; use std::cmp::Ordering; @@ -93,9 +95,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match *match_pair.pattern.kind { PatKind::Constant { value } => { - options.entry(value).or_insert_with(|| { - value.eval_bits(self.hir.tcx(), self.hir.param_env, switch_ty) - }); + options + .entry(value) + .or_insert_with(|| value.eval_bits(self.tcx, self.param_env, switch_ty)); true } PatKind::Variant { .. } => { @@ -157,7 +159,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { "perform_test({:?}, {:?}: {:?}, {:?})", block, place, - place.ty(&self.local_decls, self.hir.tcx()), + place.ty(&self.local_decls, self.tcx), test ); @@ -169,7 +171,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let num_enum_variants = adt_def.variants.len(); debug_assert_eq!(target_blocks.len(), num_enum_variants + 1); let otherwise_block = *target_blocks.last().unwrap(); - let tcx = self.hir.tcx(); + let tcx = self.tcx; let switch_targets = SwitchTargets::new( adt_def.discriminants(tcx).filter_map(|(idx, discr)| { if variants.contains(idx) { @@ -217,7 +219,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 0 => (second_bb, first_bb), v => span_bug!(test.span, "expected boolean value but got {:?}", v), }; - TerminatorKind::if_(self.hir.tcx(), Operand::Copy(place), true_bb, false_bb) + TerminatorKind::if_(self.tcx, Operand::Copy(place), true_bb, false_bb) } else { bug!("`TestKind::SwitchInt` on `bool` should have two targets") } @@ -292,7 +294,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TestKind::Len { len, op } => { let target_blocks = make_target_blocks(self); - let usize_ty = self.hir.usize_ty(); + let usize_ty = self.tcx.types.usize; let actual = self.temp(usize_ty, test.span); // actual = len(place) @@ -331,7 +333,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { left: Operand<'tcx>, right: Operand<'tcx>, ) { - let bool_ty = self.hir.bool_ty(); + let bool_ty = self.tcx.types.bool; let result = self.temp(bool_ty, source_info.span); // result = op(left, right) @@ -341,7 +343,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.terminate( block, source_info, - TerminatorKind::if_(self.hir.tcx(), Operand::Move(result), success_block, fail_block), + TerminatorKind::if_(self.tcx, Operand::Move(result), success_block, fail_block), ); } @@ -377,7 +379,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // nothing to do, neither is an array (None, None) => {} (Some((region, elem_ty, _)), _) | (None, Some((region, elem_ty, _))) => { - let tcx = self.hir.tcx(); + let tcx = self.tcx; // make both a slice ty = tcx.mk_imm_ref(region, tcx.mk_slice(elem_ty)); if opt_ref_ty.is_some() { @@ -408,10 +410,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ => bug!("non_scalar_compare called on non-reference type: {}", ty), }; - let eq_def_id = self.hir.tcx().require_lang_item(LangItem::PartialEq, None); - let method = self.hir.trait_method(eq_def_id, sym::eq, deref_ty, &[deref_ty.into()]); + let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, None); + let method = trait_method(self.tcx, eq_def_id, sym::eq, deref_ty, &[deref_ty.into()]); - let bool_ty = self.hir.bool_ty(); + let bool_ty = self.tcx.types.bool; let eq_result = self.temp(bool_ty, source_info.span); let eq_block = self.cfg.start_new_block(); self.cfg.terminate( @@ -443,12 +445,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.terminate( eq_block, source_info, - TerminatorKind::if_( - self.hir.tcx(), - Operand::Move(eq_result), - success_block, - fail_block, - ), + TerminatorKind::if_(self.tcx, Operand::Move(eq_result), success_block, fail_block), ); } else { bug!("`TestKind::Eq` should have two target blocks") @@ -632,11 +629,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { use rustc_hir::RangeEnd::*; use std::cmp::Ordering::*; - let tcx = self.hir.tcx(); + let tcx = self.tcx; let test_ty = test.lo.ty; - let lo = compare_const_vals(tcx, test.lo, pat.hi, self.hir.param_env, test_ty)?; - let hi = compare_const_vals(tcx, test.hi, pat.lo, self.hir.param_env, test_ty)?; + let lo = compare_const_vals(tcx, test.lo, pat.hi, self.param_env, test_ty)?; + let hi = compare_const_vals(tcx, test.hi, pat.lo, self.param_env, test_ty)?; match (test.end, pat.end, lo, hi) { // pat < test @@ -731,7 +728,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidate: &mut Candidate<'pat, 'tcx>, ) { let match_pair = candidate.match_pairs.remove(match_pair_index); - let tcx = self.hir.tcx(); + let tcx = self.tcx; // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`, // we want to create a set of derived match-patterns like @@ -762,10 +759,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) -> Option { use std::cmp::Ordering::*; - let tcx = self.hir.tcx(); + let tcx = self.tcx; - let a = compare_const_vals(tcx, range.lo, value, self.hir.param_env, range.lo.ty)?; - let b = compare_const_vals(tcx, value, range.hi, self.hir.param_env, range.lo.ty)?; + let a = compare_const_vals(tcx, range.lo, value, self.param_env, range.lo.ty)?; + let b = compare_const_vals(tcx, value, range.hi, self.param_env, range.lo.ty)?; match (b, range.end) { (Less, _) | (Equal, RangeEnd::Included) if a != Greater => Some(true), @@ -815,3 +812,25 @@ impl Test<'_> { fn is_switch_ty(ty: Ty<'_>) -> bool { ty.is_integral() || ty.is_char() || ty.is_bool() } + +fn trait_method<'tcx>( + tcx: TyCtxt<'tcx>, + trait_def_id: DefId, + method_name: Symbol, + self_ty: Ty<'tcx>, + params: &[GenericArg<'tcx>], +) -> &'tcx ty::Const<'tcx> { + let substs = tcx.mk_substs_trait(self_ty, params); + + // The unhygienic comparison here is acceptable because this is only + // used on known traits. + let item = tcx + .associated_items(trait_def_id) + .filter_by_name_unhygienic(method_name) + .find(|item| item.kind == ty::AssocKind::Fn) + .expect("trait method not found"); + + let method_ty = tcx.type_of(item.def_id); + let method_ty = method_ty.subst(tcx, substs); + ty::Const::zero_sized(tcx, method_ty) +} diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index db1f678a5c6..15aca0203aa 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -15,8 +15,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { subpatterns .iter() .map(|fieldpat| { - let place = - self.hir.tcx().mk_place_field(place, fieldpat.field, fieldpat.pattern.ty); + let place = self.tcx.mk_place_field(place, fieldpat.field, fieldpat.pattern.ty); MatchPair::new(place, &fieldpat.pattern) }) .collect() @@ -30,9 +29,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { opt_slice: Option<&'pat Pat<'tcx>>, suffix: &'pat [Pat<'tcx>], ) { - let tcx = self.hir.tcx(); + let tcx = self.tcx; let (min_length, exact_size) = match place.ty(&self.local_decls, tcx).ty.kind() { - ty::Array(_, length) => (length.eval_usize(tcx, self.hir.param_env), true), + ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true), _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), }; diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs index 29651d9bc66..62c217a12aa 100644 --- a/compiler/rustc_mir_build/src/build/misc.rs +++ b/compiler/rustc_mir_build/src/build/misc.rs @@ -3,10 +3,10 @@ use crate::build::Builder; -use rustc_middle::ty::{self, Ty}; - use rustc_middle::mir::*; +use rustc_middle::ty::{self, Ty}; use rustc_span::{Span, DUMMY_SP}; +use rustc_trait_selection::infer::InferCtxtExt; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Adds a new temporary value of type `ty` storing the result of @@ -37,7 +37,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Returns a zero literal operand for the appropriate type, works for // bool, char and integers. crate fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { - let literal = ty::Const::from_bits(self.hir.tcx(), 0, ty::ParamEnv::empty().and(ty)); + let literal = ty::Const::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty)); self.literal_operand(span, literal) } @@ -48,7 +48,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info: SourceInfo, value: u64, ) -> Place<'tcx> { - let usize_ty = self.hir.usize_ty(); + let usize_ty = self.tcx.types.usize; let temp = self.temp(usize_ty, source_info.span); self.cfg.push_assign_constant( block, @@ -57,16 +57,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Constant { span: source_info.span, user_ty: None, - literal: self.hir.usize_literal(value), + literal: ty::Const::from_usize(self.tcx, value), }, ); temp } crate fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> { - let tcx = self.hir.tcx(); + let tcx = self.tcx; let ty = place.ty(&self.local_decls, tcx).ty; - if !self.hir.type_is_copy_modulo_regions(ty, DUMMY_SP) { + if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, DUMMY_SP) { Operand::Move(place) } else { Operand::Copy(place) diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 3ac9c631d03..b633fe32674 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -1,7 +1,7 @@ use crate::build; use crate::build::scope::DropKind; -use crate::thir::cx::Cx; -use crate::thir::{BindingMode, LintLevel, PatKind}; +use crate::thir::cx::build_thir; +use crate::thir::{Arena, BindingMode, Expr, LintLevel, Pat, PatKind}; use rustc_attr::{self as attr, UnwindAttr}; use rustc_errors::ErrorReported; use rustc_hir as hir; @@ -9,13 +9,13 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::{GeneratorKind, HirIdMap, Node}; use rustc_index::vec::{Idx, IndexVec}; -use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_middle::hir::place::PlaceBase as HirPlaceBase; use rustc_middle::middle::region; use rustc_middle::mir::*; use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc_span::symbol::kw; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults}; +use rustc_span::symbol::{kw, sym}; use rustc_span::Span; use rustc_target::spec::abi::Abi; use rustc_target::spec::PanicStrategy; @@ -42,6 +42,8 @@ crate fn mir_built<'tcx>( /// Construct the MIR for a given `DefId`. fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_> { let id = tcx.hir().local_def_id_to_hir_id(def.did); + let body_owner_kind = tcx.hir().body_owner_kind(id); + let typeck_results = tcx.typeck_opt_const_arg(def); // Figure out what primary body this item has. let (body_id, return_ty_span, span_with_body) = match tcx.hir().get(id) { @@ -86,15 +88,15 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ // If we don't have a specialized span for the body, just use the // normal def span. let span_with_body = span_with_body.unwrap_or_else(|| tcx.hir().span(id)); + let arena = Arena::default(); tcx.infer_ctxt().enter(|infcx| { - let cx = Cx::new(&infcx, def, id); - let body = if let Some(ErrorReported) = cx.typeck_results().tainted_by_errors { - build::construct_error(cx, body_id) - } else if cx.body_owner_kind.is_fn_or_closure() { + let body = if let Some(ErrorReported) = typeck_results.tainted_by_errors { + build::construct_error(&infcx, def, id, body_id, body_owner_kind) + } else if body_owner_kind.is_fn_or_closure() { // fetch the fully liberated fn signature (that is, all bound // types/lifetimes replaced) - let fn_sig = cx.typeck_results().liberated_fn_sigs()[id]; + let fn_sig = typeck_results.liberated_fn_sigs()[id]; let fn_def_id = tcx.hir().local_def_id(id); let safety = match fn_sig.unsafety { @@ -103,6 +105,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ }; let body = tcx.hir().body(body_id); + let thir = build_thir(tcx, def, &arena, &body.value); let ty = tcx.type_of(fn_def_id); let mut abi = fn_sig.abi; let implicit_argument = match ty.kind() { @@ -178,7 +181,8 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ }; let mut mir = build::construct_fn( - cx, + &infcx, + def, id, arguments, safety, @@ -186,6 +190,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ return_ty, return_ty_span, body, + thir, span_with_body, ); if yield_ty.is_some() { @@ -205,9 +210,12 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ // place to be the type of the constant because NLL typeck will // equate them. - let return_ty = cx.typeck_results().node_type(id); + let return_ty = typeck_results.node_type(id); - build::construct_const(cx, body_id, return_ty, return_ty_span) + let ast_expr = &tcx.hir().body(body_id).value; + let thir = build_thir(tcx, def, &arena, ast_expr); + + build::construct_const(&infcx, thir, def, id, return_ty, return_ty_span) }; lints::check(tcx, &body); @@ -304,10 +312,17 @@ impl BlockFrame { struct BlockContext(Vec); struct Builder<'a, 'tcx> { - hir: Cx<'a, 'tcx>, + tcx: TyCtxt<'tcx>, + infcx: &'a InferCtxt<'a, 'tcx>, + typeck_results: &'tcx TypeckResults<'tcx>, + region_scope_tree: &'tcx region::ScopeTree, + param_env: ty::ParamEnv<'tcx>, + cfg: CFG<'tcx>, def_id: DefId, + hir_id: hir::HirId, + check_overflow: bool, fn_span: Span, arg_count: usize, generator_kind: Option, @@ -607,8 +622,9 @@ struct ArgInfo<'tcx>( Option, ); -fn construct_fn<'a, 'tcx, A>( - hir: Cx<'a, 'tcx>, +fn construct_fn<'tcx, A>( + infcx: &InferCtxt<'_, 'tcx>, + fn_def: ty::WithOptConstParam, fn_id: hir::HirId, arguments: A, safety: Safety, @@ -616,6 +632,7 @@ fn construct_fn<'a, 'tcx, A>( return_ty: Ty<'tcx>, return_ty_span: Span, body: &'tcx hir::Body<'tcx>, + expr: &Expr<'_, 'tcx>, span_with_body: Span, ) -> Body<'tcx> where @@ -623,15 +640,13 @@ where { let arguments: Vec<_> = arguments.collect(); - let tcx = hir.tcx(); - let tcx_hir = tcx.hir(); - let span = tcx_hir.span(fn_id); - - let fn_def_id = tcx_hir.local_def_id(fn_id); + let tcx = infcx.tcx; + let span = tcx.hir().span(fn_id); let mut builder = Builder::new( - hir, - fn_def_id.to_def_id(), + infcx, + fn_def, + fn_id, span_with_body, arguments.len(), safety, @@ -655,16 +670,16 @@ where Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| { builder.args_and_body( START_BLOCK, - fn_def_id.to_def_id(), + fn_def.did.to_def_id(), &arguments, arg_scope, - &body.value, + expr, ) })) })); let source_info = builder.source_info(fn_end); builder.cfg.terminate(return_block, source_info, TerminatorKind::Return); - let should_abort = should_abort_on_panic(tcx, fn_def_id, abi); + let should_abort = should_abort_on_panic(tcx, fn_def.did, abi); builder.build_drop_trees(should_abort); return_block.unit() })); @@ -675,7 +690,7 @@ where } else { None }; - debug!("fn_id {:?} has attrs {:?}", fn_def_id, tcx.get_attrs(fn_def_id.to_def_id())); + debug!("fn_id {:?} has attrs {:?}", fn_def, tcx.get_attrs(fn_def.did.to_def_id())); let mut body = builder.finish(); body.spread_arg = spread_arg; @@ -683,22 +698,20 @@ where } fn construct_const<'a, 'tcx>( - hir: Cx<'a, 'tcx>, - body_id: hir::BodyId, + infcx: &'a InferCtxt<'a, 'tcx>, + expr: &Expr<'_, 'tcx>, + def: ty::WithOptConstParam, + hir_id: hir::HirId, const_ty: Ty<'tcx>, const_ty_span: Span, ) -> Body<'tcx> { - let tcx = hir.tcx(); - let owner_id = tcx.hir().body_owner(body_id); - let def_id = tcx.hir().local_def_id(owner_id); - let span = tcx.hir().span(owner_id); + let tcx = infcx.tcx; + let span = tcx.hir().span(hir_id); let mut builder = - Builder::new(hir, def_id.to_def_id(), span, 0, Safety::Safe, const_ty, const_ty_span, None); + Builder::new(infcx, def, hir_id, span, 0, Safety::Safe, const_ty, const_ty_span, 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)); + 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); @@ -712,15 +725,19 @@ fn construct_const<'a, 'tcx>( /// /// This is required because we may still want to run MIR passes on an item /// with type errors, but normal MIR construction can't handle that in general. -fn construct_error<'a, 'tcx>(hir: Cx<'a, 'tcx>, body_id: hir::BodyId) -> Body<'tcx> { - let tcx = hir.tcx(); - let owner_id = tcx.hir().body_owner(body_id); - let def_id = tcx.hir().local_def_id(owner_id); - let span = tcx.hir().span(owner_id); +fn construct_error<'a, 'tcx>( + infcx: &'a InferCtxt<'a, 'tcx>, + def: ty::WithOptConstParam, + hir_id: hir::HirId, + body_id: hir::BodyId, + body_owner_kind: hir::BodyOwnerKind, +) -> Body<'tcx> { + let tcx = infcx.tcx; + let span = tcx.hir().span(hir_id); let ty = tcx.ty_error(); let generator_kind = tcx.hir().body(body_id).generator_kind; - let num_params = match hir.body_owner_kind { - hir::BodyOwnerKind::Fn => tcx.hir().fn_decl_by_hir_id(owner_id).unwrap().inputs.len(), + let num_params = match body_owner_kind { + hir::BodyOwnerKind::Fn => tcx.hir().fn_decl_by_hir_id(hir_id).unwrap().inputs.len(), hir::BodyOwnerKind::Closure => { if generator_kind.is_some() { // Generators have an implicit `self` parameter *and* a possibly @@ -728,22 +745,14 @@ fn construct_error<'a, 'tcx>(hir: Cx<'a, 'tcx>, body_id: hir::BodyId) -> Body<'t 2 } else { // The implicit self parameter adds another local in MIR. - 1 + tcx.hir().fn_decl_by_hir_id(owner_id).unwrap().inputs.len() + 1 + tcx.hir().fn_decl_by_hir_id(hir_id).unwrap().inputs.len() } } hir::BodyOwnerKind::Const => 0, hir::BodyOwnerKind::Static(_) => 0, }; - let mut builder = Builder::new( - hir, - def_id.to_def_id(), - span, - num_params, - Safety::Safe, - ty, - span, - generator_kind, - ); + let mut builder = + Builder::new(infcx, def, hir_id, span, num_params, Safety::Safe, ty, span, generator_kind); let source_info = builder.source_info(span); // Some MIR passes will expect the number of parameters to match the // function declaration. @@ -758,8 +767,9 @@ fn construct_error<'a, 'tcx>(hir: Cx<'a, 'tcx>, body_id: hir::BodyId) -> Body<'t impl<'a, 'tcx> Builder<'a, 'tcx> { fn new( - hir: Cx<'a, 'tcx>, - def_id: DefId, + infcx: &'a InferCtxt<'a, 'tcx>, + def: ty::WithOptConstParam, + hir_id: hir::HirId, span: Span, arg_count: usize, safety: Safety, @@ -767,10 +777,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { return_span: Span, generator_kind: Option, ) -> Builder<'a, 'tcx> { - let lint_level = LintLevel::Explicit(hir.root_lint_level); + let tcx = infcx.tcx; + let attrs = tcx.hir().attrs(hir_id); + // Some functions always have overflow checks enabled, + // however, they may not get codegen'd, depending on + // the settings for the crate they are codegened in. + let mut check_overflow = tcx.sess.contains_name(attrs, sym::rustc_inherit_overflow_checks); + // Respect -C overflow-checks. + check_overflow |= tcx.sess.overflow_checks(); + // Constants always need overflow checks. + check_overflow |= matches!( + tcx.hir().body_owner_kind(hir_id), + hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) + ); + + let lint_level = LintLevel::Explicit(hir_id); let mut builder = Builder { - hir, - def_id, + tcx, + infcx, + typeck_results: tcx.typeck_opt_const_arg(def), + region_scope_tree: tcx.region_scope_tree(def.did), + param_env: tcx.param_env(def.did), + def_id: def.did.to_def_id(), + hir_id, + check_overflow, cfg: CFG { basic_blocks: IndexVec::new() }, fn_span: span, arg_count, @@ -826,7 +856,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn_def_id: DefId, arguments: &[ArgInfo<'tcx>], argument_scope: region::Scope, - ast_body: &'tcx hir::Expr<'tcx>, + expr: &Expr<'_, 'tcx>, ) -> BlockAnd<()> { // Allocate locals for the function arguments for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() { @@ -846,9 +876,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - let tcx = self.hir.tcx(); + let tcx = self.tcx; let tcx_hir = tcx.hir(); - let hir_typeck_results = self.hir.typeck_results(); + let hir_typeck_results = self.typeck_results; // In analyze_closure() in upvar.rs we gathered a list of upvars used by a // indexed closure and we stored in a map called closure_captures in TypeckResults @@ -924,14 +954,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Make sure we drop (parts of) the argument even when not matched on. self.schedule_drop( - arg_opt.as_ref().map_or(ast_body.span, |arg| arg.pat.span), + arg_opt.as_ref().map_or(expr.span, |arg| arg.pat.span), argument_scope, local, DropKind::Value, ); if let Some(arg) = arg_opt { - let pattern = self.hir.pattern_from_hir(&arg.pat); + let pat = match tcx.hir().get(arg.pat.hir_id) { + Node::Pat(pat) | Node::Binding(pat) => pat, + node => bug!("pattern became {:?}", node), + }; + let pattern = Pat::from_hir(tcx, self.param_env, self.typeck_results, pat); let original_source_scope = self.source_scope; let span = pattern.span; self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span); @@ -966,7 +1000,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ => { scope = self.declare_bindings( scope, - ast_body.span, + expr.span, &pattern, matches::ArmHasGuard(false), Some((Some(&place), span)), @@ -983,8 +1017,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.source_scope = source_scope; } - let body = self.hir.mirror(ast_body); - self.into(Place::return_place(), block, body) + self.expr_into_dest(Place::return_place(), block, &expr) } fn set_correct_source_scope_for_arg( @@ -993,15 +1026,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { original_source_scope: SourceScope, pattern_span: Span, ) { - let tcx = self.hir.tcx(); - let current_root = tcx.maybe_lint_level_root_bounded(arg_hir_id, self.hir.root_lint_level); + let tcx = self.tcx; + let current_root = tcx.maybe_lint_level_root_bounded(arg_hir_id, self.hir_id); let parent_root = tcx.maybe_lint_level_root_bounded( self.source_scopes[original_source_scope] .local_data .as_ref() .assert_crate_local() .lint_root, - self.hir.root_lint_level, + self.hir_id, ); if current_root != parent_root { self.source_scope = @@ -1013,7 +1046,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match self.unit_temp { Some(tmp) => tmp, None => { - let ty = self.hir.unit_ty(); + let ty = self.tcx.mk_unit(); let fn_span = self.fn_span; let tmp = self.temp(ty, fn_span); self.unit_temp = Some(tmp); @@ -1031,7 +1064,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mod block; mod cfg; mod expr; -mod into; mod matches; mod misc; mod scope; diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 5e9d780d179..b637b9b70bd 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -82,7 +82,7 @@ that contains only loops and breakable blocks. It tracks where a `break`, */ 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; @@ -516,7 +516,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { { debug!("in_scope(region_scope={:?})", region_scope); let source_scope = self.source_scope; - let tcx = self.hir.tcx(); + let tcx = self.tcx; if let LintLevel::Explicit(current_hir_id) = lint_level { // Use `maybe_lint_level_root_bounded` with `root_lint_level` as a bound // to avoid adding Hir dependences on our parents. @@ -524,10 +524,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let parent_root = tcx.maybe_lint_level_root_bounded( self.source_scopes[source_scope].local_data.as_ref().assert_crate_local().lint_root, - self.hir.root_lint_level, + self.hir_id, ); - let current_root = - tcx.maybe_lint_level_root_bounded(current_hir_id, self.hir.root_lint_level); + let current_root = tcx.maybe_lint_level_root_bounded(current_hir_id, self.hir_id); if parent_root != current_root { self.source_scope = self.new_source_scope( @@ -575,7 +574,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn break_scope( &mut self, mut block: BasicBlock, - value: Option>, + value: Option<&Expr<'_, 'tcx>>, target: BreakableTarget, source_info: SourceInfo, ) -> BlockAnd<()> { @@ -612,10 +611,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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()) + self.cfg.push_assign_unit(block, source_info, destination, self.tcx) } } else { assert!(value.is_none(), "`return` and `break` should have a destination"); @@ -763,7 +762,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ) { let needs_drop = match drop_kind { DropKind::Value => { - if !self.hir.needs_drop(self.local_decls[local].ty) { + if !self.local_decls[local].ty.needs_drop(self.tcx, self.param_env) { return; } true @@ -834,10 +833,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } if scope.region_scope == region_scope { - let region_scope_span = - region_scope.span(self.hir.tcx(), &self.hir.region_scope_tree); + let region_scope_span = region_scope.span(self.tcx, &self.region_scope_tree); // Attribute scope exit drops to scope's closing brace. - let scope_end = self.hir.tcx().sess.source_map().end_point(region_scope_span); + let scope_end = self.tcx.sess.source_map().end_point(region_scope_span); scope.drops.push(DropData { source_info: SourceInfo { span: scope_end, scope: scope.source_scope }, @@ -920,13 +918,13 @@ impl<'a, 'tcx> Builder<'a, '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)); let true_block = self.cfg.start_new_block(); let false_block = self.cfg.start_new_block(); - let term = TerminatorKind::if_(self.hir.tcx(), cond.clone(), true_block, false_block); + let term = TerminatorKind::if_(self.tcx, cond.clone(), true_block, false_block); self.cfg.terminate(block, source_info, term); match cond { diff --git a/compiler/rustc_mir_build/src/thir/arena.rs b/compiler/rustc_mir_build/src/thir/arena.rs new file mode 100644 index 00000000000..aacc7b12a42 --- /dev/null +++ b/compiler/rustc_mir_build/src/thir/arena.rs @@ -0,0 +1,98 @@ +use crate::thir::*; + +macro_rules! declare_arena { + ([], [$($a:tt $name:ident: $ty:ty,)*]) => { + #[derive(Default)] + pub struct Arena<'thir, 'tcx> { + pub dropless: rustc_arena::DroplessArena, + drop: rustc_arena::DropArena, + $($name: rustc_arena::arena_for_type!($a[$ty]),)* + } + + pub trait ArenaAllocatable<'thir, 'tcx, T = Self>: Sized { + fn allocate_on(self, arena: &'thir Arena<'thir, 'tcx>) -> &'thir mut Self; + fn allocate_from_iter( + arena: &'thir Arena<'thir, 'tcx>, + iter: impl ::std::iter::IntoIterator, + ) -> &'thir mut [Self]; + } + + impl<'thir, 'tcx, T: Copy> ArenaAllocatable<'thir, 'tcx, ()> for T { + #[inline] + fn allocate_on(self, arena: &'thir Arena<'thir, 'tcx>) -> &'thir mut Self { + arena.dropless.alloc(self) + } + #[inline] + fn allocate_from_iter( + arena: &'thir Arena<'thir, 'tcx>, + iter: impl ::std::iter::IntoIterator, + ) -> &'thir mut [Self] { + arena.dropless.alloc_from_iter(iter) + } + + } + $( + impl<'thir, 'tcx> ArenaAllocatable<'thir, 'tcx, $ty> for $ty { + #[inline] + fn allocate_on(self, arena: &'thir Arena<'thir, 'tcx>) -> &'thir mut Self { + if !::std::mem::needs_drop::() { + return arena.dropless.alloc(self); + } + match rustc_arena::which_arena_for_type!($a[&arena.$name]) { + ::std::option::Option::<&rustc_arena::TypedArena>::Some(ty_arena) => { + ty_arena.alloc(self) + } + ::std::option::Option::None => unsafe { arena.drop.alloc(self) }, + } + } + + #[inline] + fn allocate_from_iter( + arena: &'thir Arena<'thir, 'tcx>, + iter: impl ::std::iter::IntoIterator, + ) -> &'thir mut [Self] { + if !::std::mem::needs_drop::() { + return arena.dropless.alloc_from_iter(iter); + } + match rustc_arena::which_arena_for_type!($a[&arena.$name]) { + ::std::option::Option::<&rustc_arena::TypedArena>::Some(ty_arena) => { + ty_arena.alloc_from_iter(iter) + } + ::std::option::Option::None => unsafe { arena.drop.alloc_from_iter(iter) }, + } + } + } + )* + + impl<'thir, 'tcx> Arena<'thir, 'tcx> { + #[inline] + pub fn alloc, U>(&'thir self, value: T) -> &'thir mut T { + value.allocate_on(self) + } + + #[allow(dead_code)] // function is never used + #[inline] + pub fn alloc_slice(&'thir self, value: &[T]) -> &'thir mut [T] { + if value.is_empty() { + return &mut []; + } + self.dropless.alloc_slice(value) + } + + pub fn alloc_from_iter, U>( + &'thir self, + iter: impl ::std::iter::IntoIterator, + ) -> &'thir mut [T] { + T::allocate_from_iter(self, iter) + } + } + } +} + +declare_arena!([], [ + [] arm: Arm<'thir, 'tcx>, + [] expr: Expr<'thir, 'tcx>, + [] field_expr: FieldExpr<'thir, 'tcx>, + [few] inline_asm_operand: InlineAsmOperand<'thir, 'tcx>, + [] stmt: Stmt<'thir, 'tcx>, +]); diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index 980888df7fe..d450f8a265d 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -1,4 +1,3 @@ -use crate::thir::cx::to_ref::ToRef; use crate::thir::cx::Cx; use crate::thir::{self, *}; @@ -8,110 +7,95 @@ use rustc_middle::ty; 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<'thir, 'tcx> Cx<'thir, 'tcx> { + crate fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block<'thir, '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.map(|expr| self.mirror_expr(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> { - 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 { + fn mirror_stmts( + &mut self, + block_id: hir::ItemLocalId, + stmts: &'tcx [hir::Stmt<'tcx>], + ) -> &'thir [Stmt<'thir, 'tcx>] { + self.arena.alloc_from_iter(stmts.iter().enumerate().filter_map(|(index, stmt)| { + 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) => Some(Stmt { kind: StmtKind::Expr { scope: region::Scope { id: hir_id.local_id, data: region::ScopeData::Node }, - expr: expr.to_ref(), + expr: self.mirror_expr(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); - - 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, - }), - }; - } + }), + hir::StmtKind::Item(..) => { + // ignore for purposes of the MIR + None } + hir::StmtKind::Local(ref local) => { + let remainder_scope = region::Scope { + id: block_id, + data: region::ScopeData::Remainder(region::FirstStatementIndex::new(index)), + }; - 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, + let mut pattern = self.pattern_from_hir(local.pat); + + 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, + }), + }; + } + } + + Some(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(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 -} - -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() } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 620ce360e7d..dfcb52c83c0 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1,8 +1,7 @@ -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_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_index::vec::Idx; @@ -17,45 +16,71 @@ use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::{self, AdtKind, Ty}; use rustc_span::Span; -impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr<'tcx> { - type Output = Expr<'tcx>; +use std::iter; - 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 }; +impl<'thir, 'tcx> Cx<'thir, 'tcx> { + /// Mirrors and allocates a single [`hir::Expr`]. If you need to mirror a whole slice + /// of expressions, prefer using [`mirror_exprs`]. + /// + /// [`mirror_exprs`]: Self::mirror_exprs + crate fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> &'thir Expr<'thir, 'tcx> { + // `mirror_expr` is recursing very deep. Make sure the stack doesn't overflow. + ensure_sufficient_stack(|| self.arena.alloc(self.mirror_expr_inner(expr))) + } - debug!("Expr::make_mirror(): id={}, span={:?}", self.hir_id, self.span); + /// Mirrors and allocates a slice of [`hir::Expr`]s. They will be allocated as a + /// contiguous sequence in memory. + crate fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> &'thir [Expr<'thir, 'tcx>] { + self.arena.alloc_from_iter(exprs.iter().map(|expr| self.mirror_expr_inner(expr))) + } - let mut expr = make_mirror_unadjusted(cx, self); + /// Mirrors a [`hir::Expr`] without allocating it into the arena. + /// This is a separate, private function so that [`mirror_expr`] and [`mirror_exprs`] can + /// decide how to allocate this expression (alone or within a slice). + /// + /// [`mirror_expr`]: Self::mirror_expr + /// [`mirror_exprs`]: Self::mirror_exprs + pub(super) fn mirror_expr_inner( + &mut self, + hir_expr: &'tcx hir::Expr<'tcx>, + ) -> Expr<'thir, '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 }; + + debug!("Expr::make_mirror(): id={}, span={:?}", hir_expr.hir_id, hir_expr.span); + + 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: self.arena.alloc(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: self.arena.alloc(expr), lint_level: LintLevel::Inherited, }, }; @@ -64,364 +89,393 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr<'tcx> { // 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; + fn apply_adjustment( + &mut self, + hir_expr: &'tcx hir::Expr<'tcx>, + mut expr: Expr<'thir, 'tcx>, + adjustment: &Adjustment<'tcx>, + ) -> Expr<'thir, '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; + // 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<'thir, '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); + let kind = match adjustment.kind { + Adjust::Pointer(PointerCast::Unsize) => { + adjust_span(&mut expr); + ExprKind::Pointer { cast: PointerCast::Unsize, source: self.arena.alloc(expr) } + } + Adjust::Pointer(cast) => ExprKind::Pointer { cast, source: self.arena.alloc(expr) }, + Adjust::NeverToAny => ExprKind::NeverToAny { source: self.arena.alloc(expr) }, + Adjust::Deref(None) => { + adjust_span(&mut expr); + ExprKind::Deref { arg: self.arena.alloc(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); - 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(), - }, - }; - - 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() } - } - }; - - Expr { temp_lifetime, ty: adjustment.target, span, kind } -} - -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 } - } - - 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. - - // rewrite f(u, v) into FnOnce::call_once(f, (u, v)) - - let method = method_callee(cx, expr, fun.span, None); - - 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), + expr = Expr { temp_lifetime, - span: expr.span, - kind: ExprKind::Tuple { fields: args.iter().map(ToRef::to_ref).collect() }, + 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: self.arena.alloc(expr), + }, }; - ExprKind::Call { - ty: method.ty, - fun: method.to_ref(), - args: vec![fun.to_ref(), tupled_args.to_ref()], - 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 = 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); + self.overloaded_place( + hir_expr, + adjustment.target, + Some(call), + self.arena.alloc_from_iter(iter::once(expr)), + deref.span, + ) + } + Adjust::Borrow(AutoBorrow::Ref(_, m)) => { + ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), arg: self.arena.alloc(expr) } + } + Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => { + ExprKind::AddressOf { mutability, arg: self.arena.alloc(expr) } + } + }; + + Expr { temp_lifetime, ty: adjustment.target, span, kind } + } + + fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'thir, '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: expr.ty, + fun: self.arena.alloc(expr), + args, + from_hir_call: true, + fn_span, + } + } + + 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) }, + }; - 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: self.arena.alloc(method), + args: self + .arena + .alloc_from_iter(vec![self.mirror_expr_inner(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); - 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::Raw, mutability, ref arg) => { - ExprKind::AddressOf { mutability, arg: arg.to_ref() } - } - - hir::ExprKind::Block(ref blk, _) => ExprKind::Block { body: &blk }, - - hir::ExprKind::Assign(ref lhs, ref rhs, _) => { - ExprKind::Assign { lhs: lhs.to_ref(), rhs: rhs.to_ref() } - } - - 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::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(), - }, - - _ => { - let op = bin_op(op.node); - ExprKind::Binary { op, lhs: lhs.to_ref(), rhs: rhs.to_ref() } + let field_refs = + self.arena.alloc_from_iter(args.iter().enumerate().map(|(idx, e)| { + FieldExpr { name: Field::new(idx), expr: self.mirror_expr(e) } + })); + 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(fun), + args: self.mirror_exprs(args), + from_hir_call: true, + fn_span: expr.span, + } } } } - } - 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::AddrOf(hir::BorrowKind::Ref, mutbl, ref arg) => { + ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg: self.mirror_expr(arg) } } - } - 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::AddrOf(hir::BorrowKind::Raw, mutability, ref arg) => { + ExprKind::AddressOf { mutability, arg: self.mirror_expr(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::Block(ref blk, _) => ExprKind::Block { body: self.mirror_block(blk) }, + + hir::ExprKind::Assign(ref lhs, ref rhs, _) => { + ExprKind::Assign { lhs: self.mirror_expr(lhs), rhs: self.mirror_expr(rhs) } } - } - 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, - } - } 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::AssignOp(op, ref lhs, ref rhs) => { + if self.typeck_results().is_method_call(expr) { + let lhs = self.mirror_expr_inner(lhs); + let rhs = self.mirror_expr_inner(rhs); + self.overloaded_operator(expr, self.arena.alloc_from_iter(vec![lhs, rhs])) + } else { + ExprKind::AssignOp { + op: bin_op(op.node), + lhs: self.mirror_expr(lhs), + rhs: self.mirror_expr(rhs), } } - 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, + 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, + }, + + hir::ExprKind::Binary(op, ref lhs, ref rhs) => { + if self.typeck_results().is_method_call(expr) { + let lhs = self.mirror_expr_inner(lhs); + let rhs = self.mirror_expr_inner(rhs); + self.overloaded_operator(expr, self.arena.alloc_from_iter(vec![lhs, rhs])) + } else { + // FIXME overflow + match op.node { + hir::BinOpKind::And => ExprKind::LogicalOp { + op: LogicalOp::And, + lhs: self.mirror_expr(lhs), + rhs: self.mirror_expr(rhs), + }, + hir::BinOpKind::Or => ExprKind::LogicalOp { + op: LogicalOp::Or, + lhs: self.mirror_expr(lhs), + rhs: self.mirror_expr(rhs), + }, + + _ => { + let op = bin_op(op.node); + ExprKind::Binary { + op, + lhs: self.mirror_expr(lhs), + rhs: self.mirror_expr(rhs), } } - _ => { - 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)) + hir::ExprKind::Index(ref lhs, ref index) => { + if self.typeck_results().is_method_call(expr) { + let lhs = self.mirror_expr_inner(lhs); + let index = self.mirror_expr_inner(index); + self.overloaded_place( + expr, + expr_ty, + None, + self.arena.alloc_from_iter(vec![lhs, index]), + expr.span, + ) + } else { + ExprKind::Index { lhs: self.mirror_expr(lhs), index: self.mirror_expr(index) } } + } + + hir::ExprKind::Unary(hir::UnOp::Deref, ref arg) => { + if self.typeck_results().is_method_call(expr) { + let arg = self.mirror_expr_inner(arg); + self.overloaded_place( + expr, + expr_ty, + None, + self.arena.alloc_from_iter(iter::once(arg)), + expr.span, + ) + } else { + ExprKind::Deref { arg: self.mirror_expr(arg) } + } + } + + hir::ExprKind::Unary(hir::UnOp::Not, ref arg) => { + if self.typeck_results().is_method_call(expr) { + let arg = self.mirror_expr_inner(arg); + self.overloaded_operator(expr, self.arena.alloc_from_iter(iter::once(arg))) + } else { + ExprKind::Unary { op: UnOp::Not, arg: self.mirror_expr(arg) } + } + } + + hir::ExprKind::Unary(hir::UnOp::Neg, ref arg) => { + if self.typeck_results().is_method_call(expr) { + let arg = self.mirror_expr_inner(arg); + self.overloaded_operator(expr, self.arena.alloc_from_iter(iter::once(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(arg) } + } + } + + 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(base), + field_types: self.arena.alloc_from_iter( + self.typeck_results().fru_field_types()[expr.hir_id] + .iter() + .cloned(), + ), + }), + } + } + 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, "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.arena.alloc_from_iter( + self.typeck_results + .closure_min_captures_flattened(def_id) + .zip(substs.upvar_tys()) + .map(|(captured_place, ty)| self.capture_upvar(expr, captured_place, ty)), + ); + 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)| { + 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: self.arena.alloc_from_iter(asm.operands.iter().map(|(op, _op_sp)| { match *op { hir::InlineAsmOperand::In { reg, ref expr } => { - InlineAsmOperand::In { reg, expr: expr.to_ref() } + 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| expr.to_ref()), + expr: expr.as_ref().map(|expr| self.mirror_expr(expr)), } } hir::InlineAsmOperand::InOut { reg, late, ref expr } => { - InlineAsmOperand::InOut { reg, late, expr: expr.to_ref() } + InlineAsmOperand::InOut { reg, late, expr: self.mirror_expr(expr) } } hir::InlineAsmOperand::SplitInOut { reg, @@ -431,11 +485,11 @@ fn make_mirror_unadjusted<'a, 'tcx>( } => InlineAsmOperand::SplitInOut { reg, late, - in_expr: in_expr.to_ref(), - out_expr: out_expr.as_ref().map(|expr| expr.to_ref()), + 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: expr.to_ref() } + InlineAsmOperand::Const { expr: self.mirror_expr(expr) } } hir::InlineAsmOperand::Sym { ref expr } => { let qpath = match expr.kind { @@ -447,25 +501,24 @@ fn make_mirror_unadjusted<'a, 'tcx>( ), }; 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); + 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 = cx.typeck_results().node_type(expr.hir_id); - let user_ty = user_substs_applied_to_res(cx, expr.hir_id, res); + 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 { + expr: self.arena.alloc(Expr { ty, temp_lifetime, span: expr.span, kind: ExprKind::Literal { - literal: ty::Const::zero_sized(cx.tcx, ty), + literal: ty::Const::zero_sized(self.tcx, ty), user_ty, const_id: None, }, - } - .to_ref(), + }), } } @@ -474,277 +527,568 @@ fn make_mirror_unadjusted<'a, 'tcx>( } _ => { - cx.tcx.sess.span_err( + 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 = cx.tcx.ty_error(); + ty = self.tcx.ty_error(); InlineAsmOperand::SymFn { - expr: Expr { + expr: self.arena.alloc(Expr { ty, temp_lifetime, span: expr.span, kind: ExprKind::Literal { - literal: ty::Const::zero_sized(cx.tcx, ty), + 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); - - 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(), + })), + options: asm.options, + line_spans: asm.line_spans, }, - 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::LlvmInlineAsm(ref asm) => ExprKind::LlvmInlineAsm { + asm: &asm.inner, + outputs: self.mirror_exprs(asm.outputs_exprs), + inputs: self.mirror_exprs(asm.inputs_exprs), }, - 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, - ); + 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); - // 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, - } - }) - } else { - None - }; + 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); - 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 }, - } - .to_ref() - }; - 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, + ExprKind::Repeat { value: self.mirror_expr(v), count } + } + hir::ExprKind::Ret(ref v) => { + ExprKind::Return { value: v.as_ref().map(|v| self.mirror_expr(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(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), + }, + hir::ExprKind::If(cond, then, else_opt) => ExprKind::If { + cond: self.mirror_expr(cond), + then: self.mirror_expr(then), + else_opt: else_opt.map(|el| self.mirror_expr(el)), + }, + hir::ExprKind::Match(ref discr, ref arms, _) => ExprKind::Match { + scrutinee: self.mirror_expr(discr), + arms: self.arena.alloc_from_iter(arms.iter().map(|a| self.convert_arm(a))), + }, + 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 = self.arena.alloc(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(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(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(source), + cast: PointerCast::ArrayToPointer, } } else { - source.to_ref() + // 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| { + self.arena.alloc(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: lhs, rhs: offset }; + self.arena.alloc(Expr { + temp_lifetime, + ty: var_ty, + span: expr.span, + kind: bin, + }) + } + None => offset, + } + } else { + self.mirror_expr(source) + }; + + ExprKind::Cast { source: source } }; - ExprKind::Cast { 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 = self.arena.alloc(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, user_ty: Some(*user_ty) } + } else { + cast + } + } + 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(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(source) } + } + hir::ExprKind::Box(ref value) => ExprKind::Box { value: self.mirror_expr(value) }, + hir::ExprKind::Array(ref fields) => { + ExprKind::Array { fields: self.mirror_exprs(fields) } + } + hir::ExprKind::Tup(ref fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) }, + + hir::ExprKind::Yield(ref v, _) => ExprKind::Yield { value: self.mirror_expr(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> { + 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<'thir, '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<'thir, '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(e)), + hir::Guard::IfLet(ref pat, ref e) => { + Guard::IfLet(self.pattern_from_hir(pat), self.mirror_expr(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, + } + } + + fn convert_path_expr( + &mut self, + expr: &'tcx hir::Expr<'tcx>, + res: Res, + ) -> ExprKind<'thir, '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, + } + } + + 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: self.arena.alloc_from_iter(iter::empty()), + 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: self.arena.alloc(Expr { ty, temp_lifetime, span: expr.span, kind }), + } + } + + Res::Local(var_hir_id) => self.convert_var(var_hir_id), + + _ => span_bug!(expr.span, "res `{:?}` not yet implemented", res), + } + } + + fn convert_var(&mut self, var_hir_id: hir::HirId) -> ExprKind<'thir, '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 } + } + } + + fn overloaded_operator( + &mut self, + expr: &'tcx hir::Expr<'tcx>, + args: &'thir [Expr<'thir, 'tcx>], + ) -> ExprKind<'thir, 'tcx> { + let fun = self.arena.alloc(self.method_callee(expr, expr.span, None)); + ExprKind::Call { ty: fun.ty, fun, args, from_hir_call: false, fn_span: expr.span } + } + + fn overloaded_place( + &mut self, + expr: &'tcx hir::Expr<'tcx>, + place_ty: Ty<'tcx>, + overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>, + args: &'thir [Expr<'thir, 'tcx>], + span: Span, + ) -> ExprKind<'thir, '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 = self.arena.alloc(self.method_callee(expr, span, overloaded_callee)); + let ref_expr = self.arena.alloc(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: &'tcx ty::CapturedPlace<'tcx>, + upvar_ty: Ty<'tcx>, + ) -> Expr<'thir, '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: self.arena.alloc(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: self.arena.alloc(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; + } }; - 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); + captured_place_expr = + Expr { temp_lifetime, ty: proj.ty, span: closure_expr.span, kind }; + } - ExprKind::ValueTypeAscription { - source: cast_expr.to_ref(), - user_ty: Some(*user_ty), + 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: self.arena.alloc(captured_place_expr), + }, } - } 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::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!(), - }; - - Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind } -} - -fn user_substs_applied_to_res<'tcx>( - cx: &mut Cx<'_, 'tcx>, - hir_id: hir::HirId, - res: Res, -) -> Option> { - 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() - } - - // 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) - } - - // `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), - - _ => 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<'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) - } - }; - 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>]) -> &'thir [FieldExpr<'thir, 'tcx>] { + self.arena.alloc_from_iter(fields.iter().map(|field| FieldExpr { + name: Field::new(self.tcx.field_index(field.hir_id, self.typeck_results)), + expr: self.mirror_expr(field.expr), + })) } } @@ -776,135 +1120,6 @@ impl ToBorrowKind for hir::Mutability { } } -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, @@ -926,139 +1141,3 @@ fn bin_op(op: hir::BinOpKind) -> BinOp { _ => bug!("no equivalent for ast binop {:?}", op), } } - -fn overloaded_operator<'a, 'tcx>( - cx: &mut Cx<'a, 'tcx>, - expr: &'tcx hir::Expr<'tcx>, - args: Vec>, -) -> 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>, - 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> { - fields - .iter() - .map(|field| FieldExprRef { - name: Field::new(cx.tcx.field_index(field.hir_id, cx.typeck_results)), - expr: field.expr.to_ref(), - }) - .collect() -} diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 465808cea9d..66c11ea9528 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -2,6 +2,7 @@ //! structures into the THIR. The `builder` is generally ignorant of the tcx, //! etc., and instead goes through the `Cx` for most of its work. +use crate::thir::arena::Arena; use crate::thir::util::UserAnnotatedTyHelpers; use crate::thir::*; @@ -9,118 +10,48 @@ use rustc_ast as ast; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::Node; -use rustc_index::vec::Idx; -use rustc_infer::infer::InferCtxt; use rustc_middle::middle::region; use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; -use rustc_middle::ty::subst::Subst; -use rustc_middle::ty::subst::{GenericArg, InternalSubsts}; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::symbol::{sym, Symbol}; -use rustc_target::abi::VariantIdx; -use rustc_trait_selection::infer::InferCtxtExt; -#[derive(Clone)] -crate struct Cx<'a, 'tcx> { +crate fn build_thir<'thir, 'tcx>( tcx: TyCtxt<'tcx>, - infcx: &'a InferCtxt<'a, 'tcx>, + owner_def: ty::WithOptConstParam, + arena: &'thir Arena<'thir, 'tcx>, + expr: &'tcx hir::Expr<'tcx>, +) -> &'thir Expr<'thir, 'tcx> { + Cx::new(tcx, owner_def, &arena).mirror_expr(expr) +} + +struct Cx<'thir, 'tcx> { + tcx: TyCtxt<'tcx>, + arena: &'thir Arena<'thir, 'tcx>, - crate root_lint_level: hir::HirId, crate param_env: ty::ParamEnv<'tcx>, - /// Identity `InternalSubsts` for use with const-evaluation. - crate identity_substs: &'tcx InternalSubsts<'tcx>, - crate region_scope_tree: &'tcx region::ScopeTree, - crate typeck_results: &'a ty::TypeckResults<'tcx>, - - /// This is `Constness::Const` if we are compiling a `static`, - /// `const`, or the body of a `const fn`. - constness: hir::Constness, + crate typeck_results: &'tcx ty::TypeckResults<'tcx>, /// The `DefId` of the owner of this body. body_owner: DefId, - - /// What kind of body is being compiled. - crate body_owner_kind: hir::BodyOwnerKind, - - /// Whether this constant/function needs overflow checks. - check_overflow: bool, } -impl<'a, 'tcx> Cx<'a, 'tcx> { - crate fn new( - infcx: &'a InferCtxt<'a, 'tcx>, +impl<'thir, 'tcx> Cx<'thir, 'tcx> { + fn new( + tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam, - src_id: hir::HirId, - ) -> Cx<'a, 'tcx> { - let tcx = infcx.tcx; + arena: &'thir Arena<'thir, 'tcx>, + ) -> Cx<'thir, 'tcx> { let typeck_results = tcx.typeck_opt_const_arg(def); - let body_owner_kind = tcx.hir().body_owner_kind(src_id); - - let constness = match body_owner_kind { - hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => hir::Constness::Const, - hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => hir::Constness::NotConst, - }; - - let attrs = tcx.hir().attrs(src_id); - - // Some functions always have overflow checks enabled, - // however, they may not get codegen'd, depending on - // the settings for the crate they are codegened in. - let mut check_overflow = tcx.sess.contains_name(attrs, sym::rustc_inherit_overflow_checks); - - // Respect -C overflow-checks. - check_overflow |= tcx.sess.overflow_checks(); - - // Constants always need overflow checks. - check_overflow |= constness == hir::Constness::Const; - Cx { tcx, - infcx, - root_lint_level: src_id, + arena, param_env: tcx.param_env(def.did), - identity_substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), region_scope_tree: tcx.region_scope_tree(def.did), typeck_results, - constness, body_owner: def.did.to_def_id(), - body_owner_kind, - check_overflow, } } -} - -impl<'a, 'tcx> Cx<'a, 'tcx> { - /// Normalizes `ast` into the appropriate "mirror" type. - crate fn mirror>(&mut self, ast: M) -> M::Output { - ast.make_mirror(self) - } - - crate fn usize_ty(&mut self) -> Ty<'tcx> { - self.tcx.types.usize - } - - crate fn usize_literal(&mut self, value: u64) -> &'tcx ty::Const<'tcx> { - ty::Const::from_usize(self.tcx, value) - } - - crate fn bool_ty(&mut self) -> Ty<'tcx> { - self.tcx.types.bool - } - - crate fn unit_ty(&mut self) -> Ty<'tcx> { - self.tcx.mk_unit() - } - - crate fn true_literal(&mut self) -> &'tcx ty::Const<'tcx> { - ty::Const::from_bool(self.tcx, true) - } - - crate fn false_literal(&mut self) -> &'tcx ty::Const<'tcx> { - ty::Const::from_bool(self.tcx, false) - } crate fn const_eval_literal( &mut self, @@ -154,69 +85,17 @@ impl<'a, 'tcx> Cx<'a, 'tcx> { }; Pat::from_hir(self.tcx, self.param_env, self.typeck_results(), p) } - - crate fn trait_method( - &mut self, - trait_def_id: DefId, - method_name: Symbol, - self_ty: Ty<'tcx>, - params: &[GenericArg<'tcx>], - ) -> &'tcx ty::Const<'tcx> { - let substs = self.tcx.mk_substs_trait(self_ty, params); - - // The unhygienic comparison here is acceptable because this is only - // used on known traits. - let item = self - .tcx - .associated_items(trait_def_id) - .filter_by_name_unhygienic(method_name) - .find(|item| item.kind == ty::AssocKind::Fn) - .expect("trait method not found"); - - let method_ty = self.tcx.type_of(item.def_id); - let method_ty = method_ty.subst(self.tcx, substs); - ty::Const::zero_sized(self.tcx, method_ty) - } - - crate fn all_fields(&mut self, adt_def: &ty::AdtDef, variant_index: VariantIdx) -> Vec { - (0..adt_def.variants[variant_index].fields.len()).map(Field::new).collect() - } - - crate fn needs_drop(&mut self, ty: Ty<'tcx>) -> bool { - ty.needs_drop(self.tcx, self.param_env) - } - - crate fn infcx(&self) -> &'a InferCtxt<'a, 'tcx> { - self.infcx - } - - crate fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - crate fn typeck_results(&self) -> &'a ty::TypeckResults<'tcx> { - self.typeck_results - } - - crate fn check_overflow(&self) -> bool { - self.check_overflow - } - - crate fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>, span: Span) -> bool { - self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) - } } impl<'tcx> UserAnnotatedTyHelpers<'tcx> for Cx<'_, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx() + self.tcx } fn typeck_results(&self) -> &ty::TypeckResults<'tcx> { - self.typeck_results() + self.typeck_results } } mod block; mod expr; -mod to_ref; diff --git a/compiler/rustc_mir_build/src/thir/cx/to_ref.rs b/compiler/rustc_mir_build/src/thir/cx/to_ref.rs deleted file mode 100644 index 53a988ebb79..00000000000 --- a/compiler/rustc_mir_build/src/thir/cx/to_ref.rs +++ /dev/null @@ -1,65 +0,0 @@ -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 -where - &'tcx T: ToRef, -{ - type Output = Option; - - fn to_ref(self) -> Option { - self.as_ref().map(|expr| expr.to_ref()) - } -} - -impl<'tcx, T, U> ToRef for &'tcx Vec -where - &'tcx T: ToRef, -{ - type Output = Vec; - - fn to_ref(self) -> Vec { - self.iter().map(|expr| expr.to_ref()).collect() - } -} - -impl<'tcx, T, U> ToRef for &'tcx [T] -where - &'tcx T: ToRef, -{ - type Output = Vec; - - fn to_ref(self) -> Vec { - self.iter().map(|expr| expr.to_ref()).collect() - } -} diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs index ce0098fdf86..27a7e99951c 100644 --- a/compiler/rustc_mir_build/src/thir/mod.rs +++ b/compiler/rustc_mir_build/src/thir/mod.rs @@ -4,7 +4,6 @@ //! 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; @@ -25,6 +24,9 @@ crate mod pattern; crate use self::pattern::PatTyProj; crate use self::pattern::{BindingMode, FieldPat, Pat, PatKind, PatRange}; +mod arena; +crate use arena::Arena; + mod util; #[derive(Copy, Clone, Debug)] @@ -33,14 +35,14 @@ crate enum LintLevel { Explicit(hir::HirId), } -#[derive(Clone, Debug)] -crate struct Block<'tcx> { +#[derive(Debug)] +crate struct Block<'thir, 'tcx> { crate targeted_by_break: bool, crate region_scope: region::Scope, crate opt_destruction_scope: Option, crate span: Span, - crate stmts: Vec>, - crate expr: Option>, + crate stmts: &'thir [Stmt<'thir, 'tcx>], + crate expr: Option<&'thir Expr<'thir, 'tcx>>, crate safety_mode: BlockSafety, } @@ -52,25 +54,20 @@ crate enum BlockSafety { PopUnsafe, } -#[derive(Clone, Debug)] -crate enum StmtRef<'tcx> { - Mirror(Box>), -} - -#[derive(Clone, Debug)] -crate struct Stmt<'tcx> { - crate kind: StmtKind<'tcx>, +#[derive(Debug)] +crate struct Stmt<'thir, 'tcx> { + crate kind: StmtKind<'thir, 'tcx>, crate opt_destruction_scope: Option, } -#[derive(Clone, Debug)] -crate enum StmtKind<'tcx> { +#[derive(Debug)] +crate enum StmtKind<'thir, 'tcx> { Expr { /// scope for this statement; may be used as lifetime of temporaries scope: region::Scope, /// expression being evaluated in this statement - expr: ExprRef<'tcx>, + expr: &'thir Expr<'thir, 'tcx>, }, Let { @@ -88,7 +85,7 @@ crate enum StmtKind<'tcx> { pattern: Pat<'tcx>, /// let pat: ty = ... - initializer: Option>, + initializer: Option<&'thir Expr<'thir, 'tcx>>, /// the lint level for this let-statement lint_level: LintLevel, @@ -97,12 +94,12 @@ crate enum StmtKind<'tcx> { // `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<'_, '_>, 144); /// 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 `&'thir Expr<'thir, '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 @@ -113,8 +110,8 @@ rustc_data_structures::static_assert_size!(Expr<'_>, 168); /// MIR simplifications are already done in the impl of `Thir`. For /// example, method calls and overloaded operators are absent: they are /// expected to be converted into `Expr::Call` instances. -#[derive(Clone, Debug)] -crate struct Expr<'tcx> { +#[derive(Debug)] +crate struct Expr<'thir, 'tcx> { /// type of this expression crate ty: Ty<'tcx>, @@ -126,92 +123,92 @@ crate struct Expr<'tcx> { crate span: Span, /// kind of expression - crate kind: ExprKind<'tcx>, + crate kind: ExprKind<'thir, 'tcx>, } -#[derive(Clone, Debug)] -crate enum ExprKind<'tcx> { +#[derive(Debug)] +crate enum ExprKind<'thir, 'tcx> { Scope { region_scope: region::Scope, lint_level: LintLevel, - value: ExprRef<'tcx>, + value: &'thir Expr<'thir, 'tcx>, }, Box { - value: ExprRef<'tcx>, + value: &'thir Expr<'thir, 'tcx>, }, If { - cond: ExprRef<'tcx>, - then: ExprRef<'tcx>, - else_opt: Option>, + cond: &'thir Expr<'thir, 'tcx>, + then: &'thir Expr<'thir, 'tcx>, + else_opt: Option<&'thir Expr<'thir, 'tcx>>, }, Call { ty: Ty<'tcx>, - fun: ExprRef<'tcx>, - args: Vec>, - // Whether this is from a call in HIR, rather than from an overloaded - // operator. True for overloaded function call. + fun: &'thir Expr<'thir, 'tcx>, + args: &'thir [Expr<'thir, '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: &'thir Expr<'thir, 'tcx>, }, // NOT overloaded! Binary { op: BinOp, - lhs: ExprRef<'tcx>, - rhs: ExprRef<'tcx>, + lhs: &'thir Expr<'thir, 'tcx>, + rhs: &'thir Expr<'thir, 'tcx>, }, // NOT overloaded! LogicalOp { op: LogicalOp, - lhs: ExprRef<'tcx>, - rhs: ExprRef<'tcx>, + lhs: &'thir Expr<'thir, 'tcx>, + rhs: &'thir Expr<'thir, 'tcx>, }, // NOT overloaded! // LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands. Unary { op: UnOp, - arg: ExprRef<'tcx>, + arg: &'thir Expr<'thir, 'tcx>, }, // NOT overloaded! Cast { - source: ExprRef<'tcx>, + source: &'thir Expr<'thir, 'tcx>, }, Use { - source: ExprRef<'tcx>, + source: &'thir Expr<'thir, 'tcx>, }, // Use a lexpr to get a vexpr. NeverToAny { - source: ExprRef<'tcx>, + source: &'thir Expr<'thir, 'tcx>, }, Pointer { cast: PointerCast, - source: ExprRef<'tcx>, + source: &'thir Expr<'thir, 'tcx>, }, Loop { - body: ExprRef<'tcx>, + body: &'thir Expr<'thir, 'tcx>, }, Match { - scrutinee: ExprRef<'tcx>, - arms: Vec>, + scrutinee: &'thir Expr<'thir, 'tcx>, + arms: &'thir [Arm<'thir, 'tcx>], }, Block { - body: &'tcx hir::Block<'tcx>, + body: Block<'thir, 'tcx>, }, Assign { - lhs: ExprRef<'tcx>, - rhs: ExprRef<'tcx>, + lhs: &'thir Expr<'thir, 'tcx>, + rhs: &'thir Expr<'thir, 'tcx>, }, AssignOp { op: BinOp, - lhs: ExprRef<'tcx>, - rhs: ExprRef<'tcx>, + lhs: &'thir Expr<'thir, 'tcx>, + rhs: &'thir Expr<'thir, 'tcx>, }, Field { - lhs: ExprRef<'tcx>, + lhs: &'thir Expr<'thir, 'tcx>, name: Field, }, Index { - lhs: ExprRef<'tcx>, - index: ExprRef<'tcx>, + lhs: &'thir Expr<'thir, 'tcx>, + index: &'thir Expr<'thir, 'tcx>, }, VarRef { id: hir::HirId, @@ -226,35 +223,35 @@ crate enum ExprKind<'tcx> { }, Borrow { borrow_kind: BorrowKind, - arg: ExprRef<'tcx>, + arg: &'thir Expr<'thir, 'tcx>, }, /// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`. AddressOf { mutability: hir::Mutability, - arg: ExprRef<'tcx>, + arg: &'thir Expr<'thir, 'tcx>, }, Break { label: region::Scope, - value: Option>, + value: Option<&'thir Expr<'thir, 'tcx>>, }, Continue { label: region::Scope, }, Return { - value: Option>, + value: Option<&'thir Expr<'thir, 'tcx>>, }, ConstBlock { value: &'tcx Const<'tcx>, }, Repeat { - value: ExprRef<'tcx>, + value: &'thir Expr<'thir, 'tcx>, count: &'tcx Const<'tcx>, }, Array { - fields: Vec>, + fields: &'thir [Expr<'thir, 'tcx>], }, Tuple { - fields: Vec>, + fields: &'thir [Expr<'thir, 'tcx>], }, Adt { adt_def: &'tcx AdtDef, @@ -265,23 +262,23 @@ crate enum ExprKind<'tcx> { /// Bar:: { ... }`. user_ty: Option>>, - fields: Vec>, - base: Option>, + fields: &'thir [FieldExpr<'thir, 'tcx>], + base: Option>, }, PlaceTypeAscription { - source: ExprRef<'tcx>, + source: &'thir Expr<'thir, 'tcx>, /// Type that the user gave to this expression user_ty: Option>>, }, ValueTypeAscription { - source: ExprRef<'tcx>, + source: &'thir Expr<'thir, 'tcx>, /// Type that the user gave to this expression user_ty: Option>>, }, Closure { closure_id: DefId, substs: UpvarSubsts<'tcx>, - upvars: Vec>, + upvars: &'thir [Expr<'thir, 'tcx>], movability: Option, }, Literal { @@ -302,7 +299,7 @@ crate enum ExprKind<'tcx> { }, InlineAsm { template: &'tcx [InlineAsmTemplatePiece], - operands: Vec>, + operands: &'thir [InlineAsmOperand<'thir, 'tcx>], options: InlineAsmOptions, line_spans: &'tcx [Span], }, @@ -310,46 +307,40 @@ crate enum ExprKind<'tcx> { ThreadLocalRef(DefId), LlvmInlineAsm { asm: &'tcx hir::LlvmInlineAsmInner, - outputs: Vec>, - inputs: Vec>, + outputs: &'thir [Expr<'thir, 'tcx>], + inputs: &'thir [Expr<'thir, 'tcx>], }, Yield { - value: ExprRef<'tcx>, + value: &'thir Expr<'thir, 'tcx>, }, } -#[derive(Clone, Debug)] -crate enum ExprRef<'tcx> { - Thir(&'tcx hir::Expr<'tcx>), - Mirror(Box>), -} - -#[derive(Clone, Debug)] -crate struct FieldExprRef<'tcx> { +#[derive(Debug)] +crate struct FieldExpr<'thir, 'tcx> { crate name: Field, - crate expr: ExprRef<'tcx>, + crate expr: &'thir Expr<'thir, 'tcx>, } -#[derive(Clone, Debug)] -crate struct FruInfo<'tcx> { - crate base: ExprRef<'tcx>, - crate field_types: Vec>, +#[derive(Debug)] +crate struct FruInfo<'thir, 'tcx> { + crate base: &'thir Expr<'thir, 'tcx>, + crate field_types: &'thir [Ty<'tcx>], } -#[derive(Clone, Debug)] -crate struct Arm<'tcx> { +#[derive(Debug)] +crate struct Arm<'thir, 'tcx> { crate pattern: Pat<'tcx>, - crate guard: Option>, - crate body: ExprRef<'tcx>, + crate guard: Option>, + crate body: &'thir Expr<'thir, '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>), +#[derive(Debug)] +crate enum Guard<'thir, 'tcx> { + If(&'thir Expr<'thir, 'tcx>), + IfLet(Pat<'tcx>, &'thir Expr<'thir, 'tcx>), } #[derive(Copy, Clone, Debug)] @@ -358,110 +349,35 @@ crate enum LogicalOp { 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> { +#[derive(Debug)] +crate enum InlineAsmOperand<'thir, 'tcx> { In { reg: InlineAsmRegOrRegClass, - expr: ExprRef<'tcx>, + expr: &'thir Expr<'thir, 'tcx>, }, Out { reg: InlineAsmRegOrRegClass, late: bool, - expr: Option>, + expr: Option<&'thir Expr<'thir, 'tcx>>, }, InOut { reg: InlineAsmRegOrRegClass, late: bool, - expr: ExprRef<'tcx>, + expr: &'thir Expr<'thir, 'tcx>, }, SplitInOut { reg: InlineAsmRegOrRegClass, late: bool, - in_expr: ExprRef<'tcx>, - out_expr: Option>, + in_expr: &'thir Expr<'thir, 'tcx>, + out_expr: Option<&'thir Expr<'thir, 'tcx>>, }, Const { - expr: ExprRef<'tcx>, + expr: &'thir Expr<'thir, 'tcx>, }, SymFn { - expr: ExprRef<'tcx>, + expr: &'thir Expr<'thir, '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 - } -}