refactor(joinir): add hints for Phase107/104/100 policy rejects

- 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 <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-17 23:45:49 +09:00
parent 2ab460f0a8
commit a9f92f8f1a
3 changed files with 31 additions and 15 deletions

View File

@ -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)",
));
}
}

View File

@ -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;

View File

@ -6,6 +6,7 @@
//! - the digit literal set used in the final `if <is_digit> { ... } 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<String> = Vec::new();
@ -60,9 +65,10 @@ impl ReadDigitsBreakConditionBox {
// Phase 104 minimal: require the canonical digit set.
let expected: Vec<String> = (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\"'",
));
}