diff --git a/docs/development/current/main/10-Now.md b/docs/development/current/main/10-Now.md index 2896956e..699e3926 100644 --- a/docs/development/current/main/10-Now.md +++ b/docs/development/current/main/10-Now.md @@ -2,7 +2,10 @@ ## Current Focus: Phase 29af(Boundary Hygiene SSOT 固定) -Next: `docs/development/current/main/phases/phase-29af/P4-LAYOUT-CONSISTENCY-CONTRACT-INSTRUCTIONS.md` +**2025-12-29: Phase 29af P4 完了** ✅ +- 目的: BoundaryCarrierLayout と header PHI の同順一致を strict/dev で Fail-Fast 固定(仕様不変) +- 入口: `src/mir/builder/control_flow/joinir/merge/contract_checks/header_phi_layout.rs` +- 検証: `cargo build --release` / `./tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh` / `./tools/smokes/v2/run.sh --profile quick` PASS **2025-12-29: Phase 29af P3 完了** ✅ - 目的: carrier の順序(loop_var + carriers)を merge 側 SSOT に統合(仕様不変) diff --git a/docs/development/current/main/30-Backlog.md b/docs/development/current/main/30-Backlog.md index 86e35fc5..631c8b6d 100644 --- a/docs/development/current/main/30-Backlog.md +++ b/docs/development/current/main/30-Backlog.md @@ -8,7 +8,7 @@ Related: ## 直近(JoinIR/selfhost) -- **Phase 29af(✅ P0–P3 COMPLETE, Next: P4): Boundary hygiene / regression entrypoint / carrier layout SSOT** +- **Phase 29af(✅ P0–P4 COMPLETE): Boundary hygiene / regression entrypoint / carrier layout SSOT** - 入口: `docs/development/current/main/phases/phase-29af/README.md` - **Phase 29ae P1(✅ COMPLETE): JoinIR Regression Pack (SSOT固定)** diff --git a/docs/development/current/main/phases/phase-29af/P4-LAYOUT-CONSISTENCY-CONTRACT-INSTRUCTIONS.md b/docs/development/current/main/phases/phase-29af/P4-LAYOUT-CONSISTENCY-CONTRACT-INSTRUCTIONS.md index 34a581b4..c5316242 100644 --- a/docs/development/current/main/phases/phase-29af/P4-LAYOUT-CONSISTENCY-CONTRACT-INSTRUCTIONS.md +++ b/docs/development/current/main/phases/phase-29af/P4-LAYOUT-CONSISTENCY-CONTRACT-INSTRUCTIONS.md @@ -1,62 +1,36 @@ # Phase 29af P4: Layout Consistency Contract — Instructions Status: Ready for execution -Scope: carrier layout / header PHI の順序整合を Fail-Fast で固定(仕様不変) +Scope: BoundaryCarrierLayout と LoopHeaderPhiInfo::carrier_order の整合を Fail-Fast で固定(仕様不変) ## Goal -Phase 29af P3 で導入した `BoundaryCarrierLayout`(order SSOT)と、merge が生成する header PHI 側の order がズレた場合に、 -JoinIR merge の入口で fail-fast できる状態にする。 - -- “BTreeMapの反復順” などの偶然に依存して順序が崩れたとき、即時に検知できる -- Pattern2/6/7/phase1883 の回帰パックを壊さず、将来の refactor を安全にする +BoundaryCarrierLayout と header PHI の順序がズレたときに、merge 入口で早期に検知する。 ## Non-goals -- 既定挙動の変更(release 既定では挙動不変) +- 挙動変更(release 既定挙動の変更) - env var の追加 -- ループ仕様の拡張(PHI/edge_args の新設など) - -## SSOT - -- Carrier order SSOT: `src/mir/builder/control_flow/joinir/merge/boundary_carrier_layout.rs` -- Header PHI Entry/Latch contract: `docs/development/current/main/phases/phase-29ae/README.md` +- fixture/smoke の増加 ## Implementation Steps -### Step 1: Boundary の “layout長” を実質的なチェックに強化 +1) contract_checks にレイアウト整合性チェックを追加 + - `src/mir/builder/control_flow/joinir/merge/contract_checks/header_phi_layout.rs` + - boundary の順序と header PHI の順序が一致することを strict/dev で検証 -対象: `src/mir/builder/control_flow/joinir/merge/contract_checks/boundary_hygiene.rs` +2) merge 入口でチェックを呼ぶ + - `src/mir/builder/control_flow/joinir/merge/coordinator.rs` + - prebuild_header_phis の直後で `verify_header_phi_layout(...)` を呼ぶ -`carrier_info` があるとき: +3) boundary_hygiene を強化 + - `src/mir/builder/control_flow/joinir/merge/contract_checks/boundary_hygiene.rs` + - carrier_info の順序と BoundaryCarrierLayout の順序が同名同順で一致することを検証 -- `boundary.loop_var_name == Some(carrier_info.loop_var_name)` を要求(名前不整合を fail-fast) -- `BoundaryCarrierLayout::from_boundary(boundary).ordered_names()` が - `["loop_var", ...carrier_info.carriers]` と **同名同順** で一致することを要求 -- `boundary.join_inputs.len() == boundary.host_inputs.len() == layout.len()` を要求 - - 注: host_inputs の中身(ValueId(0) placeholder)は問わない(SkipBinding があるため) - -実行条件は既存と同じ(`joinir_strict` または `joinir_dev` のみ)。 - -### Step 2: Header PHI 側の order と BoundaryCarrierLayout を突合して fail-fast - -新規チェック(案): -- `src/mir/builder/control_flow/joinir/merge/contract_checks/header_phi_layout.rs` - - `verify_header_phi_layout(boundary: &JoinInlineBoundary, info: &LoopHeaderPhiInfo) -> Result<(), String>` - - `BoundaryCarrierLayout` の `ordered_names()` と `info.carrier_order` が一致することを要求 - -呼び出し場所(案): -- `src/mir/builder/control_flow/joinir/merge/coordinator.rs` - - `prebuild_header_phis` 後、rewrite/merge の前(info が確定した直後) - -### Step 3: docs 更新(迷子防止) - -- `docs/development/current/main/phases/phase-29af/README.md` - - P4 として “order consistency contract” を追記し、入口ファイルを列挙 -- `docs/development/current/main/10-Now.md` - - 次にやる P4 のリンクを追記 -- `docs/development/current/main/30-Backlog.md` - - Phase 29af の “Next: P4” を追記 +4) docs 更新 + - `docs/development/current/main/phases/phase-29af/README.md` + - `docs/development/current/main/10-Now.md` + - `docs/development/current/main/30-Backlog.md` ## Verification @@ -66,6 +40,6 @@ JoinIR merge の入口で fail-fast できる状態にする。 ## Acceptance Criteria -- strict/dev を有効にしたときのみ新しい fail-fast が働く(release 既定挙動は不変) -- order mismatch を意図的に作ると、P4 の tag で freeze する(診断が安定) -- 回帰パック(phase29ae entrypoint)が PASS のまま +- strict/dev でズレを Fail-Fast できる +- quick 154/154 PASS(不変) +- JoinIR regression pack が PASS diff --git a/docs/development/current/main/phases/phase-29af/P5-CLOSEOUT-INSTRUCTIONS.md b/docs/development/current/main/phases/phase-29af/P5-CLOSEOUT-INSTRUCTIONS.md new file mode 100644 index 00000000..70286e7f --- /dev/null +++ b/docs/development/current/main/phases/phase-29af/P5-CLOSEOUT-INSTRUCTIONS.md @@ -0,0 +1,46 @@ +# Phase 29af P5: Closeout — Instructions + +Status: Ready for execution +Scope: Phase 29af の成果(boundary hygiene / regression entrypoint / layout SSOT / consistency contract)を締める(仕様不変) + +## Goal + +Phase 29af (P0–P4) の SSOT と contract を “入口が迷わない状態” に確定し、JoinIR 側の回帰確認導線を固定する。 + +## Non-goals + +- 挙動変更(release 既定挙動の変更) +- env var の追加 +- fixture/smoke の増加(回帰パックは既存を使う) + +## Deliverables + +1) Phase 29af README を “Complete” にする +- `docs/development/current/main/phases/phase-29af/README.md` + - Status: P0–P4 complete + - Next: none(または次フェーズへのリンク) + - Verification は `phase29ae_regression_pack_vm.sh` 1本に収束 + +2) Now/Backlog を 29af 完了へ更新 +- `docs/development/current/main/10-Now.md` + - Current Focus: Phase 29af complete + - JoinIR 回帰確認のSSOT: `./tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh` +- `docs/development/current/main/30-Backlog.md` + - Phase 29af: ✅ COMPLETE + - 次の候補(例)を 1 行で明記(Phase 29ag など) + +3) Command SSOT の二重化を解消 +- `docs/development/current/main/phases/phase-29ae/README.md` + - Commands: entrypoint script 1本のみ + +## Verification + +- `cargo build --release` +- `./tools/smokes/v2/run.sh --profile quick` +- `./tools/smokes/v2/profiles/integration/joinir/phase29ae_regression_pack_vm.sh` + +## Acceptance Criteria + +- JoinIR 回帰確認が “1コマンド” で PASS +- quick が 154/154 PASS(不変) +- 29af の入口ドキュメントだけ見れば “どこを見れば良いか” が分かる diff --git a/docs/development/current/main/phases/phase-29af/README.md b/docs/development/current/main/phases/phase-29af/README.md index 95016bfe..3c4eb952 100644 --- a/docs/development/current/main/phases/phase-29af/README.md +++ b/docs/development/current/main/phases/phase-29af/README.md @@ -8,6 +8,7 @@ Goal: Pattern2 の boundary 情報の歪みを SSOT で整理し、将来の回 - P1: ✅ COMPLETE(merge `contract_checks` への集約) - P2: ✅ COMPLETE(JoinIR 回帰パックを 1 コマンドに収束) - P3: ✅ COMPLETE(BoundaryCarrierLayout SSOT) +- P4: ✅ COMPLETE(layout consistency contract) ## Boundary Contract (SSOT) @@ -50,13 +51,18 @@ carrier の順序(loop_var + carriers)を merge 側の SSOT に統合する - SSOT: `src/mir/builder/control_flow/joinir/merge/boundary_carrier_layout.rs` - 適用: tail_call_policy / latch_incoming_recorder の order 統一 -- contract_checks: `phase29af/boundary_hygiene/layout_len`(strict/dev のみ) +- contract_checks: `phase29af/boundary_hygiene/layout_order`(strict/dev のみ) -## P4: Layout Consistency Contract(Next) +## P4: Layout Consistency Contract -BoundaryCarrierLayout と header PHI 側の order を突合して、順序のズレを入口で fail-fast できる状態にする(仕様不変)。 +BoundaryCarrierLayout と header PHI の順序一致を strict/dev で検証する(仕様不変)。 -- 指示書: `docs/development/current/main/phases/phase-29af/P4-LAYOUT-CONSISTENCY-CONTRACT-INSTRUCTIONS.md` +- contract_checks: `src/mir/builder/control_flow/joinir/merge/contract_checks/header_phi_layout.rs` +- 配線: `src/mir/builder/control_flow/joinir/merge/coordinator.rs` + +## P5: Closeout(Next) + +P0–P4 の SSOT/contract を確定し、入口(README/Now/Backlog)を締める。 ## Verification diff --git a/src/mir/builder/control_flow/joinir/merge/boundary_carrier_layout.rs b/src/mir/builder/control_flow/joinir/merge/boundary_carrier_layout.rs index 921f95cb..44964f55 100644 --- a/src/mir/builder/control_flow/joinir/merge/boundary_carrier_layout.rs +++ b/src/mir/builder/control_flow/joinir/merge/boundary_carrier_layout.rs @@ -42,7 +42,4 @@ impl BoundaryCarrierLayout { self.ordered_names.iter().position(|n| n == name) } - pub fn len(&self) -> usize { - self.ordered_names.len() - } } diff --git a/src/mir/builder/control_flow/joinir/merge/contract_checks/boundary_hygiene.rs b/src/mir/builder/control_flow/joinir/merge/contract_checks/boundary_hygiene.rs index 8e9f51a8..5a260a3b 100644 --- a/src/mir/builder/control_flow/joinir/merge/contract_checks/boundary_hygiene.rs +++ b/src/mir/builder/control_flow/joinir/merge/contract_checks/boundary_hygiene.rs @@ -38,17 +38,19 @@ pub(in crate::mir::builder::control_flow::joinir::merge) fn verify_boundary_hygi } if let Some(carrier_info) = &boundary.carrier_info { - let expected_len = - carrier_info.carriers.len() + if boundary.loop_var_name.is_some() { 1 } else { 0 }; - let layout_len = BoundaryCarrierLayout::from_boundary(boundary).len(); - if expected_len != layout_len { + let expected_names: Vec<&str> = std::iter::once(carrier_info.loop_var_name.as_str()) + .chain(carrier_info.carriers.iter().map(|c| c.name.as_str())) + .collect(); + let layout = BoundaryCarrierLayout::from_boundary(boundary); + let layout_names = layout.ordered_names(); + if expected_names != layout_names { return Err(error_tags::freeze_with_hint( - "phase29af/boundary_hygiene/layout_len", + "phase29af/boundary_hygiene/layout_order", &format!( - "boundary carrier layout len {} does not match carrier_info len {}", - layout_len, expected_len + "boundary carrier order {:?} does not match carrier_info order {:?}", + layout_names, expected_names ), - "ensure loop_var + carriers ordering is consistent with carrier_info", + "ensure boundary carrier order matches carrier_info", )); } diff --git a/src/mir/builder/control_flow/joinir/merge/contract_checks/header_phi_layout.rs b/src/mir/builder/control_flow/joinir/merge/contract_checks/header_phi_layout.rs new file mode 100644 index 00000000..50f4ca59 --- /dev/null +++ b/src/mir/builder/control_flow/joinir/merge/contract_checks/header_phi_layout.rs @@ -0,0 +1,39 @@ +use crate::mir::builder::control_flow::joinir::merge::boundary_carrier_layout::BoundaryCarrierLayout; +use crate::mir::builder::control_flow::joinir::merge::loop_header_phi_info::LoopHeaderPhiInfo; +use crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary; + +/// Phase 29af P4: Verify boundary carrier order matches header PHI order. +pub(in crate::mir::builder::control_flow::joinir::merge) fn verify_header_phi_layout( + boundary: &JoinInlineBoundary, + loop_header_phi_info: &LoopHeaderPhiInfo, +) -> Result<(), String> { + use crate::mir::join_ir::lowering::error_tags; + + let strict = crate::config::env::joinir_strict_enabled() + || crate::config::env::joinir_dev_enabled(); + if !strict { + return Ok(()); + } + + let boundary_layout = BoundaryCarrierLayout::from_boundary(boundary); + let boundary_names = boundary_layout.ordered_names(); + + let header_names: Vec<&str> = loop_header_phi_info + .carrier_order + .iter() + .map(|name| name.as_str()) + .collect(); + + if boundary_names != header_names { + return Err(error_tags::freeze_with_hint( + "phase29af/layout/header_phi_order", + &format!( + "boundary carrier order {:?} does not match header PHI order {:?}", + boundary_names, header_names + ), + "ensure boundary carrier layout matches header PHI construction order", + )); + } + + Ok(()) +} diff --git a/src/mir/builder/control_flow/joinir/merge/contract_checks/mod.rs b/src/mir/builder/control_flow/joinir/merge/contract_checks/mod.rs index 950883db..1719baf5 100644 --- a/src/mir/builder/control_flow/joinir/merge/contract_checks/mod.rs +++ b/src/mir/builder/control_flow/joinir/merge/contract_checks/mod.rs @@ -15,6 +15,7 @@ mod exit_bindings; mod carrier_inputs; mod boundary_creation; mod boundary_hygiene; +mod header_phi_layout; mod entry_params; mod entry_like_policy; @@ -23,6 +24,7 @@ pub(super) use terminator_targets::verify_all_terminator_targets_exist; pub(super) use exit_bindings::verify_exit_bindings_have_exit_phis; pub(super) use carrier_inputs::verify_carrier_inputs_complete; pub(super) use boundary_hygiene::verify_boundary_hygiene; +pub(super) use header_phi_layout::verify_header_phi_layout; pub(super) use entry_like_policy::is_entry_like_source; pub(in crate::mir::builder::control_flow::joinir) use boundary_creation::verify_boundary_contract_at_creation; pub(in crate::mir::builder::control_flow::joinir) use entry_params::run_all_pipeline_checks; diff --git a/src/mir/builder/control_flow/joinir/merge/coordinator.rs b/src/mir/builder/control_flow/joinir/merge/coordinator.rs index 7e66b6e7..a9a12c1d 100644 --- a/src/mir/builder/control_flow/joinir/merge/coordinator.rs +++ b/src/mir/builder/control_flow/joinir/merge/coordinator.rs @@ -224,6 +224,9 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks( &function_params, debug, )?; + if let Some(boundary) = boundary { + contract_checks::verify_header_phi_layout(boundary, &loop_header_phi_info)?; + } // Phase 3: Remap ValueIds (with reserved PHI dsts protection) // Phase 287 P0.2: Delegated to value_remapper module