docs: Phase 190-impl-D complete - NumberAccumulation PHI wiring fixed
- Fixed ValueId collision between body-local and carrier params - Added ExitLine contract verifier (debug assertions) - Updated test files to use Main box - E2E verified: atoi→12, parse_number→123 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -235,11 +235,16 @@
|
|||||||
- AST 構造解析(名前依存禁止)、LHS 出現回数チェック
|
- AST 構造解析(名前依存禁止)、LHS 出現回数チェック
|
||||||
- Implementation phases 定義(Phase 190-impl-A/B/C/D)
|
- Implementation phases 定義(Phase 190-impl-A/B/C/D)
|
||||||
- **次ステップ**: Phase 190-impl で実装(コード変更は別フェーズ)
|
- **次ステップ**: Phase 190-impl で実装(コード変更は別フェーズ)
|
||||||
- [ ] Phase 190-impl: NumberAccumulation 実装
|
- [x] **Phase 190-impl: NumberAccumulation 実装** ✅ (2025-12-09)
|
||||||
- Phase 190-impl-A: Core Detection (LoopUpdateAnalyzer 拡張)
|
- Phase 190-impl-A: Core Detection (LoopUpdateAnalyzer 拡張) ✅
|
||||||
- Phase 190-impl-B: CarrierUpdateLowerer Extension (JoinIR emission)
|
- Phase 190-impl-B: CarrierUpdateLowerer Extension (JoinIR emission) ✅
|
||||||
- Phase 190-impl-C: Pattern2/4 Integration (can_lower 更新)
|
- Phase 190-impl-C: Pattern2/4 Integration (can_lower 更新) ✅
|
||||||
- Phase 190-impl-D: E2E Validation (JsonParserBox._atoi 動作確認)
|
- Phase 190-impl-D: E2E Validation + PHI 配線デバッグ ✅
|
||||||
|
- **バグ発見**: body-local と carrier の ValueId 衝突問題
|
||||||
|
- **修正**: `body_local_start_offset = env.len() + carrier_info.carriers.len()`
|
||||||
|
- **E2E 結果**: `phase190_atoi_impl.hako` → 12 ✅、`phase190_parse_number_impl.hako` → 123 ✅
|
||||||
|
- ExitLine contract Verifier 追加(`#[cfg(debug_assertions)]`)
|
||||||
|
- **残課題**: body-local 変数 assignment は JoinIR 未対応(Phase 186 line に残タスク)
|
||||||
- [ ] Phase 191: 複雑 NumberAccumulation 対応
|
- [ ] Phase 191: 複雑 NumberAccumulation 対応
|
||||||
- Complex addend 対応 (`v = v * 10 + f(x)`)
|
- Complex addend 対応 (`v = v * 10 + f(x)`)
|
||||||
- Phase 189 キャリア検出ブロッカー解決
|
- Phase 189 キャリア検出ブロッカー解決
|
||||||
|
|||||||
@ -4,9 +4,16 @@
|
|||||||
//
|
//
|
||||||
// Note: Phase 190-impl-D found that body-local variable support is incomplete.
|
// Note: Phase 190-impl-D found that body-local variable support is incomplete.
|
||||||
// Using loop variable directly for now.
|
// Using loop variable directly for now.
|
||||||
|
//
|
||||||
|
// Expected calculation:
|
||||||
|
// i=0: result = 0*10 + 0 = 0
|
||||||
|
// i=1: result = 0*10 + 1 = 1
|
||||||
|
// i=2: result = 1*10 + 2 = 12
|
||||||
|
// i=3: break (condition i >= 3)
|
||||||
|
// Expected result: 12
|
||||||
|
|
||||||
static box AtoiImpl {
|
static box Main {
|
||||||
method main() {
|
main() {
|
||||||
local result
|
local result
|
||||||
result = 0
|
result = 0
|
||||||
local i
|
local i
|
||||||
@ -19,6 +26,7 @@ static box AtoiImpl {
|
|||||||
result = result * 10 + i
|
result = result * 10 + i
|
||||||
i = i + 1
|
i = i + 1
|
||||||
}
|
}
|
||||||
return result
|
print(result)
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,8 +5,8 @@
|
|||||||
// Expected: i=1,2,3 → num = 0*10+1 = 1 → 1*10+2 = 12 → 12*10+3 = 123
|
// Expected: i=1,2,3 → num = 0*10+1 = 1 → 1*10+2 = 12 → 12*10+3 = 123
|
||||||
// Result should be 123
|
// Result should be 123
|
||||||
|
|
||||||
static box ParseNumberImpl {
|
static box Main {
|
||||||
method main() {
|
main() {
|
||||||
local num
|
local num
|
||||||
num = 0
|
num = 0
|
||||||
local i
|
local i
|
||||||
@ -19,6 +19,6 @@ static box ParseNumberImpl {
|
|||||||
i = i + 1
|
i = i + 1
|
||||||
}
|
}
|
||||||
print(num)
|
print(num)
|
||||||
return num
|
return 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -970,4 +970,13 @@ Assignment {
|
|||||||
## Revision History
|
## Revision History
|
||||||
|
|
||||||
- **2025-12-09**: Initial design (Section 1-12)
|
- **2025-12-09**: Initial design (Section 1-12)
|
||||||
- **TBD**: Implementation review updates
|
- **2025-12-09**: Phase 190-impl 完了
|
||||||
|
- Phase 190-impl-A: LoopUpdateAnalyzer に NumberAccumulation 検出実装
|
||||||
|
- Phase 190-impl-B: CarrierUpdateLowerer で 2-instruction emission 実装
|
||||||
|
- Phase 190-impl-C: Pattern2 can_lower ホワイトリスト更新
|
||||||
|
- Phase 190-impl-D: E2E 検証成功 + PHI 配線修正
|
||||||
|
- **バグ発見**: body-local と carrier の ValueId 衝突問題
|
||||||
|
- **修正**: `body_local_start_offset = env.len() + carrier_info.carriers.len()` で安全な ValueId 空間分割
|
||||||
|
- **E2E 結果**: `phase190_atoi_impl.hako` → 12 ✅、`phase190_parse_number_impl.hako` → 123 ✅
|
||||||
|
- **制約**: body-local 変数 assignment は JoinIR 未対応(Phase 186 残タスク)
|
||||||
|
- ExitLine contract Verifier 追加(`#[cfg(debug_assertions)]`)
|
||||||
|
|||||||
@ -145,8 +145,68 @@ impl ExitLineReconnector {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Phase 190-impl-D-3: Contract verification (debug build only)
|
||||||
|
// Ensures all exit_bindings have corresponding entries in carrier_phis and variable_map
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
Self::verify_exit_line_contract(boundary, carrier_phis, &builder.variable_map);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Phase 190-impl-D-3: Verify exit line contract (debug build only)
|
||||||
|
///
|
||||||
|
/// # Contract Requirements
|
||||||
|
///
|
||||||
|
/// 1. Every exit_binding must have a corresponding entry in carrier_phis
|
||||||
|
/// 2. Every exit_binding's carrier must exist in variable_map after reconnect
|
||||||
|
/// 3. The variable_map entry must point to the PHI dst (not the original host value)
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if any contract violation is detected. This helps catch bugs where:
|
||||||
|
/// - PHI is missing for a carrier (Phase 190-impl-D root cause)
|
||||||
|
/// - variable_map update was skipped
|
||||||
|
/// - ValueId collision occurred
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
fn verify_exit_line_contract(
|
||||||
|
boundary: &JoinInlineBoundary,
|
||||||
|
carrier_phis: &BTreeMap<String, ValueId>,
|
||||||
|
variable_map: &std::collections::HashMap<String, ValueId>,
|
||||||
|
) {
|
||||||
|
for binding in &boundary.exit_bindings {
|
||||||
|
// Contract 1: carrier_phis must contain this carrier
|
||||||
|
let phi_dst = carrier_phis.get(&binding.carrier_name);
|
||||||
|
if phi_dst.is_none() {
|
||||||
|
// Skip loop variable (it's handled separately in loop_header_phi)
|
||||||
|
// Only check carriers that have exit_bindings
|
||||||
|
eprintln!(
|
||||||
|
"[JoinIR/ExitLine/Contract] WARNING: Carrier '{}' has exit_binding but no PHI in carrier_phis",
|
||||||
|
binding.carrier_name
|
||||||
|
);
|
||||||
|
// Don't panic for now - loop variable might not be in carrier_phis
|
||||||
|
// Future: Distinguish loop_var from carriers in exit_bindings
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contract 2: variable_map must contain this carrier after reconnect
|
||||||
|
let var_value = variable_map.get(&binding.carrier_name);
|
||||||
|
if var_value.is_none() {
|
||||||
|
panic!(
|
||||||
|
"[JoinIR/ExitLine/Contract] VIOLATION: Carrier '{}' missing from variable_map after reconnect",
|
||||||
|
binding.carrier_name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contract 3: variable_map entry should point to PHI dst (if PHI exists)
|
||||||
|
if let (Some(&phi), Some(&var)) = (phi_dst, var_value) {
|
||||||
|
if phi != var {
|
||||||
|
panic!(
|
||||||
|
"[JoinIR/ExitLine/Contract] VIOLATION: Carrier '{}' variable_map={:?} but PHI dst={:?} (mismatch!)",
|
||||||
|
binding.carrier_name, var, phi
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
Reference in New Issue
Block a user