refactor(joinir): Box-First cleanup - trace unification + SSOT + Fail-Fast
## Changes ### 1. eprintln! to trace.rs unification **File**: src/mir/builder/control_flow/joinir/routing.rs - Replaced direct eprintln! with trace::trace().routing() - Box-First principle: Log responsibility centralized in trace.rs - Enables filtering via HAKO_JOINIR_DEBUG=1 ### 2. Priority field removal (SSOT) **File**: src/mir/builder/control_flow/joinir/patterns/router.rs - Removed #[allow(dead_code)] priority field - Array order is SSOT (Single Source of Truth) for pattern priority - Pattern try order: Pattern5 → Pattern4 → Pattern3 → Pattern1 → Pattern2 - Eliminated dead code warning ### 3. catch_unwind removal (Fail-Fast) **File**: src/mir/builder/control_flow/joinir/routing_legacy_binding.rs - Removed catch_unwind + Ok(None) silent error swallowing - Fail-Fast principle: Panics propagate explicitly - Enables early detection of panic sources ## Verification ✅ Build: cargo build --release (0 errors) ✅ Tests: 71 JoinIR tests all PASS ✅ VM: /tmp/p1_return_i.hako → Result: 3 ✅ LLVM: /tmp/p1_return_i.hako → Mock exit code: 0 ## Design Principles Applied - **Box-First**: Log responsibility → trace.rs - **SSOT**: Array order defines priority (no redundant field) - **Fail-Fast**: Explicit failures, no silent error swallowing ## Statistics - 3 files changed - 53 deletions, 28 insertions - Net: -25 lines (code reduction) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -123,10 +123,6 @@ pub(crate) struct LoopPatternEntry {
|
|||||||
/// Human-readable pattern name for debugging
|
/// Human-readable pattern name for debugging
|
||||||
pub(crate) name: &'static str,
|
pub(crate) name: &'static str,
|
||||||
|
|
||||||
/// Priority (lower = tried first). Pattern1=10, Pattern2=20, Pattern3=30
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub(crate) priority: u8,
|
|
||||||
|
|
||||||
/// Detection function: returns true if this pattern matches
|
/// Detection function: returns true if this pattern matches
|
||||||
pub(crate) detect: fn(&MirBuilder, &LoopPatternContext) -> bool,
|
pub(crate) detect: fn(&MirBuilder, &LoopPatternContext) -> bool,
|
||||||
|
|
||||||
@ -135,29 +131,32 @@ pub(crate) struct LoopPatternEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Static table of all registered loop patterns.
|
/// Static table of all registered loop patterns.
|
||||||
/// Patterns are tried in priority order (lowest first).
|
///
|
||||||
|
/// **IMPORTANT**: Patterns are tried in array order (SSOT).
|
||||||
|
/// Array order defines priority - earlier entries are tried first.
|
||||||
|
/// Pattern5 (most specific) → Pattern4 → Pattern3 → Pattern1 → Pattern2
|
||||||
///
|
///
|
||||||
/// # Current Patterns (Phase 131-11: Pattern 5 added)
|
/// # Current Patterns (Phase 131-11: Pattern 5 added)
|
||||||
///
|
///
|
||||||
/// All patterns now use structure-based detection via LoopFeatures and classify():
|
/// All patterns now use structure-based detection via LoopFeatures and classify():
|
||||||
///
|
///
|
||||||
/// - Pattern 5 (priority 1): Infinite Loop with Early Exit (llvm_stage3_loop_only.hako) [Phase 131-11]
|
/// - Pattern 5: Infinite Loop with Early Exit (llvm_stage3_loop_only.hako) [Phase 131-11]
|
||||||
/// - Detection: pattern_kind == InfiniteEarlyExit
|
/// - Detection: pattern_kind == InfiniteEarlyExit
|
||||||
/// - Structure: is_infinite_loop && has_break && has_continue
|
/// - Structure: is_infinite_loop && has_break && has_continue
|
||||||
///
|
///
|
||||||
/// - Pattern 4 (priority 5): Loop with Continue (loop_continue_pattern4.hako)
|
/// - Pattern 4: Loop with Continue (loop_continue_pattern4.hako)
|
||||||
/// - Detection: pattern_kind == Pattern4Continue
|
/// - Detection: pattern_kind == Pattern4Continue
|
||||||
/// - Structure: has_continue && !has_break
|
/// - Structure: has_continue && !has_break
|
||||||
///
|
///
|
||||||
/// - Pattern 3 (priority 30): Loop with If-Else PHI (loop_if_phi.hako)
|
/// - Pattern 3: Loop with If-Else PHI (loop_if_phi.hako)
|
||||||
/// - Detection: pattern_kind == Pattern3IfPhi
|
/// - Detection: pattern_kind == Pattern3IfPhi
|
||||||
/// - Structure: has_if_else_phi && !has_break && !has_continue
|
/// - Structure: has_if_else_phi && !has_break && !has_continue
|
||||||
///
|
///
|
||||||
/// - Pattern 1 (priority 10): Simple While Loop (loop_min_while.hako)
|
/// - Pattern 1: Simple While Loop (loop_min_while.hako)
|
||||||
/// - Detection: pattern_kind == Pattern1SimpleWhile
|
/// - Detection: pattern_kind == Pattern1SimpleWhile
|
||||||
/// - Structure: !has_break && !has_continue && !has_if_else_phi
|
/// - Structure: !has_break && !has_continue && !has_if_else_phi
|
||||||
///
|
///
|
||||||
/// - Pattern 2 (priority 20): Loop with Conditional Break (joinir_min_loop.hako)
|
/// - Pattern 2: Loop with Conditional Break (joinir_min_loop.hako)
|
||||||
/// - Detection: pattern_kind == Pattern2Break
|
/// - Detection: pattern_kind == Pattern2Break
|
||||||
/// - Structure: has_break && !has_continue
|
/// - Structure: has_break && !has_continue
|
||||||
///
|
///
|
||||||
@ -165,31 +164,26 @@ pub(crate) struct LoopPatternEntry {
|
|||||||
pub(crate) static LOOP_PATTERNS: &[LoopPatternEntry] = &[
|
pub(crate) static LOOP_PATTERNS: &[LoopPatternEntry] = &[
|
||||||
LoopPatternEntry {
|
LoopPatternEntry {
|
||||||
name: "Pattern5_InfiniteEarlyExit",
|
name: "Pattern5_InfiniteEarlyExit",
|
||||||
priority: 1, // Highest priority - most specific (infinite loop with break+continue)
|
|
||||||
detect: super::pattern5_infinite_early_exit::can_lower,
|
detect: super::pattern5_infinite_early_exit::can_lower,
|
||||||
lower: super::pattern5_infinite_early_exit::lower,
|
lower: super::pattern5_infinite_early_exit::lower,
|
||||||
},
|
},
|
||||||
LoopPatternEntry {
|
LoopPatternEntry {
|
||||||
name: "Pattern4_WithContinue",
|
name: "Pattern4_WithContinue",
|
||||||
priority: 5, // Second priority - continue without break
|
|
||||||
detect: super::pattern4_with_continue::can_lower,
|
detect: super::pattern4_with_continue::can_lower,
|
||||||
lower: super::pattern4_with_continue::lower,
|
lower: super::pattern4_with_continue::lower,
|
||||||
},
|
},
|
||||||
LoopPatternEntry {
|
LoopPatternEntry {
|
||||||
name: "Pattern3_WithIfPhi",
|
name: "Pattern3_WithIfPhi",
|
||||||
priority: 30, // NOTE: Pattern 3 must be checked BEFORE Pattern 1 (both use "main")
|
|
||||||
detect: super::pattern3_with_if_phi::can_lower,
|
detect: super::pattern3_with_if_phi::can_lower,
|
||||||
lower: super::pattern3_with_if_phi::lower,
|
lower: super::pattern3_with_if_phi::lower,
|
||||||
},
|
},
|
||||||
LoopPatternEntry {
|
LoopPatternEntry {
|
||||||
name: "Pattern1_Minimal",
|
name: "Pattern1_Minimal",
|
||||||
priority: 10,
|
|
||||||
detect: super::pattern1_minimal::can_lower,
|
detect: super::pattern1_minimal::can_lower,
|
||||||
lower: super::pattern1_minimal::lower,
|
lower: super::pattern1_minimal::lower,
|
||||||
},
|
},
|
||||||
LoopPatternEntry {
|
LoopPatternEntry {
|
||||||
name: "Pattern2_WithBreak",
|
name: "Pattern2_WithBreak",
|
||||||
priority: 20,
|
|
||||||
detect: super::pattern2_with_break::can_lower,
|
detect: super::pattern2_with_break::can_lower,
|
||||||
lower: super::pattern2_with_break::lower,
|
lower: super::pattern2_with_break::lower,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -128,19 +128,19 @@ impl MirBuilder {
|
|||||||
// Phase 200-C: Pass fn_body_ast to LoopPatternContext if available
|
// Phase 200-C: Pass fn_body_ast to LoopPatternContext if available
|
||||||
// Clone fn_body_ast to avoid borrow checker issues
|
// Clone fn_body_ast to avoid borrow checker issues
|
||||||
let fn_body_clone = self.fn_body_ast.clone();
|
let fn_body_clone = self.fn_body_ast.clone();
|
||||||
eprintln!(
|
trace::trace().routing(
|
||||||
"[routing] fn_body_ast is {} for '{}'",
|
"router",
|
||||||
if fn_body_clone.is_some() {
|
func_name,
|
||||||
"SOME"
|
&format!(
|
||||||
} else {
|
"fn_body_ast is {}",
|
||||||
"NONE"
|
if fn_body_clone.is_some() { "SOME" } else { "NONE" }
|
||||||
},
|
),
|
||||||
func_name
|
|
||||||
);
|
);
|
||||||
let ctx = if let Some(ref fn_body) = fn_body_clone {
|
let ctx = if let Some(ref fn_body) = fn_body_clone {
|
||||||
eprintln!(
|
trace::trace().routing(
|
||||||
"[routing] Creating ctx with fn_body ({} nodes)",
|
"router",
|
||||||
fn_body.len()
|
func_name,
|
||||||
|
&format!("Creating ctx with fn_body ({} nodes)", fn_body.len()),
|
||||||
);
|
);
|
||||||
LoopPatternContext::with_fn_body(condition, body, &func_name, debug, fn_body)
|
LoopPatternContext::with_fn_body(condition, body, &func_name, debug, fn_body)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -128,35 +128,16 @@ impl MirBuilder {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Step 3: Lower to JoinIR with panic catch
|
// Step 3: Lower to JoinIR (Fail-Fast: no silent error swallowing)
|
||||||
|
// Phase 132-Post: Removed catch_unwind - panics should be fixed at the source
|
||||||
let join_module = {
|
let join_module = {
|
||||||
let json_clone = program_json.clone();
|
let json_clone = program_json.clone();
|
||||||
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
let mut lowerer = AstToJoinIrLowerer::new();
|
||||||
let mut lowerer = AstToJoinIrLowerer::new();
|
|
||||||
lowerer.lower_program_json(&json_clone)
|
|
||||||
}));
|
|
||||||
|
|
||||||
match result {
|
// If lower_program_json panics, the panic will propagate up
|
||||||
Ok(module) => module,
|
// This is intentional - we want to catch and fix panics at their source
|
||||||
Err(e) => {
|
// rather than silently swallowing them with Ok(None)
|
||||||
let panic_msg = if let Some(s) = e.downcast_ref::<&str>() {
|
lowerer.lower_program_json(&json_clone)
|
||||||
s.to_string()
|
|
||||||
} else if let Some(s) = e.downcast_ref::<String>() {
|
|
||||||
s.clone()
|
|
||||||
} else {
|
|
||||||
"unknown panic".to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
trace::trace().debug(
|
|
||||||
"router",
|
|
||||||
&format!(
|
|
||||||
"JoinIR lowering failed for {}: {} (unsupported pattern)",
|
|
||||||
func_name, panic_msg
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return Ok(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let join_meta = JoinFuncMetaMap::new();
|
let join_meta = JoinFuncMetaMap::new();
|
||||||
|
|||||||
Reference in New Issue
Block a user