From a9f92f8f1a31068d831568c5a94d0e18833e523a Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Wed, 17 Dec 2025 23:45:49 +0900 Subject: [PATCH] refactor(joinir): add hints for Phase107/104/100 policy rejects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - balanced_depth_scan: missing_tail_inc, missing_return_i hints - read_digits: missing_eos_guard, digit_set_mismatch hints - pinned: missing_host_id hint - Gradual migration (representative cases only) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../patterns/pattern2_inputs_facts_box.rs | 8 ++++--- .../policies/balanced_depth_scan_policy.rs | 24 ++++++++++++------- .../read_digits_break_condition_box.rs | 14 +++++++---- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern2_inputs_facts_box.rs b/src/mir/builder/control_flow/joinir/patterns/pattern2_inputs_facts_box.rs index b2ac3efb..d53779a4 100644 --- a/src/mir/builder/control_flow/joinir/patterns/pattern2_inputs_facts_box.rs +++ b/src/mir/builder/control_flow/joinir/patterns/pattern2_inputs_facts_box.rs @@ -193,9 +193,11 @@ impl Pattern2InputsFactsBox { } captured_env.insert_pinned(pinned_name, host_id); } else { - return Err(format!( - "Pinned local '{}' not found in variable_map (internal error)", - pinned_name + use crate::mir::join_ir::lowering::error_tags; + return Err(error_tags::freeze_with_hint( + "phase100/pinned/missing_host_id", + &format!("Pinned local '{}' not found in variable_map", pinned_name), + "define the local before the loop (dominates loop entry)", )); } } diff --git a/src/mir/builder/control_flow/joinir/patterns/policies/balanced_depth_scan_policy.rs b/src/mir/builder/control_flow/joinir/patterns/policies/balanced_depth_scan_policy.rs index 3d3ae879..e07499a1 100644 --- a/src/mir/builder/control_flow/joinir/patterns/policies/balanced_depth_scan_policy.rs +++ b/src/mir/builder/control_flow/joinir/patterns/policies/balanced_depth_scan_policy.rs @@ -176,16 +176,20 @@ fn extract_depth_scan_shape( } if !has_return_i { - return Err(error_tags::freeze( - "[phase107/balanced_depth_scan/contract/missing_return_i] missing `if depth == 0 { return i }` inside close branch", + return Err(error_tags::freeze_with_hint( + "phase107/balanced_depth_scan/missing_return_i", + "missing `if depth == 0 { return i }` inside close branch", + "ensure 'if depth == 0 { return i }' is inside close-branch", )); } // Require a tail `i = i + 1` at top-level (keeps the family narrow). let has_tail_inc = body.iter().any(|n| is_inc_assign(n, loop_counter_name, 1)); if !has_tail_inc { - return Err(error_tags::freeze( - "[phase107/balanced_depth_scan/contract/missing_tail_inc] missing `i = i + 1` tail update", + return Err(error_tags::freeze_with_hint( + "phase107/balanced_depth_scan/missing_tail_inc", + "missing `i = i + 1` tail update", + "add tail update 'i = i + 1' at top-level", )); } @@ -210,11 +214,15 @@ fn extract_depth_scan_shape( fn scan_control_flow(node: &ASTNode, return_count: &mut usize) -> Result<(), String> { match node { - ASTNode::Break { .. } => Err(error_tags::freeze( - "[phase107/balanced_depth_scan/contract/unexpected_break] break is not allowed in this family (return-in-loop only)", + ASTNode::Break { .. } => Err(error_tags::freeze_with_hint( + "phase107/balanced_depth_scan/unexpected_break", + "break is not allowed in this family (return-in-loop only)", + "use 'return i' form (no break) in this family", )), - ASTNode::Continue { .. } => Err(error_tags::freeze( - "[phase107/balanced_depth_scan/contract/unexpected_continue] continue is not allowed in this family", + ASTNode::Continue { .. } => Err(error_tags::freeze_with_hint( + "phase107/balanced_depth_scan/unexpected_continue", + "continue is not allowed in this family", + "remove continue, use tail increment instead", )), ASTNode::Return { .. } => { *return_count += 1; diff --git a/src/mir/builder/control_flow/joinir/patterns/read_digits_break_condition_box.rs b/src/mir/builder/control_flow/joinir/patterns/read_digits_break_condition_box.rs index a90058b5..1b9da19c 100644 --- a/src/mir/builder/control_flow/joinir/patterns/read_digits_break_condition_box.rs +++ b/src/mir/builder/control_flow/joinir/patterns/read_digits_break_condition_box.rs @@ -6,6 +6,7 @@ //! - the digit literal set used in the final `if { ... } else { break }` use crate::ast::{ASTNode, BinaryOperator, LiteralValue}; +use crate::mir::join_ir::lowering::error_tags; pub(crate) struct ReadDigitsBreakConditionBox; @@ -33,7 +34,11 @@ impl ReadDigitsBreakConditionBox { } let (ch_var, eos_cond) = find_eos_break_condition(body).ok_or_else(|| { - "[phase104/read-digits] missing `if ch == \"\" { break }` guard".to_string() + error_tags::freeze_with_hint( + "phase104/read_digits/missing_eos_guard", + "missing `if ch == \"\" { break }` guard", + "add 'if ch == \"\" { break }' before digit check", + ) })?; let mut digit_literals: Vec = Vec::new(); @@ -60,9 +65,10 @@ impl ReadDigitsBreakConditionBox { // Phase 104 minimal: require the canonical digit set. let expected: Vec = (0..=9).map(|d| d.to_string()).collect(); if digit_literals != expected { - return Err(format!( - "[phase104/read-digits] digit condition literal set mismatch: got={:?}, expected={:?}", - digit_literals, expected + return Err(error_tags::freeze_with_hint( + "phase104/read_digits/digit_set_mismatch", + &format!("digit condition literal set mismatch: got={:?}, expected={:?}", digit_literals, expected), + "use explicit 'ch == \"0\" || ... || ch == \"9\"'", )); }