use std::collections::HashSet;
use react_compiler_hir::{
BlockId, ReactiveFunction, ReactiveStatement, ReactiveTerminal,
ReactiveTerminalStatement, ReactiveTerminalTargetKind,
environment::Environment,
};
use crate::visitors::{transform_reactive_function, ReactiveFunctionTransform, Transformed};
pub fn prune_unused_labels(func: &mut ReactiveFunction, env: &Environment) -> Result<(), react_compiler_diagnostics::CompilerError> {
let mut transform = Transform { env };
let mut labels: HashSet<BlockId> = HashSet::new();
transform_reactive_function(func, &mut transform, &mut labels)
}
struct Transform<'a> {
env: &'a Environment,
}
impl<'a> ReactiveFunctionTransform for Transform<'a> {
type State = HashSet<BlockId>;
fn env(&self) -> &Environment { self.env }
fn transform_terminal(
&mut self,
stmt: &mut ReactiveTerminalStatement,
state: &mut HashSet<BlockId>,
) -> Result<Transformed<ReactiveStatement>, react_compiler_diagnostics::CompilerError> {
self.traverse_terminal(stmt, state)?;
match &stmt.terminal {
ReactiveTerminal::Break {
target,
target_kind: ReactiveTerminalTargetKind::Labeled,
..
}
| ReactiveTerminal::Continue {
target,
target_kind: ReactiveTerminalTargetKind::Labeled,
..
} => {
state.insert(*target);
}
_ => {}
}
let is_reachable_label = stmt
.label
.as_ref()
.map_or(false, |label| state.contains(&label.id));
if let ReactiveTerminal::Label { block, .. } = &mut stmt.terminal {
if !is_reachable_label {
let flattened = std::mem::take(block);
return Ok(Transformed::ReplaceMany(flattened));
}
}
if !is_reachable_label {
if let Some(label) = &mut stmt.label {
label.implicit = true;
}
}
Ok(Transformed::Keep)
}
}