diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index 7892cd60..bfa0939a 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -18,9 +18,12 @@ Scope: Repo root の旧リンク互換。現行の入口は `docs/development/cu **CorePlan migration 道筋 SSOT** `docs/development/current/main/design/coreplan-migration-roadmap-ssot.md` が移行タスクの Done 判定の入口。 -**Next implementation (Phase 29ao P21)** -- 目的: strict/dev Pattern1 shadow adopt の意味論破壊を防ぐため、Pattern1 subset を “body is step-only” で固定する -- 指示書: `docs/development/current/main/phases/phase-29ao/P21-PATTERN1-SUBSET-BODY-IS-STEP-ONLY-INSTRUCTIONS.md` +**Next implementation (Phase 29ao P22)** +- 目的: TBD +- 指示書: TBD + +**2025-12-30: Phase 29ao P21 COMPLETE (Pattern1 subset step-only gate)** +Pattern1 subset を body=step のみに引き締め、strict/dev shadow adopt の誤マッチを遮断した。 **2025-12-30: Phase 29ao P20 COMPLETE (CoreLoop ExitMap composition SSOT)** CoreLoop の ExitMap/Cleanup/ValueJoin 合成規約を SSOT 化し、合成境界と Fail-Fast ルールを固定した(docs-only)。 diff --git a/apps/tests/phase29ao_pattern1_subset_reject_extra_stmt.hako b/apps/tests/phase29ao_pattern1_subset_reject_extra_stmt.hako new file mode 100644 index 00000000..c5906ef1 --- /dev/null +++ b/apps/tests/phase29ao_pattern1_subset_reject_extra_stmt.hako @@ -0,0 +1,16 @@ +// Phase 29ao P21: Pattern1 subset reject (extra body statement) +// Expected: return 3 (sum increments each iteration) + +static box Main { + main() { + local i + local sum + i = 0 + sum = 0 + loop(i < 3) { + sum = sum + 1 + i = i + 1 + } + return sum + } +} diff --git a/docs/development/current/main/10-Now.md b/docs/development/current/main/10-Now.md index 54c9ffe3..5f4c3d46 100644 --- a/docs/development/current/main/10-Now.md +++ b/docs/development/current/main/10-Now.md @@ -2,12 +2,17 @@ ## Current Focus: Phase 29ao(CorePlan composition) -Next: Phase 29ao P21(Pattern1 subset: body is step-only) -指示書: `docs/development/current/main/phases/phase-29ao/P21-PATTERN1-SUBSET-BODY-IS-STEP-ONLY-INSTRUCTIONS.md` +Next: Phase 29ao P22(TBD) +指示書: TBD 運用ルール: integration filter で phase143_* は回さない(JoinIR 回帰は phase29ae pack のみ) 運用ルール: phase286_pattern9_* は legacy pack (SKIP) を使う 移行道筋 SSOT: `docs/development/current/main/design/coreplan-migration-roadmap-ssot.md` +**2025-12-30: Phase 29ao P21 完了** ✅ +- 目的: Pattern1 subset を body=step のみに引き締め、strict/dev shadow adopt の誤マッチを遮断 +- 変更: `src/mir/builder/control_flow/plan/policies/pattern1_subset_policy.rs` / `src/mir/builder/control_flow/plan/facts/pattern1_simplewhile_facts.rs` / `src/mir/builder/control_flow/plan/extractors/pattern1.rs` / `apps/tests/phase29ao_pattern1_subset_reject_extra_stmt.hako` / `tools/smokes/v2/profiles/integration/joinir/phase29ao_pattern1_subset_reject_extra_stmt_vm.sh` / `tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh` / `docs/development/current/main/phases/phase-29ae/README.md` / `docs/development/current/main/phases/phase-29ao/README.md` / `docs/development/current/main/10-Now.md` / `docs/development/current/main/30-Backlog.md` / `CURRENT_TASK.md` +- 検証: `cargo build --release` / `./tools/smokes/v2/run.sh --profile quick` / `./tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh` + **2025-12-30: Phase 29ao P20 完了** ✅ - 目的: CoreLoop の ExitMap/Cleanup/ValueJoin 合成規約を SSOT 化(docs-only) - 変更: `docs/development/current/main/design/coreloop-exitmap-composition-ssot.md` / `docs/development/current/main/design/planfrag-ssot-registry.md` / `docs/development/current/main/phases/phase-29ao/README.md` / `docs/development/current/main/10-Now.md` / `docs/development/current/main/30-Backlog.md` / `CURRENT_TASK.md` diff --git a/docs/development/current/main/30-Backlog.md b/docs/development/current/main/30-Backlog.md index 58ac3f30..6a9b6274 100644 --- a/docs/development/current/main/30-Backlog.md +++ b/docs/development/current/main/30-Backlog.md @@ -15,8 +15,8 @@ Related: - **Phase 29ao(active): CorePlan composition from Skeleton/Feature** - 入口: `docs/development/current/main/phases/phase-29ao/README.md` - - 状況: P0–P20 ✅ 完了 / Next: P21(Pattern1 subset hardening) - - Next 指示書: `docs/development/current/main/phases/phase-29ao/P21-PATTERN1-SUBSET-BODY-IS-STEP-ONLY-INSTRUCTIONS.md` + - 状況: P0–P21 ✅ 完了 / Next: P22(TBD) + - Next 指示書: TBD - **Phase 29af(✅ COMPLETE): Boundary hygiene / regression entrypoint / carrier layout SSOT** - 入口: `docs/development/current/main/phases/phase-29af/README.md` diff --git a/docs/development/current/main/phases/phase-29ae/README.md b/docs/development/current/main/phases/phase-29ae/README.md index e9cd90f6..6da9c3f7 100644 --- a/docs/development/current/main/phases/phase-29ae/README.md +++ b/docs/development/current/main/phases/phase-29ae/README.md @@ -8,6 +8,7 @@ Goal: JoinIR の最小回帰セットを SSOT として固定する。 - Pattern2 (real-world): `phase263_pattern2_*` - Pattern3 (If‑Phi, VM): `phase118_pattern3_if_sum_vm` - Pattern1 (strict shadow, VM): `phase29ao_pattern1_strict_shadow_vm` +- Pattern1 (subset reject, VM): `phase29ao_pattern1_subset_reject_extra_stmt_vm` - Pattern5 (Break, VM): `phase286_pattern5_break_vm` - Pattern6: `phase29ab_pattern6_*` - Pattern7: `phase29ab_pattern7_*` diff --git a/docs/development/current/main/phases/phase-29ao/README.md b/docs/development/current/main/phases/phase-29ao/README.md index 0b640b5b..88a447b6 100644 --- a/docs/development/current/main/phases/phase-29ao/README.md +++ b/docs/development/current/main/phases/phase-29ao/README.md @@ -127,7 +127,11 @@ Gate(SSOT): - 指示書: `docs/development/current/main/phases/phase-29ao/P20-CORELOOP-EXITMAP-COMPOSITION-SSOT-INSTRUCTIONS.md` - ねらい: Loop skeleton に対する ExitMap/Cleanup/ValueJoin の合成規約を SSOT として固定 +## P21: Pattern1 subset body is step-only(shadow adopt safety)✅ + +- 指示書: `docs/development/current/main/phases/phase-29ao/P21-PATTERN1-SUBSET-BODY-IS-STEP-ONLY-INSTRUCTIONS.md` +- ねらい: Pattern1 subset を body=step のみに引き締め、strict/dev shadow adopt の誤マッチを遮断 + ## Next(planned) -- P21: Pattern1 subset “body is step-only” hardening - - 指示書: `docs/development/current/main/phases/phase-29ao/P21-PATTERN1-SUBSET-BODY-IS-STEP-ONLY-INSTRUCTIONS.md` +- P22: TBD diff --git a/src/mir/builder/control_flow/plan/extractors/pattern1.rs b/src/mir/builder/control_flow/plan/extractors/pattern1.rs index 915c6c43..b1851ae9 100644 --- a/src/mir/builder/control_flow/plan/extractors/pattern1.rs +++ b/src/mir/builder/control_flow/plan/extractors/pattern1.rs @@ -5,6 +5,7 @@ use crate::ast::{ASTNode, BinaryOperator}; // Phase 282 P9a: Use common_helpers use super::common_helpers::has_control_flow_statement as common_has_control_flow; +use crate::mir::builder::control_flow::plan::policies::pattern1_subset_policy::is_pattern1_step_only_body; #[derive(Debug, Clone)] pub(crate) struct Pattern1Parts { @@ -200,6 +201,10 @@ pub(crate) fn extract_pattern1_plan( None => return Ok(None), // No loop increment found }; + if !is_pattern1_step_only_body(body, &parts.loop_var) { + return Ok(None); + } + Ok(Some(DomainPlan::Pattern1SimpleWhile(Pattern1SimpleWhilePlan { loop_var: parts.loop_var, condition: condition.clone(), diff --git a/src/mir/builder/control_flow/plan/facts/pattern1_simplewhile_facts.rs b/src/mir/builder/control_flow/plan/facts/pattern1_simplewhile_facts.rs index 9d46df35..d580c30b 100644 --- a/src/mir/builder/control_flow/plan/facts/pattern1_simplewhile_facts.rs +++ b/src/mir/builder/control_flow/plan/facts/pattern1_simplewhile_facts.rs @@ -6,6 +6,7 @@ use crate::mir::builder::control_flow::plan::extractors::common_helpers::{ extract_loop_increment_plan, has_break_statement, has_continue_statement, has_if_else_statement, has_return_statement, }; +use crate::mir::builder::control_flow::plan::policies::pattern1_subset_policy::is_pattern1_step_only_body; #[derive(Debug, Clone)] pub(in crate::mir::builder) struct Pattern1SimpleWhileFacts { @@ -35,6 +36,10 @@ pub(in crate::mir::builder) fn try_extract_pattern1_simplewhile_facts( _ => return Ok(None), }; + if !is_pattern1_step_only_body(body, &loop_var) { + return Ok(None); + } + if !is_increment_step_one(&loop_increment, &loop_var) { return Ok(None); } diff --git a/src/mir/builder/control_flow/plan/mod.rs b/src/mir/builder/control_flow/plan/mod.rs index a215fe89..dbd8a5e6 100644 --- a/src/mir/builder/control_flow/plan/mod.rs +++ b/src/mir/builder/control_flow/plan/mod.rs @@ -40,6 +40,8 @@ pub(in crate::mir::builder) mod composer; pub(in crate::mir::builder) mod emit; // Phase 29ai P6: Extractors moved into plan layer pub(in crate::mir::builder) mod extractors; +// Phase 29ao P21: Pattern1 subset policy (SSOT gate) +pub(in crate::mir::builder) mod policies; // Phase 29ai P5: JoinIR router → single plan extraction entrypoint pub(in crate::mir::builder) mod single_planner; diff --git a/src/mir/builder/control_flow/plan/policies/mod.rs b/src/mir/builder/control_flow/plan/policies/mod.rs new file mode 100644 index 00000000..7988b3db --- /dev/null +++ b/src/mir/builder/control_flow/plan/policies/mod.rs @@ -0,0 +1,3 @@ +//! Phase 29ao P21: Pattern1 subset policy SSOT + +pub(in crate::mir::builder) mod pattern1_subset_policy; diff --git a/src/mir/builder/control_flow/plan/policies/pattern1_subset_policy.rs b/src/mir/builder/control_flow/plan/policies/pattern1_subset_policy.rs new file mode 100644 index 00000000..b62fe37f --- /dev/null +++ b/src/mir/builder/control_flow/plan/policies/pattern1_subset_policy.rs @@ -0,0 +1,42 @@ +//! Phase 29ao P21: Pattern1 subset policy (step-only body) + +use crate::ast::{ASTNode, BinaryOperator, LiteralValue}; + +pub(crate) fn is_pattern1_step_only_body(body: &[ASTNode], loop_var: &str) -> bool { + if body.len() != 1 { + return false; + } + + let ASTNode::Assignment { target, value, .. } = &body[0] else { + return false; + }; + + let ASTNode::Variable { name, .. } = target.as_ref() else { + return false; + }; + if name != loop_var { + return false; + } + + let ASTNode::BinaryOp { + operator: BinaryOperator::Add, + left, + right, + .. + } = value.as_ref() + else { + return false; + }; + + if !matches!(left.as_ref(), ASTNode::Variable { name, .. } if name == loop_var) { + return false; + } + + matches!( + right.as_ref(), + ASTNode::Literal { + value: LiteralValue::Integer(1), + .. + } + ) +} diff --git a/tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh b/tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh index d032a6a3..f0b6c574 100644 --- a/tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh +++ b/tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh @@ -21,6 +21,7 @@ run_filter "pattern2" "phase29ab_pattern2_" || exit 1 run_filter "pattern2_realworld" "phase263_pattern2_" || exit 1 run_filter "pattern3_ifphi_vm" "phase118_pattern3_if_sum_vm" || exit 1 run_filter "pattern1_strict_shadow_vm" "phase29ao_pattern1_strict_shadow_vm" || exit 1 +run_filter "pattern1_subset_reject_extra_stmt_vm" "phase29ao_pattern1_subset_reject_extra_stmt_vm" || exit 1 run_filter "pattern5_break_vm" "phase286_pattern5_break_vm" || exit 1 run_filter "pattern6" "phase29ab_pattern6_" || exit 1 run_filter "pattern7" "phase29ab_pattern7_" || exit 1 diff --git a/tools/smokes/v2/profiles/integration/joinir/phase29ao_pattern1_subset_reject_extra_stmt_vm.sh b/tools/smokes/v2/profiles/integration/joinir/phase29ao_pattern1_subset_reject_extra_stmt_vm.sh new file mode 100644 index 00000000..1f94f62e --- /dev/null +++ b/tools/smokes/v2/profiles/integration/joinir/phase29ao_pattern1_subset_reject_extra_stmt_vm.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# phase29ao_pattern1_subset_reject_extra_stmt_vm.sh - Pattern1 subset reject extra stmt (VM) +# +# Purpose: +# - Ensure Pattern1 subset enforces "step-only body" under strict/dev shadow adopt. +# +# Expected: +# - Exit code 3 (sum increments to 3). If body is dropped, exit would be 0. + +source "$(dirname "$0")/../../../lib/test_runner.sh" +require_env || exit 2 + +FIXTURE="$NYASH_ROOT/apps/tests/phase29ao_pattern1_subset_reject_extra_stmt.hako" +RUN_TIMEOUT_SECS=${RUN_TIMEOUT_SECS:-10} + +set +e +OUTPUT=$(timeout "$RUN_TIMEOUT_SECS" env NYASH_DISABLE_PLUGINS=1 HAKO_JOINIR_STRICT=1 "$NYASH_BIN" --backend vm "$FIXTURE" 2>&1) +EXIT_CODE=$? +set -e + +if [ "$EXIT_CODE" -eq 124 ]; then + log_error "phase29ao_pattern1_subset_reject_extra_stmt_vm: hakorune timed out (>${RUN_TIMEOUT_SECS}s)" + exit 1 +fi + +if [ "$EXIT_CODE" -ne 3 ]; then + log_error "phase29ao_pattern1_subset_reject_extra_stmt_vm: expected exit code 3, got $EXIT_CODE" + echo "$OUTPUT" + exit 1 +fi + +log_success "phase29ao_pattern1_subset_reject_extra_stmt_vm: PASS (exit=3)" +exit 0