Store blocks in Thir.

Like expressions, statements, and match arms. This shrinks `thir::Stmt`
and is a precursor to further shrinking `thir::Expr`.
This commit is contained in:
Nicholas Nethercote 2022-08-24 12:02:17 +10:00
parent e7c25c3a97
commit 2df805fc7a
11 changed files with 66 additions and 47 deletions

View file

@ -75,6 +75,7 @@ macro_rules! thir_with_elements {
thir_with_elements! { thir_with_elements! {
arms: ArmId => Arm<'tcx> => "a{}", arms: ArmId => Arm<'tcx> => "a{}",
blocks: BlockId => Block => "b{}",
exprs: ExprId => Expr<'tcx> => "e{}", exprs: ExprId => Expr<'tcx> => "e{}",
stmts: StmtId => Stmt<'tcx> => "s{}", stmts: StmtId => Stmt<'tcx> => "s{}",
} }
@ -168,7 +169,7 @@ pub enum StmtKind<'tcx> {
initializer: Option<ExprId>, initializer: Option<ExprId>,
/// `let pat: ty = <INIT> else { <ELSE> } /// `let pat: ty = <INIT> else { <ELSE> }
else_block: Option<Block>, else_block: Option<BlockId>,
/// The lint level for this `let` statement. /// The lint level for this `let` statement.
lint_level: LintLevel, lint_level: LintLevel,
@ -292,7 +293,7 @@ pub enum ExprKind<'tcx> {
}, },
/// A block. /// A block.
Block { Block {
body: Block, block: BlockId,
}, },
/// An assignment: `lhs = rhs`. /// An assignment: `lhs = rhs`.
Assign { Assign {
@ -802,5 +803,5 @@ mod size_asserts {
static_assert_size!(Block, 56); static_assert_size!(Block, 56);
static_assert_size!(Expr<'_>, 88); static_assert_size!(Expr<'_>, 88);
static_assert_size!(Pat<'_>, 24); static_assert_size!(Pat<'_>, 24);
static_assert_size!(Stmt<'_>, 120); static_assert_size!(Stmt<'_>, 72);
} }

View file

@ -75,7 +75,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
visitor.visit_arm(&visitor.thir()[arm]); visitor.visit_arm(&visitor.thir()[arm]);
} }
} }
Block { ref body } => visitor.visit_block(body), Block { block } => visitor.visit_block(&visitor.thir()[block]),
Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => { Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => {
visitor.visit_expr(&visitor.thir()[lhs]); visitor.visit_expr(&visitor.thir()[lhs]);
visitor.visit_expr(&visitor.thir()[rhs]); visitor.visit_expr(&visitor.thir()[rhs]);
@ -174,7 +174,7 @@ pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stm
} }
visitor.visit_pat(pattern); visitor.visit_pat(pattern);
if let Some(block) = else_block { if let Some(block) = else_block {
visitor.visit_block(block) visitor.visit_block(&visitor.thir()[*block])
} }
} }
} }

View file

@ -10,7 +10,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
&mut self, &mut self,
destination: Place<'tcx>, destination: Place<'tcx>,
block: BasicBlock, block: BasicBlock,
ast_block: &Block, ast_block: BlockId,
source_info: SourceInfo, source_info: SourceInfo,
) -> BlockAnd<()> { ) -> BlockAnd<()> {
let Block { let Block {
@ -21,7 +21,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
expr, expr,
targeted_by_break, targeted_by_break,
safety_mode, safety_mode,
} = *ast_block; } = self.thir[ast_block];
let expr = expr.map(|expr| &self.thir[expr]); let expr = expr.map(|expr| &self.thir[expr]);
self.in_opt_scope(opt_destruction_scope.map(|de| (de, source_info)), move |this| { 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| { this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
@ -130,7 +130,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block, block,
init, init,
initializer_span, initializer_span,
else_block, *else_block,
visibility_scope, visibility_scope,
*remainder_scope, *remainder_scope,
remainder_span, remainder_span,

View file

@ -83,8 +83,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Don't bother with StorageLive and Dead for these temporaries, // Don't bother with StorageLive and Dead for these temporaries,
// they are never assigned. // they are never assigned.
ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } => (), ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } => (),
ExprKind::Block { body: Block { expr: None, targeted_by_break: false, .. } } ExprKind::Block { block }
if expr_ty.is_never() => {} if let Block { expr: None, targeted_by_break: false, .. } = this.thir[block]
&& expr_ty.is_never() => {}
_ => { _ => {
this.cfg this.cfg
.push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) }); .push(block, Statement { source_info, kind: StatementKind::StorageLive(temp) });

View file

@ -46,7 +46,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}) })
}) })
} }
ExprKind::Block { body: ref ast_block } => { ExprKind::Block { block: ast_block } => {
this.ast_block(destination, block, ast_block, source_info) this.ast_block(destination, block, ast_block, source_info)
} }
ExprKind::Match { scrutinee, ref arms } => { ExprKind::Match { scrutinee, ref arms } => {

View file

@ -116,14 +116,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// it is usually better to focus on `the_value` rather // it is usually better to focus on `the_value` rather
// than the entirety of block(s) surrounding it. // than the entirety of block(s) surrounding it.
let adjusted_span = (|| { let adjusted_span = (|| {
if let ExprKind::Block { body } = &expr.kind && let Some(tail_ex) = body.expr { if let ExprKind::Block { block } = expr.kind
&& let Some(tail_ex) = this.thir[block].expr
{
let mut expr = &this.thir[tail_ex]; let mut expr = &this.thir[tail_ex];
while let ExprKind::Block { loop {
body: Block { expr: Some(nested_expr), .. }, match expr.kind {
} ExprKind::Block { block }
| ExprKind::Scope { value: nested_expr, .. } = expr.kind if let Some(nested_expr) = this.thir[block].expr =>
{ {
expr = &this.thir[nested_expr]; expr = &this.thir[nested_expr];
}
ExprKind::Scope { value: nested_expr, .. } => {
expr = &this.thir[nested_expr];
}
_ => break,
}
} }
this.block_context.push(BlockFrame::TailExpr { this.block_context.push(BlockFrame::TailExpr {
tail_result_is_ignored: true, tail_result_is_ignored: true,

View file

@ -2280,15 +2280,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
mut block: BasicBlock, mut block: BasicBlock,
init: &Expr<'tcx>, init: &Expr<'tcx>,
initializer_span: Span, initializer_span: Span,
else_block: &Block, else_block: BlockId,
visibility_scope: Option<SourceScope>, visibility_scope: Option<SourceScope>,
remainder_scope: region::Scope, remainder_scope: region::Scope,
remainder_span: Span, remainder_span: Span,
pattern: &Pat<'tcx>, pattern: &Pat<'tcx>,
) -> BlockAnd<()> { ) -> BlockAnd<()> {
let else_block_span = self.thir[else_block].span;
let (matching, failure) = self.in_if_then_scope(remainder_scope, |this| { let (matching, failure) = self.in_if_then_scope(remainder_scope, |this| {
let scrutinee = unpack!(block = this.lower_scrutinee(block, init, initializer_span)); let scrutinee = unpack!(block = this.lower_scrutinee(block, init, initializer_span));
let pat = Pat { ty: init.ty, span: else_block.span, kind: Box::new(PatKind::Wild) }; let pat = Pat { ty: init.ty, span: else_block_span, kind: Box::new(PatKind::Wild) };
let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false); let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false);
this.declare_bindings( this.declare_bindings(
visibility_scope, visibility_scope,
@ -2318,7 +2319,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
); );
// This block is for the failure case // This block is for the failure case
let failure = this.bind_pattern( let failure = this.bind_pattern(
this.source_info(else_block.span), this.source_info(else_block_span),
wildcard, wildcard,
None, None,
&fake_borrow_temps, &fake_borrow_temps,
@ -2334,19 +2335,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// This place is not really used because this destination place // This place is not really used because this destination place
// should never be used to take values at the end of the failure // should never be used to take values at the end of the failure
// block. // block.
let dummy_place = self.temp(self.tcx.types.never, else_block.span); let dummy_place = self.temp(self.tcx.types.never, else_block_span);
let failure_block; let failure_block;
unpack!( unpack!(
failure_block = self.ast_block( failure_block = self.ast_block(
dummy_place, dummy_place,
failure, failure,
else_block, else_block,
self.source_info(else_block.span), self.source_info(else_block_span),
) )
); );
self.cfg.terminate( self.cfg.terminate(
failure_block, failure_block,
self.source_info(else_block.span), self.source_info(else_block_span),
TerminatorKind::Unreachable, TerminatorKind::Unreachable,
); );
matching.unit() matching.unit()

View file

@ -9,13 +9,13 @@ use rustc_index::vec::Idx;
use rustc_middle::ty::CanonicalUserTypeAnnotation; use rustc_middle::ty::CanonicalUserTypeAnnotation;
impl<'tcx> Cx<'tcx> { impl<'tcx> Cx<'tcx> {
pub(crate) fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block { pub(crate) fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> BlockId {
// We have to eagerly lower the "spine" of the statements // We have to eagerly lower the "spine" of the statements
// in order to get the lexical scoping correctly. // in order to get the lexical scoping correctly.
let stmts = self.mirror_stmts(block.hir_id.local_id, block.stmts); let stmts = self.mirror_stmts(block.hir_id.local_id, block.stmts);
let opt_destruction_scope = let opt_destruction_scope =
self.region_scope_tree.opt_destruction_scope(block.hir_id.local_id); self.region_scope_tree.opt_destruction_scope(block.hir_id.local_id);
Block { let block = Block {
targeted_by_break: block.targeted_by_break, targeted_by_break: block.targeted_by_break,
region_scope: region::Scope { region_scope: region::Scope {
id: block.hir_id.local_id, id: block.hir_id.local_id,
@ -34,7 +34,9 @@ impl<'tcx> Cx<'tcx> {
BlockSafety::ExplicitUnsafe(block.hir_id) BlockSafety::ExplicitUnsafe(block.hir_id)
} }
}, },
} };
self.thir.blocks.push(block)
} }
fn mirror_stmts( fn mirror_stmts(

View file

@ -108,8 +108,8 @@ impl<'tcx> Cx<'tcx> {
// // ^ error message points at this expression. // // ^ error message points at this expression.
// } // }
let mut adjust_span = |expr: &mut Expr<'tcx>| { let mut adjust_span = |expr: &mut Expr<'tcx>| {
if let ExprKind::Block { body } = &expr.kind { if let ExprKind::Block { block } = expr.kind {
if let Some(last_expr) = body.expr { if let Some(last_expr) = self.thir[block].expr {
span = self.thir[last_expr].span; span = self.thir[last_expr].span;
expr.span = span; expr.span = span;
} }
@ -369,7 +369,7 @@ impl<'tcx> Cx<'tcx> {
ExprKind::AddressOf { mutability, arg: self.mirror_expr(arg) } ExprKind::AddressOf { mutability, arg: self.mirror_expr(arg) }
} }
hir::ExprKind::Block(ref blk, _) => ExprKind::Block { body: self.mirror_block(blk) }, hir::ExprKind::Block(ref blk, _) => ExprKind::Block { block: self.mirror_block(blk) },
hir::ExprKind::Assign(ref lhs, ref rhs, _) => { hir::ExprKind::Assign(ref lhs, ref rhs, _) => {
ExprKind::Assign { lhs: self.mirror_expr(lhs), rhs: self.mirror_expr(rhs) } ExprKind::Assign { lhs: self.mirror_expr(lhs), rhs: self.mirror_expr(rhs) }
@ -680,8 +680,8 @@ impl<'tcx> Cx<'tcx> {
let body = self.thir.exprs.push(Expr { let body = self.thir.exprs.push(Expr {
ty: block_ty, ty: block_ty,
temp_lifetime, temp_lifetime,
span: block.span, span: self.thir[block].span,
kind: ExprKind::Block { body: block }, kind: ExprKind::Block { block },
}); });
ExprKind::Loop { body } ExprKind::Loop { body }
} }

View file

@ -311,8 +311,15 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
// bar::<{ N + 1 }>(); // bar::<{ N + 1 }>();
// } // }
// ``` // ```
ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. } } => { ExprKind::Block { block } => {
self.recurse_build(*e)? if let thir::Block { stmts: box [], expr: Some(e), .. } = &self.body.blocks[*block] {
self.recurse_build(*e)?
} else {
self.maybe_supported_error(
node.span,
"blocks are not supported in generic constant",
)?
}
} }
// `ExprKind::Use` happens when a `hir::ExprKind::Cast` is a // `ExprKind::Use` happens when a `hir::ExprKind::Cast` is a
// "coercion cast" i.e. using a coercion or is a no-op. // "coercion cast" i.e. using a coercion or is a no-op.
@ -349,10 +356,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
node.span, node.span,
"array construction is not supported in generic constants", "array construction is not supported in generic constants",
)?, )?,
ExprKind::Block { .. } => self.maybe_supported_error(
node.span,
"blocks are not supported in generic constant",
)?,
ExprKind::NeverToAny { .. } => self.maybe_supported_error( ExprKind::NeverToAny { .. } => self.maybe_supported_error(
node.span, node.span,
"converting nevers to any is not supported in generic constant", "converting nevers to any is not supported in generic constant",

View file

@ -1,6 +1,17 @@
DefId(0:3 ~ thir_tree[8f1d]::main): DefId(0:3 ~ thir_tree[8f1d]::main):
Thir { Thir {
arms: [], arms: [],
blocks: [
Block {
targeted_by_break: false,
region_scope: Node(1),
opt_destruction_scope: None,
span: $DIR/thir-tree.rs:4:15: 4:17 (#0),
stmts: [],
expr: None,
safety_mode: Safe,
},
],
exprs: [ exprs: [
Expr { Expr {
ty: (), ty: (),
@ -9,15 +20,7 @@ Thir {
), ),
span: $DIR/thir-tree.rs:4:15: 4:17 (#0), span: $DIR/thir-tree.rs:4:15: 4:17 (#0),
kind: Block { kind: Block {
body: Block { block: b0,
targeted_by_break: false,
region_scope: Node(1),
opt_destruction_scope: None,
span: $DIR/thir-tree.rs:4:15: 4:17 (#0),
stmts: [],
expr: None,
safety_mode: Safe,
},
}, },
}, },
Expr { Expr {