Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/mir/borrowck.rs')
-rw-r--r--crates/hir-ty/src/mir/borrowck.rs125
1 files changed, 67 insertions, 58 deletions
diff --git a/crates/hir-ty/src/mir/borrowck.rs b/crates/hir-ty/src/mir/borrowck.rs
index 878d584a4e..9830fa1ca7 100644
--- a/crates/hir-ty/src/mir/borrowck.rs
+++ b/crates/hir-ty/src/mir/borrowck.rs
@@ -386,82 +386,91 @@ fn ever_initialized_map(
fn dfs(
db: &dyn HirDatabase,
body: &MirBody,
- b: BasicBlockId,
l: LocalId,
+ stack: &mut Vec<BasicBlockId>,
result: &mut ArenaMap<BasicBlockId, ArenaMap<LocalId, bool>>,
) {
- let mut is_ever_initialized = result[b][l]; // It must be filled, as we use it as mark for dfs
- let block = &body.basic_blocks[b];
- for statement in &block.statements {
- match &statement.kind {
- StatementKind::Assign(p, _) => {
- if p.projection.lookup(&body.projection_store).is_empty() && p.local == l {
- is_ever_initialized = true;
+ while let Some(b) = stack.pop() {
+ let mut is_ever_initialized = result[b][l]; // It must be filled, as we use it as mark for dfs
+ let block = &body.basic_blocks[b];
+ for statement in &block.statements {
+ match &statement.kind {
+ StatementKind::Assign(p, _) => {
+ if p.projection.lookup(&body.projection_store).is_empty() && p.local == l {
+ is_ever_initialized = true;
+ }
}
- }
- StatementKind::StorageDead(p) => {
- if *p == l {
- is_ever_initialized = false;
+ StatementKind::StorageDead(p) => {
+ if *p == l {
+ is_ever_initialized = false;
+ }
}
+ StatementKind::Deinit(_)
+ | StatementKind::FakeRead(_)
+ | StatementKind::Nop
+ | StatementKind::StorageLive(_) => (),
}
- StatementKind::Deinit(_)
- | StatementKind::FakeRead(_)
- | StatementKind::Nop
- | StatementKind::StorageLive(_) => (),
- }
- }
- let Some(terminator) = &block.terminator else {
- never!(
- "Terminator should be none only in construction.\nThe body:\n{}",
- body.pretty_print(db)
- );
- return;
- };
- let mut process = |target, is_ever_initialized| {
- if !result[target].contains_idx(l) || !result[target][l] && is_ever_initialized {
- result[target].insert(l, is_ever_initialized);
- dfs(db, body, target, l, result);
- }
- };
- match &terminator.kind {
- TerminatorKind::Goto { target } => process(*target, is_ever_initialized),
- TerminatorKind::SwitchInt { targets, .. } => {
- targets.all_targets().iter().for_each(|&it| process(it, is_ever_initialized));
}
- TerminatorKind::UnwindResume
- | TerminatorKind::Abort
- | TerminatorKind::Return
- | TerminatorKind::Unreachable => (),
- TerminatorKind::Call { target, cleanup, destination, .. } => {
- if destination.projection.lookup(&body.projection_store).is_empty()
- && destination.local == l
- {
- is_ever_initialized = true;
+ let Some(terminator) = &block.terminator else {
+ never!(
+ "Terminator should be none only in construction.\nThe body:\n{}",
+ body.pretty_print(db)
+ );
+ return;
+ };
+ let mut process = |target, is_ever_initialized| {
+ if !result[target].contains_idx(l) || !result[target][l] && is_ever_initialized {
+ result[target].insert(l, is_ever_initialized);
+ stack.push(target);
+ }
+ };
+ match &terminator.kind {
+ TerminatorKind::Goto { target } => process(*target, is_ever_initialized),
+ TerminatorKind::SwitchInt { targets, .. } => {
+ targets.all_targets().iter().for_each(|&it| process(it, is_ever_initialized));
+ }
+ TerminatorKind::UnwindResume
+ | TerminatorKind::Abort
+ | TerminatorKind::Return
+ | TerminatorKind::Unreachable => (),
+ TerminatorKind::Call { target, cleanup, destination, .. } => {
+ if destination.projection.lookup(&body.projection_store).is_empty()
+ && destination.local == l
+ {
+ is_ever_initialized = true;
+ }
+ target.iter().chain(cleanup).for_each(|&it| process(it, is_ever_initialized));
+ }
+ TerminatorKind::Drop { target, unwind, place: _ } => {
+ iter::once(target)
+ .chain(unwind)
+ .for_each(|&it| process(it, is_ever_initialized));
+ }
+ TerminatorKind::DropAndReplace { .. }
+ | TerminatorKind::Assert { .. }
+ | TerminatorKind::Yield { .. }
+ | TerminatorKind::CoroutineDrop
+ | TerminatorKind::FalseEdge { .. }
+ | TerminatorKind::FalseUnwind { .. } => {
+ never!("We don't emit these MIR terminators yet");
}
- target.iter().chain(cleanup).for_each(|&it| process(it, is_ever_initialized));
- }
- TerminatorKind::Drop { target, unwind, place: _ } => {
- iter::once(target).chain(unwind).for_each(|&it| process(it, is_ever_initialized));
- }
- TerminatorKind::DropAndReplace { .. }
- | TerminatorKind::Assert { .. }
- | TerminatorKind::Yield { .. }
- | TerminatorKind::CoroutineDrop
- | TerminatorKind::FalseEdge { .. }
- | TerminatorKind::FalseUnwind { .. } => {
- never!("We don't emit these MIR terminators yet");
}
}
}
+ let mut stack = Vec::new();
for &l in &body.param_locals {
result[body.start_block].insert(l, true);
- dfs(db, body, body.start_block, l, &mut result);
+ stack.clear();
+ stack.push(body.start_block);
+ dfs(db, body, l, &mut stack, &mut result);
}
for l in body.locals.iter().map(|it| it.0) {
db.unwind_if_cancelled();
if !result[body.start_block].contains_idx(l) {
result[body.start_block].insert(l, false);
- dfs(db, body, body.start_block, l, &mut result);
+ stack.clear();
+ stack.push(body.start_block);
+ dfs(db, body, l, &mut stack, &mut result);
}
}
result