// Unique-tail function name resolution // Extracted from execute_legacy_call to keep handlers lean use std::collections::HashMap; use super::MirFunction; /// Resolve function name using unique-tail matching algorithm. /// /// Resolution strategy: /// 1. Fast path: exact match on raw name /// 2. Normalize with arity: "base/N" /// 3. Unique-tail matching: find candidates ending with ".method/N" /// 4. Same-box preference: prioritize functions in the same box as current_function /// /// Returns resolved function name, or None if resolution fails. pub(super) fn resolve_function_name( raw: &str, arity: usize, functions: &HashMap, current_function: Option<&str>, ) -> Option { // Fast path: exact match if functions.contains_key(raw) { return Some(raw.to_string()); } // Robust normalization for names like "Box.method/Arity" or just "method" let (base, ar_from_raw) = if let Some((b, a)) = raw.rsplit_once('/') { (b.to_string(), a.parse::().ok()) } else { (raw.to_string(), None) }; let want_arity = ar_from_raw.unwrap_or(arity); // Try exact canonical form: "base/arity" let exact = format!("{}/{}", base, want_arity); if functions.contains_key(&exact) { return Some(exact); } // Split base into optional box and method name let (maybe_box, method) = if let Some((bx, m)) = base.split_once('.') { (Some(bx.to_string()), m.to_string()) } else { (None, base.clone()) }; // Collect candidates that end with ".method/arity" let mut cands: Vec = Vec::new(); let tail = format!(".{}{}", method, format!("/{}", want_arity)); for k in functions.keys() { if k.ends_with(&tail) { if let Some(ref bx) = maybe_box { if k.starts_with(&format!("{}.", bx)) { cands.push(k.clone()); } } else { cands.push(k.clone()); } } } if cands.len() > 1 { // Prefer same-box candidate based on current function's box if let Some(cur) = current_function { let cur_box = cur.split('.').next().unwrap_or(""); let scoped: Vec = cands .iter() .filter(|k| k.starts_with(&format!("{}.", cur_box))) .cloned() .collect(); if scoped.len() == 1 { cands = scoped; } } } match cands.len() { 0 => None, 1 => Some(cands.into_iter().next().unwrap()), _ => { // Multiple candidates: sort and pick first (deterministic fallback) let mut c = cands; c.sort(); Some(c.into_iter().next().unwrap()) } } }