mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
fix(semantic/cfg): correct unreachability propagation in try-finally. (#3667)
closes #3663 [oxlint-ecosystem-ci](https://github.com/rzvxa/oxlint-ecosystem-ci/actions/runs/9511509383/job/26217870705) From this:  To this:  Since try-finally (without a catch) wouldn't join after finalization.
This commit is contained in:
parent
c7c22b70eb
commit
e148a32ce3
4 changed files with 23 additions and 18 deletions
|
|
@ -50,25 +50,18 @@ impl Rule for NoUnreachable {
|
|||
// In our first path we first check if each block is definitely unreachable, If it is then
|
||||
// we set it as such, If we encounter an infinite loop we keep its end block since it can
|
||||
// prevent other reachable blocks from ever getting executed.
|
||||
let _: Control<()> = depth_first_search(graph, Some(root.cfg_id()), |event| match event {
|
||||
DfsEvent::Finish(node, _) => {
|
||||
let bb = cfg.basic_block(node);
|
||||
let unreachable = if bb.unreachable {
|
||||
true
|
||||
} else {
|
||||
graph
|
||||
.edges_directed(node, Direction::Incoming)
|
||||
.any(|edge| matches!(edge.weight(), EdgeType::Join))
|
||||
};
|
||||
let _: Control<()> = depth_first_search(graph, Some(root.cfg_id()), |event| {
|
||||
if let DfsEvent::Finish(node, _) = event {
|
||||
let unreachable = cfg.basic_block(node).unreachable;
|
||||
unreachables[node.index()] = unreachable;
|
||||
|
||||
if let Some(it) = cfg.is_infinite_loop_start(node, nodes) {
|
||||
infinite_loops.push(it);
|
||||
if !unreachable {
|
||||
if let Some(it) = cfg.is_infinite_loop_start(node, nodes) {
|
||||
infinite_loops.push(it);
|
||||
}
|
||||
}
|
||||
|
||||
Control::Continue
|
||||
}
|
||||
_ => Control::Continue,
|
||||
Control::Continue
|
||||
});
|
||||
|
||||
// In the second path we go for each infinite loop end block and follow it marking all
|
||||
|
|
@ -255,6 +248,14 @@ fn test() {
|
|||
b();
|
||||
}
|
||||
",
|
||||
"
|
||||
try {
|
||||
a();
|
||||
} finally {
|
||||
b();
|
||||
}
|
||||
c();
|
||||
",
|
||||
];
|
||||
|
||||
let fail = vec![
|
||||
|
|
|
|||
|
|
@ -1248,7 +1248,11 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
self.cfg.add_edge(
|
||||
finally_block_end_ix,
|
||||
after_try_statement_block_ix,
|
||||
EdgeType::Join,
|
||||
if self.cfg.basic_block(after_try_block_graph_ix).unreachable {
|
||||
EdgeType::Unreachable
|
||||
} else {
|
||||
EdgeType::Join
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ impl<'a> ControlFlowGraphBuilder<'a> {
|
|||
pub fn add_edge(&mut self, a: BasicBlockId, b: BasicBlockId, weight: EdgeType) {
|
||||
if matches!(weight, EdgeType::NewFunction) {
|
||||
self.basic_block_mut(b).unreachable = false;
|
||||
} else if self.basic_block(a).unreachable {
|
||||
} else if matches!(weight, EdgeType::Unreachable) || self.basic_block(a).unreachable {
|
||||
if self.graph.edges_directed(b, Direction::Incoming).count() == 0 {
|
||||
self.basic_block_mut(b).unreachable = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ digraph {
|
|||
7 -> 8 [ label = "Unreachable" , style = "dotted" ]
|
||||
9 -> 2 [ label = "Error(Implicit)" , style = "dotted" ]
|
||||
3 -> 5 [ label = "Normal" ]
|
||||
8 -> 9 [ label = "Join" , style = "dotted" ]
|
||||
8 -> 9 [ label = "Unreachable" , style = "dotted" ]
|
||||
10 -> 2 [ label = "Error(Implicit)" ]
|
||||
9 -> 10 [ label = "Normal" , style = "dotted" ]
|
||||
7 -> 10 [ label = "Jump" ]
|
||||
|
|
|
|||
Loading…
Reference in a new issue