Files
hakorune/docs/development/current/main/phase84-2-case-d-investigation.md
nyash-codex 4ef5eec162 feat(mir): Phase 84-2 CopyTypePropagator for Copy chain type propagation
- Add CopyTypePropagator box (ChatGPT Pro design) for fixed-point
  Copy instruction type propagation
- Integrate into lifecycle.rs before return type inference
- Case D reduced from 12 to 9 (25% reduction)

Implementation:
- src/mir/phi_core/copy_type_propagator.rs: New box with fixed-point loop
- src/mir/phi_core/mod.rs: Add module export
- src/mir/builder/lifecycle.rs: Call propagator before return inference

Test results:
- Baseline: 494 passed, 33 failed (was 489/34)
- Case D: 9 remaining (from 12)
- Unit tests: 4/4 passed

Remaining 9 Case D breakdown:
- GroupA: Loop Edge Copy (7 cases) - PHI incoming needs Copy trace
- GroupB: Multi-level PHI (2 cases) - Recursive PHI resolution needed

Phase 84-3 will address GroupA with Edge Copy tracing in GenericTypeResolver.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 19:37:01 +09:00

435 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Phase 84-2: Case D 残り 9件の詳細調査
## 概要
Phase 84-2 で CopyTypePropagator を実装した結果、Case D は 12件 → 9件に削減されました。
本ドキュメントは残り 9件の詳細分析結果をまとめます。
## 削減された 3件Phase 84-2 で解決)
CopyTypePropagator により以下のパターンが解決されました:
- **Copy チェーン伝播**: `r1 = Copy r0``r2 = PHI [r1, r3]` で r0 の型が r2 に伝播
- **多段 Copy 追跡**: Copy 命令を遡って元の ValueId の型を発見
## 残り 9件の一覧
| # | テスト名 | ValueId | パターン分類 |
|---|---------|---------|------------|
| 1 | `test_lowering_await_expression` | ValueId(2) | GroupC: await 特殊パターン |
| 2 | `loop_with_continue_and_break_edge_copy_merge` | ValueId(56) | GroupA: Loop + continue/break PHI |
| 3 | `nested_loop_with_multi_continue_break_edge_copy_merge` | ValueId(135) | GroupA: Nested loop 複雑 PHI |
| 4 | `loop_inner_if_multilevel_edge_copy` | ValueId(74) | GroupA: Loop + 多段 if |
| 5 | `loop_break_and_early_return_edge_copy` | ValueId(40) | GroupA: Loop + early return |
| 6 | `vm_exec_break_inside_if` | ValueId(27) | GroupA: Loop + if-break |
| 7 | `loop_if_three_level_merge_edge_copy` | ValueId(75) | GroupA: Loop + 3段 if |
| 8 | `mir_stage1_cli_emit_program_min_exec_hits_type_error` | ValueId(7) | GroupB: Stage1Cli 複雑型推論 |
| 9 | `mir_stage1_cli_emit_program_min_compiles_and_verifies` | ValueId(7) | GroupB: Stage1Cli 複雑型推論 |
## パターン分類の詳細
### GroupA: Loop 制御フロー PHI7件
**共通特徴**:
- `NYASH_MIR_NO_PHI=1` でテストPHI-off モード)
- Loop + continue/break による複雑な制御フロー
- Edge Copy が複数の経路から合流する PHI
**典型的な制御フロー**:
```
loop(condition) {
if (cond1) { break } // → after_loop へ edge copy
if (cond2) { continue } // → loop_header へ edge copy
normal_path // → loop_header へ edge copy
}
return merged_value // ← PHI の型が未解決
```
**問題の本質**:
- PHI の incoming 値が全て Edge Copy の dst ValueId
- Edge Copy の src ValueId は value_types に登録されている
- しかし、GenericTypeResolver は **PHI の incoming 値の型** しか見ない
- **Copy の src を遡る処理が不足**
**なぜ CopyTypePropagator で解決できなかったか**:
```rust
// CopyTypePropagator の現在のロジック
if let Some(ty) = types.get(&src) {
types.insert(dst, ty.clone()); // ← dst に型を登録
}
```
問題点:
- PHI の incoming 値 (dst) に型を登録
- しかし、GenericTypeResolver::resolve_from_phi() は **既に登録された型** を参照
- **参照のタイミングが遅い**: lifecycle.rs が return 型を要求する時点で、
CopyTypePropagator はまだ実行されていない
**具体例: loop_with_continue_and_break_edge_copy_merge**
```hako
// 簡略化したコード
i = 0
sum = 0
loop(i < 5) {
i = i + 1
if (i == 3) { break } // → edge copy: sum_final = sum
if (i % 2 == 0) { continue } // → edge copy: sum_loop = sum
sum = sum + i
}
return sum // ← ValueId(56) の型が未解決
```
MIR 構造(推測):
```
Block1 (loop_header):
%sum_header = PHI [%sum_init, %sum_loop, %sum_updated]
Block2 (break):
%sum_final = Copy %sum_header ← value_types に型登録済み
Jump after_loop
Block3 (continue):
%sum_loop = Copy %sum_header ← value_types に型登録済み
Jump loop_header
Block4 (after_loop):
%56 = PHI [%sum_final] ← incoming の型が未登録!
Return %56
```
**テストファイルの所在**:
- `src/tests/loop_continue_break_no_phi_tests.rs`
- `src/tests/loop_nested_no_phi_tests.rs`
- `src/tests/loop_return_no_phi_tests.rs`
- `src/tests/mir_ctrlflow_break_continue.rs`
### GroupB: Stage1Cli 複雑型推論2件
**共通特徴**:
- `mir_stage1_cli_emit_program_min.rs` の 2テスト
- static box + env.get/set による複雑な型フロー
- ValueId(7) が Main.main の戻り値
**コードの特徴**:
```hako
static box Stage1Cli {
emit_program_json(source) {
if source == null || source == "" { return null }
return "{prog:" + source + "}"
}
stage1_main(args) {
local src = env.get("STAGE1_SOURCE")
if src == null || src == "" { return 96 }
local prog = me.emit_program_json(src)
if prog == null { return 96 }
print(prog)
return 0
}
}
static box Main {
main(args) {
env.set("STAGE1_SOURCE", "apps/tests/stage1_using_minimal.hako")
return Stage1Cli.stage1_main(args) // ← ValueId(7) の型
}
}
```
**問題の本質**:
- 多段メソッド呼び出し: `Main.main``Stage1Cli.stage1_main``emit_program_json`
- 複数の return 経路: null / 96 / 0
- PHI が複数の経路から合流
**デバッグ情報**:
```
[DEBUG/build_block] Completed, returning value ValueId(14)
[DEBUG/build_block] Completed, returning value ValueId(83)
[DEBUG/build_block] Completed, returning value ValueId(95)
[DEBUG/build_block] Completed, returning value ValueId(47)
[DEBUG/build_block] Completed, returning value ValueId(63)
[DEBUG/build_block] Completed, returning value ValueId(7)
```
多数の ValueId が生成されており、PHI 合流が複雑であることを示唆。
**テストファイル**:
- `src/tests/mir_stage1_cli_emit_program_min.rs`
### GroupC: await 特殊パターン1件
**テスト**: `test_lowering_await_expression`
**ValueId**: ValueId(2)
**コードの特徴**:
```rust
// src/mir/mod.rs:363
let ast = ASTNode::AwaitExpression {
expression: Box::new(ASTNode::Literal {
value: LiteralValue::Integer(1),
span: crate::ast::Span::unknown(),
}),
span: crate::ast::Span::unknown(),
};
```
**問題の本質**:
- await 式の MIR lowering が特殊な制御フローを生成
- Core-13 pure mode では skip される(非同期システム未実装)
- ValueId(2) は await の戻り値
**なぜ特殊か**:
- await は将来的に Safepoint/Checkpoint 命令に変換される予定
- 現在は簡易実装のため、型推論が不完全
**テストファイル**:
- `src/mir/mod.rs:363-384`
## Phase 84-3 で必要な機能の推奨
### 推奨1: Edge Copy 追跡 PHI 型推論(優先度: 高)
**対象**: GroupA7件
**アルゴリズム**:
```rust
// GenericTypeResolver に追加
pub fn resolve_from_phi_with_copy_trace(
function: &MirFunction,
ret_val: ValueId,
types: &BTreeMap<ValueId, MirType>,
) -> Option<MirType> {
// 1. PHI 命令を探索
for inst in find_phi_instructions(function, ret_val) {
if let MirInstruction::Phi { inputs, .. } = inst {
// 2. incoming 値ごとに Copy を遡る
let mut inferred_types = Vec::new();
for (_, incoming_val) in inputs {
// 2-1. incoming_val の型を直接取得
if let Some(ty) = types.get(incoming_val) {
inferred_types.push(ty.clone());
continue;
}
// 2-2. incoming_val を定義する Copy 命令を探索
if let Some(src_val) = find_copy_src(function, *incoming_val) {
if let Some(ty) = types.get(&src_val) {
inferred_types.push(ty.clone());
continue;
}
}
// 2-3. 多段 Copy を再帰的に遡る
if let Some(ty) = trace_copy_chain(function, *incoming_val, types, 10) {
inferred_types.push(ty);
}
}
// 3. 全ての型が一致すれば返す
if let Some(first) = inferred_types.first() {
if inferred_types.iter().all(|t| t == first) {
return Some(first.clone());
}
}
}
}
None
}
fn trace_copy_chain(
function: &MirFunction,
start: ValueId,
types: &BTreeMap<ValueId, MirType>,
max_depth: usize,
) -> Option<MirType> {
let mut current = start;
for _ in 0..max_depth {
if let Some(ty) = types.get(&current) {
return Some(ty.clone());
}
if let Some(src) = find_copy_src(function, current) {
current = src;
} else {
break;
}
}
None
}
```
**実装箇所**:
- `src/mir/join_ir/lowering/generic_type_resolver.rs`
**期待効果**:
- GroupA の 7件を一気に解決
- Loop + continue/break パターンの完全対応
### 推奨2: 多段 PHI 型推論(優先度: 中)
**対象**: GroupB2件
**問題**:
```
Block1:
%a = PHI [const_96, const_0]
Block2:
%b = PHI [%a, const_0]
Block3:
%7 = PHI [%b] ← %b の型が未解決
```
**アルゴリズム**:
```rust
pub fn resolve_from_phi_recursive(
function: &MirFunction,
ret_val: ValueId,
types: &BTreeMap<ValueId, MirType>,
visited: &mut HashSet<ValueId>,
) -> Option<MirType> {
if visited.contains(&ret_val) {
return None; // 循環検出
}
visited.insert(ret_val);
// 1. 直接型推論を試みる
if let Some(ty) = resolve_from_phi(function, ret_val, types) {
return Some(ty);
}
// 2. PHI の incoming 値を再帰的に解決
for inst in find_phi_instructions(function, ret_val) {
if let MirInstruction::Phi { inputs, .. } = inst {
let mut inferred_types = Vec::new();
for (_, incoming_val) in inputs {
// 再帰的に型を解決
if let Some(ty) = resolve_from_phi_recursive(
function, *incoming_val, types, visited
) {
inferred_types.push(ty);
}
}
if let Some(first) = inferred_types.first() {
if inferred_types.iter().all(|t| t == first) {
return Some(first.clone());
}
}
}
}
None
}
```
**実装箇所**:
- `src/mir/join_ir/lowering/generic_type_resolver.rs`
**期待効果**:
- GroupB の 2件を解決
- 多段メソッド呼び出しの型推論強化
### 推奨3: await 型推論特殊処理(優先度: 低)
**対象**: GroupC1件
**短期対応**:
```rust
// lifecycle.rs に特殊ケース追加
if function_name == "main" && is_await_expression {
// await の戻り値型は Unknown で許容
return MirType::Unknown;
}
```
**長期対応**:
- Phase 67+ で async/await システム完全実装
- Safepoint/Checkpoint 命令の型推論統合
**実装箇所**:
- `src/mir/builder/lifecycle.rs`
**期待効果**:
- GroupC の 1件を解決暫定
## 推奨実装順序
### Phase 84-3: Edge Copy 追跡 PHI 型推論1-2日
**目標**: GroupA の 7件を解決
**ステップ**:
1. `GenericTypeResolver::resolve_from_phi_with_copy_trace()` 実装
2. `trace_copy_chain()` ヘルパー関数実装
3. `find_copy_src()` ヘルパー関数実装
4. lifecycle.rs から新関数を呼び出す
5. テスト実行: 7件 → 0件 を確認
### Phase 84-4: 多段 PHI 型推論1-2日
**目標**: GroupB の 2件を解決
**ステップ**:
1. `GenericTypeResolver::resolve_from_phi_recursive()` 実装
2. 循環検出ロジック実装
3. lifecycle.rs から新関数を呼び出す
4. テスト実行: 2件 → 0件 を確認
### Phase 84-5: await 暫定対応30分
**目標**: GroupC の 1件を解決暫定
**ステップ**:
1. lifecycle.rs に await 特殊ケース追加
2. テスト実行: 1件 → 0件 を確認
## 完了条件
```bash
# Phase 84-3 完了
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
# 期待: 2 (GroupB のみ残存)
# Phase 84-4 完了
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
# 期待: 1 (GroupC のみ残存)
# Phase 84-5 完了
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
# 期待: 0 (全件解決)
```
## ChatGPT Pro との設計相談ポイント
### 相談1: Edge Copy 追跡の最適化
**質問**:
- Copy チェーンの追跡深度は 10 で十分か?
- 循環 Copy 検出は必要か?(理論上は発生しないが)
- パフォーマンス最適化(キャッシュ戦略)
### 相談2: 多段 PHI の循環検出
**質問**:
- 循環 PHI は実際に発生するか?
- 発生する場合、どう処理すべきか?(エラー or Unknown
- visited セットの最適なデータ構造
### 相談3: await 型推論の長期戦略
**質問**:
- Phase 67+ async/await システムの型推論設計
- Safepoint/Checkpoint 命令の型情報統合方法
- 現在の暫定対応が将来の実装を妨げないか
## まとめ
Phase 84-2 の CopyTypePropagator により 12件 → 9件に削減成功。
残り 9件は以下の 3パターンに分類:
- **GroupA**: Loop 制御フロー PHI7件→ Edge Copy 追跡で解決可能
- **GroupB**: 多段 PHI2件→ 再帰的型推論で解決可能
- **GroupC**: await 特殊1件→ 暫定対応で解決可能
Phase 84-3/4/5 の実装により、**Case D を完全解決** できる見込み。