fix(joinir): avoid false rejects in balanced depth-scan policy

This commit is contained in:
nyash-codex
2025-12-17 22:52:29 +09:00
parent d42117ac5f
commit 6036627920

View File

@ -49,7 +49,8 @@ fn classify_balanced_depth_scan(
}; };
let summary = match extract_depth_scan_shape(body, &loop_counter_name, open, close) { let summary = match extract_depth_scan_shape(body, &loop_counter_name, open, close) {
Ok(v) => v, Ok(Some(v)) => v,
Ok(None) => return PolicyDecision::None,
Err(reason) => return PolicyDecision::Reject(reason), Err(reason) => return PolicyDecision::Reject(reason),
}; };
@ -128,7 +129,7 @@ fn extract_depth_scan_shape(
loop_counter_name: &str, loop_counter_name: &str,
open: &str, open: &str,
close: &str, close: &str,
) -> Result<DepthScanShapeSummary, String> { ) -> Result<Option<DepthScanShapeSummary>, String> {
if body.is_empty() { if body.is_empty() {
return Err(error_tags::freeze( return Err(error_tags::freeze(
"[phase107/balanced_depth_scan/contract/empty_body] empty loop body", "[phase107/balanced_depth_scan/contract/empty_body] empty loop body",
@ -146,16 +147,20 @@ fn extract_depth_scan_shape(
} }
// Find `local ch = s.substring(i, i+1)` (name may vary, but must be a single local). // Find `local ch = s.substring(i, i+1)` (name may vary, but must be a single local).
let ch_name = find_substring_body_local(body, loop_counter_name).ok_or_else(|| { // If missing, this is not a depth-scan candidate.
error_tags::freeze( let Some(ch_name) = find_substring_body_local(body, loop_counter_name) else {
"[phase107/balanced_depth_scan/contract/missing_ch] missing body-local `ch = s.substring(i, i+1)`", return Ok(None);
) };
})?;
// Find open/close branches and extract `depth` name. // Find open/close branches and extract `depth` name.
let (depth_from_open, depth_from_close, has_return_i) = let (depth_from_open, depth_from_close, has_return_i) =
find_depth_branches(body, &ch_name, loop_counter_name, open, close)?; find_depth_branches(body, &ch_name, loop_counter_name, open, close)?;
let (Some(depth_from_open), Some(depth_from_close)) = (depth_from_open, depth_from_close) else {
// Not a depth-scan candidate: no `if ch == open/close` pair.
return Ok(None);
};
if depth_from_open != depth_from_close { if depth_from_open != depth_from_close {
return Err(error_tags::freeze(&format!( return Err(error_tags::freeze(&format!(
"[phase107/balanced_depth_scan/contract/depth_mismatch] depth variable differs: open='{}', close='{}'", "[phase107/balanced_depth_scan/contract/depth_mismatch] depth variable differs: open='{}', close='{}'",
@ -189,11 +194,11 @@ fn extract_depth_scan_shape(
))); )));
} }
Ok(DepthScanShapeSummary { Ok(Some(DepthScanShapeSummary {
ch_name, ch_name,
depth_name: depth_from_open, depth_name: depth_from_open,
declared_locals, declared_locals,
}) }))
} }
fn scan_control_flow(node: &ASTNode, return_count: &mut usize) -> Result<(), String> { fn scan_control_flow(node: &ASTNode, return_count: &mut usize) -> Result<(), String> {
@ -276,7 +281,7 @@ fn find_depth_branches(
loop_counter_name: &str, loop_counter_name: &str,
open: &str, open: &str,
close: &str, close: &str,
) -> Result<(String, String, bool), String> { ) -> Result<(Option<String>, Option<String>, bool), String> {
let mut open_depth: Option<String> = None; let mut open_depth: Option<String> = None;
let mut close_depth: Option<String> = None; let mut close_depth: Option<String> = None;
let mut has_return_i = false; let mut has_return_i = false;
@ -314,18 +319,6 @@ fn find_depth_branches(
has_return_i = find_depth_zero_return(then_body, &depth_name, loop_counter_name); has_return_i = find_depth_zero_return(then_body, &depth_name, loop_counter_name);
} }
} }
let open_depth = open_depth.ok_or_else(|| {
error_tags::freeze(
"[phase107/balanced_depth_scan/contract/missing_open_branch] missing `if ch == open { depth = depth + 1 }`",
)
})?;
let close_depth = close_depth.ok_or_else(|| {
error_tags::freeze(
"[phase107/balanced_depth_scan/contract/missing_close_branch] missing `if ch == close { depth = depth - 1 ... }`",
)
})?;
Ok((open_depth, close_depth, has_return_i)) Ok((open_depth, close_depth, has_return_i))
} }