phase29ac(p1): normalize pattern6 reverse scan and flip smoke to PASS
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
// Phase 29ab P7: Pattern6 reverse scan first-fail (step contract violation)
|
||||
// Expect: JoinIR freeze (reverse step must be i = i - 1)
|
||||
// Phase 29ac P1: Pattern6 reverse scan OK minimal
|
||||
// Expect: last_index_bad_step("abc", "b") -> 1
|
||||
|
||||
static box Main {
|
||||
last_index_bad_step(s, ch) {
|
||||
@ -8,7 +8,7 @@ static box Main {
|
||||
if s.substring(i, i + 1) == ch {
|
||||
return i
|
||||
}
|
||||
i = i + 1
|
||||
i = i - 1
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ Freeze conditions:
|
||||
- forward scan with step != `i = i + 1`
|
||||
- reverse scan with step != `i = i - 1`
|
||||
Note:
|
||||
- plan line is forward-only; reverse scans are currently treated as NotApplicable
|
||||
- plan line supports reverse scan (cond: `i >= 0`, step: `i = i - 1`)
|
||||
|
||||
## Pattern7 (SplitScan)
|
||||
|
||||
|
||||
24
docs/development/current/main/phases/phase-29ac/README.md
Normal file
24
docs/development/current/main/phases/phase-29ac/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
# Phase 29ac: JoinIR thaw plan (Pattern6/7 near-miss → PASS)
|
||||
|
||||
Goal: Convert freeze-fixed Pattern6/7 near-miss cases into PASS while keeping contracts intact (no by-name or silent fallback).
|
||||
|
||||
## Target list (current freeze fixtures)
|
||||
|
||||
- `apps/tests/phase29ab_pattern6_firstfail_min.hako`
|
||||
- `apps/tests/phase29ab_pattern6_matchscan_firstfail_min.hako`
|
||||
- `apps/tests/phase29ab_pattern7_firstfail_min.hako`
|
||||
|
||||
## Pass order (recommended)
|
||||
|
||||
1. **Pattern6 reverse scan**
|
||||
- Plan/Normalizer: add reverse support (`i >= 0`, step `i = i - 1`).
|
||||
- Smoke: `phase29ab_pattern6_reverse_firstfail_min` now OK PASS (RC=1).
|
||||
2. **Pattern6 matchscan missing step**
|
||||
- Decide whether step can be synthesized safely; otherwise mark out-of-scope and add explicit contract note.
|
||||
3. **Pattern7 split-scan near-miss**
|
||||
- Resolve then/else update mismatches without relaxing contracts.
|
||||
|
||||
## Commands
|
||||
|
||||
- `./tools/smokes/v2/run.sh --profile integration --filter "phase29ab_pattern6_*"`
|
||||
- `./tools/smokes/v2/run.sh --profile integration --filter "phase29ab_pattern7_*"`
|
||||
@ -65,14 +65,6 @@ pub(crate) fn extract_scan_with_init_plan(
|
||||
"phase29ab/pattern6/contract",
|
||||
)?;
|
||||
|
||||
// Phase 273 P1: Filter out patterns not supported by Plan-based normalizer
|
||||
if let Some(ref p) = parts {
|
||||
// P1 scope: Only forward scan (step=1) supported
|
||||
if p.step_lit != 1 {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap in DomainPlan if extracted successfully
|
||||
Ok(parts.map(DomainPlan::ScanWithInit))
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use super::{CoreEffectPlan, CoreLoopPlan, CorePhiInfo, CorePlan, ScanWithInitPlan};
|
||||
use crate::mir::builder::control_flow::plan::ScanDirection;
|
||||
use crate::mir::basic_block::EdgeArgs;
|
||||
use crate::mir::builder::control_flow::edgecfg::api::{BranchStub, EdgeStub, ExitKind, Frag};
|
||||
use crate::mir::builder::control_flow::joinir::patterns::router::LoopPatternContext;
|
||||
@ -34,12 +35,21 @@ impl super::PlanNormalizer {
|
||||
);
|
||||
}
|
||||
|
||||
// P1 Scope: Forward scan (step=1) only
|
||||
if parts.step_lit != 1 {
|
||||
return Err(format!(
|
||||
"[normalizer] P1 scope: only forward scan supported (step={})",
|
||||
parts.step_lit
|
||||
));
|
||||
// P1 Scope: forward (step=1) or reverse (step=-1)
|
||||
match parts.scan_direction {
|
||||
ScanDirection::Forward if parts.step_lit != 1 => {
|
||||
return Err(format!(
|
||||
"[normalizer] P1 scope: forward scan requires step=1 (step={})",
|
||||
parts.step_lit
|
||||
));
|
||||
}
|
||||
ScanDirection::Reverse if parts.step_lit != -1 => {
|
||||
return Err(format!(
|
||||
"[normalizer] P1 scope: reverse scan requires step=-1 (step={})",
|
||||
parts.step_lit
|
||||
));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Step 1: Get host ValueIds for variables
|
||||
@ -169,30 +179,55 @@ impl super::PlanNormalizer {
|
||||
});
|
||||
}
|
||||
|
||||
// len = s.length()
|
||||
header_effects.push(CoreEffectPlan::MethodCall {
|
||||
dst: Some(len_val),
|
||||
object: s_host,
|
||||
method: "length".to_string(),
|
||||
args: vec![],
|
||||
effects: EffectMask::PURE.add(Effect::Io),
|
||||
});
|
||||
match parts.scan_direction {
|
||||
ScanDirection::Forward => {
|
||||
// len = s.length()
|
||||
header_effects.push(CoreEffectPlan::MethodCall {
|
||||
dst: Some(len_val),
|
||||
object: s_host,
|
||||
method: "length".to_string(),
|
||||
args: vec![],
|
||||
effects: EffectMask::PURE.add(Effect::Io),
|
||||
});
|
||||
|
||||
// bound = len - needle_len
|
||||
header_effects.push(CoreEffectPlan::BinOp {
|
||||
dst: bound_val,
|
||||
lhs: len_val,
|
||||
op: BinaryOp::Sub,
|
||||
rhs: needle_len_val,
|
||||
});
|
||||
// bound = len - needle_len
|
||||
header_effects.push(CoreEffectPlan::BinOp {
|
||||
dst: bound_val,
|
||||
lhs: len_val,
|
||||
op: BinaryOp::Sub,
|
||||
rhs: needle_len_val,
|
||||
});
|
||||
|
||||
// cond_loop = i <= bound
|
||||
header_effects.push(CoreEffectPlan::Compare {
|
||||
dst: cond_loop,
|
||||
lhs: i_current,
|
||||
op: CompareOp::Le,
|
||||
rhs: bound_val,
|
||||
});
|
||||
// cond_loop = i <= bound
|
||||
header_effects.push(CoreEffectPlan::Compare {
|
||||
dst: cond_loop,
|
||||
lhs: i_current,
|
||||
op: CompareOp::Le,
|
||||
rhs: bound_val,
|
||||
});
|
||||
}
|
||||
ScanDirection::Reverse => {
|
||||
let zero_val = builder.next_value_id();
|
||||
builder
|
||||
.type_ctx
|
||||
.value_types
|
||||
.insert(zero_val, MirType::Integer);
|
||||
|
||||
// zero = 0
|
||||
header_effects.push(CoreEffectPlan::Const {
|
||||
dst: zero_val,
|
||||
value: ConstValue::Integer(0),
|
||||
});
|
||||
|
||||
// cond_loop = i >= 0
|
||||
header_effects.push(CoreEffectPlan::Compare {
|
||||
dst: cond_loop,
|
||||
lhs: i_current,
|
||||
op: CompareOp::Ge,
|
||||
rhs: zero_val,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Step 6: Build body (emitted in body_bb)
|
||||
let body = vec![
|
||||
@ -221,15 +256,22 @@ impl super::PlanNormalizer {
|
||||
];
|
||||
|
||||
// Step 7: Build step_effects (emitted in step_bb)
|
||||
let step_effects = vec![
|
||||
// i_next = i + 1
|
||||
CoreEffectPlan::BinOp {
|
||||
let step_effects = match parts.scan_direction {
|
||||
ScanDirection::Forward => vec![CoreEffectPlan::BinOp {
|
||||
// i_next = i + 1
|
||||
dst: i_next_val,
|
||||
lhs: i_current,
|
||||
op: BinaryOp::Add,
|
||||
rhs: one_val,
|
||||
},
|
||||
];
|
||||
}],
|
||||
ScanDirection::Reverse => vec![CoreEffectPlan::BinOp {
|
||||
// i_next = i - 1
|
||||
dst: i_next_val,
|
||||
lhs: i_current,
|
||||
op: BinaryOp::Sub,
|
||||
rhs: one_val,
|
||||
}],
|
||||
};
|
||||
|
||||
// Step 8: Build block_effects (Phase 273 P2)
|
||||
let block_effects = vec![
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
# Phase 29ab P7: Pattern6 reverse scan first-fail (contract violation)
|
||||
# Tests: reverse scan step mismatch must fail-fast
|
||||
# Phase 29ac P1: Pattern6 reverse scan OK minimal
|
||||
# Tests: return index 1
|
||||
|
||||
source "$(dirname "$0")/../../../lib/test_runner.sh"
|
||||
export SMOKES_USE_PYVM=0
|
||||
@ -19,22 +19,12 @@ if [ "$EXIT_CODE" -eq 124 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$EXIT_CODE" -eq 0 ]; then
|
||||
echo "[FAIL] Expected JoinIR contract freeze error, got exit 0"
|
||||
echo "[INFO] Output:"
|
||||
echo "$OUTPUT" | tail -n 40 || true
|
||||
test_fail "phase29ab_pattern6_reverse_firstfail_min_vm: Unexpected success"
|
||||
exit 1
|
||||
if [ "$EXIT_CODE" -eq 1 ]; then
|
||||
test_pass "phase29ab_pattern6_reverse_firstfail_min_vm: RC=1 (expected)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if echo "$OUTPUT" | grep -q "\[joinir/phase29ab/pattern6/contract\]"; then
|
||||
test_pass "phase29ab_pattern6_reverse_firstfail_min_vm: joinir contract freeze detected"
|
||||
exit 0
|
||||
else
|
||||
echo "[FAIL] Expected joinir contract freeze tag in output"
|
||||
echo "[INFO] Exit code: $EXIT_CODE"
|
||||
echo "[INFO] Output:"
|
||||
echo "$OUTPUT" | tail -n 60 || true
|
||||
test_fail "phase29ab_pattern6_reverse_firstfail_min_vm: Missing joinir contract freeze tag"
|
||||
exit 1
|
||||
fi
|
||||
echo "[FAIL] Expected exit 1, got $EXIT_CODE"
|
||||
echo "$OUTPUT" | tail -n 40 || true
|
||||
test_fail "phase29ab_pattern6_reverse_firstfail_min_vm: Unexpected RC"
|
||||
exit 1
|
||||
|
||||
Reference in New Issue
Block a user