fix(joinir): avoid false rejects in balanced depth-scan policy
This commit is contained in:
@ -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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user