use cljrs_ir::lower::{EscapeState, UseInfo, UseKind};
fn use_contribution(kind: &UseKind) -> EscapeState {
match kind {
UseKind::Return => EscapeState::Returns,
UseKind::DefVar
| UseKind::SetBang
| UseKind::ClosureCapture
| UseKind::Throw
| UseKind::StoredInHeap
| UseKind::Recur => EscapeState::Escapes,
UseKind::UnknownCallArg { .. } | UseKind::CallCallee => EscapeState::Escapes,
UseKind::KnownCallArg { .. } => EscapeState::ArgEscape,
UseKind::PhiInput | UseKind::BranchCond | UseKind::Deref => EscapeState::NoEscape,
}
}
pub fn blame_use(uses: &[UseInfo], verdict: EscapeState) -> Option<&UseInfo> {
if verdict == EscapeState::NoEscape {
return None;
}
uses.iter()
.find(|u| rank(use_contribution(&u.kind)) >= rank(verdict))
}
fn rank(s: EscapeState) -> u8 {
match s {
EscapeState::NoEscape => 0,
EscapeState::ArgEscape => 1,
EscapeState::Returns => 2,
EscapeState::Escapes => 3,
}
}
pub fn use_kind_label(kind: &UseKind) -> String {
match kind {
UseKind::Return => "return value".into(),
UseKind::DefVar => "stored in def'd var".into(),
UseKind::SetBang => "set!".into(),
UseKind::ClosureCapture => "captured by closure".into(),
UseKind::Throw => "thrown".into(),
UseKind::StoredInHeap => "stored into heap object".into(),
UseKind::Recur => "passed to recur".into(),
UseKind::KnownCallArg {
func, arg_index, ..
} => {
format!("arg {arg_index} of known call {func:?}")
}
UseKind::UnknownCallArg { arg_index, .. } => {
format!("arg {arg_index} of unknown call")
}
UseKind::CallCallee => "callee of unknown call".into(),
UseKind::PhiInput => "phi input".into(),
UseKind::BranchCond => "branch condition".into(),
UseKind::Deref => "deref'd".into(),
}
}
pub fn state_label(state: EscapeState) -> &'static str {
match state {
EscapeState::NoEscape => "no-escape",
EscapeState::ArgEscape => "arg-escape",
EscapeState::Returns => "returns",
EscapeState::Escapes => "escapes",
}
}