use rustc_hash::FxHashSet;
use react_compiler_hir::{
BlockId, ReactiveFunction, ReactiveStatement, ReactiveTerminal, ReactiveTerminalStatement,
ReactiveTerminalTargetKind, environment::Environment,
};
use crate::visitors::{ReactiveFunctionTransform, Transformed, transform_reactive_function};
pub fn prune_unused_labels(
func: &mut ReactiveFunction,
env: &Environment,
) -> Result<(), react_compiler_diagnostics::CompilerError> {
let mut transform = Transform { env };
let mut labels: FxHashSet<BlockId> = FxHashSet::default();
transform_reactive_function(func, &mut transform, &mut labels)
}
struct Transform<'a> {
env: &'a Environment,
}
impl<'a> ReactiveFunctionTransform for Transform<'a> {
type State = FxHashSet<BlockId>;
fn env(&self) -> &Environment {
self.env
}
fn transform_terminal(
&mut self,
stmt: &mut ReactiveTerminalStatement,
state: &mut FxHashSet<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)
}
}