Extended PatternPipelineContext and CarrierUpdateInfo for Pattern 3 AST-based generalization. Changes: 1. PatternPipelineContext: - Added loop_condition: Option<ASTNode> - Added loop_body: Option<Vec<ASTNode>> - Added loop_update_summary: Option<LoopUpdateSummary> - Updated build_pattern_context() for Pattern 3 2. CarrierUpdateInfo: - Added then_expr: Option<ASTNode> - Added else_expr: Option<ASTNode> - Updated analyze_loop_updates() with None defaults Status: Phase 213-2 Steps 2-2 & 2-3 complete Next: Create Pattern3IfAnalyzer to extract if statement and populate update summary
11 KiB
Phase 213: Pattern3 Lowerer 汎用化(if-sum minimal)
Phase: 213 Date: 2025-12-09 Status: 🚧 In Progress Prerequisite: Phase 212.5 完了(構造ベース if 検出 + Pattern 3 routing)
🎯 Phase 213 の目的
Phase 212.5 で正しく Pattern 3 にルーティングされるようになった phase212_if_sum_min.hako を、JoinIR Pattern 3(If-PHI)で正しく実行できるようにする。
問題: 現在の Pattern 3 lowerer は test-only PoC 実装
- Loop condition:
i <= 5(hardcoded) - If condition:
i % 2 == 1(hardcoded) - Update logic:
sum + i(hardcoded)
目標: AST-based 汎用 Pattern 3 lowerer の実装
- LoopUpdateSummary / CarrierInfo / BoolExprLowerer ベースの汎用実装
phase212_if_sum_min.hakoで RC=2 達成- 既存パターン(
loop_if_phi.hako等)の後方互換維持
📋 現状の Pattern 3 実装の問題点
1. ハードコードされた条件・更新式
Loop condition (loop_with_if_phi_minimal.rs):
// Hardcoded: i <= 5
let loop_cond_value = /* ... */;
If condition:
// Hardcoded: i % 2 == 1
let if_cond = /* modulo operation */;
Update expressions:
// Hardcoded: sum = sum + i, count = count + 1
let sum_update = /* sum + i */;
let count_update = /* count + 1 */;
2. テスト専用の ValueId マッピング
const PATTERN3_K_EXIT_SUM_FINAL_ID: ValueId = ValueId(24);
const PATTERN3_K_EXIT_COUNT_FINAL_ID: ValueId = ValueId(25);
これらは特定のテストケース用に固定されており、異なる carrier 構成には対応できない。
3. 汎用性の欠如
phase212_if_sum_min.hakoのような実際の if-sum パターンが動かない- Carrier 構成が変わると動作しない
- If 条件が変わると対応できない
🏗️ 新しい入力情報アーキテクチャ
入力: PatternPipelineContext
Phase 213 では、以下の情報を利用して汎用的な lowering を実現:
1. LoopFeatures (from pattern_pipeline.rs)
has_if: Loop body に if 文が存在するかhas_if_else_phi: PHI merge が必要な if-else かcarrier_count: Carrier 変数の数
2. CarrierInfo
- Carrier 変数のリスト(名前、host_id、join_id)
- 各 carrier の UpdateKind(CounterLike, AccumulationLike, etc.)
3. LoopUpdateSummary
pub struct LoopUpdateSummary {
pub updates: Vec<CarrierUpdateInfo>, // 各 carrier の更新情報
}
pub struct CarrierUpdateInfo {
pub carrier_name: String,
pub update_kind: UpdateKind,
pub then_expr: Option<ASTNode>, // then branch update
pub else_expr: Option<ASTNode>, // else branch update
}
4. BoolExprLowerer / condition_to_joinir
- 任意の bool 条件を JoinIR に変換
- 既存の
condition_to_joinir()関数を活用
5. ConditionEnv / JoinValueSpace
- Variable → ValueId マッピング
- ValueId allocation 管理
🔄 目標となる変換フロー
Phase 213 汎用 Lowering Pipeline
Input: PatternPipelineContext
├─ loop_condition: ASTNode (e.g., "i < 3")
├─ loop_body: Vec<ASTNode> (contains if statement)
├─ CarrierInfo (e.g., [i, sum])
└─ LoopUpdateSummary (e.g., sum: then=sum+1, else=sum+0)
Step 1: Loop Condition Lowering
loop_condition AST → BoolExprLowerer
→ JoinIR loop_cond: ValueId
Step 2: Extract If Statement from Loop Body
Find ASTNode::If in loop_body
→ if_condition: ASTNode (e.g., "i > 0")
→ then_body: Vec<ASTNode>
→ else_body: Option<Vec<ASTNode>>
Step 3: If Condition Lowering
if_condition AST → BoolExprLowerer
→ JoinIR if_cond: ValueId
Step 4: Carrier Update Lowering (from LoopUpdateSummary)
For each carrier in CarrierInfo:
- Get then_expr from LoopUpdateSummary
- Get else_expr from LoopUpdateSummary
- Lower then_expr → JoinIR then_value: ValueId
- Lower else_expr → JoinIR else_value: ValueId
- Generate PHI: carrier_new = phi [then_value, else_value]
Step 5: JoinIR Function Generation
- entry(): Initialize carriers
- loop_step(i, carrier1, carrier2, ...):
if if_cond:
then_branch → update carriers (then values)
else:
else_branch → update carriers (else values)
PHI merge → carrier_new values
next iteration or exit
- k_exit(carrier1_final, carrier2_final, ...): Return final values
Step 6: ExitMeta Construction
ExitMeta {
carriers: [
{ name: "sum", join_id: ValueId(X), host_slot: ValueId(Y) },
...
]
}
Output: (JoinModule, ExitMeta)
🚨 Fail-Fast ポリシー
対応外パターンの明示的エラー
Pattern 3 lowerer は以下の場合に 明示的にエラーを返す:
1. LoopUpdateSummary 不整合
if carrier.then_expr.is_none() || carrier.else_expr.is_none() {
return Err(JoinIrError::UnsupportedPattern {
reason: format!("Carrier '{}' missing then/else update", carrier.name)
});
}
2. UpdateKind 未対応
match carrier.update_kind {
UpdateKind::Complex | UpdateKind::Unknown => {
return Err(JoinIrError::UnsupportedPattern {
reason: format!("Carrier '{}' has unsupported UpdateKind: {:?}",
carrier.name, carrier.update_kind)
});
}
_ => { /* OK */ }
}
3. If 構造不整合
if loop_body.iter().filter(|n| matches!(n, ASTNode::If { .. })).count() != 1 {
return Err(JoinIrError::UnsupportedPattern {
reason: "Pattern 3 requires exactly one if statement in loop body".to_string()
});
}
禁止事項:
- ❌ Silent fallback to Pattern 1
- ❌ Default values for missing updates
- ❌ Ignoring unsupported UpdateKind
原則: すべての制約は明示的エラーで通知(Fail-Fast)
📐 設計の核心アイデア
1. 入力を「箱」として分離
現状: ハードコードされた値が scattered Phase 213: 入力情報を構造化された箱から取得
// Before (Phase 195)
const LOOP_BOUND: i64 = 5; // Hardcoded
const IF_MODULO: i64 = 2; // Hardcoded
// After (Phase 213)
let loop_cond = ctx.loop_condition; // From PatternPipelineContext
let if_cond = extract_if_condition(&ctx.loop_body)?; // From AST
let updates = ctx.loop_update_summary; // From LoopUpdateSummary
2. Lowering を既存箱に委譲
BoolExprLowerer: Bool condition → JoinIR
let loop_cond_value = condition_to_joinir(
loop_cond,
&condition_env,
&mut join_value_space
)?;
CarrierUpdateEmitter: Update expression → JoinIR
let then_value = emit_carrier_update_with_env(
carrier.then_expr,
&update_env,
&mut join_value_space
)?;
3. ExitMeta で複数 Carrier を統一的に扱う
現状: 固定 ValueId の const 定義 Phase 213: ExitMeta に動的登録
// Before
exit_bindings.push(LoopExitBinding {
carrier_name: "sum".to_string(),
join_exit_value: PATTERN3_K_EXIT_SUM_FINAL_ID, // Hardcoded!
host_slot: sum_var_id,
});
// After
for carrier in carrier_info.carriers.iter() {
exit_bindings.push(LoopExitBinding {
carrier_name: carrier.name.clone(),
join_exit_value: carrier.join_final_id, // From JoinIR generation
host_slot: carrier.host_id,
});
}
🔧 実装の構造
Target Files
1. JoinIR Lowerer
src/mir/join_ir/lowering/loop_with_if_phi_minimal.rs- 変更内容:
- ハードコード削除
- PatternPipelineContext からの入力受け取り
- BoolExprLowerer / CarrierUpdateEmitter への委譲
2. Pattern 3 Entry Point
src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs- 変更内容:
- PatternPipelineContext の構築
- ExitMeta の動的構築
- Fail-Fast エラーハンドリング
Signature Changes
Before (Phase 195):
pub fn lower_loop_with_if_phi_pattern(
scope: LoopScopeShape,
join_value_space: &mut JoinValueSpace,
) -> Option<JoinModule>
After (Phase 213):
pub fn lower_loop_with_if_phi_pattern(
ctx: &PatternPipelineContext,
join_value_space: &mut JoinValueSpace,
) -> Result<(JoinModule, ExitMeta), JoinIrError>
変更点:
- 入力:
LoopScopeShape→PatternPipelineContext - 戻り値:
Option<JoinModule>→Result<(JoinModule, ExitMeta), JoinIrError> - ExitMeta を返して動的 exit binding を可能に
✅ 検証計画
Test Case 1: phase212_if_sum_min.hako(主目標)
Input:
loop(i < 3) {
if i > 0 {
sum = sum + 1
}
i = i + 1
}
Expected:
- RC: 2
- Pattern: Pattern 3 (If-Else PHI)
- Carriers:
i(CounterLike),sum(AccumulationLike) - Trace:
[joinir/pattern3] Generated JoinIR for Loop with If-Else PHI
Test Case 2: loop_if_phi.hako(後方互換)
既存の Phase 195 テストケース:
loop(i < 5) {
if i % 2 == 1 {
sum = sum + i
} else {
sum = sum + 0
}
i = i + 1
}
Expected:
- 既存と同じ出力・RC
- Regression なし
Test Case 3: Multi-carrier Phase 195 tests
Phase 195 で追加された multi-carrier tests:
- sum + count の 2-carrier
- sum + count + index の 3-carrier (if exists)
Expected:
- 既存と同じ挙動
- ExitMeta が複数 carrier を正しく処理
📊 Phase 213 タスクチェックリスト
- Task 213-1: 設計ドキュメント作成 ✅ (this file)
- Task 213-2: Pattern3 Lowerer 本体リファクタリング
- Step 2-1: ハードコード削除
- Step 2-2: 入力を Context ベースに変更
- Step 2-3: 条件 lowering を BoolExprLowerer に委譲
- Step 2-4: キャリア更新の一般化
- Step 2-5: PHI 生成
- Step 2-6: 戻り値と boundary 連携
- Task 213-3: Fail-Fast 条件の明確化
- Task 213-4: テスト & 検証
- phase212_if_sum_min.hako → RC=2
- loop_if_phi.hako → Regression check
- Multi-carrier tests → Regression check
- Task 213-5: ドキュメント更新
- phase212-if-sum-impl.md
- joinir-architecture-overview.md
- CURRENT_TASK.md
🎯 Success Criteria
Phase 213 is complete when:
- ✅
phase212_if_sum_min.hakoproduces RC=2 - ✅ All existing Pattern 3 tests pass (no regression)
- ✅ No hardcoded conditions/updates in Pattern 3 lowerer
- ✅ Fail-Fast errors for unsupported patterns
- ✅ Documentation updated (3 files)
Commit message format:
feat(joinir): Phase 213 Pattern3 AST-based generalization
Phase 213 で Pattern3 lowerer を AST-based 汎用実装に書き換え。
phase212_if_sum_min.hako が RC=2 で正常動作。
- Removed hardcoded conditions/updates
- Integrated BoolExprLowerer for dynamic condition lowering
- Generalized carrier update via LoopUpdateSummary
- Dynamic ExitMeta construction for multi-carrier support
- Fail-Fast for unsupported patterns
Phase 213: READY TO START 🚀