Files
hakorune/docs/development/current/main/phases/phase-131/p1.5-implementation-guide.md

323 lines
9.3 KiB
Markdown
Raw Normal View History

# Phase 131 P1.5: Implementation Guide (Quick Reference)
Status: Implementation Guide
Scope: Step-by-step implementation instructions for Option B
Related:
- Root Cause: `p1.5-root-cause-summary.md`
- Design: `p1.5-option-b-analysis.md`
## Implementation Sequence
### Step 1: Create ExitReconnectorBox (New File)
**File**: `src/mir/control_tree/normalized_shadow/exit_reconnector.rs`
**Responsibility**: Generate host variable bindings from k_exit env parameters (Normalized IR only, PHI-free)
**API**:
```rust
pub struct ExitReconnectorBox;
impl ExitReconnectorBox {
/// Reconnect k_exit env parameters to host variable_map
///
/// For Normalized IR only: k_exit env params are SSOT for final values
pub fn reconnect(
builder: &mut MirBuilder,
exit_meta: &ExitMeta,
env_layout: &EnvLayout,
debug: bool,
) -> Result<(), String> {
// For each exit_value (var_name, k_exit_param_vid)
// - k_exit_param_vid is already the final value (SSOT)
// - Update builder.variable_ctx.variable_map[var_name] = k_exit_param_vid
//
// Strict mode: verify all env_layout.writes are in exit_meta
//
// Returns: Ok(()) on success, Err(msg) on contract violation
}
}
```
**Algorithm**:
```rust
// 1. Validate (strict mode only)
if strict_enabled() {
for var in &env_layout.writes {
if !exit_meta.exit_values.iter().any(|(name, _)| name == var) {
return Err(freeze_with_hint(
"phase131/exit_reconnect/missing",
&format!("Variable '{}' in writes but not in k_exit env", var),
"Ensure env_layout.writes matches k_exit parameter list (SSOT)"
));
}
}
}
// 2. Update variable_map directly (no PHI)
for (var_name, k_exit_param_vid) in &exit_meta.exit_values {
// k_exit_param_vid is the final value (SSOT)
builder.variable_ctx.variable_map.insert(
var_name.clone(),
*k_exit_param_vid
);
if debug {
eprintln!(
"[phase131/exit_reconnect] {} → {:?}",
var_name, k_exit_param_vid
);
}
}
```
**File Template**:
```rust
//! Phase 131 P1.5: ExitReconnectorBox - Normalized Exit Reconnection
//!
//! ## Responsibility
//!
//! - Wire k_exit env parameters to host variable_map (Normalized IR only)
//! - PHI-free: k_exit env params are SSOT for final values
//! - Fail-Fast: Strict mode catches contract violations
//!
//! ## Contract
//!
//! - Only used for Normalized shadow path
//! - k_exit env parameters represent final variable values (SSOT)
//! - No PHI generation (direct variable_map update)
//!
//! ## Design Philosophy
//!
//! Normalized IR uses continuation-based control flow:
//! - main(env) → loop_step(env) → loop_body(env) → k_exit(env)
//! - k_exit receives final env state as parameters
//! - No loop back edges, no PHI merging needed
//! - k_exit env params ARE the truth (SSOT)
use crate::mir::builder::MirBuilder;
use crate::mir::control_tree::normalized_shadow::env_layout::EnvLayout;
use crate::mir::join_ir::lowering::carrier_info::ExitMeta;
use crate::mir::join_ir::lowering::error_tags;
pub struct ExitReconnectorBox;
impl ExitReconnectorBox {
// ... implementation here ...
}
#[cfg(test)]
mod tests {
// ... tests here ...
}
```
### Step 2: Update routing.rs (Bypass Merge Pipeline)
**File**: `src/mir/builder/control_flow/joinir/routing.rs`
**Location**: Lines 441-532 (current Normalized shadow handling)
**Changes**:
1. **Add env_layout to JoinFragmentMeta** (if not already there)
2. **Detect Normalized shadow path**
3. **Use ExitReconnectorBox instead of merge pipeline**
**Code Change**:
```rust
// Around line 441
match StepTreeNormalizedShadowLowererBox::try_lower_if_only(&tree, &available_inputs) {
Ok(Some((join_module, join_meta))) => {
// ... existing trace ...
// Phase 131 P1.5: Normalized-specific exit reconnection
// Bypass PHI-based merge pipeline, use direct env→host wiring
use crate::mir::control_tree::normalized_shadow::exit_reconnector::ExitReconnectorBox;
use crate::mir::control_tree::normalized_shadow::env_layout::EnvLayout;
// Build env_layout from contract (or get from join_meta if available)
let env_layout = EnvLayout::from_contract(&tree.contract, &available_inputs);
// Direct reconnection (no PHI)
ExitReconnectorBox::reconnect(
self,
&join_meta.exit_meta,
&env_layout,
debug,
)?;
trace::trace().routing(
"router/normalized",
func_name,
"Normalized exit reconnection complete (PHI-free)",
);
// Return void constant (loop executed successfully)
// Note: If k_exit returns a value, use that instead
use crate::mir::{ConstValue, MirInstruction};
let void_id = self.next_value_id();
self.emit_instruction(MirInstruction::Const {
dst: void_id,
value: ConstValue::Void,
})?;
Ok(Some(void_id))
}
Ok(None) => {
// ... existing fallback ...
}
Err(e) => {
// ... existing error handling ...
}
}
```
**Note**: Remove the existing `ExitMetaCollector::collect()` and `JoinIRConversionPipeline::execute()` calls - those are for standard loops with PHI.
### Step 3: Update mod.rs (Export ExitReconnectorBox)
**File**: `src/mir/control_tree/normalized_shadow/mod.rs`
**Add**:
```rust
pub mod exit_reconnector;
pub use exit_reconnector::ExitReconnectorBox;
```
### Step 4: Testing
#### Unit Tests (in exit_reconnector.rs)
```rust
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty_writes() {
// When env_layout.writes is empty
// Should return Ok(()) without updating variable_map
}
#[test]
fn test_single_write() {
// When env_layout.writes = ["x"]
// And exit_meta.exit_values = [("x", ValueId(6))]
// Should update variable_map["x"] = ValueId(6)
}
#[test]
#[should_panic]
fn test_missing_variable_strict() {
// When strict mode enabled
// And env_layout.writes = ["x", "y"]
// But exit_meta.exit_values = [("x", ValueId(6))]
// Should panic with freeze_with_hint
}
}
```
#### Integration Tests
1. **VM Smoke**:
```bash
bash tools/smokes/v2/profiles/integration/apps/phase131_loop_true_break_once_vm.sh
```
Expected: `[PASS] Output verified: 1 (exit code: 1)`
2. **LLVM EXE Smoke**:
```bash
bash tools/smokes/v2/profiles/integration/apps/phase131_loop_true_break_once_llvm_exe.sh
```
Expected: `[PASS] Output verified: 1`
3. **Regression**:
```bash
# If-only patterns (Phase 130)
bash tools/smokes/v2/profiles/integration/apps/phase130_if_only_post_if_add_vm.sh
# Existing JoinIR patterns (Phase 97)
bash tools/smokes/v2/profiles/integration/apps/phase97_next_non_ws_llvm_exe.sh
```
Expected: All PASS (既定挙動不変)
### Step 5: Verification Checklist
Before committing:
- [ ] `cargo build --release` → 0 errors
- [ ] `cargo test --lib` → all tests pass
- [ ] Phase 131 VM smoke → PASS
- [ ] Phase 131 LLVM EXE smoke → PASS
- [ ] Phase 130 regression → PASS
- [ ] Phase 97 regression → PASS
## Commit Sequence
### Commit 1: Create ExitReconnectorBox
```
feat(normalized): Phase 131 P1.5 ExitReconnectorBox for host variable propagation
- Add exit_reconnector.rs with pure function design
- Wire k_exit env params to host variable_map (PHI-free)
- Strict mode verifier for contract violations
- Unit tests for empty/single/multiple writes
```
### Commit 2: Update Routing
```
fix(joinir/dev): bypass PHI generation for Normalized path
- Detect Normalized shadow in routing.rs
- Use ExitReconnectorBox instead of merge pipeline
- Direct env→host wiring (no PHI generation)
- Existing patterns (Pattern 1-4) unaffected
```
### Commit 3: Enable Tests
```
test(joinir): Phase 131 P1.5 enforce return parity (VM + LLVM EXE)
- Enable phase131 VM/LLVM EXE smokes
- Verify regression tests (phase130, phase97)
- Update test expectations
```
### Commit 4: Documentation
```
docs: Phase 131 P1.5 DONE (Normalized exit reconnection via Option B)
- Update 10-Now.md with completion status
- Update phase-131/README.md with P1.5 summary
- Add root cause analysis docs
```
## Common Pitfalls to Avoid
1. **Don't touch merge pipeline**: Standard loops (Pattern 1-4) still use it
2. **Don't generate PHI**: Normalized IR is PHI-free by design
3. **Don't forget strict mode**: Contract violations should freeze
4. **Don't skip regression tests**: 既定挙動不変 is critical
## Key Principles (SSOT)
1. **PHI禁止維持**: Normalized IR never generates PHI nodes
2. **既定挙動不変**: Standard patterns use existing merge pipeline
3. **責務分離**: ExitReconnectorBox handles Normalized-specific wiring
4. **箱化モジュール化**: New logic in dedicated box
5. **Fail-Fast**: Strict mode catches violations immediately
## Success Criteria
- [ ] loop(true) { x=1; break }; return x → returns 1 (not 0)
- [ ] VM and LLVM EXE both produce same result
- [ ] No regression in existing patterns
- [ ] Clean trace output (no PHI errors)
- [ ] Strict mode catches contract violations
## Reference
- Root Cause: `p1.5-root-cause-summary.md`
- Design Rationale: `p1.5-option-b-analysis.md`
- Phase 131 Overview: `README.md`