docs(joinir): Phase 232-239 documentation and ExprLowerer refinements
Documentation: - Move completion reports to docs/archive/reports/ - Add phase232-238 design/inventory documents - Update joinir-architecture-overview.md - Add doc-status-policy.md Code refinements: - ExprLowerer: condition catalog improvements - ScopeManager: boundary clarifications - CarrierInfo: cleanup 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -16,6 +16,8 @@
|
||||
|
||||
## JoinIR / Selfhost 関連の入口
|
||||
|
||||
- 「JoinIR / Selfhost まわりで、まずどのドキュメントを読むべきか」は
|
||||
`docs/development/current/main/01-JoinIR-Selfhost-INDEX.md` を入口として使ってね。
|
||||
- JoinIR 全体のアーキテクチャと箱の関係は
|
||||
`docs/development/current/main/joinir-architecture-overview.md` を参照してね。
|
||||
- selfhost / .hako 側から JoinIR を使うときも、この設計を SSOT として運用する方針だよ。
|
||||
`docs/development/current/main/joinir-architecture-overview.md` を SSOT として参照するよ。
|
||||
- selfhost / .hako 側から JoinIR を使うときも、この JoinIR 設計を前提にして設計・実装する方針だよ。
|
||||
|
||||
71
docs/development/current/main/01-JoinIR-Selfhost-INDEX.md
Normal file
71
docs/development/current/main/01-JoinIR-Selfhost-INDEX.md
Normal file
@ -0,0 +1,71 @@
|
||||
# JoinIR / Selfhost INDEX(読み始めガイド)
|
||||
|
||||
Status: Active
|
||||
Scope: JoinIR と Selfhost(Stage‑B/Stage‑1/Stage‑3)に関する「最初に読むべき現役ドキュメント」だけを集約した入口。
|
||||
|
||||
このファイルは、JoinIR と Selfhost ラインの主戦場をすばやく把握するためのインデックスだよ。
|
||||
歴史メモや詳細な Phase 文書に飛ぶ前に、まずここに載っている現役ドキュメントから辿っていくことを想定しているよ。
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 1. まず全体像だけ掴みたいとき
|
||||
|
||||
- JoinIR 全体像(SSOT)
|
||||
- `docs/development/current/main/joinir-architecture-overview.md`
|
||||
- Selfhost / Stage‑B〜3 の代表フロー
|
||||
- `docs/development/current/main/selfhost_stage3_expected_flow.md`
|
||||
- 「いまどこまで進んでいるか」の現状サマリ
|
||||
- `docs/development/current/main/10-Now.md`
|
||||
- 「JoinIR / Loop / If ライン」
|
||||
- 「JsonParser / Selfhost depth‑2 ライン」
|
||||
|
||||
---
|
||||
|
||||
## 2. JoinIR をこれから触る人向け
|
||||
|
||||
JoinIR の箱構造と責務、ループ/if の lowering パターンを把握したいときの読み順だよ。
|
||||
|
||||
1. JoinIR の基本設計(SSOT)
|
||||
- `docs/development/current/main/joinir-architecture-overview.md`
|
||||
2. ループパターン空間とパターン番号の意味
|
||||
- `docs/development/current/main/loop_pattern_space.md`
|
||||
3. Boundary / ExitLine / Carrier の具体パターン
|
||||
- `docs/development/current/main/joinir-boundary-builder-pattern.md`
|
||||
4. 代表的な Phase 文書(現役ラインとの接点だけ絞ったもの)
|
||||
- `docs/development/current/main/phase33-16-INDEX.md`
|
||||
- `docs/development/current/main/phase33-17-joinir-modularization-analysis.md`
|
||||
- `docs/development/current/main/phase183-selfhost-depth2-joinir-status.md`
|
||||
|
||||
Phase 文書は歴史や検証ログも含むので、「JoinIR の現役設計を確認した上で、必要なときだけ掘る」という前提で読んでね。
|
||||
|
||||
---
|
||||
|
||||
## 3. Selfhost(Stage‑B / Stage‑1 / Stage‑3)を触る人向け
|
||||
|
||||
自己ホストコンパイラのフローや実行手順、Ny Executor ラインの計画を押さえたいときの読み順だよ。
|
||||
|
||||
1. Selfhost 全体フロー(Stage‑B / Stage‑1 / Stage‑3 と JSON v0)
|
||||
- `docs/development/current/main/selfhost_stage3_expected_flow.md`
|
||||
2. 実行手順・クイックスタート
|
||||
- `docs/development/selfhosting/quickstart.md`
|
||||
- `docs/development/testing/selfhost_exe_stageb_quick_guide.md`
|
||||
3. Ny Executor(Ny で MIR(JSON v0) を実行)のロードマップ
|
||||
- `docs/development/roadmap/selfhosting-ny-executor.md`
|
||||
4. Stage‑3 / depth‑2 関連で「現役」として参照する Phase 文書
|
||||
- `docs/development/current/main/phase150_selfhost_stage3_depth1_baseline.md`
|
||||
- `docs/development/current/main/phase150_selfhost_stage3_depth1_results.md`
|
||||
- `docs/development/current/main/phase183-selfhost-depth2-joinir-status.md`
|
||||
- `docs/development/current/main/phase120_selfhost_stable_paths.md`
|
||||
|
||||
---
|
||||
|
||||
## 4. 迷ったときの読み分けガイド
|
||||
|
||||
- JoinIR の箱や契約で迷っているとき
|
||||
- → 2章の 1〜3 をこの順番で読む。
|
||||
- Selfhost のビルド / 実行フローで迷っているとき
|
||||
- → 3章の 1〜3 をこの順番で読む。
|
||||
- 「この Phase 文書は現役か?」で迷ったとき
|
||||
- → まず `docs/development/current/main/10-Now.md` と
|
||||
`docs/development/current/main/30-Backlog.md` を確認し、そこで名前が挙がっている Phase 文書を優先して読んでね。
|
||||
@ -367,7 +367,6 @@ Local Region (1000+):
|
||||
- **Two-tier promotion**: Step1 で A-3 Trim 試行 → 失敗なら Step2 で A-4 DigitPos 試行 → 両方失敗で Fail-Fast。
|
||||
- **DigitPosPromoter 統合**: cascading indexOf パターン(substring → indexOf → comparison)の昇格をサポート。
|
||||
- **Unit test 完全成功**: 6/6 PASS(promoter 自体は完璧動作)。
|
||||
- **Phase 224-D**: ConditionAlias/CarrierInfo との連携により、昇格済み LoopBodyLocal 名(`digit_pos` 等)を ConditionEnv から見えるようにブリッジ。
|
||||
- **残りの制約**: body-local init の MethodCall(`substring` 等)の lowering は Phase 193/224-B/C のスコープ外で、今後の Phase で対応。
|
||||
- 設計原則:
|
||||
- **Thin coordinator**: 専門 Promoter(LoopBodyCarrierPromoter / DigitPosPromoter)に昇格ロジックを委譲。
|
||||
@ -405,7 +404,7 @@ Local Region (1000+):
|
||||
- **単体テスト**: 5/5 PASS(happy path, wrong operator/variable/constant, non-binary-op)。
|
||||
- **E2E テスト**: `phase2235_p2_digit_pos_min.hako` で型エラー解消確認。
|
||||
- **回帰テスト**: digitpos (11 tests), trim (32 tests) 全て PASS。
|
||||
- **digit_pos 正規化ライン**: DigitPosPromoter + ConditionAlias + DigitPosConditionNormalizer で `digit_pos < 0` を bool キャリア `is_digit_pos` ベースの条件(`!is_digit_pos`)に直してから ConditionEnv / BoolExprLowerer へ渡す。
|
||||
- **digit_pos 正規化ライン**: DigitPosPromoter + CarrierInfo.promoted_loopbodylocals + DigitPosConditionNormalizer で `digit_pos < 0` を bool キャリア `is_digit_pos` ベースの条件(`!is_digit_pos`)に直してから ConditionEnv / ConditionPatternBox / ExprLowerer 系の条件 lowering に渡す。
|
||||
- 参考:
|
||||
- 設計ドキュメント: `docs/development/current/main/phase224-digitpos-condition-normalizer.md`
|
||||
- 実装サマリ: `docs/development/current/main/PHASE_224_SUMMARY.md`
|
||||
@ -799,6 +798,27 @@ Phase 210–221 で「数値ループ+if-sum」を実戦投入し、JoinIR イ
|
||||
- **Phase 230(ExprLowerer / ScopeManager 設計フェーズ)**
|
||||
- 目標: 条件式 / init 式 / carrier 更新式の lowering を将来ひとつの ExprLowerer + ScopeManager に統合できるよう、既存の散在する lowering/API/Env を設計レベルで整理する(このフェーズではコード変更なし)。
|
||||
|
||||
- **Phase 233(loop_update_summary テスト刷新フェーズ)**
|
||||
- 目標: deprecated `analyze_loop_updates()` 依存のテストを廃止し、`analyze_loop_updates_from_ast()` に揃えたユニットで if-sum 判定ラインの期待値を固定する。
|
||||
|
||||
- **Phase 232(Failing Tests の棚卸しフェーズ)**
|
||||
- 目標: `cargo test --release` で残っている 7 件の FAIL を「どの箱 / どのパターン / どのレイヤ」の問題かで整理し、P0/P1/P2 に分類して次フェーズのターゲットを決める(core バグを見つけるフェーズではなく、未対応領域の可視化フェーズ)。
|
||||
|
||||
- **Phase 234(ArrayFilter / Pattern3 設計フェーズ)**
|
||||
- 目標: ArrayExtBox.filter 系 3 テストを P3 if-PHI の正式対象に含めるか、当面は PoC 領域として Fail-Fast を仕様として維持するかを docs ベースで決める(コード変更なし)。
|
||||
|
||||
- **Phase 235(ExprLowerer / ScopeManager パイロット実装 & テスト)**
|
||||
- 目標: ExprLowerer/ScopeManager の Condition 文脈を小さな範囲でユニットテストしつつ、Pattern2 の break 条件で validation-only の経路として動かし、既存の legacy lowering と挙動が一致することを確認する(本番 lowering の置き換えは後続フェーズ)。
|
||||
|
||||
- **Phase 236-EX(ExprLowerer / ScopeManager 本番導入 - Pattern2 break 条件)**
|
||||
- 目標: Pattern2 の break 条件 lowering を ExprLowerer/ScopeManager 経由の本番経路に切り替え、既存の condition_to_joinir ベース実装と RC / JoinIR 構造 / ログ挙動が一致することを確認する(影響範囲は Pattern2 break 条件のみに限定)。
|
||||
|
||||
- **Phase 237-EX(ExprLowerer 条件パターン棚卸しフェーズ)**
|
||||
- 目標: JsonParser / selfhost のループ条件・break/continue 条件をカタログ化し、ExprLowerer/ScopeManager で優先的に扱うパターンと後回しにするパターンを SSOT 化する(コード変更なし)。
|
||||
|
||||
- **Phase 238-EX(ExprLowerer / ScopeManager Scope Boundaries)**
|
||||
- 目標: ExprLowerer / ScopeManager / ConditionEnv / LoopBodyLocalEnv / UpdateEnv の責務と参照範囲を文書化し、「誰がどこまで見てよいか」を SSOT として固定する(コード変更なし、ガイドライン整備)。***
|
||||
|
||||
---
|
||||
|
||||
## 5. selfhost / .hako JoinIR Frontend との関係
|
||||
|
||||
@ -1,346 +0,0 @@
|
||||
# Phase 166 Validation Report: JsonParserBox Unit Test with BoolExprLowerer
|
||||
|
||||
**Date**: 2025-12-06 (Updated: 2025-12-07 Phase 170)
|
||||
**Status**: ⚠️ **Blocked** - ValueId boundary mapping issue
|
||||
**Blocker**: Condition variables not included in JoinInlineBoundary
|
||||
|
||||
**Phase 170 Update**: BoolExprLowerer is now integrated (Phase 167-169), but a critical ValueId boundary mapping bug prevents runtime execution. See [phase170-valueid-boundary-analysis.md](phase170-valueid-boundary-analysis.md) for details.
|
||||
|
||||
---
|
||||
|
||||
## Phase 170 Re-validation Results (2025-12-07)
|
||||
|
||||
After Phase 167-169 (BoolExprLowerer integration), Phase 170 re-tested JsonParserBox with the following results:
|
||||
|
||||
### ✅ Whitelist Expansion Complete
|
||||
- Added 6 JsonParserBox methods to routing whitelist
|
||||
- Methods now route to JoinIR instead of `[joinir/freeze]`
|
||||
- Pattern matching works correctly (Pattern2 detected for `_trim`)
|
||||
|
||||
### ⚠️ Runtime Failure: ValueId Boundary Issue
|
||||
**Test**: `local_tests/test_trim_main_pattern.hako`
|
||||
**Pattern Matched**: Pattern2 (twice, for 2 loops)
|
||||
**Result**: Silent runtime failure (no output)
|
||||
|
||||
**Root Cause**: Condition variables (`start`, `end`) are resolved from HOST `variable_map` but not included in `JoinInlineBoundary`, causing undefined ValueId references.
|
||||
|
||||
**Evidence**:
|
||||
```
|
||||
[ssa-undef-debug] fn=TrimTest.trim/1 bb=BasicBlockId(12) inst_idx=0 used=ValueId(33)
|
||||
[ssa-undef-debug] fn=TrimTest.trim/1 bb=BasicBlockId(12) inst_idx=0 used=ValueId(34)
|
||||
```
|
||||
|
||||
**Solution**: Option A in [phase170-valueid-boundary-analysis.md](phase170-valueid-boundary-analysis.md) - Extract condition variables and add to boundary.
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary (Original Phase 166)
|
||||
|
||||
Phase 166 aimed to validate that JsonParserBox can parse JSON through the JoinIR path, confirming Pattern1-4 support. However, investigation revealed that:
|
||||
|
||||
1. **✅ JoinIR Pattern Detection Works**: Pattern 2 (break) correctly detected ← **Still true in Phase 170**
|
||||
2. **✅ Simple JSON Parsing Works**: Non-loop or simple-condition patterns execute fine
|
||||
3. **~~❌ Complex Conditions Blocked~~** ← **FIXED in Phase 169**: BoolExprLowerer integrated
|
||||
4. **❌ NEW BLOCKER (Phase 170)**: ValueId boundary mapping prevents runtime execution
|
||||
|
||||
---
|
||||
|
||||
## Test Results
|
||||
|
||||
### ✅ Test 1: Simple JSON Parser (No Loops)
|
||||
**File**: `local_tests/test_json_parser_simple_string.hako`
|
||||
|
||||
```bash
|
||||
./target/release/hakorune local_tests/test_json_parser_simple_string.hako
|
||||
# Output: PASS: Got 'hello'
|
||||
```
|
||||
|
||||
**Result**: **SUCCESS** - Basic string parsing without complex conditions works.
|
||||
|
||||
---
|
||||
|
||||
### ❌ Test 2: _trim Pattern with OR Chains
|
||||
**File**: `local_tests/test_trim_or_pattern.hako`
|
||||
|
||||
```bash
|
||||
./target/release/hakorune local_tests/test_trim_or_pattern.hako
|
||||
# Output: [joinir/freeze] Loop lowering failed
|
||||
```
|
||||
|
||||
**Result**: **BLOCKED** - OR condition causes `[joinir/freeze]` error.
|
||||
|
||||
---
|
||||
|
||||
### ⚠️ Test 3: _trim Pattern in main() with Simple Condition
|
||||
**File**: `local_tests/test_trim_main_pattern.hako`
|
||||
|
||||
```bash
|
||||
./target/release/hakorune local_tests/test_trim_main_pattern.hako
|
||||
# Output: FAIL - Result: ' hello ' (not trimmed)
|
||||
```
|
||||
|
||||
**Result**: **PATTERN DETECTED BUT LOGIC WRONG** - Pattern 2 matches, but uses hardcoded `i < 3` instead of actual condition.
|
||||
|
||||
**Debug Output**:
|
||||
```
|
||||
[trace:pattern] route: Pattern2_WithBreak MATCHED
|
||||
[trace:varmap] pattern2_start: end→r9, s→r4, start→r6
|
||||
Final start: 0 (unchanged - loop didn't execute properly)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Root Cause Analysis
|
||||
|
||||
### Discovery 1: Function Name Whitelisting
|
||||
|
||||
**File**: `src/mir/builder/control_flow/joinir/routing.rs` (lines 44-68)
|
||||
|
||||
JoinIR is **ONLY enabled for specific function names**:
|
||||
- `"main"`
|
||||
- `"JoinIrMin.main/0"`
|
||||
- `"JsonTokenizer.print_tokens/0"`
|
||||
- `"ArrayExtBox.filter/2"`
|
||||
|
||||
**Impact**: `JsonParserBox._trim/1` is NOT whitelisted → `[joinir/freeze]` error.
|
||||
|
||||
**Workaround**: Test in `main()` function instead.
|
||||
|
||||
---
|
||||
|
||||
### Discovery 2: Hardcoded Conditions in Minimal Lowerers
|
||||
|
||||
**File**: `src/mir/join_ir/lowering/loop_with_break_minimal.rs` (lines 171-197)
|
||||
|
||||
```rust
|
||||
// HARDCODED: !(i < 3)
|
||||
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: const_3,
|
||||
value: ConstValue::Integer(3), // ← HARDCODED VALUE
|
||||
}));
|
||||
|
||||
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Compare {
|
||||
dst: cmp_lt,
|
||||
op: CompareOp::Lt, // ← HARDCODED OPERATOR
|
||||
lhs: i_param,
|
||||
rhs: const_3,
|
||||
}));
|
||||
```
|
||||
|
||||
**Impact**: Pattern 2 lowerer generates fixed `i < 3` check, **ignoring the actual AST condition**.
|
||||
|
||||
**Current Behavior**:
|
||||
- AST condition: `start < end` with `ch == " "` check
|
||||
- Generated JoinIR: `i < 3` with `i >= 2` break check
|
||||
- Result: Loop doesn't execute correctly
|
||||
|
||||
---
|
||||
|
||||
### Discovery 3: BoolExprLowerer Not Integrated
|
||||
|
||||
**Files**:
|
||||
- `src/mir/join_ir/lowering/bool_expr_lowerer.rs` (Phase 167-168, 436 lines, complete)
|
||||
- `src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs` (line 58)
|
||||
|
||||
```rust
|
||||
// Current code:
|
||||
let loop_var_name = self.extract_loop_variable_from_condition(condition)?;
|
||||
|
||||
// Missing:
|
||||
// use crate::mir::join_ir::lowering::bool_expr_lowerer::BoolExprLowerer;
|
||||
// let mut bool_lowerer = BoolExprLowerer::new(self.builder);
|
||||
// let cond_val = bool_lowerer.lower_condition(&ctx.condition)?;
|
||||
```
|
||||
|
||||
**Impact**: BoolExprLowerer exists but isn't called by Pattern 2/4 lowerers.
|
||||
|
||||
---
|
||||
|
||||
### Discovery 4: LoopBuilder Hard Freeze
|
||||
|
||||
**File**: `src/mir/builder/control_flow/mod.rs` (lines 112-119)
|
||||
|
||||
```rust
|
||||
// Phase 186: LoopBuilder Hard Freeze - Legacy path disabled
|
||||
// Phase 187-2: LoopBuilder module removed - all loops must use JoinIR
|
||||
return Err(format!(
|
||||
"[joinir/freeze] Loop lowering failed: JoinIR does not support this pattern, and LoopBuilder has been removed.\n\
|
||||
Function: {}\n\
|
||||
Hint: This loop pattern is not supported. All loops must use JoinIR lowering.",
|
||||
self.current_function.as_ref().map(|f| f.signature.name.as_str()).unwrap_or("<unknown>")
|
||||
));
|
||||
```
|
||||
|
||||
**Impact**: NO fallback exists when JoinIR patterns don't match.
|
||||
|
||||
---
|
||||
|
||||
## Architecture Issues
|
||||
|
||||
### Issue 1: Minimal Lowerers Are Test-Specific
|
||||
|
||||
**Design**: Pattern 1-4 lowerers are "minimal implementations" for specific test cases:
|
||||
- Pattern 1: `apps/tests/joinir_simple_loop.hako` (`i < 5`)
|
||||
- Pattern 2: `apps/tests/joinir_min_loop.hako` (`i < 3`, `i >= 2`)
|
||||
- Pattern 3: `apps/tests/loop_if_phi_sum.hako` (hardcoded sum accumulation)
|
||||
- Pattern 4: `apps/tests/loop_continue_pattern4.hako` (hardcoded continue logic)
|
||||
|
||||
**Problem**: These lowerers are **NOT** generic - they can't handle arbitrary conditions.
|
||||
|
||||
---
|
||||
|
||||
### Issue 2: Condition Extraction vs. Evaluation
|
||||
|
||||
**Current**:
|
||||
- `extract_loop_variable_from_condition()` - Extracts variable name (`i`, `start`)
|
||||
- Used for: Carrier detection, not condition evaluation
|
||||
- Only supports: Simple comparisons like `i < 3`
|
||||
|
||||
**Missing**:
|
||||
- Dynamic condition evaluation (BoolExprLowerer)
|
||||
- OR chain support
|
||||
- Complex boolean expressions
|
||||
|
||||
---
|
||||
|
||||
### Issue 3: JoinIR Generation Architecture
|
||||
|
||||
**Current Pipeline**:
|
||||
```
|
||||
AST Loop → Pattern Detection → Hardcoded JoinIR Generator
|
||||
↓
|
||||
Fixed condition (i < 3)
|
||||
```
|
||||
|
||||
**Needed Pipeline**:
|
||||
```
|
||||
AST Loop → Pattern Detection → BoolExprLowerer → Dynamic JoinIR Generator
|
||||
↓ ↓
|
||||
Condition MIR → Convert to JoinInst
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Phase 166 Status Update
|
||||
|
||||
### ✅ Completed Validation
|
||||
1. **Pattern Detection**: Pattern 2 (break) correctly identified
|
||||
2. **Simple Cases**: Non-loop JSON parsing works
|
||||
3. **Infrastructure**: JoinIR pipeline functional
|
||||
4. **Whitelist Behavior**: Function name routing confirmed
|
||||
|
||||
### ❌ Remaining Blockers
|
||||
1. **OR Chains**: `ch == " " || ch == "\t"...` not supported
|
||||
2. **Dynamic Conditions**: Hardcoded `i < 3` instead of actual condition
|
||||
3. **BoolExprLowerer Integration**: Phase 167-168 code not used
|
||||
4. **JsonParserBox._trim**: Cannot execute due to whitelisting
|
||||
|
||||
---
|
||||
|
||||
## Recommended Next Steps
|
||||
|
||||
### Phase 169: BoolExprLowerer Integration (HIGH PRIORITY)
|
||||
|
||||
**Goal**: Make JoinIR patterns support arbitrary conditions.
|
||||
|
||||
**Tasks**:
|
||||
1. **Modify Pattern 2 Lowerer** (`loop_with_break_minimal.rs`):
|
||||
- Accept `condition: &ASTNode` parameter
|
||||
- Call `BoolExprLowerer::lower_condition(condition)`
|
||||
- Generate JoinIR instructions from condition MIR
|
||||
- Replace hardcoded `const_3`, `cmp_lt` with dynamic values
|
||||
|
||||
2. **Modify Pattern 4 Lowerer** (`loop_with_continue_minimal.rs`):
|
||||
- Same changes as Pattern 2
|
||||
|
||||
3. **Update Caller** (`pattern2_with_break.rs`):
|
||||
- Pass `ctx.condition` to lowerer
|
||||
- Handle condition evaluation errors
|
||||
|
||||
4. **Test Coverage**:
|
||||
- `_trim` pattern with OR chains
|
||||
- Complex boolean expressions
|
||||
- Nested conditions
|
||||
|
||||
**Estimated Effort**: 2-3 hours (architecture already designed in Phase 167-168)
|
||||
|
||||
---
|
||||
|
||||
### Phase 170: Function Whitelist Expansion (MEDIUM PRIORITY)
|
||||
|
||||
**Goal**: Enable JoinIR for JsonParserBox methods.
|
||||
|
||||
**Options**:
|
||||
1. **Option A**: Add to whitelist:
|
||||
```rust
|
||||
"JsonParserBox._trim/1" => true,
|
||||
"JsonParserBox._skip_whitespace/2" => true,
|
||||
```
|
||||
|
||||
2. **Option B**: Enable JoinIR globally for all functions:
|
||||
```rust
|
||||
let is_target = true; // Always try JoinIR first
|
||||
```
|
||||
|
||||
3. **Option C**: Add pattern-based routing (e.g., all `_trim*` functions)
|
||||
|
||||
**Recommended**: Option A (conservative, safe)
|
||||
|
||||
---
|
||||
|
||||
### Phase 171: JsonParserBox Full Validation (POST-169)
|
||||
|
||||
**Goal**: Validate all JsonParserBox methods work through JoinIR.
|
||||
|
||||
**Tests**:
|
||||
- `_trim` (OR chains)
|
||||
- `_skip_whitespace` (OR chains)
|
||||
- `_parse_number` (digit loop)
|
||||
- `_parse_string` (escape sequences)
|
||||
- `_parse_array` (recursive calls)
|
||||
- `_parse_object` (key-value pairs)
|
||||
|
||||
---
|
||||
|
||||
## Files Modified This Session
|
||||
|
||||
### Created Test Files
|
||||
1. `local_tests/test_json_parser_simple_string.hako` - Simple JSON test (PASS)
|
||||
2. `local_tests/test_trim_or_pattern.hako` - OR chain test (BLOCKED)
|
||||
3. `local_tests/test_trim_simple_pattern.hako` - Simple condition test (BLOCKED)
|
||||
4. `local_tests/test_trim_main_pattern.hako` - Whitelisted function test (WRONG LOGIC)
|
||||
5. `local_tests/test_trim_debug.hako` - Debug output test
|
||||
|
||||
### Documentation
|
||||
1. `docs/development/current/main/phase166-validation-report.md` (this file)
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
**Phase 166 Validation Status**: ⚠️ **Partially Complete**
|
||||
|
||||
**Key Findings**:
|
||||
1. JoinIR Pattern Detection **works correctly**
|
||||
2. Simple patterns **execute successfully**
|
||||
3. Complex OR chains **are blocked** by hardcoded conditions
|
||||
4. BoolExprLowerer (Phase 167-168) **exists but isn't integrated**
|
||||
|
||||
**Next Critical Phase**: **Phase 169 - BoolExprLowerer Integration** to unblock JsonParserBox._trim and enable dynamic condition evaluation.
|
||||
|
||||
**Timeline**:
|
||||
- Phase 169: 2-3 hours (integration work)
|
||||
- Phase 170: 30 minutes (whitelist update)
|
||||
- Phase 171: 1 hour (full validation testing)
|
||||
|
||||
**Total Estimated Time to Complete Phase 166**: 4-5 hours
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- **Phase 166 Goal**: `docs/development/current/main/phase166-joinir-json-parser-validation.md`
|
||||
- **Phase 167-168**: `src/mir/join_ir/lowering/bool_expr_lowerer.rs`
|
||||
- **Pattern 2 Lowerer**: `src/mir/join_ir/lowering/loop_with_break_minimal.rs`
|
||||
- **Routing Logic**: `src/mir/builder/control_flow/joinir/routing.rs`
|
||||
- **LoopBuilder Freeze**: `src/mir/builder/control_flow/mod.rs` (lines 112-119)
|
||||
@ -1,450 +0,0 @@
|
||||
# Phase 170: JsonParserBox JoinIR Preparation & Re-validation - Completion Report
|
||||
|
||||
**Date**: 2025-12-07
|
||||
**Duration**: 2 sessions (autonomous work + bug fix verification)
|
||||
**Status**: ✅ **Complete** - Environment prepared, bug fix verified, next phase planned
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Phase 170 successfully prepared the environment for JsonParserBox JoinIR validation and identified the critical ValueId boundary mapping issue blocking runtime execution. All tasks completed:
|
||||
|
||||
- ✅ **Task A-1**: JoinIR routing whitelist expanded (6 JsonParserBox methods + test helper)
|
||||
- ✅ **Task A-2**: ValueId boundary issue identified with full root cause analysis
|
||||
- ⚠️ **Task B**: Mini tests blocked by `using` statement (workaround: simplified test created)
|
||||
- ✅ **Task C**: Next phase direction decided (Option A: Fix boundary mapping)
|
||||
|
||||
**Key Achievement**: Identified that BoolExprLowerer integration (Phase 167-169) is correct, but the boundary mechanism needs condition variable extraction to work properly.
|
||||
|
||||
---
|
||||
|
||||
## Phase 170-A: Environment Setup ✅
|
||||
|
||||
### Task A-1: JoinIR Routing Whitelist Expansion
|
||||
|
||||
**Objective**: Allow JsonParserBox methods to route to JoinIR patterns instead of `[joinir/freeze]`.
|
||||
|
||||
**Changes Made**:
|
||||
|
||||
**File**: `src/mir/builder/control_flow/joinir/routing.rs` (lines 68-76)
|
||||
|
||||
**Added entries**:
|
||||
```rust
|
||||
// Phase 170-A-1: Enable JsonParserBox methods for JoinIR routing
|
||||
"JsonParserBox._trim/1" => true,
|
||||
"JsonParserBox._skip_whitespace/2" => true,
|
||||
"JsonParserBox._match_literal/2" => true,
|
||||
"JsonParserBox._parse_string/2" => true,
|
||||
"JsonParserBox._parse_array/2" => true,
|
||||
"JsonParserBox._parse_object/2" => true,
|
||||
// Phase 170-A-1: Test methods (simplified versions)
|
||||
"TrimTest.trim/1" => true,
|
||||
```
|
||||
|
||||
**Result**: ✅ Methods now route to pattern matching instead of immediate `[joinir/freeze]` rejection.
|
||||
|
||||
**Evidence**:
|
||||
```bash
|
||||
HAKO_JOINIR_DEBUG=1 ./target/release/hakorune local_tests/test_trim_main_pattern.hako
|
||||
# Output: [joinir/pattern2] Generated JoinIR for Loop with Break Pattern (Phase 169)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task A-2: ValueId Boundary Issue Identification
|
||||
|
||||
**Objective**: Understand if ValueId boundary mapping affects JsonParserBox tests.
|
||||
|
||||
**Test Created**: `local_tests/test_trim_main_pattern.hako` (48 lines)
|
||||
- Simplified `_trim` method with same loop structure as JsonParserBox
|
||||
- Two loops with break (Pattern2 x 2)
|
||||
- Condition variables: `start < end`, `end > start`
|
||||
|
||||
**Findings**:
|
||||
|
||||
1. **Pattern Detection**: ✅ Works correctly
|
||||
- Both loops match Pattern2
|
||||
- JoinIR generation succeeds
|
||||
|
||||
2. **Runtime Execution**: ❌ Silent failure
|
||||
- Program compiles successfully
|
||||
- No output produced
|
||||
- Exit code 0 (but no print statements executed)
|
||||
|
||||
3. **Root Cause Identified**: ValueId boundary mapping
|
||||
- Condition variables (`start`, `end`) resolved from HOST `variable_map`
|
||||
- HOST ValueIds (33, 34, 48, 49) used directly in JoinIR
|
||||
- Not included in `JoinInlineBoundary`
|
||||
- Merge process doesn't remap them → undefined at runtime
|
||||
|
||||
**Evidence**:
|
||||
```
|
||||
[ssa-undef-debug] fn=TrimTest.trim/1 bb=BasicBlockId(12) inst_idx=0 used=ValueId(33) inst=Compare { dst: ValueId(26), op: Lt, lhs: ValueId(33), rhs: ValueId(34) }
|
||||
[ssa-undef-debug] fn=TrimTest.trim/1 bb=BasicBlockId(12) inst_idx=0 used=ValueId(34) inst=Compare { dst: ValueId(26), op: Lt, lhs: ValueId(33), rhs: ValueId(34) }
|
||||
```
|
||||
|
||||
**Impact**: CRITICAL - Blocks ALL JsonParserBox methods with complex conditions.
|
||||
|
||||
**Detailed Analysis**: See [phase170-valueid-boundary-analysis.md](phase170-valueid-boundary-analysis.md)
|
||||
|
||||
---
|
||||
|
||||
## Phase 170-B: JsonParserBox Mini Test Re-execution ⚠️
|
||||
|
||||
### Original Test Files
|
||||
|
||||
**Location**: `tools/selfhost/json_parser_{string,array,object}_min.hako`
|
||||
|
||||
**Blocker**: `using` statement not working
|
||||
```
|
||||
[using] not found: 'tools/hako_shared/json_parser.hako" with JsonParserBox'
|
||||
```
|
||||
|
||||
**Root Cause**: JsonParserBox is defined in external file, not compiled/loaded at runtime.
|
||||
|
||||
**Impact**: Can't run original integration tests in current form.
|
||||
|
||||
---
|
||||
|
||||
### Workaround: Simplified Test
|
||||
|
||||
**Created**: `local_tests/test_trim_main_pattern.hako`
|
||||
|
||||
**Purpose**: Test same loop structure without `using` dependency.
|
||||
|
||||
**Structure**:
|
||||
```nyash
|
||||
static box TrimTest {
|
||||
method trim(s) {
|
||||
// Same structure as JsonParserBox._trim
|
||||
loop(start < end) { ... break }
|
||||
loop(end > start) { ... break }
|
||||
}
|
||||
main(args) { ... }
|
||||
}
|
||||
```
|
||||
|
||||
**Result**: Successfully routes to Pattern2, exposes boundary issue.
|
||||
|
||||
---
|
||||
|
||||
## Phase 170-C: Next Phase Planning ✅
|
||||
|
||||
### Immediate TODOs (Phase 171+ Candidates)
|
||||
|
||||
**Priority 1: Fix ValueId Boundary Mapping** (HIGHEST PRIORITY)
|
||||
- **Why**: Blocks all JsonParserBox complex condition tests
|
||||
- **What**: Extract condition variables and add to `JoinInlineBoundary`
|
||||
- **Where**: Pattern lowerers (pattern1/2/3/4)
|
||||
- **Estimate**: 4.5 hours
|
||||
- **Details**: See Option A in [phase170-valueid-boundary-analysis.md](phase170-valueid-boundary-analysis.md)
|
||||
|
||||
**Priority 2: Using Statement / Box Loading** (MEDIUM)
|
||||
- **Why**: Enable actual JsonParserBox integration tests
|
||||
- **What**: Compile and register boxes from `using` statements
|
||||
- **Alternatives**:
|
||||
- Inline JsonParser code in tests (quick workaround)
|
||||
- Auto-compile static boxes (proper solution)
|
||||
|
||||
**Priority 3: Multi-Loop Function Support** (LOW)
|
||||
- **Why**: `_trim` has 2 loops in one function
|
||||
- **Current**: Each loop calls JoinIR routing separately (seems to work)
|
||||
- **Risk**: May need validation that multiple JoinIR calls per function work correctly
|
||||
|
||||
---
|
||||
|
||||
### Recommended Next Phase Direction
|
||||
|
||||
**Option A: Fix Boundary Mapping First** ✅ **RECOMMENDED**
|
||||
|
||||
**Rationale**:
|
||||
1. **Root blocker**: Boundary issue blocks ALL tests, not just one
|
||||
2. **BoolExprLowerer correct**: Phase 169 integration is solid
|
||||
3. **Pattern matching correct**: Routing and detection work perfectly
|
||||
4. **Isolated fix**: Boundary extraction is well-scoped and testable
|
||||
5. **High impact**: Once fixed, all JsonParser methods should work
|
||||
|
||||
**Alternative**: Option B (simplify code) or Option C (postpone) - both less effective.
|
||||
|
||||
---
|
||||
|
||||
## Test Results Matrix
|
||||
|
||||
| Method/Test | Pattern | JoinIR Status | Blocker | Notes |
|
||||
|-------------|---------|---------------|---------|-------|
|
||||
| `TrimTest.trim/1` (loop 1) | Pattern2 | ⚠️ Routes OK, runtime fail | ValueId boundary | `start < end` uses undefined ValueId(33, 34) |
|
||||
| `TrimTest.trim/1` (loop 2) | Pattern2 | ⚠️ Routes OK, runtime fail | ValueId boundary | `end > start` uses undefined ValueId(48, 49) |
|
||||
| `JsonParserBox._trim/1` | (untested) | - | Using statement | Can't load JsonParserBox at runtime |
|
||||
| `JsonParserBox._skip_whitespace/2` | (untested) | - | Using statement | Can't load JsonParserBox at runtime |
|
||||
| `JsonParserBox._match_literal/2` | (untested) | - | Using statement | Can't load JsonParserBox at runtime |
|
||||
| `JsonParserBox._parse_string/2` | (untested) | - | Using statement | Can't load JsonParserBox at runtime |
|
||||
| `JsonParserBox._parse_array/2` | (untested) | - | Using statement | Can't load JsonParserBox at runtime |
|
||||
| `JsonParserBox._parse_object/2` | (untested) | - | Using statement | Can't load JsonParserBox at runtime |
|
||||
|
||||
**Summary**:
|
||||
- **Routing**: ✅ All methods whitelisted, pattern detection works
|
||||
- **Compilation**: ✅ BoolExprLowerer generates correct JoinIR
|
||||
- **Runtime**: ❌ ValueId boundary issue prevents execution
|
||||
- **Integration**: ⚠️ `using` statement blocks full JsonParser tests
|
||||
|
||||
---
|
||||
|
||||
## Files Modified
|
||||
|
||||
**Modified**:
|
||||
- `src/mir/builder/control_flow/joinir/routing.rs` (+8 lines, whitelist expansion)
|
||||
|
||||
**Created**:
|
||||
- `local_tests/test_trim_main_pattern.hako` (+48 lines, test file)
|
||||
- `docs/development/current/main/phase170-valueid-boundary-analysis.md` (+270 lines, analysis)
|
||||
- `docs/development/current/main/phase170-completion-report.md` (+THIS file)
|
||||
|
||||
**Updated**:
|
||||
- `CURRENT_TASK.md` (added Phase 170 section with progress summary)
|
||||
- `docs/development/current/main/phase166-validation-report.md` (added Phase 170 update section)
|
||||
|
||||
---
|
||||
|
||||
## Technical Insights
|
||||
|
||||
### Boundary Mechanism Gap
|
||||
|
||||
**Current Design**:
|
||||
```rust
|
||||
JoinInlineBoundary::new_inputs_only(
|
||||
vec![ValueId(0)], // JoinIR loop variable
|
||||
vec![loop_var_id], // HOST loop variable
|
||||
);
|
||||
```
|
||||
|
||||
**What's Missing**: Condition variables!
|
||||
|
||||
**Needed Design**:
|
||||
```rust
|
||||
JoinInlineBoundary::new_inputs_only(
|
||||
vec![ValueId(0), ValueId(1), ValueId(2)], // loop var + cond vars
|
||||
vec![loop_var_id, start_id, end_id], // HOST ValueIds
|
||||
);
|
||||
```
|
||||
|
||||
**Why It Matters**:
|
||||
- `condition_to_joinir.rs` directly references HOST `variable_map` ValueIds
|
||||
- These ValueIds are NOT in JoinIR's fresh allocator space
|
||||
- Without boundary mapping, they remain undefined after merge
|
||||
- Silent failure: compiles but doesn't execute
|
||||
|
||||
### Two ValueId Namespaces
|
||||
|
||||
**HOST Context** (Main MirBuilder):
|
||||
- ValueIds from 0 upward (e.g., `start = ValueId(33)`)
|
||||
- All variables in `builder.variable_map`
|
||||
- Pre-existing before JoinIR call
|
||||
|
||||
**JoinIR Context** (Fresh Allocator):
|
||||
- ValueIds from 0 upward (independent sequence)
|
||||
- Generated by JoinIR lowerer
|
||||
- Post-merge: remapped to new HOST ValueIds
|
||||
|
||||
**Bridge**: `JoinInlineBoundary` maps between the two spaces with Copy instructions.
|
||||
|
||||
**Current Gap**: Only explicitly listed variables get bridged. Condition variables are implicitly referenced but not bridged.
|
||||
|
||||
---
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
- [x] Whitelist expanded (6 JsonParserBox methods + test)
|
||||
- [x] Pattern routing verified (Pattern2 detected correctly)
|
||||
- [x] BoolExprLowerer integration verified (generates JoinIR correctly)
|
||||
- [x] Boundary issue identified (root cause documented)
|
||||
- [x] Test file created (simplified _trim test)
|
||||
- [x] Root cause analysis completed (270-line document)
|
||||
- [x] Next phase direction decided (Option A recommended)
|
||||
- [x] Documentation updated (CURRENT_TASK.md, phase166 report)
|
||||
- [x] Files committed (ready for next phase)
|
||||
|
||||
---
|
||||
|
||||
## Next Phase: Phase 171 - Boundary Mapping Fix
|
||||
|
||||
**Recommended Implementation**:
|
||||
|
||||
1. **Create condition variable extractor** (30 min)
|
||||
- File: `src/mir/builder/control_flow/joinir/patterns/cond_var_extractor.rs`
|
||||
- Function: `extract_condition_variables(ast: &ASTNode, builder: &MirBuilder) -> Vec<(String, ValueId)>`
|
||||
|
||||
2. **Update Pattern2** (1 hour)
|
||||
- Extract condition variables before lowering
|
||||
- Create expanded boundary with condition vars
|
||||
- Test with `TrimTest.trim/1`
|
||||
|
||||
3. **Update Pattern1, Pattern3, Pattern4** (3 hours)
|
||||
- Apply same pattern
|
||||
- Ensure all patterns include condition vars in boundary
|
||||
|
||||
4. **Validation** (30 min)
|
||||
- Re-run `TrimTest.trim/1` → should print output
|
||||
- Re-run JsonParserBox tests (if `using` resolved)
|
||||
|
||||
**Total Estimate**: 5 hours
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
Phase 170 successfully prepared the environment for JsonParserBox validation and identified the critical blocker preventing runtime execution. The boundary mapping issue is well-understood, with a clear solution path (Option A: extract condition variables).
|
||||
|
||||
**Key Achievements**:
|
||||
- ✅ Whitelist expansion enables JsonParserBox routing
|
||||
- ✅ BoolExprLowerer integration verified working correctly
|
||||
- ✅ Boundary issue root cause identified and documented
|
||||
- ✅ Clear next steps with 5-hour implementation estimate
|
||||
|
||||
**Next Step**: Implement Phase 171 - Condition Variable Extraction for Boundary Mapping.
|
||||
|
||||
---
|
||||
|
||||
## Phase 170‑C‑1: CaseA Shape 検出の暫定実装メモ
|
||||
|
||||
Phase 170‑C‑1 では、当初「LoopUpdateAnalyzer (AST) → UpdateExpr を使って Generic 判定を減らす」方針だったが、
|
||||
実装コストと他フェーズとの依存関係を考慮し、まずは **carrier 名ベースの軽量ヒューリスティック** を導入した。
|
||||
|
||||
### 現状の実装方針
|
||||
|
||||
- `CaseALoweringShape::detect_from_features()` の内部で、LoopFeatures だけでは足りない情報を
|
||||
**carrier 名からのヒント** で補っている:
|
||||
- `i`, `e`, `idx`, `pos` など → 「位置・インデックス」寄りのキャリア
|
||||
- `result`, `defs` など → 「蓄積・結果」寄りのキャリア
|
||||
- これにより、`Generic` 一択だったものを簡易的に:
|
||||
- StringExamination 系(位置スキャン系)
|
||||
- ArrayAccumulation 系(配列への追加系)
|
||||
に二分できるようにしている。
|
||||
|
||||
### 限界と今後
|
||||
|
||||
- これはあくまで **Phase 170‑C‑1 の暫定策** であり、箱理論上の最終形ではない:
|
||||
- 変数名に依存しているため、完全にハードコードを排除できているわけではない。
|
||||
- 真に綺麗にするには、LoopUpdateAnalyzer / 型推定層から UpdateKind や carrier 型情報を LoopFeatures に統合する必要がある。
|
||||
- 今後のフェーズ(170‑C‑2 以降)では:
|
||||
- `LoopUpdateAnalyzer` に `UpdateKind` の分類を追加し、
|
||||
- `CounterLike` / `AccumulationLike` 等を LoopFeatures に持たせる。
|
||||
- 可能であれば carrier の型(String / Array 等)を推定する軽量層を追加し、
|
||||
`CaseALoweringShape` は **名前ではなく UpdateKind/型情報だけ** を見て判定する方向に寄せていく。
|
||||
|
||||
この暫定実装は「Phase 200 での loop_to_join.rs ハードコード削除に向けた足場」として扱い、
|
||||
将来的には carrier 名依存のヒューリスティックを段階的に薄めていく予定。
|
||||
|
||||
---
|
||||
|
||||
## Phase 170‑C‑2b: LoopUpdateSummary 統合(実装メモ)
|
||||
|
||||
Phase 170‑C‑2b では、LoopUpdateSummaryBox を実コードに差し込み、
|
||||
CaseALoweringShape が直接 carrier 名を見ることなく UpdateKind 経由で判定できるようにした。
|
||||
|
||||
### 実装ポイント
|
||||
|
||||
- 既存の `LoopUpdateSummary` 型を活用し、`LoopFeatures` にフィールドを追加:
|
||||
|
||||
```rust
|
||||
pub struct LoopFeatures {
|
||||
// 既存フィールド …
|
||||
pub update_summary: Option<LoopUpdateSummary>, // ← new
|
||||
}
|
||||
```
|
||||
|
||||
- `CaseALoweringShape` 側に `detect_with_updates()` を追加し、
|
||||
`LoopUpdateSummary` 内の `UpdateKind` を見て形を決めるようにした:
|
||||
|
||||
```rust
|
||||
match update.kind {
|
||||
UpdateKind::CounterLike => CaseALoweringShape::StringExamination,
|
||||
UpdateKind::AccumulationLike => CaseALoweringShape::ArrayAccumulation,
|
||||
UpdateKind::Other => CaseALoweringShape::Generic,
|
||||
}
|
||||
```
|
||||
|
||||
- `loop_to_join.rs` では、まず `detect_with_updates()` を試し、
|
||||
それで決まらない場合のみ従来のフォールバックに流す構造に変更。
|
||||
|
||||
### 効果と現状
|
||||
|
||||
- carrier 名に依存するロジックは `LoopUpdateSummaryBox` の内部に閉じ込められ、
|
||||
CaseALoweringShape / loop_to_join.rs からは UpdateKind だけが見える形になった。
|
||||
- 代表的な ループスモーク 16 本のうち 15 本が PASS(1 本は既知の別問題)で、
|
||||
既存パターンへの回帰は維持されている。
|
||||
|
||||
この状態を起点に、今後 Phase 170‑C‑3 以降で `LoopUpdateSummary` の中身(AST/MIR ベースの解析)だけを差し替えることで、
|
||||
段階的に carrier 名ヒューリスティックを薄めていく計画。
|
||||
|
||||
---
|
||||
|
||||
## Phase 170-D: Loop Condition Scope Analysis - Bug Fix Verification ✅
|
||||
|
||||
**Date**: 2025-12-07 (Session 2)
|
||||
**Status**: ✅ **Bug Fix Complete and Verified**
|
||||
|
||||
### Bug Fix: Function Parameter Misclassification
|
||||
|
||||
**Issue**: Function parameters (`s`, `pos` in JsonParser methods) were incorrectly classified as **LoopBodyLocal** when used in loop conditions.
|
||||
|
||||
**Root Cause**: `is_outer_scope_variable()` in `condition_var_analyzer.rs` defaulted unknown variables (not in `variable_definitions`) to LoopBodyLocal.
|
||||
|
||||
**Fix** (User Implemented):
|
||||
```rust
|
||||
// File: src/mir/loop_pattern_detection/condition_var_analyzer.rs (lines 175-184)
|
||||
|
||||
// At this point:
|
||||
// - Variable is NOT in body_locals
|
||||
// - No explicit definition info
|
||||
// This typically means "function parameter" or "outer local"
|
||||
true // ✅ Default to OuterLocal for function parameters
|
||||
```
|
||||
|
||||
### Verification Results
|
||||
|
||||
**Test 1: Function Parameter Loop** ✅
|
||||
- **File**: `/tmp/test_jsonparser_simple.hako`
|
||||
- **Result**: `Phase 170-D: Condition variables verified: {"pos", "s", "len"}`
|
||||
- **Analysis**: Function parameters correctly classified as OuterLocal
|
||||
- **New blocker**: Method calls (Pattern 5+ feature, not a bug)
|
||||
|
||||
**Test 2: LoopBodyLocal Correct Rejection** ✅
|
||||
- **File**: `local_tests/test_trim_main_pattern.hako`
|
||||
- **Result**: `Phase 170-D: Condition variables verified: {"ch", "end", "start"}`
|
||||
- **Error**: "Variable 'ch' not bound in ConditionEnv" (correct rejection)
|
||||
- **Analysis**: `ch` is defined inside loop, correctly rejected by Pattern 2
|
||||
|
||||
**Test 3: JsonParser Full File** ✅
|
||||
- **File**: `tools/hako_shared/json_parser.hako`
|
||||
- **Result**: Error about MethodCall, not variable classification
|
||||
- **Analysis**: Variable scope classification now correct, remaining errors are legitimate feature gaps
|
||||
|
||||
### Impact
|
||||
|
||||
**What the Fix Achieves**:
|
||||
- ✅ Function parameters work correctly: `s`, `pos` in JsonParser
|
||||
- ✅ Carrier variables work correctly: `start`, `end` in trim loops
|
||||
- ✅ Outer locals work correctly: `len`, `maxLen` from outer scope
|
||||
- ✅ Correct rejection: LoopBodyLocal `ch` properly rejected (not a bug)
|
||||
|
||||
**Remaining Blockers** (Pattern 5+ features, not bugs):
|
||||
- ⚠️ Method calls in conditions: `loop(pos < s.length())`
|
||||
- ⚠️ Method calls in loop body: `s.substring(pos, pos+1)`
|
||||
- ⚠️ LoopBodyLocal in break conditions: `if ch == " " { break }`
|
||||
|
||||
### Documentation
|
||||
|
||||
**Created**:
|
||||
1. ✅ `phase170-d-fix-verification.md` - Comprehensive verification report
|
||||
2. ✅ `phase170-d-fix-summary.md` - Executive summary
|
||||
3. ✅ Updated `CURRENT_TASK.md` - Bug fix section added
|
||||
4. ✅ Updated `phase170-d-impl-design.md` - Bug fix notes
|
||||
|
||||
### Next Steps
|
||||
|
||||
**Priority 1**: Pattern 5+ implementation for LoopBodyLocal in break conditions
|
||||
**Priority 2**: .hako rewrite strategy for complex method calls
|
||||
**Priority 3**: Coverage metrics for JsonParser loop support
|
||||
|
||||
**Build Status**: ✅ `cargo build --release` successful (0 errors, 50 warnings)
|
||||
@ -1,299 +0,0 @@
|
||||
# Phase 171: JoinIR → MIR ValueId Boundary Mapping Fix - Completion Report
|
||||
|
||||
**Date**: 2025-12-07
|
||||
**Status**: ✅ Infrastructure Complete (Testing in Progress)
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Successfully implemented the infrastructure to map condition-only input variables across the JoinIR → MIR boundary. This fixes the root cause of "undefined ValueId" errors for variables like `start`, `end`, `len` that appear only in loop conditions.
|
||||
|
||||
**Problem Solved**: Variables used only in loop conditions (not loop parameters) were using HOST ValueIds directly in JoinIR, causing undefined value errors when merged into MIR.
|
||||
|
||||
**Solution Implemented**: Extended `JoinInlineBoundary` with `condition_inputs` field and updated the entire merge pipeline to collect, remap, and inject Copy instructions for these variables.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Phases Completed
|
||||
|
||||
### ✅ Phase 171-1: Boundary Coverage Analysis
|
||||
|
||||
**Deliverable**: `phase171-1-boundary-analysis.md` (documented current state)
|
||||
|
||||
**Key Findings**:
|
||||
- Loop variables (`i`): ✅ Properly mapped via `join_inputs`
|
||||
- Carriers (`sum`, `count`): ✅ Properly mapped via `exit_bindings`
|
||||
- **Condition inputs (`start`, `end`)**: ❌ NOT MAPPED → **ROOT CAUSE**
|
||||
|
||||
### ✅ Phase 171-2: Design Decision
|
||||
|
||||
**Deliverable**: `phase171-2-condition-inputs-design.md`
|
||||
|
||||
**Decision**: **Option A - Extend JoinInlineBoundary**
|
||||
|
||||
Added field:
|
||||
```rust
|
||||
pub condition_inputs: Vec<(String, ValueId)>
|
||||
```
|
||||
|
||||
**Rationale**:
|
||||
1. Minimal invasiveness
|
||||
2. Clear semantics
|
||||
3. Reuses existing Copy injection mechanism
|
||||
4. Future-proof design
|
||||
|
||||
### ✅ Phase 171-3: Infrastructure Implementation
|
||||
|
||||
**Deliverable**: `phase171-3-implementation-report.md`
|
||||
|
||||
**Files Modified**:
|
||||
|
||||
1. **`inline_boundary.rs`** (+93 lines)
|
||||
- Added `condition_inputs` field
|
||||
- Added 2 new constructors
|
||||
- Updated 4 existing constructors
|
||||
|
||||
2. **`condition_to_joinir.rs`** (+180 lines)
|
||||
- Implemented `extract_condition_variables()`
|
||||
- Added recursive AST traversal
|
||||
- Added 3 comprehensive tests
|
||||
|
||||
3. **`exit_binding.rs`** (+2 lines)
|
||||
- Fixed test boundary initialization
|
||||
|
||||
**Build Status**: ✅ Successful (0 errors, 57 warnings)
|
||||
|
||||
### ✅ Phase 171-4: Merge Logic Integration
|
||||
|
||||
**Files Modified**:
|
||||
|
||||
1. **`pattern2_with_break.rs`** (+19 lines)
|
||||
- Extract condition variables from AST
|
||||
- Look up HOST ValueIds
|
||||
- Pass to boundary constructor
|
||||
|
||||
2. **`merge/mod.rs`** (+13 lines)
|
||||
- Add condition_inputs to used_values for remapping
|
||||
- Debug logging for condition inputs
|
||||
|
||||
3. **`merge/instruction_rewriter.rs`** (+17 lines)
|
||||
- Add condition_inputs to value_map_for_injector
|
||||
- Enable remapping of HOST ValueIds
|
||||
|
||||
4. **`joinir_inline_boundary_injector.rs`** (+35 lines)
|
||||
- Inject Copy instructions for condition inputs
|
||||
- Handle both join_inputs and condition_inputs
|
||||
|
||||
**Build Status**: ✅ Successful (0 errors, 57 warnings)
|
||||
|
||||
---
|
||||
|
||||
## Technical Changes Summary
|
||||
|
||||
### Data Flow: Before vs After
|
||||
|
||||
#### Before (Broken)
|
||||
```
|
||||
HOST: start = ValueId(33)
|
||||
↓ condition_to_joinir reads directly
|
||||
JoinIR: uses ValueId(33) in Compare
|
||||
↓ NO BOUNDARY, NO REMAP
|
||||
MIR: ValueId(33) undefined → ERROR ❌
|
||||
```
|
||||
|
||||
#### After (Fixed)
|
||||
```
|
||||
HOST: start = ValueId(33)
|
||||
↓ pattern2_with_break extracts "start"
|
||||
↓ boundary.condition_inputs = [("start", ValueId(33))]
|
||||
↓ merge adds to used_values
|
||||
↓ remap_values: ValueId(33) → ValueId(100)
|
||||
↓ BoundaryInjector: Copy ValueId(100) = Copy ValueId(33)
|
||||
JoinIR: uses ValueId(33) in Compare
|
||||
↓ instruction_rewriter remaps to ValueId(100)
|
||||
MIR: ValueId(100) = Copy ValueId(33) → SUCCESS ✅
|
||||
```
|
||||
|
||||
### Key Implementation Points
|
||||
|
||||
**1. Condition Variable Extraction** (`condition_to_joinir.rs:326-361`)
|
||||
```rust
|
||||
pub fn extract_condition_variables(
|
||||
cond_ast: &ASTNode,
|
||||
exclude_vars: &[String], // Loop parameters to exclude
|
||||
) -> Vec<String>
|
||||
```
|
||||
- Recursively traverses condition AST
|
||||
- Collects unique variable names
|
||||
- Filters out loop parameters
|
||||
- Returns sorted list (BTreeSet for determinism)
|
||||
|
||||
**2. Boundary Registration** (`pattern2_with_break.rs:73-92`)
|
||||
```rust
|
||||
let condition_var_names = extract_condition_variables(condition, &[loop_var_name.clone()]);
|
||||
let mut condition_inputs = Vec::new();
|
||||
for var_name in &condition_var_names {
|
||||
let host_value_id = self.variable_map.get(var_name)
|
||||
.copied()
|
||||
.ok_or_else(|| ...)?;
|
||||
condition_inputs.push((var_name.clone(), host_value_id));
|
||||
}
|
||||
```
|
||||
|
||||
**3. Value Collection** (`merge/mod.rs:80-91`)
|
||||
```rust
|
||||
// Add condition_inputs to used_values for remapping
|
||||
if let Some(boundary) = boundary {
|
||||
for (var_name, host_value_id) in &boundary.condition_inputs {
|
||||
used_values.insert(*host_value_id);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**4. Value Remapping** (`merge/instruction_rewriter.rs:402-415`)
|
||||
```rust
|
||||
// Add condition_inputs to value_map
|
||||
for (var_name, host_value_id) in &boundary.condition_inputs {
|
||||
if let Some(remapped) = remapper.get_value(*host_value_id) {
|
||||
value_map_for_injector.insert(*host_value_id, remapped);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**5. Copy Injection** (`joinir_inline_boundary_injector.rs:86-116`)
|
||||
```rust
|
||||
// Inject Copy instructions for condition_inputs
|
||||
for (var_name, host_value_id) in &boundary.condition_inputs {
|
||||
if let Some(&remapped_value) = value_map.get(host_value_id) {
|
||||
let copy_inst = MirInstruction::Copy {
|
||||
dst: remapped_value,
|
||||
src: *host_value_id,
|
||||
};
|
||||
copy_instructions.push(copy_inst);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Test Status
|
||||
|
||||
### ✅ Unit Tests Pass
|
||||
|
||||
**Extraction function tests** (`condition_to_joinir.rs`):
|
||||
- `test_extract_condition_variables_simple` ✅
|
||||
- `test_extract_condition_variables_with_exclude` ✅
|
||||
- `test_extract_condition_variables_complex` ✅
|
||||
|
||||
### 🔄 Integration Tests (In Progress)
|
||||
|
||||
**Test File**: `local_tests/test_trim_main_pattern.hako`
|
||||
|
||||
**Current Status**: Still shows undefined ValueId errors:
|
||||
```
|
||||
[ssa-undef-debug] fn=TrimTest.trim/1 bb=BasicBlockId(8) inst_idx=0 used=ValueId(33)
|
||||
[ssa-undef-debug] fn=TrimTest.trim/1 bb=BasicBlockId(17) inst_idx=0 used=ValueId(49)
|
||||
```
|
||||
|
||||
**Next Debugging Steps**:
|
||||
1. Add debug output to Pattern 2 lowerer to confirm condition variable extraction
|
||||
2. Verify boundary condition_inputs are populated
|
||||
3. Check value remapping in merge logic
|
||||
4. Verify Copy instruction injection
|
||||
|
||||
---
|
||||
|
||||
## Remaining Work
|
||||
|
||||
### Phase 171-5: Verification & Documentation
|
||||
|
||||
**Tasks**:
|
||||
1. ✅ Unit tests complete
|
||||
2. 🔄 Integration tests (debugging in progress)
|
||||
3. ⏳ Update CURRENT_TASK.md
|
||||
4. ⏳ Final documentation
|
||||
|
||||
**Blocker**: Need to debug why ValueId(33) is still undefined despite infrastructure being in place.
|
||||
|
||||
**Hypothesis**: The issue might be:
|
||||
- Condition variable extraction not running (check debug output)
|
||||
- Boundary not being passed correctly
|
||||
- Value remapping not applying to all instruction types
|
||||
- Copy instructions not being injected
|
||||
|
||||
---
|
||||
|
||||
## Files Modified (Summary)
|
||||
|
||||
| File | Lines Changed | Purpose |
|
||||
|------|--------------|---------|
|
||||
| `inline_boundary.rs` | +93 | Add condition_inputs field + constructors |
|
||||
| `condition_to_joinir.rs` | +180 | Extract condition variables from AST |
|
||||
| `exit_binding.rs` | +2 | Fix test |
|
||||
| `pattern2_with_break.rs` | +19 | Register condition inputs |
|
||||
| `merge/mod.rs` | +13 | Add to used_values |
|
||||
| `merge/instruction_rewriter.rs` | +17 | Add to value_map |
|
||||
| `joinir_inline_boundary_injector.rs` | +35 | Inject Copy instructions |
|
||||
| **Total** | **+359 lines** | **Complete infrastructure** |
|
||||
|
||||
---
|
||||
|
||||
## Design Principles Applied
|
||||
|
||||
1. **Box-First Philosophy** ✅
|
||||
- Clean separation: JoinIR frontier, boundary metadata, merge logic
|
||||
- Each component has single responsibility
|
||||
|
||||
2. **Fail-Fast** ✅
|
||||
- Explicit error when condition variable not in variable_map
|
||||
- No silent fallbacks
|
||||
|
||||
3. **Determinism** ✅
|
||||
- BTreeSet for sorted variable names
|
||||
- Consistent iteration order
|
||||
|
||||
4. **80/20 Rule** ✅
|
||||
- Infrastructure first (80%)
|
||||
- Debugging and edge cases (20% - in progress)
|
||||
|
||||
---
|
||||
|
||||
## Known Limitations
|
||||
|
||||
1. **Pattern 1/3/4 Not Yet Updated**
|
||||
- Only Pattern 2 (loop_with_break) currently implements condition input extraction
|
||||
- Other patterns will need similar updates
|
||||
|
||||
2. **No Condition-Only Outputs**
|
||||
- Current design handles inputs only
|
||||
- Outputs would need similar treatment (future extension point)
|
||||
|
||||
3. **Manual Debugging Required**
|
||||
- Integration tests not yet passing
|
||||
- Need to trace execution to find where mapping breaks down
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
**Immediate**:
|
||||
1. Add debug output to confirm condition variable extraction runs
|
||||
2. Verify boundary.condition_inputs is populated
|
||||
3. Check if Copy instructions are actually injected
|
||||
4. Trace ValueId remapping through merge pipeline
|
||||
|
||||
**Follow-up**:
|
||||
1. Update Pattern 1/3/4 lowerers with same infrastructure
|
||||
2. Add integration tests for each pattern
|
||||
3. Document edge cases and limitations
|
||||
4. Update CURRENT_TASK.md with completion status
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- Phase 171-1 Analysis: `phase171-1-boundary-analysis.md`
|
||||
- Phase 171-2 Design: `phase171-2-condition-inputs-design.md`
|
||||
- Phase 171-3 Implementation: `phase171-3-implementation-report.md`
|
||||
- Phase 170 Background: `phase170-completion-report.md`
|
||||
@ -1,138 +0,0 @@
|
||||
# Phase 176-1: Pattern2 Limitation Investigation - Completion Report
|
||||
|
||||
**Date**: 2025-12-08
|
||||
**Status**: ✅ COMPLETE
|
||||
**Task**: Mark all single-carrier limitations in Pattern2 lowerer
|
||||
|
||||
---
|
||||
|
||||
## What Was Done
|
||||
|
||||
Investigated `src/mir/join_ir/lowering/loop_with_break_minimal.rs` and identified **10 critical points** where the lowerer currently only handles the position carrier (`i`) and ignores `CarrierInfo.carriers`.
|
||||
|
||||
### Files Modified
|
||||
|
||||
1. **`src/mir/join_ir/lowering/loop_with_break_minimal.rs`**
|
||||
- Added 10 TODO comments marking limitation points
|
||||
- No code changes (read + memo level only)
|
||||
|
||||
2. **`docs/development/current/main/phase176-pattern2-limitations.md`**
|
||||
- Created comprehensive limitation report
|
||||
- Detailed explanation of each limitation point
|
||||
- Impact analysis and next steps
|
||||
|
||||
---
|
||||
|
||||
## Limitation Points Identified
|
||||
|
||||
### Easy Fixes (9 points) - Iteration-based
|
||||
1. **ValueId Allocation** (Line 172) - Only allocates for position carrier
|
||||
2. **Main Function Params** (Line 208) - Only takes `i_init`
|
||||
3. **Loop Step Call Args** (Line 214) - Only passes `i_init`
|
||||
4. **Loop Step Params** (Line 234) - Only takes `i_param`
|
||||
5. **Natural Exit Jump** (Line 257) - Only passes `i_param` to k_exit
|
||||
6. **Break Exit Jump** (Line 272) - Only passes `i_param` to k_exit
|
||||
7. **Tail Call Args** (Line 304) - Only passes `i_next`
|
||||
8. **K_Exit Params** (Line 319) - Only takes `i_exit`
|
||||
9. **ExitMeta Construction** (Line 344) - Only includes position carrier
|
||||
|
||||
### Hard Fix (1 point) - Requires AST Body Analysis
|
||||
10. **Loop Body Updates** (Line 284) - Only computes `i_next = i + 1`
|
||||
- **Challenge**: Need to analyze AST body to determine carrier updates
|
||||
- **Example**: How do we know `sum = sum + x` updates the `sum` carrier?
|
||||
|
||||
---
|
||||
|
||||
## Key Findings
|
||||
|
||||
### Architecture Issue
|
||||
The Pattern2 lowerer completely ignores `CarrierInfo.carriers`:
|
||||
|
||||
```rust
|
||||
pub struct CarrierInfo {
|
||||
pub loop_var_name: String, // Used ✅
|
||||
pub loop_var_id: ValueId, // Used ✅
|
||||
pub carriers: Vec<CarrierVar>, // IGNORED ❌
|
||||
pub trim_helper: Option<TrimLoopHelper>,
|
||||
}
|
||||
```
|
||||
|
||||
The function signature only takes `loop_var_name` as a separate string parameter, losing access to the full CarrierInfo structure.
|
||||
|
||||
### Infrastructure Ready
|
||||
- ✅ **CarrierInfo**: Already multi-carrier ready (Phase 175)
|
||||
- ✅ **ExitMeta**: Supports `ExitMeta::multiple(vec![...])` for multi-carrier
|
||||
- ✅ **LoopHeaderPhiBuilder**: Multi-carrier ready (Phase 175)
|
||||
- ✅ **ExitPhiBuilder**: Multi-carrier ready (Phase 175)
|
||||
|
||||
**Problem**: Pattern2 lowerer doesn't use these capabilities!
|
||||
|
||||
---
|
||||
|
||||
## Next Phase Roadmap
|
||||
|
||||
### Phase 176-2: Iteration-Based Fixes
|
||||
**Difficulty**: Easy
|
||||
**Estimate**: 1-2 hours
|
||||
|
||||
Fix points 1-6, 8-10 by iterating over `CarrierInfo.carriers`:
|
||||
- Allocate ValueIds for all carriers
|
||||
- Extend function params/call args/jump args
|
||||
- Build multi-carrier ExitMeta
|
||||
|
||||
### Phase 176-3: Loop Body Analysis
|
||||
**Difficulty**: Hard
|
||||
**Estimate**: 3-4 hours
|
||||
|
||||
Fix point 7 by analyzing AST body:
|
||||
- Track carrier assignments in loop body
|
||||
- Emit update instructions for each carrier
|
||||
- Handle complex cases (conditional updates, etc.)
|
||||
|
||||
### Integration Test
|
||||
Pattern 3 (trim) with Pattern 2 shape:
|
||||
```nyash
|
||||
loop(pos < len) {
|
||||
if ch == ' ' { break }
|
||||
pos = pos + 1
|
||||
}
|
||||
```
|
||||
|
||||
Verify sum/count carriers survive through break exits.
|
||||
|
||||
---
|
||||
|
||||
## Deliverables
|
||||
|
||||
1. ✅ **TODO Comments**: 10 markers added to `loop_with_break_minimal.rs`
|
||||
2. ✅ **Limitation Report**: `phase176-pattern2-limitations.md`
|
||||
3. ✅ **Completion Report**: This document
|
||||
|
||||
---
|
||||
|
||||
## How to Use This Report
|
||||
|
||||
For Task 176-2/3 implementers:
|
||||
|
||||
1. **Read the limitation report first**: `phase176-pattern2-limitations.md`
|
||||
2. **Start with easy fixes**: Points 1-6, 8-10 (iteration-based)
|
||||
3. **Tackle hard fix last**: Point 7 (loop body analysis)
|
||||
4. **Use TODO markers as guide**: Search for `TODO(Phase 176)` in code
|
||||
5. **Test with Pattern 3**: Use trim pattern as integration test
|
||||
|
||||
---
|
||||
|
||||
## Related Files
|
||||
|
||||
- **Main file**: `src/mir/join_ir/lowering/loop_with_break_minimal.rs`
|
||||
- **CarrierInfo**: `src/mir/join_ir/lowering/carrier_info.rs`
|
||||
- **Limitation report**: `docs/development/current/main/phase176-pattern2-limitations.md`
|
||||
- **This report**: `docs/development/current/main/phase176-1-completion-report.md`
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
Task 176-1 successfully identified and documented all 10 single-carrier limitations in the Pattern2 lowerer. The code is now well-marked with TODO comments, and a comprehensive analysis report is available for the next implementation phases.
|
||||
|
||||
**Ready for Phase 176-2/3 implementation!** 🚀
|
||||
@ -1,63 +0,0 @@
|
||||
# Phase 176: Pattern2 Multi-Carrier Lowering - 完了レポート
|
||||
|
||||
**日付**: 2025-12-08
|
||||
**ステータス**: ✅ 完全成功
|
||||
|
||||
---
|
||||
|
||||
## 概要
|
||||
|
||||
Phase 175 で「アーキテクチャは multi-carrier ready だが、Pattern2 lowerer の実装が pos のみ」という問題を発見。
|
||||
Phase 176 でこの実装ギャップを埋め、Pattern2 が複数キャリアに完全対応した。
|
||||
|
||||
---
|
||||
|
||||
## 実装内容
|
||||
|
||||
### Task 176-1: 制限ポイント特定
|
||||
- 10箇所の「pos だけ」制約を TODO コメントでマーク
|
||||
- ヘッダ PHI / ループ更新 / ExitLine の 3 カテゴリに分類
|
||||
|
||||
### Task 176-2: CarrierUpdateLowerer ヘルパ
|
||||
- `emit_carrier_update()` 関数実装(UpdateExpr → JoinIR 変換)
|
||||
- CounterLike / AccumulationLike 両対応
|
||||
- 6 unit tests 全てパス
|
||||
|
||||
### Task 176-3: Pattern2 Lowerer 拡張
|
||||
- ヘッダ PHI: 全キャリア分の PHI パラメータを生成
|
||||
- ループ更新: CarrierInfo.carriers をループして emit_carrier_update() 呼び出し
|
||||
- ExitLine: 全キャリアの ExitMeta を構築
|
||||
|
||||
### Task 176-4: E2E テスト
|
||||
- 2キャリア(pos + result)テストが完全動作
|
||||
- **バグ修正 1**: Trim pattern で loop_var_name が上書きされていた(pattern2_with_break.rs:271-272)
|
||||
- **バグ修正 2**: InstructionRewriter が loop_var を exit_bindings から除外していなかった
|
||||
|
||||
### Task 176-5: ドキュメント更新
|
||||
- phase175-multicarrier-design.md に完了マーク
|
||||
- joinir-architecture-overview.md の F軸更新
|
||||
- CURRENT_TASK.md に Phase 177 メモ追加
|
||||
|
||||
---
|
||||
|
||||
## テスト結果
|
||||
|
||||
✅ E2E テスト: 3 件全てパス(RC=0)
|
||||
✅ Unit テスト: 6 件全てパス
|
||||
✅ 回帰テストなし
|
||||
|
||||
---
|
||||
|
||||
## 技術的成果
|
||||
|
||||
- **コード削減**: Phase 176-1 の調査で、将来的に数百行の単純化が可能と判明
|
||||
- **汎用性**: Pattern2 が単一/複数キャリアの両方に対応(Trim / JsonParser で共通利用可能)
|
||||
- **設計修正**: Trim pattern の「キャリア = ループ変数」という誤解を解消
|
||||
|
||||
---
|
||||
|
||||
## 次のステップ (Phase 177)
|
||||
|
||||
- JsonParser `_parse_string` 本体を P2+P5 で通す
|
||||
- pos + result の 2 キャリアが正しく動作することを確認
|
||||
- エスケープ処理は Phase 178+ で対応
|
||||
@ -1,390 +0,0 @@
|
||||
# Phase 182 Completion Report: JsonParser Simple Loop Implementation (P2/P1 Verification)
|
||||
|
||||
**Date**: 2025-12-08
|
||||
**Status**: ✅ **PARTIAL SUCCESS** - Pattern routing verified, blockers identified
|
||||
**Goal**: Implement JsonParser simple loops (_parse_number, _atoi, _match_literal) using existing P2/P1 patterns
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Phase 182 successfully verified that Pattern1 (Simple) and Pattern2 (Break) routing and execution work correctly for basic loop patterns. However, we discovered **two fundamental blockers** that prevent the actual JsonParser loops from working:
|
||||
|
||||
1. **LoopBodyLocal variable handling** - Current system assumes Trim-specific carrier promotion
|
||||
2. **String concatenation filter** - Phase 178's conservative rejection of string operations
|
||||
|
||||
### Achievement Status
|
||||
|
||||
| Task | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| 182-1: Design Document | ✅ COMPLETE | phase182-simple-loops-design.md created |
|
||||
| 182-2: Routing Whitelist | ✅ COMPLETE | Added 3 methods, fixed _match_literal arity |
|
||||
| 182-3: Pattern Routing | ✅ VERIFIED | P1/P2 route correctly with structure-only mode |
|
||||
| 182-5: Representative Tests | ✅ PASSING | 2 tests created, both PASS |
|
||||
| 182-6: Documentation | ✅ COMPLETE | Updated architecture docs + CURRENT_TASK |
|
||||
|
||||
---
|
||||
|
||||
## Detailed Results
|
||||
|
||||
### Task 182-1: Design Document ✅
|
||||
|
||||
**File**: `docs/development/current/main/phase182-simple-loops-design.md`
|
||||
|
||||
Created comprehensive design memo covering:
|
||||
- Target loop analysis (3 loops: _parse_number, _atoi, _match_literal)
|
||||
- Pattern mapping (P2 Break × 2, P1 Simple × 1)
|
||||
- Pipeline integration strategy (reuse PatternPipelineContext)
|
||||
- Verification plan (structure-only tracing + representative tests)
|
||||
|
||||
**Commit**: `5d99c31c` - "docs(joinir): Add Phase 182 simple loops design memo"
|
||||
|
||||
---
|
||||
|
||||
### Task 182-2: Routing Whitelist Update ✅
|
||||
|
||||
**File**: `src/mir/builder/control_flow/joinir/routing.rs`
|
||||
|
||||
**Changes Made**:
|
||||
1. Added `JsonParserBox._parse_number/2` → P2 Break
|
||||
2. Added `JsonParserBox._atoi/1` → P2 Break
|
||||
3. Fixed `JsonParserBox._match_literal` arity: `/2` → `/3` (s, pos, literal)
|
||||
|
||||
**Rationale**:
|
||||
- Phase 181 analysis identified these 3 loops as high-priority, low-difficulty targets
|
||||
- Verified actual signatures from `tools/hako_shared/json_parser.hako`
|
||||
- Arity counting follows Nyash convention (excludes implicit `me` parameter)
|
||||
|
||||
**Commit**: `be063658` - "feat(joinir): Phase 182-2 Add _parse_number/_atoi to routing whitelist"
|
||||
|
||||
---
|
||||
|
||||
### Task 182-3: Pattern Routing Verification ✅
|
||||
|
||||
**Method**: Used `NYASH_JOINIR_STRUCTURE_ONLY=1` + `NYASH_JOINIR_DEBUG=1` tracing
|
||||
|
||||
**Results**:
|
||||
|
||||
#### Pattern1 (_match_literal) - ✅ SUCCESS
|
||||
```bash
|
||||
[trace:pattern] route: Pattern1_Minimal MATCHED
|
||||
[joinir/pattern1] Generated JoinIR for Simple While Pattern
|
||||
[joinir/pattern1] Functions: main, loop_step, k_exit
|
||||
```
|
||||
|
||||
#### Pattern2 (Simple integer loop) - ✅ SUCCESS
|
||||
```bash
|
||||
[trace:pattern] route: Pattern2_WithBreak MATCHED
|
||||
[pattern2/init] PatternPipelineContext: loop_var='i', loop_var_id=ValueId(5), carriers=3
|
||||
[joinir/pattern2] Phase 170-D: Condition variables verified: {"i", "limit"}
|
||||
[joinir/pattern2] Generated JoinIR for Loop with Break Pattern
|
||||
```
|
||||
|
||||
#### Full JsonParser Loops - ❌ BLOCKED (Expected)
|
||||
|
||||
**Blocker 1**: LoopBodyLocal promotion error
|
||||
```
|
||||
[ERROR] ❌ [TrimLoopLowerer] Cannot promote LoopBodyLocal variables ["digit_pos"]:
|
||||
No promotable Trim pattern detected
|
||||
```
|
||||
|
||||
**Blocker 2**: String operation filter (Phase 178)
|
||||
```
|
||||
[pattern2/can_lower] Phase 178: String/complex update detected, rejecting Pattern 2 (unsupported)
|
||||
[ERROR] ❌ [joinir/freeze] Loop lowering failed: JoinIR does not support this pattern
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 182-5: Representative Tests ✅
|
||||
|
||||
Created 2 representative tests in `apps/tests/` (tracked directory):
|
||||
|
||||
#### Test 1: Pattern1 (Simple) - `phase182_p1_match_literal.hako`
|
||||
|
||||
**Purpose**: Verify Pattern1 routing and execution with early return
|
||||
**Loop Structure**: Simple while loop with conditional return (matches `_match_literal` logic)
|
||||
|
||||
**Result**: ✅ **PASS**
|
||||
```
|
||||
Result: MATCH
|
||||
RC: 0
|
||||
```
|
||||
|
||||
**Verification**:
|
||||
- Correctly routes to Pattern1_Minimal
|
||||
- 3 JoinIR functions generated (main, loop_step, k_exit)
|
||||
- Early return mechanism works correctly
|
||||
- String matching logic verified
|
||||
|
||||
#### Test 2: Pattern2 (Break) - `phase182_p2_break_integer.hako`
|
||||
|
||||
**Purpose**: Verify Pattern2 routing and execution with break statement
|
||||
**Loop Structure**: Integer accumulation with conditional break (simplified _atoi/_parse_number)
|
||||
|
||||
**Result**: ✅ **PASS**
|
||||
```
|
||||
PASS: P2 Break works correctly
|
||||
RC: 0
|
||||
```
|
||||
|
||||
**Verification**:
|
||||
- Correctly routes to Pattern2_WithBreak
|
||||
- Multi-carrier handling works (result + i)
|
||||
- Break condition properly evaluated
|
||||
- Integer arithmetic in carriers verified
|
||||
|
||||
**Commit**: `d5b63e09` - "test(joinir): Phase 182-5 Add P1/P2 pattern verification tests"
|
||||
|
||||
---
|
||||
|
||||
### Task 182-6: Documentation Updates ✅
|
||||
|
||||
**Files Updated**:
|
||||
|
||||
1. **`docs/development/current/main/joinir-architecture-overview.md`**
|
||||
- Added Phase 182 verification status to Section 4.1 (JsonParser ループ空間と P1–P5)
|
||||
- Documented blockers and workaround strategies
|
||||
- Updated implementation status for _match_literal (✅ verified)
|
||||
|
||||
2. **`CURRENT_TASK.md`**
|
||||
- Added Phase 182 completion entry with detailed task breakdown
|
||||
- Documented both blockers with technical details
|
||||
- Created Phase 183 next steps (LoopBodyLocal handling + string ops)
|
||||
|
||||
**Commit**: `0772dc3e` - "docs(joinir): Phase 182-6 Update documentation with P1/P2 verification results"
|
||||
|
||||
---
|
||||
|
||||
## Blockers Identified
|
||||
|
||||
### Blocker 1: LoopBodyLocal Variable Handling
|
||||
|
||||
**Problem**:
|
||||
Current system attempts Trim-specific carrier promotion for all LoopBodyLocal variables.
|
||||
|
||||
**Example**:
|
||||
```hako
|
||||
loop(p < s.length()) {
|
||||
local ch = s.substring(p, p+1) // LoopBodyLocal
|
||||
local digit_pos = digits.indexOf(ch) // LoopBodyLocal
|
||||
if digit_pos < 0 { break }
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**Current Behavior**:
|
||||
1. LoopConditionScopeBox detects `ch` and `digit_pos` as LoopBodyLocal
|
||||
2. TrimLoopLowerer tries to promote them to carriers
|
||||
3. Promotion fails (not a Trim pattern) → Error
|
||||
|
||||
**Required Fix**:
|
||||
- P1/P2 patterns should allow purely local variables (no carrier promotion needed)
|
||||
- Only Trim pattern requires carrier promotion for `ch`
|
||||
- Distinction: "LoopBodyLocal used in condition" (Trim) vs "LoopBodyLocal used in body only" (normal)
|
||||
|
||||
**Impact**: Blocks _parse_number, _atoi, and most other JsonParser loops
|
||||
|
||||
---
|
||||
|
||||
### Blocker 2: String Concatenation Filter (Phase 178)
|
||||
|
||||
**Problem**:
|
||||
Phase 178 conservatively rejects string concatenation in Pattern2/4 carrier updates.
|
||||
|
||||
**Example**:
|
||||
```hako
|
||||
loop(p < s.length()) {
|
||||
num_str = num_str + ch // Rejected by filter
|
||||
p = p + 1
|
||||
}
|
||||
```
|
||||
|
||||
**Current Behavior**:
|
||||
```rust
|
||||
UpdateRhs::StringLiteral(_) | UpdateRhs::Other => {
|
||||
eprintln!("[pattern2/can_lower] Phase 178: String/complex update detected, rejecting Pattern 2 (unsupported)");
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
**Required Fix**:
|
||||
- Gradual enablement of string operations in P2/P4
|
||||
- Distinguish between:
|
||||
- Simple concat: `s = s + literal` (should work)
|
||||
- Complex string ops: `s = method_call()` (may need special handling)
|
||||
- Consider allowing string concat for JsonParser-specific functions
|
||||
|
||||
**Impact**: Blocks _parse_number, _parse_string, and all loops with string building
|
||||
|
||||
---
|
||||
|
||||
## Implementation Strategy (Phase 183+)
|
||||
|
||||
### Option A: Minimal Fix (Recommended)
|
||||
|
||||
**For Blocker 1 (LoopBodyLocal)**:
|
||||
1. Add check in `lower_loop_pattern2_with_break()`:
|
||||
```rust
|
||||
if !ctx.loop_body_locals.is_empty() && !is_trim_pattern {
|
||||
// Allow LoopBodyLocal if not used in loop condition
|
||||
// (Trim pattern promotes to carrier, others remain local)
|
||||
}
|
||||
```
|
||||
|
||||
2. Distinguish between:
|
||||
- Trim-style LoopBodyLocal (used in condition) → promote
|
||||
- Normal LoopBodyLocal (used in body only) → keep local
|
||||
|
||||
**For Blocker 2 (String ops)**:
|
||||
1. Relax filter in `can_lower()`:
|
||||
```rust
|
||||
UpdateRhs::StringLiteral(_) => {
|
||||
// Allow simple string literals for now
|
||||
// (JsonParser needs this for _parse_number, etc.)
|
||||
}
|
||||
UpdateRhs::Other => {
|
||||
// Still reject complex expressions
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
2. Add function-specific whitelist if needed
|
||||
|
||||
### Option B: Comprehensive Refactor (Future)
|
||||
|
||||
1. Create `LoopBodyLocalRole` enum:
|
||||
```rust
|
||||
enum LoopBodyLocalRole {
|
||||
ConditionCarrier, // Trim pattern (promote)
|
||||
BodyOnly, // Normal pattern (local)
|
||||
}
|
||||
```
|
||||
|
||||
2. Extend `UpdateRhs` to track string operation complexity
|
||||
3. Add gradual string operation support (Phase 184+)
|
||||
|
||||
---
|
||||
|
||||
## Metrics
|
||||
|
||||
### Code Changes
|
||||
|
||||
| Metric | Count |
|
||||
|--------|-------|
|
||||
| Files Modified | 3 |
|
||||
| Files Created (docs) | 2 |
|
||||
| Files Created (tests) | 2 |
|
||||
| Lines Added (code) | ~10 |
|
||||
| Lines Added (docs) | ~350 |
|
||||
| Lines Added (tests) | ~60 |
|
||||
|
||||
### Commits
|
||||
|
||||
| Commit SHA | Description |
|
||||
|------------|-------------|
|
||||
| `5d99c31c` | docs(joinir): Add Phase 182 simple loops design memo |
|
||||
| `be063658` | feat(joinir): Phase 182-2 Add _parse_number/_atoi to routing whitelist |
|
||||
| `d5b63e09` | test(joinir): Phase 182-5 Add P1/P2 pattern verification tests |
|
||||
| `0772dc3e` | docs(joinir): Phase 182-6 Update documentation with P1/P2 verification results |
|
||||
|
||||
**Total Commits**: 4
|
||||
**Build Status**: ✅ All builds successful
|
||||
**Test Status**: ✅ 2/2 representative tests PASS
|
||||
**Global Tests**: Not run (blockers prevent JsonParser loops from compiling)
|
||||
|
||||
---
|
||||
|
||||
## Lessons Learned
|
||||
|
||||
### What Worked Well
|
||||
|
||||
1. **Structure-based routing** (`NYASH_JOINIR_STRUCTURE_ONLY=1`) is excellent for development
|
||||
2. **PatternPipelineContext reuse** - No new infrastructure needed
|
||||
3. **Existing P1/P2 lowerers** - Worked perfectly for basic cases
|
||||
4. **Phase 181 analysis** - Accurate predictions saved time
|
||||
|
||||
### What Needs Improvement
|
||||
|
||||
1. **LoopBodyLocal handling** - Too Trim-specific, needs generalization
|
||||
2. **String operation filter** - Too conservative, needs gradual relaxation
|
||||
3. **Test coverage** - Need tests for LoopBodyLocal edge cases
|
||||
|
||||
### Design Insights
|
||||
|
||||
1. **Trim pattern is special** - Requires carrier promotion, but not all patterns do
|
||||
2. **String ops are common** - JsonParser heavily uses string building
|
||||
3. **Filter granularity** - Need finer-grained control than "accept all" or "reject all"
|
||||
4. **Pattern verification approach** - Starting with simplified tests was correct strategy
|
||||
|
||||
---
|
||||
|
||||
## Recommendations for Phase 183
|
||||
|
||||
### High Priority
|
||||
|
||||
1. **LoopBodyLocal handling**
|
||||
- Add role-based distinction (condition vs body-only)
|
||||
- Allow body-only locals in P1/P2 without promotion
|
||||
- Keep Trim-specific promotion for condition locals
|
||||
|
||||
2. **String concat enablement**
|
||||
- Allow simple string concatenation in P2/P4
|
||||
- Add safety checks (e.g., carrier type verification)
|
||||
- Document supported vs unsupported string operations
|
||||
|
||||
### Medium Priority
|
||||
|
||||
3. **Test coverage expansion**
|
||||
- Add tests for LoopBodyLocal edge cases
|
||||
- Add tests for string concat patterns
|
||||
- Add negative tests (verify correct rejection)
|
||||
|
||||
4. **Documentation refinement**
|
||||
- Create decision tree for LoopBodyLocal handling
|
||||
- Document string operation support matrix
|
||||
|
||||
### Low Priority
|
||||
|
||||
5. **Refactoring opportunities**
|
||||
- Consider `LoopBodyLocalRole` enum (future)
|
||||
- Consider `UpdateRhs` extension for operation types
|
||||
- Consider function-specific routing configuration
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
Phase 182 successfully **verified the foundation** for JsonParser simple loop support:
|
||||
|
||||
✅ **Pattern1 and Pattern2 routing works correctly**
|
||||
✅ **Basic execution verified with representative tests**
|
||||
✅ **Blockers identified with clear remediation paths**
|
||||
|
||||
The blockers are **architectural constraints** rather than bugs:
|
||||
- LoopBodyLocal promotion is Trim-specific by design
|
||||
- String operation filter is conservative by design (Phase 178)
|
||||
|
||||
**Next Steps**: Phase 183 will address both blockers with minimal, targeted fixes to enable JsonParser loops while maintaining the existing architecture's safety guarantees.
|
||||
|
||||
**Success Criteria Met**:
|
||||
- Pattern routing verified ✅
|
||||
- Representative tests created ✅
|
||||
- Blockers documented ✅
|
||||
- Remediation paths identified ✅
|
||||
- Documentation updated ✅
|
||||
|
||||
**Overall Assessment**: **Successful verification phase** with clear path forward for full implementation in Phase 183.
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- Design Document: `docs/development/current/main/phase182-simple-loops-design.md`
|
||||
- Phase 181 Analysis: `docs/development/current/main/phase181-jsonparser-loop-roadmap.md`
|
||||
- Architecture Overview: `docs/development/current/main/joinir-architecture-overview.md`
|
||||
- Test Files:
|
||||
- `apps/tests/phase182_p1_match_literal.hako`
|
||||
- `apps/tests/phase182_p2_break_integer.hako`
|
||||
- Routing Code: `src/mir/builder/control_flow/joinir/routing.rs`
|
||||
- Pattern2 Filter: `src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs`
|
||||
@ -1,320 +0,0 @@
|
||||
# Phase 185 Completion Report: Body-local Pattern2 Integration (Partial)
|
||||
|
||||
**Date**: 2025-12-09
|
||||
**Status**: ⚠️ **Partially Complete** - Infrastructure integrated, init lowering blocked
|
||||
**Duration**: ~2 hours
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Phase 185 successfully integrated Phase 184's body-local infrastructure into Pattern2's API and code structure, but discovered that **body-local initialization lowering** was never implemented in Phase 184. The integration skeleton is complete and builds successfully, but tests fail due to undefined ValueIds from uninitialized body-local variables.
|
||||
|
||||
**Key outcome**: Identified Phase 186 scope (body-local init lowering) as prerequisite for functional body-local variable support.
|
||||
|
||||
---
|
||||
|
||||
## Completed Work
|
||||
|
||||
### ✅ Task 185-1: Design Document
|
||||
|
||||
**File**: `docs/development/current/main/phase185-body-local-integration.md`
|
||||
|
||||
- Comprehensive architecture design
|
||||
- Integration approach documented
|
||||
- Test strategy defined
|
||||
- Scope and constraints clarified
|
||||
|
||||
### ✅ Task 185-2: Pattern2 Integration Skeleton
|
||||
|
||||
**Modified files**:
|
||||
1. `src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs`:
|
||||
- Added `collect_body_local_variables()` helper function
|
||||
- Created LoopBodyLocalEnv from collected locals
|
||||
- Pass body_local_env to lower_loop_with_break_minimal
|
||||
|
||||
2. `src/mir/join_ir/lowering/loop_with_break_minimal.rs`:
|
||||
- Added `body_local_env: Option<&LoopBodyLocalEnv>` parameter
|
||||
- Added imports for LoopBodyLocalEnv, UpdateEnv, emit_carrier_update_with_env
|
||||
- Modified carrier update emission to use UpdateEnv when body_local_env present
|
||||
- Backward compatibility: existing callers pass None
|
||||
|
||||
**Build status**: ✅ `cargo build --release` SUCCESS (0 errors)
|
||||
|
||||
**Code quality**:
|
||||
- Clean separation of concerns
|
||||
- Backward compatible API
|
||||
- Box-first design principles followed
|
||||
|
||||
### ✅ Task 185-3: Pattern4 Deferred
|
||||
|
||||
**Decision**: Pattern4 uses different architecture (inline lowering, no emit_carrier_update).
|
||||
|
||||
**Rationale**:
|
||||
- Pattern4 has custom inline update logic
|
||||
- Variable resolution is hardcoded
|
||||
- "Minimal" scope constraint
|
||||
- Would require significant refactoring
|
||||
|
||||
**Documentation**: Clearly marked as future work in design doc.
|
||||
|
||||
### ✅ Task 185-4: Test Created, Blocker Identified
|
||||
|
||||
**Test file**: `apps/tests/phase185_p2_body_local_int_min.hako`
|
||||
|
||||
**Test content**: JsonParser-style loop with body-local integer calculation (`local digit_pos = pos - start`).
|
||||
|
||||
**Test result**: ❌ BLOCKED
|
||||
|
||||
**Error**:
|
||||
```
|
||||
[ERROR] use of undefined value ValueId(11)
|
||||
```
|
||||
|
||||
**Root cause identified**: Body-local variables are **collected but not initialized**.
|
||||
|
||||
**What works**:
|
||||
- ✅ Variable name collection: `[pattern2/body-local] Collected local 'digit_pos' → ValueId(2)`
|
||||
- ✅ LoopBodyLocalEnv creation: `Phase 185-2: Collected 1 body-local variables`
|
||||
- ✅ Pattern2 routing: Correctly detected and lowered to JoinIR
|
||||
|
||||
**What doesn't work**:
|
||||
- ❌ Init expression lowering: `local digit_pos = pos - start` never lowered to JoinIR
|
||||
- ❌ ValueId definition: ValueId(11) allocated but never assigned a value
|
||||
- ❌ Runtime execution: VM error on use of undefined value
|
||||
|
||||
### ✅ Task 185-5: Documentation Updated
|
||||
|
||||
**Updated files**:
|
||||
1. `phase185-body-local-integration.md`: Status section with detailed analysis
|
||||
2. `phase185-completion-report.md`: This file
|
||||
3. `CURRENT_TASK.md`: (will be updated after this report)
|
||||
|
||||
**Documentation quality**:
|
||||
- Root cause clearly explained
|
||||
- Phase 186 scope defined
|
||||
- Alternative approaches provided
|
||||
- Lessons learned documented
|
||||
|
||||
---
|
||||
|
||||
## Technical Analysis
|
||||
|
||||
### What Was Assumed (Incorrectly)
|
||||
|
||||
**Phase 184 was assumed to include**:
|
||||
- ✅ LoopBodyLocalEnv (storage) - **Actually implemented**
|
||||
- ✅ UpdateEnv (resolution) - **Actually implemented**
|
||||
- ✅ emit_carrier_update_with_env() - **Actually implemented**
|
||||
- ❌ Body-local init lowering - **NOT implemented**
|
||||
|
||||
### What Phase 184 Actually Delivered
|
||||
|
||||
**Infrastructure only**:
|
||||
- Data structures (LoopBodyLocalEnv, UpdateEnv)
|
||||
- API extensions (emit_carrier_update_with_env)
|
||||
- Variable resolution priority logic
|
||||
- Unit tests for storage and resolution
|
||||
|
||||
**Missing piece**:
|
||||
- AST expression → JoinIR instruction lowering for body-local init
|
||||
- Integration of init instructions into loop body
|
||||
- Full E2E test (would have caught this)
|
||||
|
||||
### What Phase 185 Accomplished
|
||||
|
||||
**API integration**:
|
||||
- Pattern2 now accepts body_local_env parameter
|
||||
- lower_loop_with_break_minimal ready to use UpdateEnv
|
||||
- Backward compatibility maintained
|
||||
|
||||
**Discovered gap**:
|
||||
- Identified init lowering as blocking issue
|
||||
- Defined Phase 186 scope clearly
|
||||
- Provided implementation roadmap
|
||||
|
||||
---
|
||||
|
||||
## Phase 186 Requirements
|
||||
|
||||
### Goal
|
||||
|
||||
Implement body-local variable initialization lowering to make Phase 185 integration functional.
|
||||
|
||||
### Scope
|
||||
|
||||
1. **Expression lowering** (`local digit_pos = pos - start`):
|
||||
- Lower AST BinOp nodes to JoinIR BinOp instructions
|
||||
- Lower AST Variable nodes to ValueId lookups in ConditionEnv
|
||||
- Handle nested expressions recursively
|
||||
|
||||
2. **Init instruction insertion**:
|
||||
- Emit init instructions at start of loop_step function
|
||||
- Before break condition, after parameter allocation
|
||||
- Update LoopBodyLocalEnv with resulting ValueIds
|
||||
|
||||
3. **Helper refactoring**:
|
||||
- Replace `collect_body_local_variables()` with `collect_and_lower_body_locals()`
|
||||
- Add `lower_expr_to_joinir()` helper function
|
||||
- Pass instruction vector to enable emission
|
||||
|
||||
### Estimate
|
||||
|
||||
**Full implementation**: 6-7 hours
|
||||
- Expression lowerer: 2-3 hours
|
||||
- Integration: 2 hours
|
||||
- Testing: 2 hours
|
||||
|
||||
**Simplified (variables only)**: 2-3 hours
|
||||
- Only support `local temp = var` (no binops)
|
||||
- Defer complex expressions to Phase 187
|
||||
|
||||
---
|
||||
|
||||
## Files Modified
|
||||
|
||||
### Source Code (3 files)
|
||||
|
||||
1. `src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs`
|
||||
- Lines added: ~35 (helper function + integration)
|
||||
- Changes: collect_body_local_variables(), LoopBodyLocalEnv creation, lower call update
|
||||
|
||||
2. `src/mir/join_ir/lowering/loop_with_break_minimal.rs`
|
||||
- Lines added: ~20 (imports + parameter + conditional emission)
|
||||
- Changes: body_local_env parameter, UpdateEnv usage, emit_carrier_update_with_env call
|
||||
|
||||
### Documentation (3 files)
|
||||
|
||||
3. `docs/development/current/main/phase185-body-local-integration.md`
|
||||
- Lines: ~680 (comprehensive design + status update)
|
||||
|
||||
4. `docs/development/current/main/phase185-completion-report.md`
|
||||
- Lines: ~350 (this file)
|
||||
|
||||
### Tests (1 file, non-functional)
|
||||
|
||||
5. `apps/tests/phase185_p2_body_local_int_min.hako`
|
||||
- Lines: ~25 (test blocked by init lowering)
|
||||
|
||||
---
|
||||
|
||||
## Build & Test Results
|
||||
|
||||
### Build Status
|
||||
|
||||
```bash
|
||||
$ cargo build --release
|
||||
Compiling nyash-rust v0.1.0
|
||||
Finished `release` profile [optimized] target(s) in 1m 07s
|
||||
```
|
||||
|
||||
✅ **SUCCESS** - No compilation errors, no warnings in modified files
|
||||
|
||||
### Test Execution
|
||||
|
||||
```bash
|
||||
$ NYASH_JOINIR_CORE=1 ./target/release/hakorune apps/tests/phase185_p2_body_local_int_min.hako
|
||||
[pattern2/body-local] Collected local 'digit_pos' → ValueId(2)
|
||||
[pattern2/body-local] Phase 185-2: Collected 1 body-local variables
|
||||
[pattern2/before_lowerer] About to call lower_loop_with_break_minimal with carrier_info.loop_var_name='pos'
|
||||
[ERROR] use of undefined value ValueId(11)
|
||||
```
|
||||
|
||||
❌ **BLOCKED** - Runtime error due to uninitialized body-local variable
|
||||
|
||||
---
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
- [x] Design document created
|
||||
- [x] Pattern2 integration skeleton implemented
|
||||
- [x] Build succeeds with no errors
|
||||
- [x] Backward compatibility maintained (existing tests pass)
|
||||
- [x] Pattern4 scope decision documented
|
||||
- [x] Test file created
|
||||
- [ ] Test execution successful ❌ (blocked by init lowering)
|
||||
- [ ] Representative test outputs correct value ❌ (blocked)
|
||||
- [x] Documentation updated with status and next steps
|
||||
- [x] Root cause analysis completed
|
||||
- [x] Phase 186 requirements defined
|
||||
|
||||
**7/10 completed** (3 blocked by missing init lowering)
|
||||
|
||||
---
|
||||
|
||||
## Lessons Learned
|
||||
|
||||
### 1. Infrastructure ≠ Implementation
|
||||
|
||||
**Issue**: Phase 184 delivered "infrastructure" but left core functionality (init lowering) unimplemented.
|
||||
|
||||
**Impact**: Phase 185 integration appeared complete (builds successfully) but fails at runtime.
|
||||
|
||||
**Lesson**: "Infrastructure" phases must include E2E test to validate full functionality, not just API structure.
|
||||
|
||||
### 2. Test Early, Test Often
|
||||
|
||||
**Issue**: Phase 184 had unit tests but no E2E test showing body-local variables actually working.
|
||||
|
||||
**Impact**: Missing init lowering wasn't discovered until Phase 185 integration testing.
|
||||
|
||||
**Lesson**: Even "infrastructure-only" phases need at least one E2E test demonstrating the feature works end-to-end.
|
||||
|
||||
### 3. Scope Boundaries Must Be Clear
|
||||
|
||||
**Issue**: Phase 184/185 scope boundary was unclear - where does "infrastructure" end and "implementation" begin?
|
||||
|
||||
**Impact**: Phase 185 assumed init lowering was done, wasted time on integration before discovering blocker.
|
||||
|
||||
**Lesson**: Explicitly document what IS and IS NOT in scope for each phase. Use "In Scope" / "Out of Scope" sections.
|
||||
|
||||
### 4. Pattern4 Architecture Differences
|
||||
|
||||
**Issue**: Pattern4 uses inline lowering (no emit_carrier_update), different from Pattern2.
|
||||
|
||||
**Decision**: Deferred Pattern4 integration to avoid scope creep.
|
||||
|
||||
**Lesson**: "Minimal" integration for Phase 185 was correct - Pattern4 needs its own refactoring phase.
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
### Immediate (Phase 186)
|
||||
|
||||
1. **Implement body-local init lowering**:
|
||||
- Add `lower_expr_to_joinir()` helper
|
||||
- Refactor `collect_body_local_variables()` to `collect_and_lower_body_locals()`
|
||||
- Emit init instructions in loop_step function
|
||||
|
||||
2. **Test Phase 185 integration**:
|
||||
- Run phase185_p2_body_local_int_min.hako
|
||||
- Verify output: `123`
|
||||
- Confirm no [joinir/freeze] or SSA-undef errors
|
||||
|
||||
3. **Document Phase 186 completion**:
|
||||
- Update CURRENT_TASK.md
|
||||
- Mark Phase 185 as fully complete
|
||||
- Provide Phase 187 preview
|
||||
|
||||
### Future (Phase 187+)
|
||||
|
||||
1. **Phase 187**: String UpdateKind support (careful, gradual)
|
||||
2. **Phase 188**: Pattern4 body-local integration (refactor inline lowering)
|
||||
3. **Phase 189**: JsonParser full loop coverage (_parse_number, _atoi, etc.)
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
Phase 185 successfully prepared the API and code structure for body-local variable support in Pattern2, but revealed that the core initialization lowering was never implemented in Phase 184. This is a valuable discovery that clarifies the scope for Phase 186 and provides a clear implementation roadmap.
|
||||
|
||||
**Value delivered**:
|
||||
- ✅ API integration skeleton (builds successfully)
|
||||
- ✅ Root cause analysis (init lowering missing)
|
||||
- ✅ Phase 186 requirements defined
|
||||
- ✅ Test infrastructure in place
|
||||
|
||||
**Phase 185 status**: Partially complete - integration skeleton done, awaiting Phase 186 for functional completion.
|
||||
|
||||
**Next phase**: Phase 186 - Body-local Init Lowering (2-3 hours simplified, 6-7 hours full)
|
||||
@ -162,3 +162,11 @@ Phase 230 の時点では「どの箱をどこに収めるか」をざっくり
|
||||
結論として Phase 230 は、JoinIR ラインにおける「式」と「スコープ」の SSOT を見据えた
|
||||
**設計フェーズ(ドキュメントのみ)** として完了させるイメージだよ。
|
||||
|
||||
補足(Phase 231 時点の実装状況メモ):
|
||||
|
||||
- `src/mir/join_ir/lowering/expr_lowerer.rs` / `scope_manager.rs` には、Phase 231 のパイロット実装が入っている。
|
||||
- コンテキストは `ExprContext::Condition` のみサポート。
|
||||
- 実装は ScopeManager → ConditionEnv を構築してから、既存の `lower_condition_to_joinir` に委譲する薄いラッパー。
|
||||
- `pattern2_with_break.rs` では **バリデーション専用(結果は捨てて、実際の lowering は従来経路)の呼び出し**になっている。
|
||||
- 本ドキュメントは「最終的に目指す ExprLowerer/ScopeManager 像」の設計であり、Phase 231 の実装はあくまで
|
||||
その前段階のパイロットという位置づけだよ(実装が完全にこの API 図のとおりになっているわけではない点に注意)。
|
||||
|
||||
@ -0,0 +1,190 @@
|
||||
# Phase 232: Failing Tests Inventory & Classification
|
||||
|
||||
このドキュメントは、2025-12 時点の `cargo test --release` で残っている 7 件の FAIL を
|
||||
「どの箱/どのパターン/どのレイヤの問題か」で棚卸しするフェーズ用のメモだよ。
|
||||
|
||||
---
|
||||
|
||||
## 1. 失敗テスト一覧(Task 232-1)
|
||||
|
||||
ベースコマンド:
|
||||
|
||||
```bash
|
||||
cargo test --release
|
||||
```
|
||||
|
||||
このセッションでの FAIL は次の 7 件だったよ(当時: 890 passed / 7 failed / 64 ignored)。
|
||||
**Update (Phase 233)**: `loop_update_summary` の 4 件を AST ベーステストに刷新して PASS 化し、いまは **894 passed / 3 failed / 64 ignored** だよ(残りは array_filter 系 3 件のみ)。
|
||||
|
||||
### 1.1 loop_update_summary 系ユニットテスト(4 件 → Phase 233 で解消済み)
|
||||
|
||||
対象ファイル: `src/mir/join_ir/lowering/loop_update_summary.rs`
|
||||
|
||||
1. `mir::join_ir::lowering::loop_update_summary::tests::test_analyze_mixed`
|
||||
- パターン: if-sum / Counter+Accumulation 検出ロジック(P3 if-sum 用の分析箱)。
|
||||
- 失敗種類: **期待値 mismatch(名前ベースヒューリスティック vs 新 AST ベース実装)**
|
||||
- 現行実装 `analyze_loop_updates()` は deprecated だが、テストはまだ古いヒューリスティック前提。
|
||||
- 備考: 実運用では `analyze_loop_updates_from_ast()` が主経路(Phase 219)。
|
||||
|
||||
2. `mir::join_ir::lowering::loop_update_summary::tests::test_analyze_single_counter`
|
||||
- パターン: CounterOnly(単一カウンタ)判定。
|
||||
- 失敗種類: **期待値 mismatch(deprecated API の挙動とテスト期待のズレ)**
|
||||
- 備考: `analyze_loop_updates()` 内で kind を全て AccumulationLike にしているため、テストの CounterLike 期待と合わない。
|
||||
|
||||
3. `mir::join_ir::lowering::loop_update_summary::tests::test_is_simple_if_sum_pattern_basic`
|
||||
- パターン: P3 if-sum の「i + sum」基本パターン検出。
|
||||
- 失敗種類: **期待値 mismatch(is_simple_if_sum_pattern の入力を deprecated wrapper で生成している)**
|
||||
- 備考: 本番 if-sum 経路は Phase 219 以降、AST ベースの update 検出に移行済み。
|
||||
|
||||
4. `mir::join_ir::lowering::loop_update_summary::tests::test_is_simple_if_sum_pattern_with_count`
|
||||
- パターン: P3 if-sum の「i + sum + count」マルチキャリアパターン。
|
||||
- 失敗種類: **期待値 mismatch(上と同様、テスト専用の古い summary 生成ロジック)**
|
||||
|
||||
Update (Phase 233): 上記 1–4 はすべて `analyze_loop_updates_from_ast()` を直接呼ぶ AST フィクスチャベースのテストに置き換え、`cargo test --release` で PASS になったよ。
|
||||
|
||||
### 1.2 ArrayExtBox.filter まわりの joinir mainline テスト(3 件)
|
||||
|
||||
対象ファイル: `src/tests/joinir/mainline_phase49.rs`
|
||||
|
||||
5. `tests::joinir::mainline_phase49::phase49_joinir_array_filter_smoke`
|
||||
- パターン: P3 if-phi / Array filter ループ(実戦寄り PoC)。
|
||||
- 失敗種類: **[joinir/freeze] 系エラー → accumulator `'sum' not found in variable_map` で panic**
|
||||
- メッセージ: `"[cf_loop/pattern3] Accumulator variable 'sum' not found in variable_map"`
|
||||
- 備考: JoinIR mainline に route したあと、Pattern3 PoC lowerer が `sum` を carrier として見つけられず Fail-Fast。
|
||||
|
||||
6. `tests::joinir::mainline_phase49::phase49_joinir_array_filter_fallback`
|
||||
- パターン: 同じ ArrayExtBox.filter の fallback 経路(Structure-only / legacy PoC の確認用)。
|
||||
- 失敗種類: **テスト側期待値「fallback compile should succeed」 vs 実際は Fail-Fast エラー**
|
||||
- つまり「今は array_filter の JoinIR 対応をまだ本番とみなさない」状態をどう扱うかのポリシーの問題。
|
||||
|
||||
7. `tests::joinir::mainline_phase49::phase49_joinir_array_filter_ab_comparison`
|
||||
- パターン: Array filter の route A/B 比較テスト。
|
||||
- 失敗種類: **Route A compile should succeed → 同じ `'sum' not found` エラーで失敗**
|
||||
- 備考: いずれも core バグというより「ArrayExtBox.filter の JoinIR 適用方針が途中」のフェーズ感のテストだよ。
|
||||
|
||||
---
|
||||
|
||||
## 2. 箱・レイヤごとの分類(Task 232-2)
|
||||
|
||||
ここでは「どのラインの箱から見た問題か」をざっくり割り当てるよ。
|
||||
|
||||
### 2.1 JoinIR core ライン
|
||||
|
||||
- ArrayExtBox.filter 系(テスト 5–7)
|
||||
- 主に Pattern3 if-phi / carrier detection / variable_map との橋渡しライン。
|
||||
- エラー文言から見えるのは:
|
||||
- `Accumulator variable 'sum' not found in variable_map`
|
||||
- → **LoopPattern + CarrierInfo + ExitLine の間の「carrier 定義/再接続」が足りない**。
|
||||
- ただし、これは「内部の SSOT が崩れている」というより、PoC lowerer と本線 lowerer が混在している歴史的ライン。
|
||||
|
||||
### 2.2 LoopPattern ライン
|
||||
|
||||
- loop_update_summary 系(テスト 1–4)
|
||||
- P3 if-sum / CaseA パターン検出の一部。
|
||||
- 現行本番経路:
|
||||
- AST ベースの `analyze_loop_updates_from_ast()` + P3 if-sum 実装(Phase 212/213/220)。
|
||||
- テストが見ているのは:
|
||||
- deprecated な `analyze_loop_updates()`(名前ベース)と、それにぶら下がる is_simple_if_sum_pattern の挙動。
|
||||
- 位置づけとしては **LoopPattern (分析箱) の「旧 API テスト」**。
|
||||
|
||||
### 2.3 表現ライン(ConditionEnv / ExprLowerer / MethodCallLowerer / LoopBodyLocalEnv)
|
||||
|
||||
- 今回の 7 件の FAIL は、直接にはこの表現レイヤにはかかっていない:
|
||||
- Type error / SSA-undef / alias 解決の失敗ではなく、
|
||||
- 「古い分析 API のテスト期待値のまま」
|
||||
- 「PoC lowerer の carrier 認識が足りない」
|
||||
といったレベルの問題に収まっている。
|
||||
- つまり Phase 232 時点では、ExprLowerer/ScopeManager まわりの **新実装が原因の FAIL はゼロ** という整理でよさそうだよ。
|
||||
|
||||
---
|
||||
|
||||
## 3. P0/P1/P2 分類(Task 232-3)
|
||||
|
||||
ここでは、次フェーズでどう扱うかの優先度分類をするよ。
|
||||
|
||||
### 3.1 P0: すぐ直したい JoinIR core バグ
|
||||
|
||||
- **今回は P0 該当なし** として扱うのがよさそう。
|
||||
- 理由:
|
||||
- SSA-undef / PHI 破損 / ValueId 衝突 / ExitLine 契約違反のような「core 崩壊系」の FAIL は含まれていない。
|
||||
- ArrayExtBox.filter 系も「PoC lowerer の制約に当たって Fail-Fast」が明示的に出ているだけで、
|
||||
既存の JsonParser / if-sum ラインを壊しているわけではない。
|
||||
|
||||
### 3.2 P1: パターン拡張で解決できるもの
|
||||
|
||||
候補としては次の 2 グループだよ(Phase 232 時点の整理; その後の更新を併記するね):
|
||||
|
||||
1. **loop_update_summary ユニット(テスト 1–4)** → Phase 233 で解消済み
|
||||
- 実際の本番 if-sum ラインは AST ベースで動いているので、
|
||||
- これらのテストを「deprecated wrapper の振る舞いテスト」ではなく、
|
||||
- `analyze_loop_updates_from_ast()` ベースのテストに差し替える
|
||||
ことで自然に緑にできる。
|
||||
- つまり「core バグ」ではなく **テストの更新/仕様の追随** で解消可能。
|
||||
- **Phase 233 で実施済み(PASS 化)**。
|
||||
|
||||
2. **ArrayExtBox.filter 系(テスト 5–7)**
|
||||
- Pattern3 if-phi / Accumulation パターンとして見れば、
|
||||
- `sum` を carrier として認識する
|
||||
- legacy PoC lowerer のエラー文言を **「意図的な Fail-Fast」か「サポートする方向」か** 決める
|
||||
といった「パターン拡張 or ポリシー明確化」で解決可能。
|
||||
- ただし、こちらは実戦 ArrayExtBox.filter の仕様をどうしたいかに依存するので、
|
||||
先に loop_update_summary 側を P1 で触るほうがスコープが小さくて良さそう。
|
||||
|
||||
### 3.3 P2: 当面 Fail-Fast に残すもの
|
||||
|
||||
Phase 234 の結論:
|
||||
|
||||
- **ArrayExtBox.filter 系 3 テスト(5–7)は P2 に固定**(意図した Fail-Fast / 将来拡張候補)。
|
||||
- 理由:
|
||||
- ArrayFilter は「BoxCall ベース Accumulation(out.push)」であり、数値 if-sum ラインとは別系統の設計が必要。
|
||||
- JsonParser / selfhost / ExprLowerer など、既に進行中のコアラインより優先して手を入れる理由がまだ弱い。
|
||||
- 現状の `[cf_loop/pattern3] Accumulator variable 'sum' not found in variable_map` は、「P3 if-PHI の外側にある PoC 領域」を示すラベルとして有用。
|
||||
- したがって Phase 234 では:
|
||||
- コード変更は行わず、
|
||||
- `phase234-array-filter-design.md` に ArrayFilter パターンと P3 if-PHI との関係、将来フェーズでの拡張案だけを整理する。
|
||||
|
||||
一方、loop_update_summary ユニット(1–4)は:
|
||||
|
||||
- P1(「次にテストを更新するときに一緒に触る」)として扱うのが妥当だよ。
|
||||
- 本番経路は既に `analyze_loop_updates_from_ast()` を使っており、
|
||||
deprecated wrapper の仕様を保つ必要は低い。
|
||||
|
||||
---
|
||||
|
||||
## 4. 次フェーズ候補(Task 232-4)
|
||||
|
||||
Phase 232 の整理を前提にした「次の軸」の候補だけメモしておくね(コードはまだ書かない)。
|
||||
|
||||
- **Phase 233(P1: 分析箱テストのアップデート)**
|
||||
- ねらい:
|
||||
- `loop_update_summary.rs` のテスト 1–4 を `analyze_loop_updates_from_ast()` ベースに更新し、
|
||||
実戦 if-sum ラインとテスト仕様を揃える。
|
||||
- やることの例:
|
||||
- AST フィクスチャ(簡単な if-sum ループ)を直接組んで `analyze_loop_updates_from_ast()` をテスト。
|
||||
- deprecated `analyze_loop_updates()` のテストは「歴史メモ」扱いに移すか、最小限だけ残す。
|
||||
|
||||
- **Phase 234(P1: ArrayExtBox.filter ラインの設計再検討)**
|
||||
- ねらい:
|
||||
- ArrayExtBox.filter を「P3 if-phi + Accumulation pattern」として本当に JoinIR で扱うかどうかを設計レベルで決める。
|
||||
- やることの例:
|
||||
- phase49 の mainline テストが期待しているシナリオを整理(route A/B、fallback の位置づけ)。
|
||||
- Pattern3 if-sum / array filter / map/filter 系の位置づけを `loop_pattern_space.md` に追記。
|
||||
- まだコードには触らず、「やるならこういう箱に分ける」という案まで。
|
||||
|
||||
- **Phase 235(P2: B 系パターンの扱い方の設計だけ)**
|
||||
- ねらい:
|
||||
- いまは Fail-Fast している B 系パターン(複雑ネスト / 多段メソッドチェーンなど)を
|
||||
「今後も Fail-Fast のままにするのか」「別レイヤの箱で扱うか」を整理する。
|
||||
- やることの例:
|
||||
- `[joinir/freeze]` 系メッセージを洗い出して、B 系パターンの代表例を docs にまとめる。
|
||||
- async / catch / filter/map 連鎖などを、JoinIR 本体ではなく上位レイヤに逃がす設計案を書くだけに留める。
|
||||
|
||||
---
|
||||
|
||||
## 5. まとめ
|
||||
|
||||
- 現状の 7 FAIL は:
|
||||
- 4 件: **loop_update_summary の deprecated API テスト**(Phase 233 で AST ベースに刷新し PASS 化済み)。
|
||||
- 3 件: **ArrayExtBox.filter の PoC パターン3 lowerer に対する挙動確認テスト**(意図的 Fail-Fast に近い) ← 現在残っている FAIL。
|
||||
- JoinIR core(PHI/ValueId/ExitLine/SSA)としての致命的な崩れは含まれていないので、
|
||||
Phase 232 の結論としては「**今の FAIL は “どこをまだやっていないか” を教えてくれるラベル**」とみなしてよさそうだよ。
|
||||
@ -0,0 +1,47 @@
|
||||
# Phase 233: loop_update_summary テスト刷新
|
||||
|
||||
目的: deprecated な `analyze_loop_updates()` 依存の期待値を捨てて、Phase 219 で本番化した `analyze_loop_updates_from_ast()` に合わせてユニットテストを組み直すよ。ロジック本体は既に AST ベースで動いているので、テスト側の追随だけを行うフェーズだよ。
|
||||
|
||||
---
|
||||
|
||||
## 1. 旧 API (`analyze_loop_updates`) の前提
|
||||
|
||||
- 入力: carrier 名リストだけ(RHS や AST 構造を見ない)。
|
||||
- ヒューリスティック: すべて AccumulationLike 扱い(名前ベースの Counter 推定は撤廃済み)。
|
||||
- テストで見ていたもの:
|
||||
- `test_analyze_single_counter` / `test_analyze_mixed`: 名前だけで Counter/Accumulation を判断する期待。
|
||||
- `test_is_simple_if_sum_pattern_*`: deprecated wrapper で組んだ summary をそのまま `is_simple_if_sum_pattern` に渡していた。
|
||||
- 問題: 本番 if-sum ラインは AST ベースに移行済みのため、これらのテストは現実の入力と乖離して FAIL していた。
|
||||
|
||||
## 2. 新 API (`analyze_loop_updates_from_ast`) の前提
|
||||
|
||||
- 入力: carrier 名リスト + ループ body の AST。
|
||||
- 処理:
|
||||
- `extract_assigned_variables` で実際に LHS に現れた変数だけを対象にする。
|
||||
- `find_assignment_rhs` で RHS を拾い、`classify_update_kind_from_rhs` で CounterLike / AccumulationLike を決定。
|
||||
- ループインデックスっぽい名前(i/j/k/idx/index/pos/n)だけは Counter 扱いに固定。
|
||||
- 実運用:
|
||||
- PatternPipelineContext から if-sum 判定に使われる唯一の経路。
|
||||
- Phantom carrier 解消(Phase 219)の一環として既に配線済み。
|
||||
|
||||
## 3. テストケースの扱い(棚卸し結果)
|
||||
|
||||
- `test_analyze_single_counter` → **AST ベースに組み直す**
|
||||
- ループ body に `i = i + 1` を置き、`has_single_counter()` が真になることだけを確認。
|
||||
- `test_analyze_accumulation` → **AST ベースに置き換え**
|
||||
- `sum = sum + i` のような RHS を与え、非 index 名が AccumulationLike になることを確認。
|
||||
- `test_analyze_mixed` → **Counter + Accumulation の AST で再構成**
|
||||
- `i = i + 1` と `sum = sum + i` の 2 本で、counter=1 / accumulation=1 を確認。
|
||||
- `test_is_simple_if_sum_pattern_basic` → **if-body に accumulator 更新を置いた AST で検証**
|
||||
- `if (cond) { sum = sum + i }` + `i = i + 1` の組み合わせで true を確認。
|
||||
- `test_is_simple_if_sum_pattern_with_count` → **accumulator 2 本の AST で検証**
|
||||
- `sum` / `count` 両方が AccumulationLike になり、2 本まで許容する条件を確認。
|
||||
- 旧 wrapper への期待は残さず、どうしても残す場合は `#[ignore]` で歴史テストにする方針。
|
||||
|
||||
---
|
||||
|
||||
## 4. 期待する着地
|
||||
|
||||
- ユニットテストは `analyze_loop_updates_from_ast()` を直接呼ぶ形に揃える。
|
||||
- `is_simple_if_sum_pattern` は AST 由来の summary を入力として検証するだけにする(パターン検出ロジック本体の契約をテスト)。
|
||||
- Phase 232 時点の FAIL(4 件)は、テスト刷新で 0 件にする。***
|
||||
137
docs/development/current/main/phase234-array-filter-design.md
Normal file
137
docs/development/current/main/phase234-array-filter-design.md
Normal file
@ -0,0 +1,137 @@
|
||||
# Phase 234: ArrayFilter / Pattern3 設計フェーズ
|
||||
|
||||
目的: ArrayExtBox.filter 系 3 テスト(Phase 49-4)の役割と期待値を整理し、Pattern3 if-PHI として正式サポートするか、当面は Fail-Fast を仕様として維持するかを設計レベルで決めるフェーズだよ(コード変更なし)。
|
||||
|
||||
---
|
||||
|
||||
## 1. ArrayExtBox.filter テスト仕様(Task 234-1)
|
||||
|
||||
対象: `src/tests/joinir/mainline_phase49.rs`
|
||||
|
||||
### 1.1 phase49_joinir_array_filter_smoke
|
||||
|
||||
- 目的:
|
||||
- dev フラグ `HAKO_JOINIR_ARRAY_FILTER_MAIN=1` で JoinIR Frontend mainline を経由したときに、ArrayExtBox.filter のコンパイルがクラッシュしないことを確認する。
|
||||
- filter 実装の形:
|
||||
- `filter(arr, pred)` で `out: ArrayBox`, `i`, `n` をローカルとして持つ。
|
||||
- ループ本体:
|
||||
- `loop(i < n) {`
|
||||
- `v = arr.get(i)`
|
||||
- `if pred(v) { out.push(v) }`
|
||||
- `i = i + 1`
|
||||
- `return out`
|
||||
- 期待しているのは:
|
||||
- 「Route B (JoinIR Frontend mainline) で compile が `Ok` を返すこと」(実行結果まではテストしていない)。
|
||||
|
||||
### 1.2 phase49_joinir_array_filter_fallback
|
||||
|
||||
- 目的:
|
||||
- dev フラグ OFF(`HAKO_JOINIR_ARRAY_FILTER_MAIN` 未設定)のときは、従来の(JoinIR mainline を通らない)経路でコンパイルが成功することを確認する。
|
||||
- filter 実装の形:
|
||||
- ソースは smoke と同一(同じ filter 実装)。
|
||||
- 期待しているのは:
|
||||
- dev フラグ OFF の Route A が「従来経路で compile `Ok`」になること。
|
||||
- JoinIR mainline を切った状態での後方互換性チェック。
|
||||
|
||||
### 1.3 phase49_joinir_array_filter_ab_comparison
|
||||
|
||||
- 目的:
|
||||
- ArrayExtBox.filter に対して Route A(legacy)と Route B(JoinIR Frontend)を A/B 比較し、両経路とも compile だけは成功しつつ、生成される MIR ブロック数をログで観察する。
|
||||
- filter 実装の形:
|
||||
- ソースは前二つと同一。
|
||||
- 期待しているのは:
|
||||
- Route A: `HAKO_JOINIR_ARRAY_FILTER_MAIN` OFF で compile `Ok`。
|
||||
- Route B: `HAKO_JOINIR_ARRAY_FILTER_MAIN=1` で compile `Ok`。
|
||||
- 実行結果ではなく、コンパイル成功と大まかなブロック構造(ブロック数)の健全性を確認するテスト。
|
||||
|
||||
---
|
||||
|
||||
## 2. 既存 Pattern / Box との対応付け(Task 234-2)
|
||||
|
||||
### 2.1 パターン構造の分類
|
||||
|
||||
- loop 形:
|
||||
- `loop(i < n) { ... i = i + 1 }` → ループ条件 `i < n` + カウンタ更新 `i = i + 1` は既存の Pattern2(break)/Pattern3(if-PHI)と同型。
|
||||
- 条件分岐:
|
||||
- `if pred(v) { out.push(v) }`
|
||||
- `pred` はラムダ(関数)で、ループ内から呼び出される。
|
||||
- `out.push(v)` は ArrayBox への蓄積(Accumulation)だが、ループの「キャリア」としては `out` をどう扱うかが問題になる。
|
||||
- 変数役割(ざっくり):
|
||||
- ループインデックス: `i`(既存 CounterLike)
|
||||
- ループ境界: `n`(captured const 相当)
|
||||
- 出力配列: `out`(Array 型 accumulator)
|
||||
- 一時変数: `v`(body-local)
|
||||
|
||||
### 2.2 Pattern3 If-PHI との関係
|
||||
|
||||
- 既存の P3 if-sum:
|
||||
- `if (cond) { sum = sum + x }` という「条件付き Accumulation」を、Counter (`i`) + Accumulator (`sum`) の 2 キャリアで扱う。
|
||||
- LoopUpdateSummary + CarrierInfo + ExitLine で Counter/Accumulator を JoinIR の PHI / Exit に接続する。
|
||||
- ArrayFilter の if:
|
||||
- `if pred(v) { out.push(v) }` は、`sum = sum + x` の配列版(filter 型 Accumulation)に近い。
|
||||
- ただし:
|
||||
- Accumulator の更新が「BoxCall(push)」であり、純粋な数値加算ではない。
|
||||
- `out` はループ外でも使われるオブジェクト(ループ終了後に return)で、スカラ accumulator と扱いが異なる。
|
||||
- まとめ:
|
||||
- **構造的には P3 if-PHI と似ているが、更新が BoxCall ベースであり、現在の数値 if-sum パイプラインとは別系統の扱いが必要**。
|
||||
|
||||
### 2.3 既存箱でどこまで表現可能か
|
||||
|
||||
- PatternPipelineContext / CarrierInfo / ExitLine だけで無理なく扱えるか?
|
||||
- ループキャリアとして `out` を登録し、ExitLine で `out` を JoinIR の戻り値に接続すること自体は可能そう。
|
||||
- しかし、現行の P3 if-sum は「スカラ accumulator の PHI 合成」を前提にしており、配列の push を Accumulation として静的に扱うための契約(SideEffect・Alias・BoxCall 許容範囲)が決まっていない。
|
||||
- ラムダ内のループかどうか?
|
||||
- 今回の ArrayExtBox.filter 実装は「ラムダの中にループがある」のではなく、「filter 本体にループがあり、ラムダ `pred` をコールする」形。
|
||||
- したがって「ラムダ内のループ」という意味での特別扱いは不要だが、「Box メソッドとして公開されるループ」という観点では selfhost/JsonParser とは少し違うレイヤ。
|
||||
|
||||
---
|
||||
|
||||
## 3. 方針決定(Task 234-3)
|
||||
|
||||
ここでは **Phase 234 時点での方針** を決めるだけで、コードはまだ触らないよ。
|
||||
|
||||
### Option A: P3 If-PHI の正式対象としてサポートする
|
||||
|
||||
- やることのイメージ(将来フェーズで):
|
||||
- P3 if-sum パイプラインを一般化して「BoxCall ベースの Accumulation(push など)」も扱えるようにする。
|
||||
- CarrierInfo に「配列 accumulator」を追加し、ExitLine で `out` を JoinIR 経由で返り値に接続。
|
||||
- Pattern3 lowerer に「ArrayFilter パターン」用のサブ箱を足すか、既存 Accumulation 判定を拡張する。
|
||||
- 必要な投資:
|
||||
- BoxCall の side-effect モデル(純粋な Accumulation として扱って安全か)を整理する。
|
||||
- JsonParser / selfhost よりも優先する理由が必要(現状は数値/JsonParser ラインが主戦場)。
|
||||
|
||||
### Option B: 当面は Fail-Fast を仕様として維持する(Phase 234 の結論)
|
||||
|
||||
- ここまでの整理から見えること:
|
||||
- 現在の FAIL は `[cf_loop/pattern3] Accumulator variable 'sum' not found in variable_map` という **PoC lowerer の制約に当たっての Fail-Fast** であり、JoinIR core(PHI/ValueId/ExitLine)の崩れではない。
|
||||
- JsonParser / selfhost / ExprLowerer ラインがまだ道半ばで、P3 if-sum も「数値 accumulator」を中心に設計されている。
|
||||
- ArrayFilter のような「BoxCall ベースの Accumulation」を安全に一般化するには、BoxCall/side-effect モデルと LoopPattern の交差設計が必要で、Phase 234 の守備範囲を超える。
|
||||
- したがって Phase 234 の結論としては:
|
||||
- **ArrayExtBox.filter 系 3 テストは、当面「P3 if-PHI の外側にある PoC 領域」として Fail-Fast を仕様として維持する**。
|
||||
- 将来フェーズ(例: Phase 24x)で「Box ベース Accumulation / ArrayFilter パターン」を正式に設計するまでは、
|
||||
- 今のエラーメッセージと FAIL は「未対応領域を示すラベル」として残す。
|
||||
|
||||
---
|
||||
|
||||
## 4. FAIL の位置づけ更新(Task 234-4)
|
||||
|
||||
- Phase 232 では array_filter 3 件を P1/P2 候補として挙げていたが、Phase 234 の結論に従って:
|
||||
- **分類: P2(意図的 Fail-Fast / 将来拡張候補)**
|
||||
- ラベル: 「ArrayExtBox.filter / BoxCall ベース Accumulation パターン(将来の P3 拡張候補)」。
|
||||
- `phase232-failing-tests-inventory.md` では:
|
||||
- loop_update_summary 系 4 件は Phase 233 で解消済み。
|
||||
- 残る array_filter 3 件は「Phase 234 の結論により、当面は Fail-Fast を仕様として維持する P2」として位置づける。
|
||||
|
||||
---
|
||||
|
||||
## 5. 次フェーズ候補(メモ)
|
||||
|
||||
- Phase 24x: ArrayFilter / BoxCall Accumulation の設計フェーズ
|
||||
- ねらい:
|
||||
- P3 if-PHI の「accumulator」概念を、数値 + 配列(BoxCall push)まで拡張できるか検討する。
|
||||
- 具体案:
|
||||
- CarrierInfo に「Box ベース accumulator」を追加するかどうか。
|
||||
- LoopPatternSpace に「filter パターン」を追加するか、既存 P3 のバリエーションとして扱うか。
|
||||
- JsonParser / selfhost で類似パターンが出てきたときに、ArrayFilter と同じ箱で扱えるか評価する。
|
||||
|
||||
このフェーズ(Phase 234)では、ここまでの設計メモだけに留めて、実装やテスト期待値の変更は行わないよ。***
|
||||
@ -0,0 +1,63 @@
|
||||
# Phase 236-EX: ExprLowerer/ScopeManager 本番導入(Pattern2 条件)
|
||||
|
||||
目的: Phase 231/235 でパイロット実装・テストしてきた ExprLowerer/ScopeManager を、Pattern2 の break 条件 lowering に実際に使ってみて、既存の condition_to_joinir ベース経路と挙動が一致することを確認するフェーズだよ。影響範囲は Pattern2 の「break 条件」だけに限定する。
|
||||
|
||||
---
|
||||
|
||||
## 1. 現状の経路(Task 236-1 メモ)
|
||||
|
||||
### 1.1 関連ファイル
|
||||
|
||||
- `src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs`
|
||||
- Pattern 2 のルーティングと、`lower_loop_with_break_minimal` 呼び出しの入口。
|
||||
- Phase 231 で ExprLowerer による **validation-only** 呼び出しが挿入されている。
|
||||
- `src/mir/join_ir/lowering/loop_with_break_minimal.rs`
|
||||
- Pattern2 本体の JoinIR ライン。
|
||||
- `lower_loop_with_break_minimal()` の中で、`condition_to_joinir::lower_condition_to_joinir` を用いて
|
||||
- ループ条件
|
||||
- break 条件
|
||||
の両方を JoinIR に lower している。
|
||||
- `src/mir/join_ir/lowering/expr_lowerer.rs`
|
||||
- Phase 231/235: ExprLowerer 本体。ScopeManager から ConditionEnv を組み立てて `condition_lowerer::lower_condition_to_joinir` に委譲する薄い箱。
|
||||
- `src/mir/join_ir/lowering/scope_manager.rs`
|
||||
- Phase 231: `Pattern2ScopeManager` 実装。ConditionEnv / LoopBodyLocalEnv / CapturedEnv / CarrierInfo を束ねて、名前→ValueId / VarScopeKind を返す。
|
||||
- `src/mir/join_ir/lowering/condition_to_joinir.rs`
|
||||
- 既存の condition lowering オーケストレータ。`ConditionEnv` + `lower_condition_to_joinir` + 変数抽出をまとめた API。
|
||||
|
||||
### 1.2 現在の break 条件 lowering の流れ
|
||||
|
||||
1. `pattern2_with_break.rs` で:
|
||||
- LoopScopeShape や LoopBodyLocalEnv を構築。
|
||||
- ConditionEnvBuilder v2 相当で `env: ConditionEnv` を用意。
|
||||
- `carrier_info` / `carrier_updates` など Pattern2 メタ情報を集約。
|
||||
2. Phase 231 追加分:
|
||||
- `Pattern2ScopeManager` を上記 env + body_local_env + captured_env + carrier_info から組み立てる。
|
||||
- ExprLowerer を `ExprContext::Condition` で生成し、`effective_break_condition` を **一度 lower してみるだけ**(結果 ValueId は捨てる)。
|
||||
- UnsupportedNode / VariableNotFound などはログ出力にとどめ、実際の lowering には関与しない。
|
||||
3. 本番 lowering:
|
||||
- `lower_loop_with_break_minimal(...)` を呼び出し、
|
||||
- その内部で `condition_to_joinir::lower_condition_to_joinir` により
|
||||
- ループ条件 AST
|
||||
- break 条件 AST
|
||||
をそれぞれ `env: ConditionEnv` を使って JoinIR 命令列 & ValueId に変換している。
|
||||
|
||||
### 1.3 Phase 236 の狙い
|
||||
|
||||
- `loop_with_break_minimal.rs` 内の break 条件 lowering を、
|
||||
- 「ConditionEnv → lower_condition_to_joinir」から、
|
||||
- 「ScopeManager + ExprLowerer(内部は既存 lower_condition_to_joinir を利用)」に置き換える。
|
||||
- ループ条件(自然終了条件)の lowering は従来どおり condition_to_joinir 経路のまま保持し、差分を break 条件のみに限定する。
|
||||
|
||||
---
|
||||
|
||||
## 2. 次フェーズとのつながり(Phase 237-EX 予告)
|
||||
|
||||
- Phase 237-EX では JsonParser/selfhost の条件パターンを棚卸しし、ExprLowerer/ScopeManager が今後どの条件を優先的に扱うかのカタログを作る予定だよ。
|
||||
- 参照: `phase237-exprlowerer-condition-catalog.md`(条件パターン一覧と ExprLowerer サポート状況の SSOT)。
|
||||
|
||||
---
|
||||
|
||||
## 3. その先(Phase 238-EX との接続)
|
||||
|
||||
- Phase 238-EX で Scope/Env の境界ルールを文書化し、ExprLowerer/ScopeManager/ConditionEnv/LoopBodyLocalEnv/UpdateEnv の責務を固定する予定。
|
||||
- 参照: `phase238-exprlowerer-scope-boundaries.md`(境界ルールと将来のガード案)。***
|
||||
@ -0,0 +1,109 @@
|
||||
# Phase 237-EX: ExprLowerer 条件パターンカタログ(JsonParser / selfhost)
|
||||
|
||||
目的: JsonParser/selfhost に存在するループ条件・break/continue 条件を棚卸しし、ExprLowerer/ScopeManager で必ず扱いたいパターンと後回しにしてよいパターンを整理する。コード変更は行わず、設計 SSOT としてのカタログを作るフェーズだよ。
|
||||
|
||||
---
|
||||
|
||||
## 1. 対象範囲
|
||||
|
||||
- **JsonParser**: `tools/hako_shared/json_parser.hako` の主要ループ(_parse_number / _parse_string / _parse_array / _parse_object / _skip_whitespace / _trim / _match_literal / _atoi)。
|
||||
- **selfhost 代表ループ**: `apps/tests/phase190_atoi_impl.hako`, `apps/tests/phase190_parse_number_impl.hako`(Stage-3/コンパイラ本体に類似する最小パターン)。
|
||||
- 既存設計メモ: `phase230-expr-lowerer-design.md`, `phase230-expr-lowering-inventory.md`, `phase236-exprlowerer-integration.md`, `joinir-architecture-overview.md`。
|
||||
|
||||
---
|
||||
|
||||
## 2. 条件パターン一覧(サマリ)
|
||||
|
||||
| ID | Source | Function/Loop | Pattern (P1–P5) | Position | AST Pattern | Uses | ExprLowerer Support (P236時点) | Notes |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| JP-01 | json_parser.hako | _parse_number | P2 | header | `p < s.length()` | LoopParam + MethodCall(length) | PARTIAL | MethodCall(length)はBoolExprLowererで許容済み。ExprLowererではMethodCall未対応のため NO に近い扱い。 |
|
||||
| JP-02 | json_parser.hako | _parse_number | P2 | break | `digit_pos < 0` | LoopBodyLocal(digit_pos) + OuterLocal(digits) | YES | Phase 223–236 で昇格済み (ConditionOnly carrier経由)。 |
|
||||
| JP-03 | json_parser.hako | _parse_string | P2-ish (early return) | break/return | `p < s.length()` / `ch == "\"" -> return` | LoopParam + MethodCall(substring/length) | PARTIAL | returnで抜ける構造。ExprLowererはMethodCall未対応なので当面 ConditionEnv 経由。 |
|
||||
| JP-04 | json_parser.hako | _parse_array | P4 | header | `p < s.length()` | LoopParam + MethodCall(length) | PARTIAL | continue/returnを含む。MethodCall未対応。 |
|
||||
| JP-05 | json_parser.hako | _parse_array | P4 | break/return | `ch == "]"` / `ch == ","` | LoopBodyLocal(ch) + MethodCall(substring) | PARTIAL | substring + equality。ExprLowererにMethodCall対応が必要。 |
|
||||
| JP-06 | json_parser.hako | _parse_object | P4 | header | `p < s.length()` | LoopParam + MethodCall(length) | PARTIAL | 上と同様。 |
|
||||
| JP-07 | json_parser.hako | _skip_whitespace | P4 | continue | `p < s.length()` + whitespace 判定 | LoopParam + MethodCall(substring) | PARTIAL | 文字比較のみ。MethodCall(substring)が鍵。 |
|
||||
| JP-08 | json_parser.hako | _trim (leading) | P4 | continue | `start < end` + whitespace 判定 | LoopBodyLocal(start/end) + MethodCall(substring) | PARTIAL | 先頭/末尾トリム。 |
|
||||
| JP-09 | json_parser.hako | _match_literal | P2 | header | `i < len` | LoopParam + OuterLocal(len) | YES | 純スカラ比較のみ。 |
|
||||
| JP-10 | json_parser.hako | _atoi | P2 | header | `i < n` | LoopParam + OuterLocal(n) | YES | 純スカラ比較。 |
|
||||
| SH-01 | phase190_atoi_impl.hako | main loop | P2 | header | `i < 10` | LoopParam | YES | ExprLowerer 条件対応済み。 |
|
||||
| SH-02 | phase190_atoi_impl.hako | break | `i >= 3` | LoopParam | YES | 比較のみ。 |
|
||||
| SH-03 | phase190_parse_number_impl.hako | header | `i < 10` | LoopParam | YES | 比較のみ。 |
|
||||
| SH-04 | phase190_parse_number_impl.hako | break | `i > 3` | LoopParam | YES | 比較のみ。 |
|
||||
|
||||
※ Support 列の解釈: YES = Phase 236 までの ExprLowerer/condition_to_joinir で扱えるか実績あり、PARTIAL = BoolExprLowerer/ConditionEnv では対応しているが ExprLowerer で MethodCall 等が未実装、NO = まだ扱っていない。
|
||||
|
||||
---
|
||||
|
||||
## 3. パターン詳細(JsonParser)
|
||||
|
||||
- **_parse_number**
|
||||
- header: `loop(p < s.length())` — MethodCall(length) を含む。現在は ConditionEnv + condition_to_joinir で処理、ExprLowererは MethodCall 未対応なので PARTIAL。
|
||||
- break: `if digit_pos < 0 { break }` — digit_pos は body-local → ConditionOnly carrier として昇格済み。ExprLowerer 対応可。
|
||||
- continue path: digit が見つかったら `p = p + 1` で次イテレーション。
|
||||
- **_parse_string**
|
||||
- header: `loop(p < s.length())` — MethodCall(length)。
|
||||
- break/return: `if ch == "\"" { return ... }` / escape 判定など。MethodCall(substring) + equality の組み合わせ。
|
||||
- **_parse_array**
|
||||
- header: `loop(p < s.length())` — MethodCall(length)。
|
||||
- 内部: `if ch == "]" { return ... }`, `if ch == "," { ...; continue }` — substring + equality。
|
||||
- **_parse_object**
|
||||
- header: `loop(p < s.length())` — MethodCall(length)。
|
||||
- 内部: `if ch == "}" { return ... }` / `if ch == "," { continue }` — substring + equality。
|
||||
- **_skip_whitespace**
|
||||
- header: `loop(p < s.length())`
|
||||
- continue: whitespace 判定 (`" " || "\t" || "\n" || "\r"`) → continue、そうでなければ break 相当。
|
||||
- **_trim**
|
||||
- leading trim: `loop(start < end)` + whitespace 判定 → continue/break。
|
||||
- trailing trim: `loop(end > start)` + whitespace 判定 → continue/break。
|
||||
- **_match_literal**
|
||||
- header: `loop(i < len)`、body: 文字比較 + break。
|
||||
- ExprLowerer で既に扱える純スカラ比較。
|
||||
- **_atoi**
|
||||
- header: `loop(i < n)`
|
||||
- break: 非 digit を見つけたら break。
|
||||
- 文字比較 + indexOf(digit) などが絡むが、条件自体は比較のみ。
|
||||
|
||||
---
|
||||
|
||||
## 4. パターン詳細(selfhost 代表)
|
||||
|
||||
- **phase190_atoi_impl.hako**
|
||||
- header: `loop(i < 10)`、break: `if i >= 3 { break }`
|
||||
- 純スカラ比較のみ。ExprLowerer 本番経路で扱える。
|
||||
- **phase190_parse_number_impl.hako**
|
||||
- header: `loop(i < 10)`、break: `if i > 3 { break }`
|
||||
- 純スカラ比較のみ。ExprLowerer 本番経路で扱える。
|
||||
- (selfhost コンパイラ本体の Stage-3 ループは JsonParser と同型/サブセットであることが多く、上記 JP パターンに準拠する想定。必要に応じて SH-xx を追加する。)
|
||||
|
||||
---
|
||||
|
||||
## 5. ExprLowerer/ScopeManager へのマッピング
|
||||
|
||||
- **YES(Phase 236 時点で処理可能)**
|
||||
- スカラ比較のみの header/break: `i < 10`, `i > 3`, `digit_pos < 0`(昇格済み ConditionOnly carrier)。
|
||||
- `_match_literal`, `_atoi` のループ条件・break 条件のような純スカラ比較。
|
||||
- **PARTIAL**
|
||||
- MethodCall を含む header 条件: `p < s.length()`(length 呼び出し)、`ch == s.substring(...)` など。
|
||||
- substring/indexOf を含む break/continue 条件: `_parse_array/_object/_string` 内の `ch == "]"` / `ch == ","` 等。
|
||||
- → ExprLowerer で MethodCall (length/substring/indexOf) を許可する拡張が必要。
|
||||
- **NO(未対応)**
|
||||
- return ベースでループを抜けるパターン(_parse_string のように return で終了するケース)は、ExprLowerer 以前に LoopPattern 側での扱いを要検討。
|
||||
- 文字列操作が複合的に絡む条件(escape 処理など)も当面は ConditionEnv + legacy lowerer 維持を推奨。
|
||||
|
||||
---
|
||||
|
||||
## 6. 次フェーズ候補(実装案のメモ)
|
||||
|
||||
- 候補 A: Pattern2 header 条件の MethodCall(length) を ExprLowerer で扱う(JP-01/03/04/06 の header を統一)。
|
||||
- 候補 B: substring + equality のシンプル条件を ExprLowerer に許可し、_parse_array/_object の `ch == "]"` / `ch == ","` を扱う。
|
||||
- 候補 C: selfhost の P2 ループ(header/break)を ExprLowerer 本番経路に順次寄せて、実戦ループのカバレッジを測定する。
|
||||
- 候補 D: return ベースの終了条件を LoopPattern 側でどこまで扱うか設計し、ExprLowerer への影響範囲を決める。
|
||||
|
||||
---
|
||||
|
||||
## 7. 完了の定義(Phase 237-EX)
|
||||
|
||||
- JsonParser 11 ループの主要条件(header/break/continue/if-guard)が JP-xx 行としてカタログに掲載されている。
|
||||
- selfhost 代表ループ 3〜5 例(SH-xx)が掲載されている。
|
||||
- 各行に ExprLowerer Support (YES/PARTIAL/NO) と簡単な Notes が入っており、今後どの箱を触ればよいか判断できる。***
|
||||
@ -0,0 +1,60 @@
|
||||
# Phase 238-EX: ExprLowerer/ScopeManager Scope Boundaries
|
||||
|
||||
目的: ExprLowerer / ScopeManager / ConditionEnv / LoopBodyLocalEnv / UpdateEnv の責務と参照範囲を文章で固定し、「誰がどこまで見てよいか」を SSOT 化する。コード変更は行わず、ガイドラインと境界ルールを整備するフェーズだよ。
|
||||
|
||||
---
|
||||
|
||||
## 1. 対象コンポーネント
|
||||
|
||||
- ExprLowerer(条件式 lowering 箱)
|
||||
- ScopeManager(名前解決の窓口)
|
||||
- ConditionEnv(条件式用の名前→ValueId マップ)
|
||||
- LoopBodyLocalEnv(body-local init 専用の環境)
|
||||
- UpdateEnv(carrier 更新専用の環境)
|
||||
|
||||
---
|
||||
|
||||
## 2. 境界ルール(原則)
|
||||
|
||||
- **名前解決は ScopeManager 経由のみ**: ExprLowerer は ConditionEnv / LoopBodyLocalEnv / CapturedEnv / CarrierInfo に直接触らない。ScopeManager の lookup/scope_of を唯一の窓口とする。
|
||||
- **条件式から UpdateEnv へは触らない**: header/break/continue 条件は carrier 更新専用の UpdateEnv にアクセスしない。更新式は UpdateEnv / LoopBodyLocalInitLowerer に限定。
|
||||
- **ConditionEnv は「条件で参照する値のみ」**: loop var / carriers / ConditionOnly / captured const など、条件式で参照する JoinIR ValueId のみを持ち、body-local を直接含めない(昇格する場合は ScopeManager+CarrierInfo 経由)。
|
||||
- **LoopBodyLocalEnv は init 専用**: body 内 local 定義の init 式だけを扱い、条件式の参照は ScopeManager が仲介する(条件側から直接参照しない)。
|
||||
- **Fail-Fast / by-name 禁止**: ExprLowerer/ScopeManager は「名前ヒューリスティック」や silent fallback を行わず、Unsupported/NotFound は明示エラー(上位で Fail-Fast ポリシーに従う)。
|
||||
|
||||
---
|
||||
|
||||
## 3. JsonParser/selfhost 条件パターンへの対応(237 カタログとの橋渡し)
|
||||
|
||||
- **優先対応(YES/PARTIAL で拾いたいもの)**
|
||||
- P2/P4 header の単純比較 (`i < n`, `p < s.length()`): LoopParam + OuterLocal/Captured/MethodCall(length)。ScopeManager で loop var / captured const を解決し、MethodCall 対応は将来 ExprLowerer 拡張で吸収。
|
||||
- P2 break 条件 `digit_pos < 0`: body-local 昇格済み (ConditionOnly carrier)。ScopeManager が `digit_pos`→`is_digit_pos` を解決。
|
||||
- substring + equality の単純分岐(`ch == "]"` など): LoopBodyLocal + MethodCall(substring)。MethodCallLowerer 経由で ExprLowerer へ委譲する拡張が必要。
|
||||
- **当面後回し**
|
||||
- return ベースの終了(_parse_string のように return で抜ける): LoopPattern 側の設計が先。ExprLowerer は条件式評価に限定。
|
||||
- 複合的な文字列操作(escape 処理など): legacy ConditionEnv +専用 lowerer 維持。
|
||||
|
||||
ScopeManager が解決する名前の例:
|
||||
- LoopParam: `i`, `p`, `start`, `end`
|
||||
- Captured/OuterLocal: `len`, `n`, `digits`
|
||||
- Promoted LoopBodyLocal: `digit_pos` → `is_digit_pos`
|
||||
- BodyLocal(条件で参照する場合): `ch`, `temp` など(LoopBodyLocalEnv → ScopeManager 経由)
|
||||
|
||||
---
|
||||
|
||||
## 4. LAYER_GUARD / ガード実装案(構造メモ)
|
||||
|
||||
- 将来的に `src/mir/join_ir/lowering/LAYER_GUARD.rs` 相当で、以下を静的に検知する案を検討:
|
||||
- ExprLowerer が ConditionEnv / LoopBodyLocalEnv を直接 import していないか。
|
||||
- ScopeManager が UpdateEnv を参照していないか。
|
||||
- condition_to_joinir から ScopeManager をバイパスするパスが残っていないか。
|
||||
- 既存の AGENTS 原則(by-name ハードコード禁止 / Fail-Fast / 構造優先)を lint 的に守る仕組みの叩き台にする。
|
||||
|
||||
---
|
||||
|
||||
## 5. 次フェーズ候補(実装 TODO のメモ)
|
||||
|
||||
- ExprLowerer に MethodCall(length/substring/indexOf) の条件用 lowering を追加(カタログ JP-01/03/04/06/08/07 対応)。
|
||||
- ScopeManager のガード強化(条件式から UpdateEnv へのアクセス禁止を型/モジュール境界で表現)。
|
||||
- ConditionEnv 構築を ScopeManager 中心に巻き直す(ConditionEnvBuilder v2 を ScopeManager-front に寄せる)。
|
||||
- LAYER_GUARD 的な静的チェックの導入検討。***
|
||||
@ -1,326 +0,0 @@
|
||||
# Phase 33-17: JoinIR Modularization - Final Report
|
||||
|
||||
## Executive Summary
|
||||
|
||||
✅ **Phase 33-17-A Completed Successfully**
|
||||
|
||||
- **Files Created**: 2 new modules (tail_call_classifier.rs, merge_result.rs)
|
||||
- **Lines Reduced**: instruction_rewriter.rs (649 → 589 lines, -9.2%)
|
||||
- **Tests Added**: 4 unit tests for TailCallClassifier
|
||||
- **Build Status**: ✅ Success (1m 03s)
|
||||
- **All Tests**: ✅ Pass
|
||||
|
||||
---
|
||||
|
||||
## 📊 File Size Analysis (After Phase 33-17-A)
|
||||
|
||||
### Top 15 Largest Files
|
||||
|
||||
| Rank | Lines | File | Status |
|
||||
|------|-------|------|--------|
|
||||
| 1 | 589 | instruction_rewriter.rs | ⚠️ Still large (was 649) |
|
||||
| 2 | 405 | exit_binding.rs | ✅ Good (includes tests) |
|
||||
| 3 | 355 | pattern4_with_continue.rs | ⚠️ Large but acceptable |
|
||||
| 4 | 338 | routing.rs | ⚠️ Large but acceptable |
|
||||
| 5 | 318 | loop_header_phi_builder.rs | ⚠️ Next target |
|
||||
| 6 | 306 | merge/mod.rs | ✅ Good |
|
||||
| 7 | 250 | trace.rs | ✅ Good |
|
||||
| 8 | 228 | ast_feature_extractor.rs | ✅ Good |
|
||||
| 9 | 214 | pattern2_with_break.rs | ✅ Good |
|
||||
| 10 | 192 | router.rs | ✅ Good |
|
||||
| 11 | 176 | pattern1_minimal.rs | ✅ Good |
|
||||
| 12 | 163 | pattern3_with_if_phi.rs | ✅ Good |
|
||||
| 13 | 157 | exit_line/reconnector.rs | ✅ Good |
|
||||
| 14 | 139 | exit_line/meta_collector.rs | ✅ Good |
|
||||
| 15 | 107 | tail_call_classifier.rs | ✅ New module |
|
||||
|
||||
### Progress Metrics
|
||||
|
||||
**Before Phase 33-17**:
|
||||
- Files over 200 lines: 5
|
||||
- Largest file: 649 lines
|
||||
|
||||
**After Phase 33-17-A**:
|
||||
- Files over 200 lines: 5 (no change)
|
||||
- Largest file: 589 lines (-9.2%)
|
||||
|
||||
**Target Goal (Phase 33-17 Complete)**:
|
||||
- Files over 200 lines: ≤2
|
||||
- Largest file: ≤350 lines
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Implementation Details
|
||||
|
||||
### New Modules Created
|
||||
|
||||
#### 1. tail_call_classifier.rs (107 lines)
|
||||
|
||||
**Purpose**: Classifies tail calls into LoopEntry/BackEdge/ExitJump
|
||||
|
||||
**Contents**:
|
||||
- TailCallKind enum (3 variants)
|
||||
- classify_tail_call() function
|
||||
- 4 unit tests
|
||||
|
||||
**Box Theory Compliance**: ✅
|
||||
- **Single Responsibility**: Classification logic only
|
||||
- **Testability**: Fully unit tested
|
||||
- **Independence**: No dependencies on other modules
|
||||
|
||||
#### 2. merge_result.rs (46 lines)
|
||||
|
||||
**Purpose**: Data structure for merge results
|
||||
|
||||
**Contents**:
|
||||
- MergeResult struct
|
||||
- Helper methods (new, add_exit_phi_input, add_carrier_input)
|
||||
|
||||
**Box Theory Compliance**: ✅
|
||||
- **Single Responsibility**: Data management only
|
||||
- **Encapsulation**: All fields public but managed
|
||||
- **Independence**: Pure data structure
|
||||
|
||||
### Modified Modules
|
||||
|
||||
#### 3. instruction_rewriter.rs (649 → 589 lines)
|
||||
|
||||
**Changes**:
|
||||
- Removed TailCallKind enum definition (60 lines)
|
||||
- Removed classify_tail_call() function
|
||||
- Removed MergeResult struct definition
|
||||
- Added imports from new modules
|
||||
- Updated documentation
|
||||
|
||||
**Remaining Issues**:
|
||||
- Still 589 lines (2.9x target of 200)
|
||||
- Further modularization recommended (Phase 33-17-C)
|
||||
|
||||
#### 4. merge/mod.rs (300 → 306 lines)
|
||||
|
||||
**Changes**:
|
||||
- Added module declarations (tail_call_classifier, merge_result)
|
||||
- Re-exported public APIs
|
||||
- Updated documentation
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Architecture Improvements
|
||||
|
||||
### Box Theory Design
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ TailCallClassifier Box │
|
||||
│ - Responsibility: Tail call classification │
|
||||
│ - Input: Context flags │
|
||||
│ - Output: TailCallKind enum │
|
||||
│ - Tests: 4 unit tests │
|
||||
└─────────────────────────────────────────────────┘
|
||||
▼
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ InstructionRewriter Box │
|
||||
│ - Responsibility: Instruction transformation │
|
||||
│ - Delegates to: TailCallClassifier │
|
||||
│ - Produces: MergeResult │
|
||||
└─────────────────────────────────────────────────┘
|
||||
▼
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ MergeResult Box │
|
||||
│ - Responsibility: Result data management │
|
||||
│ - Fields: exit_block_id, exit_phi_inputs, etc. │
|
||||
│ - Used by: exit_phi_builder │
|
||||
└─────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Dependency Graph
|
||||
|
||||
```
|
||||
merge/mod.rs
|
||||
├── tail_call_classifier.rs (independent)
|
||||
├── merge_result.rs (independent)
|
||||
└── instruction_rewriter.rs
|
||||
├─uses→ tail_call_classifier
|
||||
└─produces→ merge_result
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📈 Quality Metrics
|
||||
|
||||
### Code Coverage
|
||||
|
||||
| Module | Tests | Coverage |
|
||||
|--------|-------|----------|
|
||||
| tail_call_classifier.rs | 4 | 100% |
|
||||
| merge_result.rs | 0 | N/A (data structure) |
|
||||
| instruction_rewriter.rs | 0 | Integration tested |
|
||||
|
||||
### Documentation
|
||||
|
||||
| Module | Doc Comments | Quality |
|
||||
|--------|--------------|---------|
|
||||
| tail_call_classifier.rs | ✅ Complete | Excellent |
|
||||
| merge_result.rs | ✅ Complete | Excellent |
|
||||
| instruction_rewriter.rs | ✅ Updated | Good |
|
||||
|
||||
### Maintainability
|
||||
|
||||
| Metric | Before | After | Change |
|
||||
|--------|--------|-------|--------|
|
||||
| Max file size | 649 | 589 | -9.2% |
|
||||
| Files >200 lines | 5 | 5 | - |
|
||||
| Modules total | 18 | 20 | +2 |
|
||||
| Test coverage | N/A | 4 tests | +4 |
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Recommendations
|
||||
|
||||
### Phase 33-17-B: loop_header_phi_builder Split (HIGH PRIORITY)
|
||||
|
||||
**Target**: 318 lines → ~170 lines
|
||||
|
||||
**Proposed Split**:
|
||||
```
|
||||
loop_header_phi_builder.rs (318)
|
||||
├── loop_header_phi_info.rs (150)
|
||||
│ └── Data structures (LoopHeaderPhiInfo, CarrierPhiEntry)
|
||||
└── loop_header_phi_builder.rs (170)
|
||||
└── Builder logic (build, finalize)
|
||||
```
|
||||
|
||||
**Benefits**:
|
||||
- ✅ LoopHeaderPhiInfo independently reusable
|
||||
- ✅ Cleaner separation of data and logic
|
||||
- ✅ Both files under 200 lines
|
||||
|
||||
**Estimated Time**: 1-2 hours
|
||||
|
||||
---
|
||||
|
||||
### Phase 33-17-C: instruction_rewriter Further Split (MEDIUM PRIORITY)
|
||||
|
||||
**Current**: 589 lines (still large)
|
||||
|
||||
**Proposed Split** (if needed):
|
||||
```
|
||||
instruction_rewriter.rs (589)
|
||||
├── boundary_injector.rs (180)
|
||||
│ └── BoundaryInjector wrapper logic
|
||||
├── parameter_binder.rs (60)
|
||||
│ └── Tail call parameter binding
|
||||
└── instruction_mapper.rs (350)
|
||||
└── Core merge_and_rewrite logic
|
||||
```
|
||||
|
||||
**Decision Criteria**:
|
||||
- ✅ Implement: If instruction_rewriter grows >600 lines
|
||||
- ⚠️ Consider: If >400 lines and clear boundaries exist
|
||||
- ❌ Skip: If <400 lines and well-organized
|
||||
|
||||
**Current Recommendation**: ⚠️ Monitor, implement in Phase 33-18 if needed
|
||||
|
||||
---
|
||||
|
||||
### Phase 33-17-D: Pattern File Deduplication (LOW PRIORITY)
|
||||
|
||||
**Investigation Needed**:
|
||||
- Check for common code in pattern1/2/3/4
|
||||
- Extract to pattern_helpers.rs if >50 lines duplicated
|
||||
|
||||
**Current Status**: Not urgent, defer to Phase 34
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Achievements
|
||||
|
||||
### Technical
|
||||
|
||||
1. ✅ **Modularization**: Extracted 2 focused modules
|
||||
2. ✅ **Testing**: Added 4 unit tests
|
||||
3. ✅ **Documentation**: Comprehensive box theory comments
|
||||
4. ✅ **Build**: No errors, clean compilation
|
||||
|
||||
### Process
|
||||
|
||||
1. ✅ **Box Theory**: Strict adherence to single responsibility
|
||||
2. ✅ **Naming**: Clear, consistent naming conventions
|
||||
3. ✅ **Incremental**: Safe, testable changes
|
||||
4. ✅ **Documentation**: Analysis → Implementation → Report
|
||||
|
||||
### Impact
|
||||
|
||||
1. ✅ **Maintainability**: Easier to understand and modify
|
||||
2. ✅ **Testability**: TailCallClassifier fully unit tested
|
||||
3. ✅ **Reusability**: MergeResult reusable across modules
|
||||
4. ✅ **Clarity**: Clear separation of concerns
|
||||
|
||||
---
|
||||
|
||||
## 📝 Lessons Learned
|
||||
|
||||
### What Worked Well
|
||||
|
||||
1. **Incremental Approach**: Extract one module at a time
|
||||
2. **Test Coverage**: Write tests immediately after extraction
|
||||
3. **Documentation**: Document box theory role upfront
|
||||
4. **Build Verification**: Test after each change
|
||||
|
||||
### What Could Be Improved
|
||||
|
||||
1. **Initial Planning**: Could have identified all extraction targets upfront
|
||||
2. **Test Coverage**: Could add integration tests for instruction_rewriter
|
||||
3. **Documentation**: Could add more code examples
|
||||
|
||||
### Best Practices Established
|
||||
|
||||
1. **Module Size**: Target 200 lines per file
|
||||
2. **Single Responsibility**: One clear purpose per module
|
||||
3. **Box Theory**: Explicit delegation and composition
|
||||
4. **Testing**: Unit tests for pure logic, integration tests for composition
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Next Steps
|
||||
|
||||
### Immediate (Phase 33-17-B)
|
||||
|
||||
1. Extract loop_header_phi_info.rs
|
||||
2. Reduce loop_header_phi_builder.rs to ~170 lines
|
||||
3. Update merge/mod.rs exports
|
||||
4. Verify build and tests
|
||||
|
||||
### Short-term (Phase 33-18)
|
||||
|
||||
1. Re-evaluate instruction_rewriter.rs size
|
||||
2. Implement further split if >400 lines
|
||||
3. Update documentation
|
||||
|
||||
### Long-term (Phase 34+)
|
||||
|
||||
1. Pattern file deduplication analysis
|
||||
2. routing.rs optimization review
|
||||
3. Overall JoinIR architecture documentation
|
||||
|
||||
---
|
||||
|
||||
## 📊 Final Status
|
||||
|
||||
**Phase 33-17-A**: ✅ Complete
|
||||
**Build Status**: ✅ Success
|
||||
**Test Status**: ✅ All Pass
|
||||
**Next Phase**: Phase 33-17-B (loop_header_phi_builder split)
|
||||
|
||||
**Time Invested**: ~2 hours
|
||||
**Lines of Code**: +155 (new modules) -60 (removed duplication) = +95 net
|
||||
**Modules Created**: 2
|
||||
**Tests Added**: 4
|
||||
**Quality Improvement**: Significant (better separation of concerns)
|
||||
|
||||
---
|
||||
|
||||
**Completion Date**: 2025-12-07
|
||||
**Implemented By**: Claude Code
|
||||
**Reviewed By**: Pending
|
||||
**Status**: Ready for Phase 33-17-B
|
||||
@ -1,134 +0,0 @@
|
||||
# Phase 61-5.3: If PHI 関数優先度表
|
||||
|
||||
## 目的
|
||||
Phase 61-5.2 で作成した If PHI 関数表に削減優先度(P1/P2/P3)を追加する。
|
||||
|
||||
## 優先度の定義
|
||||
|
||||
### P1(最優先削減候補)
|
||||
- すでに JoinIR でほぼ構造が決まっていて、削るだけの関数(薄いラッパー)
|
||||
- 条件:
|
||||
- `joinir_coverage=in_loop` or `toplevel_return`(完全カバー済み)
|
||||
- 既存経路を削除するだけで JoinIR に完全移行可能
|
||||
- 実装コストが低い(数十行レベル)
|
||||
|
||||
### P2(次期削減候補)
|
||||
- JoinIR パターンを少し拡張すれば寄せられそうな関数
|
||||
- 条件:
|
||||
- `joinir_coverage=partial`(部分カバー)
|
||||
- IfMerge や PhiSpec を拡張すれば統合可能
|
||||
- 実装コストが中程度(数百行レベル)
|
||||
|
||||
### P3(将来の削減候補)
|
||||
- 型情報やより強い If パターン(nested/複雑)を待つべき関数
|
||||
- 条件:
|
||||
- `joinir_coverage=none`(未カバー)
|
||||
- 型システムや高度な解析が必要
|
||||
- 実装コストが高い(Phase 63+ で対応)
|
||||
|
||||
---
|
||||
|
||||
## If PHI 関数優先度表(Phase 61-5.3)
|
||||
|
||||
| 関数名 | ファイル | JoinIR Coverage | Priority | 削減方針(1行) |
|
||||
|--------|----------|-----------------|----------|----------------|
|
||||
| **PhiBuilderBox系** | | | | |
|
||||
| `set_if_context` | phi_builder_box.rs | in_loop | **P1** | IfPhiContext 生成を直接呼び出しに置き換え、ラッパー削除 |
|
||||
| `generate_if_phis` | phi_builder_box.rs | partial | **P2** | IfInLoopPhiEmitter で代替、統一後に薄い箱として残すかインライン化 |
|
||||
| `compute_modified_names_if` | phi_builder_box.rs | partial | **P2** | JoinIR の modified 変数集合解析に統合、ヘルパー削除 |
|
||||
| `get_conservative_if_values` | phi_builder_box.rs | partial | **P2** | JoinIR の incoming 値解決に統合、void fallback を PhiSpec に移行 |
|
||||
| **JoinIR Lowering系** | | | | |
|
||||
| `try_lower_if_to_joinir` | if_select.rs / if_merge.rs | in_loop | **P1** | If パターンマッチング完了後、デフォルト有効化して薄いルーティング関数に |
|
||||
| `find_if_pattern` | if_select.rs | in_loop | **P1** | Simple/Local パターン検出は完成、ラッパー層削減可能 |
|
||||
| `find_if_merge_pattern` | if_merge.rs | in_loop | **P1** | IfMerge 検出は完成、ラッパー層削減可能 |
|
||||
| **JoinIR Context系** | | | | |
|
||||
| `IfPhiContext::for_loop_body` | if_phi_context.rs | in_loop | **P1** | コンストラクタは軽量、loop_builder.rs から直接呼び出し継続 |
|
||||
| `IfPhiContext::pure_if` | if_phi_context.rs | none | **P3** | Pure If 経路は Phase 63+ で統合、現状維持 |
|
||||
| `is_carrier` | if_phi_context.rs | in_loop | **P1** | carrier 判定ロジックは完成、ヘルパーとして残す |
|
||||
| **PhiSpec系** | | | | |
|
||||
| `compute_phi_spec_from_joinir` | if_phi_spec.rs | in_loop | **P1** | JoinInst から PhiSpec を計算、Phase 61-3 で variable_name 逆引き完成後そのまま使用 |
|
||||
| `extract_phi_spec_from_builder` | if_phi_spec.rs | partial | **P2** | PhiBuilderBox 経路観察用、JoinIR 移行完了後は削除候補 |
|
||||
| `compare_and_log_phi_specs` | if_phi_spec.rs | partial | **P2** | A/B テスト用ロギング、移行完了後は削除候補 |
|
||||
| **If-in-Loop Emitter系** | | | | |
|
||||
| `IfInLoopPhiEmitter::emit` | if_in_loop/mod.rs | in_loop | **P1** | PHI 生成の SSOT、既に動作済み、デフォルト有効化で完成 |
|
||||
| `emit_single_var_phi` | if_in_loop/lowering/single_var_*.rs | in_loop | **P1** | SingleVarThen/Both パターンは実装完了、薄いヘルパーとして残す |
|
||||
| `emit_conditional_effect_phi` | if_in_loop/lowering/conditional_effect.rs | in_loop | **P1** | ConditionalEffect パターンは実装完了、薄いヘルパーとして残す |
|
||||
| **Conservative系** | | | | |
|
||||
| `ConservativeMerge::analyze` | conservative.rs | none | **P3** | 型推論(infer_type_from_phi)依存、Phase 63+ で型システム統合 |
|
||||
| `infer_type_from_phi` | conservative.rs | none | **P3** | レガシー型推論箱、JoinIR 型情報導入後の削減候補(Phase 63+) |
|
||||
| **IfMerge系** | | | | |
|
||||
| `lower_if_to_if_merge` | if_merge.rs | in_loop | **P1** | IfMerge 変換ロジックは完成、デフォルト有効化で完成 |
|
||||
| `extract_written_vars` | if_merge.rs | in_loop | **P1** | 変数書き込み検出は完成、薄いヘルパーとして残す |
|
||||
| `find_written_value` | if_merge.rs | in_loop | **P1** | 値検出は完成、薄いヘルパーとして残す |
|
||||
| **IfSelect系** | | | | |
|
||||
| `lower_if_to_select` | if_select.rs | in_loop | **P1** | Select 変換ロジックは完成、デフォルト有効化で完成 |
|
||||
| `try_match_simple_pattern` | if_select.rs | in_loop | **P1** | Simple パターンは完成、薄いヘルパーとして残す |
|
||||
| `try_match_local_pattern` | if_select.rs | in_loop | **P1** | Local パターンは完成、薄いヘルパーとして残す |
|
||||
| `is_side_effect_free` | if_select.rs | in_loop | **P1** | 副作用なし判定は完成、薄いヘルパーとして残す |
|
||||
|
||||
---
|
||||
|
||||
## 優先度別サマリー
|
||||
|
||||
### P1(最優先削減候補): 18関数
|
||||
- **JoinIR Lowering系**: `try_lower_if_to_joinir`, `find_if_pattern`, `find_if_merge_pattern`, `lower_if_to_if_merge`, `lower_if_to_select`
|
||||
- **PhiBuilderBox系**: `set_if_context`(薄いラッパー削除候補)
|
||||
- **Context系**: `IfPhiContext::for_loop_body`, `is_carrier`
|
||||
- **PhiSpec系**: `compute_phi_spec_from_joinir`
|
||||
- **Emitter系**: `IfInLoopPhiEmitter::emit`, `emit_single_var_phi`, `emit_conditional_effect_phi`
|
||||
- **IfMerge/IfSelect ヘルパー**: `extract_written_vars`, `find_written_value`, `try_match_simple_pattern`, `try_match_local_pattern`, `is_side_effect_free`
|
||||
|
||||
### P2(次期削減候補): 5関数
|
||||
- **PhiBuilderBox系**: `generate_if_phis`, `compute_modified_names_if`, `get_conservative_if_values`
|
||||
- **PhiSpec系**: `extract_phi_spec_from_builder`, `compare_and_log_phi_specs`
|
||||
|
||||
### P3(将来の削減候補): 3関数
|
||||
- **Conservative系**: `ConservativeMerge::analyze`, `infer_type_from_phi`
|
||||
- **Context系**: `IfPhiContext::pure_if`
|
||||
|
||||
---
|
||||
|
||||
## Phase 61-6 実装推奨順序
|
||||
|
||||
### Step 1: P1 薄いラッパー削除(~50行削減)
|
||||
1. `set_if_context`: loop_builder.rs から直接 `IfPhiContext::for_loop_body` 呼び出しに置き換え
|
||||
2. If Lowering ルーティング関数のデフォルト有効化(dev フラグ削除)
|
||||
|
||||
### Step 2: P2 統合(~200行削減)
|
||||
1. `compute_modified_names_if`: JoinIR の modified 変数集合解析に統合
|
||||
2. `get_conservative_if_values`: incoming 値解決を PhiSpec に移行
|
||||
3. `extract_phi_spec_from_builder`, `compare_and_log_phi_specs`: A/B テスト完了後削除
|
||||
|
||||
### Step 3: P3 延期(Phase 63+)
|
||||
1. `ConservativeMerge::analyze`: 型推論システム統合待ち
|
||||
2. `infer_type_from_phi`: JoinIR 型情報導入待ち
|
||||
3. `IfPhiContext::pure_if`: Pure If 経路統合待ち
|
||||
|
||||
---
|
||||
|
||||
## 期待される削減効果
|
||||
|
||||
| Phase | 削減対象 | 見込み削減行数 | 累積削減 |
|
||||
|-------|---------|--------------|---------|
|
||||
| 61-6.1 | P1 ラッパー削除 | ~50 | 50 |
|
||||
| 61-6.2 | P2 統合 | ~200 | 250 |
|
||||
| 63+ | P3 型システム統合 | ~150 | 400 |
|
||||
|
||||
---
|
||||
|
||||
## 実装時の注意事項
|
||||
|
||||
1. **Fail-Fast原則**: フォールバックなし、エラーは即座に失敗
|
||||
2. **決定的順序**: BTreeSet/BTreeMap で ValueId 割り当ての決定性保証
|
||||
3. **箱理論**: 境界を守りながら、SSOT を JoinIR 側に寄せる
|
||||
4. **テスト**: 各ステップで全 JoinIR tests PASS を確認
|
||||
5. **ドキュメント**: PHI_BOX_INVENTORY.md と CURRENT_TASK.md を更新
|
||||
|
||||
---
|
||||
|
||||
## 関連ドキュメント
|
||||
|
||||
- Phase 61-1: [if_phi_context.rs](../../../src/mir/join_ir/lowering/if_phi_context.rs)
|
||||
- Phase 61-2: [if_phi_spec.rs](../../../src/mir/join_ir/lowering/if_phi_spec.rs)
|
||||
- Phase 61-3: [if_in_loop/mod.rs](../../../src/mir/join_ir/frontend/ast_lowerer/if_in_loop/mod.rs)
|
||||
- PHI Inventory: [PHI_BOX_INVENTORY.md](../../../docs/private/roadmap2/phases/phase-30-final-joinir-world/PHI_BOX_INVENTORY.md)
|
||||
@ -1,131 +0,0 @@
|
||||
# Phase 61-5: If PHI 削減計画策定 - サマリー
|
||||
|
||||
## 目的
|
||||
Phase 61-3 で JoinIR 経路による If-in-Loop PHI 生成が完全動作したため、既存の If PHI 関数群を整理し、削減計画を策定する。
|
||||
|
||||
---
|
||||
|
||||
## 実施内容(4ステップ完了)
|
||||
|
||||
### Phase 61-5.1: If PHI 関数リスト作成 ✅
|
||||
- **成果物**: [phase61-5-1-if-phi-function-list.md](phase61-5-1-if-phi-function-list.md)
|
||||
- **内容**: If PHI 関連の全関数を 3 カテゴリに分類
|
||||
- PhiBuilderBox系: 4関数(set_if_context, generate_if_phis 等)
|
||||
- JoinIR Lowering系: 14関数(try_lower_if_to_joinir, find_if_pattern 等)
|
||||
- 補助系: 8関数(IfPhiContext, PhiSpec, Conservative 等)
|
||||
- **合計**: 26関数をリスト化
|
||||
|
||||
### Phase 61-5.2: JoinIR カバレッジ調査 ✅
|
||||
- **成果物**: [phase61-5-2-if-phi-coverage-table.md](phase61-5-2-if-phi-coverage-table.md)
|
||||
- **内容**: 各関数の JoinIR カバレッジを調査
|
||||
- `in_loop`: 完全カバー済み(18関数)
|
||||
- `partial`: 部分カバー(5関数)
|
||||
- `none`: 未カバー(3関数)
|
||||
- **重要発見**: If-in-Loop PHI は JoinIR で 100% カバー達成済み
|
||||
|
||||
### Phase 61-5.3: 優先度表作成 ✅
|
||||
- **成果物**: [phase61-5-3-if-phi-priority-table.md](phase61-5-3-if-phi-priority-table.md)
|
||||
- **内容**: カバレッジ調査を基に削減優先度を設定
|
||||
- **P1(最優先)**: 18関数 - 薄いラッパー、既に JoinIR で完全カバー
|
||||
- **P2(次期候補)**: 5関数 - JoinIR 拡張で統合可能
|
||||
- **P3(将来候補)**: 3関数 - 型システム統合待ち
|
||||
|
||||
### Phase 61-5.4: 次フェーズ候補選定 ✅
|
||||
- **成果物**: [phase61-5.4-next-phase-candidates.md](phase61-5.4-next-phase-candidates.md)
|
||||
- **内容**: Phase 61-6 で削減する 3 個の候補を選定
|
||||
1. **`set_if_context` 削除**(P1, 11行)- 最優先、最も安全
|
||||
2. **If Lowering dev フラグ削除**(P1, 15行)- デフォルト有効化
|
||||
3. **A/B テスト観察関数削除**(P2, 50行)- 最も削減効果が高い
|
||||
|
||||
---
|
||||
|
||||
## Phase 61-6 実装計画
|
||||
|
||||
### Wave 1: P1 薄いラッパー削除(26行削減)
|
||||
1. `set_if_context` 削除
|
||||
- `loop_builder/if_lowering.rs:259-262` で直接 `IfPhiContext::for_loop_body()` 呼び出しに置き換え
|
||||
- リスク: 低
|
||||
2. If Lowering dev フラグ削除
|
||||
- `joinir_if_select_enabled()` チェック削除、デフォルト有効化
|
||||
- リスク: 中(全テスト PASS 必須)
|
||||
|
||||
### Wave 2: P2 A/B テスト削除(50行削減)
|
||||
1. `extract_phi_spec_from_builder`, `compare_and_log_phi_specs` 削除
|
||||
- if_lowering.rs の A/B 比較ロジック削除
|
||||
- if_phi_spec.rs は `compute_phi_spec_from_joinir()` のみ残す
|
||||
- リスク: 低(観察専用関数)
|
||||
|
||||
### 期待削減効果
|
||||
- **合計**: 76行削減
|
||||
- **JoinIR SSOT**: PhiBuilderBox 経路の観察コード完全削除
|
||||
- **カバー率**: If-in-Loop PHI 100% JoinIR 化完了
|
||||
|
||||
---
|
||||
|
||||
## 保留候補(Phase 61-7+ で検討)
|
||||
|
||||
### P2 大型統合(145行削減見込み)
|
||||
1. `compute_modified_names_if`: 変更変数検出を JoinIR に統合(~75行)
|
||||
2. `get_conservative_if_values`: incoming 値解決を PhiSpec に移行(~70行)
|
||||
|
||||
### 保留理由
|
||||
- Phase 61-6 では最小限の削除に集中(リスク最小化)
|
||||
- P2 大型統合は Phase 61-7 で慎重に実装
|
||||
|
||||
---
|
||||
|
||||
## 技術的成果
|
||||
|
||||
### 1. If PHI 関数の完全インベントリ作成
|
||||
- 26関数の全体像を把握
|
||||
- 責務とカバレッジを明確化
|
||||
- 削減優先度を定量的に決定
|
||||
|
||||
### 2. JoinIR カバレッジ 100% 達成確認
|
||||
- If-in-Loop PHI は JoinIR で完全カバー
|
||||
- PhiBuilderBox 経路は観察用のみ
|
||||
- SSOT を JoinIR 側に完全移行済み
|
||||
|
||||
### 3. 段階的削減計画の確立
|
||||
- P1(薄いラッパー)→ P2(統合)→ P3(型システム)の 3 段階
|
||||
- Wave 1(26行)→ Wave 2(50行)→ Phase 61-7(145行)の段階的実装
|
||||
- リスク最小化と削減効果のバランス
|
||||
|
||||
---
|
||||
|
||||
## 実装時の原則
|
||||
|
||||
1. **Fail-Fast**: エラーは即座に失敗、フォールバック禁止
|
||||
2. **決定的順序**: BTreeSet/BTreeMap で ValueId 割り当ての決定性保証
|
||||
3. **箱理論**: SSOT を JoinIR 側に寄せる、PhiBuilderBox は最小限に
|
||||
4. **テスト**: 各ステップで全 JoinIR tests PASS を確認(268 tests)
|
||||
5. **ドキュメント**: PHI_BOX_INVENTORY.md と CURRENT_TASK.md を更新
|
||||
|
||||
---
|
||||
|
||||
## 関連ドキュメント
|
||||
|
||||
### Phase 61-5 成果物
|
||||
- [phase61-5-1-if-phi-function-list.md](phase61-5-1-if-phi-function-list.md)
|
||||
- [phase61-5-2-if-phi-coverage-table.md](phase61-5-2-if-phi-coverage-table.md)
|
||||
- [phase61-5-3-if-phi-priority-table.md](phase61-5-3-if-phi-priority-table.md)
|
||||
- [phase61-5.4-next-phase-candidates.md](phase61-5.4-next-phase-candidates.md)
|
||||
|
||||
### 関連 Phase
|
||||
- Phase 61-1: [if_phi_context.rs](../../../src/mir/join_ir/lowering/if_phi_context.rs) - If PHI Context 設計
|
||||
- Phase 61-2: [if_phi_spec.rs](../../../src/mir/join_ir/lowering/if_phi_spec.rs) - PHI Spec 抽象化
|
||||
- Phase 61-3: [if_in_loop/mod.rs](../../../src/mir/join_ir/frontend/ast_lowerer/if_in_loop/mod.rs) - If-in-Loop PHI Emitter
|
||||
- Phase 61-4: [phase61-4-toplevel-if-design.md](phase61-4-toplevel-if-design.md) - Toplevel If PHI 設計
|
||||
- PHI Inventory: [PHI_BOX_INVENTORY.md](../../../docs/private/roadmap2/phases/phase-30-final-joinir-world/PHI_BOX_INVENTORY.md)
|
||||
|
||||
---
|
||||
|
||||
## 次のステップ
|
||||
|
||||
### 即座に実装可能(Phase 61-6)
|
||||
1. `set_if_context` 削除(11行、リスク低)
|
||||
2. If Lowering dev フラグ削除(15行、リスク中)
|
||||
3. A/B テスト観察関数削除(50行、リスク低)
|
||||
|
||||
### 合計削減見込み: 76行
|
||||
### 期待成果: JoinIR SSOT 確立、PhiBuilderBox 観察コード完全削除
|
||||
@ -1,113 +0,0 @@
|
||||
# Phase 61-5.4: 次フェーズ候補選定(2〜3個)
|
||||
|
||||
## 目的
|
||||
Phase 61-5.3 の優先度表から、Phase 61-6(If PHI JoinIR 化 第2弾)で触る候補を 2〜3 個だけ選定する。
|
||||
|
||||
## 選定基準
|
||||
|
||||
### P1 候補(薄いラッパー削除)
|
||||
- コード量が少ない(50行以下)
|
||||
- 依存関係が少ない
|
||||
- 削除による影響範囲が明確
|
||||
- テストが既存のもので十分
|
||||
|
||||
### P2 候補(JoinIR 拡張)
|
||||
- PhiSpec や IfMerge との 1:1 対応が明確
|
||||
- 既存の JoinIR 構造に自然に統合できる
|
||||
- 削減効果が高い(100行以上)
|
||||
|
||||
---
|
||||
|
||||
## Phase 61-6 削減候補(2〜3個)
|
||||
|
||||
### Phase 61-6.1: P1 薄いラッパー削除
|
||||
|
||||
#### 1. **`set_if_context` 削除**
|
||||
- **ファイル**: `src/mir/phi_core/phi_builder_box.rs:143-152`
|
||||
- **削減見込み**: 10行(関数本体)+ 呼び出し側1行 = **11行**
|
||||
- **実装方針**: `loop_builder/if_lowering.rs:259-262` で直接 `IfPhiContext::for_loop_body(true, carrier_names.clone())` を生成してフィールドに代入
|
||||
- **リスク**: **低** - 単純なラッパー削除、既存ロジックに影響なし
|
||||
- **備考**: 現在は `set_if_context()` → `IfPhiContext { in_loop_body, loop_carrier_names }` 構造体生成のみ
|
||||
|
||||
#### 2. **If Lowering ルーティング関数のデフォルト有効化**
|
||||
- **ファイル**: `src/mir/join_ir/lowering/mod.rs:132-141`
|
||||
- **削減見込み**: dev フラグチェック削除 8行 + 環境変数関数削除 = **15行**
|
||||
- **実装方針**: `joinir_if_select_enabled()` チェックを削除、デフォルトで有効化
|
||||
- **リスク**: **中** - 全関数でデフォルト有効化されるため、テスト全通過が必須
|
||||
- **備考**: 現在は `NYASH_JOINIR_IF_SELECT=1` で制御、Phase 33-8 で導入済み
|
||||
|
||||
---
|
||||
|
||||
### Phase 61-6.2: P2 JoinIR 拡張
|
||||
|
||||
#### 3. **A/B テスト観察用関数の削除**
|
||||
- **関数**: `extract_phi_spec_from_builder`, `compare_and_log_phi_specs`
|
||||
- **ファイル**: `src/mir/join_ir/lowering/if_phi_spec.rs:97-140`
|
||||
- **削減見込み**: 2関数 + テスト削除 = **50行**
|
||||
- **実装方針**:
|
||||
1. Phase 61-3 で JoinIR 経路が完全動作確認済み
|
||||
2. `if_lowering.rs:273-290` の A/B 比較ロジック削除
|
||||
3. `extract_phi_spec_from_builder()` と `compare_and_log_phi_specs()` 削除
|
||||
4. if_phi_spec.rs は `compute_phi_spec_from_joinir()` のみ残す
|
||||
- **リスク**: **低** - 観察専用関数、実行経路に影響なし
|
||||
- **備考**: Phase 61-2 で導入、Phase 61-3 で検証完了済み
|
||||
|
||||
---
|
||||
|
||||
## 期待される効果
|
||||
|
||||
| Wave | 削減対象 | 見込み削減行数 | 累積削減 |
|
||||
|------|---------|--------------|---------|
|
||||
| 61-6.1 | P1 薄いラッパー削除 (set_if_context) | 11 | 11 |
|
||||
| 61-6.1 | P1 dev フラグ削除 | 15 | 26 |
|
||||
| 61-6.2 | P2 A/B テスト削除 | 50 | **76** |
|
||||
|
||||
### JoinIR カバー率
|
||||
- **現在**: If-in-Loop PHI 生成は JoinIR で 100% カバー(Phase 61-3 完了)
|
||||
- **61-6 後**: PhiBuilderBox 経路の観察コード削除、JoinIR SSOT 確立
|
||||
|
||||
---
|
||||
|
||||
## 実装順序
|
||||
|
||||
### Wave 1: P1 削除(Phase 61-6.1)
|
||||
1. **`set_if_context` 削除** - 最優先(最も安全)
|
||||
2. **dev フラグ削除** - 全テストPASS確認後
|
||||
|
||||
### Wave 2: P2 削除(Phase 61-6.2)
|
||||
1. **A/B テスト観察関数削除** - 最も削減効果が高い
|
||||
|
||||
### 各 Wave の完了条件
|
||||
- Wave 1: 全 JoinIR tests PASS(268 tests)
|
||||
- Wave 2: if_phi_spec.rs が `compute_phi_spec_from_joinir()` のみに(観察コード完全削除)
|
||||
|
||||
---
|
||||
|
||||
## 実装時の注意事項
|
||||
|
||||
1. **Fail-Fast原則**: エラーは即座に失敗、フォールバック禁止
|
||||
2. **決定的順序**: BTreeSet/BTreeMap で ValueId 割り当ての決定性保証
|
||||
3. **箱理論**: SSOT を JoinIR 側に寄せる、PhiBuilderBox は最小限に
|
||||
4. **テスト**: 各ステップで全 JoinIR tests PASS を確認
|
||||
5. **ドキュメント**: PHI_BOX_INVENTORY.md と CURRENT_TASK.md を更新
|
||||
|
||||
---
|
||||
|
||||
## 保留候補(Phase 61-7+ で検討)
|
||||
|
||||
### P2 候補(Phase 61-7 で検討)
|
||||
1. **`compute_modified_names_if`** - 変更変数検出を JoinIR の modified 変数集合解析に統合(~75行削減)
|
||||
2. **`get_conservative_if_values`** - incoming 値解決を PhiSpec に移行、void fallback 削除(~70行削減)
|
||||
|
||||
### 保留理由
|
||||
- Phase 61-6 では最小限の削除に集中(76行削減)
|
||||
- P2 大型統合は Phase 61-7 で慎重に実装(145行削減見込み)
|
||||
|
||||
---
|
||||
|
||||
## 関連ドキュメント
|
||||
|
||||
- Phase 61-5.3: [if-phi-priority-table.md](phase61-5-3-if-phi-priority-table.md)
|
||||
- PHI Inventory: [PHI_BOX_INVENTORY.md](../../../docs/private/roadmap2/phases/phase-30-final-joinir-world/PHI_BOX_INVENTORY.md)
|
||||
- If PHI Context: [if_phi_context.rs](../../../src/mir/join_ir/lowering/if_phi_context.rs)
|
||||
- If PHI Spec: [if_phi_spec.rs](../../../src/mir/join_ir/lowering/if_phi_spec.rs)
|
||||
@ -1,434 +0,0 @@
|
||||
# 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 制御フロー PHI(7件)
|
||||
|
||||
**共通特徴**:
|
||||
- `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 型推論(優先度: 高)
|
||||
|
||||
**対象**: GroupA(7件)
|
||||
|
||||
**アルゴリズム**:
|
||||
```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(¤t) {
|
||||
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 型推論(優先度: 中)
|
||||
|
||||
**対象**: GroupB(2件)
|
||||
|
||||
**問題**:
|
||||
```
|
||||
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 型推論特殊処理(優先度: 低)
|
||||
|
||||
**対象**: GroupC(1件)
|
||||
|
||||
**短期対応**:
|
||||
```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 制御フロー PHI(7件)→ Edge Copy 追跡で解決可能
|
||||
- **GroupB**: 多段 PHI(2件)→ 再帰的型推論で解決可能
|
||||
- **GroupC**: await 特殊(1件)→ 暫定対応で解決可能
|
||||
|
||||
Phase 84-3/4/5 の実装により、**Case D を完全解決** できる見込み。
|
||||
@ -1,390 +0,0 @@
|
||||
# Phase 84-2: Case D 失敗パターン詳細
|
||||
|
||||
## GroupA: Loop 制御フロー PHI(7件)
|
||||
|
||||
### パターン A-1: continue + break
|
||||
|
||||
**テスト**: `loop_with_continue_and_break_edge_copy_merge`
|
||||
**ValueId**: 56
|
||||
|
||||
**コード構造**:
|
||||
```hako
|
||||
i = 0
|
||||
sum = 0
|
||||
loop(i < 5) {
|
||||
i = i + 1
|
||||
if (i == 3) { break } // ← break 経路
|
||||
if (i % 2 == 0) { continue } // ← continue 経路
|
||||
sum = sum + i // ← normal 経路
|
||||
}
|
||||
return sum // ← ValueId(56) の型が未解決
|
||||
```
|
||||
|
||||
**MIR 構造(推測)**:
|
||||
```
|
||||
Block_LoopHeader:
|
||||
%sum_phi = PHI [%sum_init, %sum_continue, %sum_normal]
|
||||
%i_phi = PHI [%i_init, %i_continue, %i_normal]
|
||||
...
|
||||
|
||||
Block_Break:
|
||||
%sum_break = Copy %sum_phi ← value_types に型登録済み
|
||||
Jump after_loop
|
||||
|
||||
Block_Continue:
|
||||
%sum_continue = Copy %sum_phi ← value_types に型登録済み
|
||||
Jump loop_header
|
||||
|
||||
Block_Normal:
|
||||
%sum_normal = BinOp Add %sum_phi %i_phi
|
||||
Jump loop_header
|
||||
|
||||
Block_AfterLoop:
|
||||
%56 = PHI [%sum_break] ← incoming の型が未登録!
|
||||
Return %56
|
||||
```
|
||||
|
||||
**問題の本質**:
|
||||
- PHI(56) の incoming 値は `%sum_break`
|
||||
- `%sum_break` は Copy の dst で、value_types に未登録
|
||||
- Copy の src `%sum_phi` は型登録済みだが、GenericTypeResolver は追跡しない
|
||||
|
||||
**解決策**:
|
||||
```rust
|
||||
// GenericTypeResolver::resolve_from_phi_with_copy_trace()
|
||||
for (_, incoming_val) in phi_inputs {
|
||||
// Copy を遡る
|
||||
if let Some(src) = find_copy_src(function, incoming_val) {
|
||||
if let Some(ty) = types.get(&src) {
|
||||
return Some(ty.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### パターン A-2: 多段 continue/break
|
||||
|
||||
**テスト**: `nested_loop_with_multi_continue_break_edge_copy_merge`
|
||||
**ValueId**: 135
|
||||
|
||||
**コード構造**:
|
||||
```hako
|
||||
i = 0
|
||||
sum = 0
|
||||
loop(i < 10) {
|
||||
i = i + 1
|
||||
if (i == 2 || i == 4) { continue } // ← continue 経路1
|
||||
if (i == 7) {
|
||||
if (1 == 1) { break } // ← break 経路(ネスト)
|
||||
}
|
||||
if ((i % 3) == 0) { continue } // ← continue 経路2
|
||||
sum = sum + i // ← normal 経路
|
||||
}
|
||||
return sum // ← ValueId(135)
|
||||
```
|
||||
|
||||
**特徴**:
|
||||
- 複数の continue 経路
|
||||
- ネストした if 内の break
|
||||
- PHI の incoming 値が多い(4-5個)
|
||||
|
||||
### パターン A-3: Loop + 多段 if
|
||||
|
||||
**テスト**: `loop_inner_if_multilevel_edge_copy`
|
||||
**ValueId**: 74
|
||||
|
||||
**コード構造**:
|
||||
```hako
|
||||
j = 0
|
||||
acc = 0
|
||||
loop(j < 6) {
|
||||
j = j + 1
|
||||
if (j < 3) {
|
||||
if (j % 2 == 0) { continue } // ← 2段 if + continue
|
||||
acc = acc + 10
|
||||
} else {
|
||||
if (j == 5) { break } // ← 2段 if + break
|
||||
acc = acc + 1
|
||||
}
|
||||
}
|
||||
return acc // ← ValueId(74)
|
||||
```
|
||||
|
||||
**特徴**:
|
||||
- then/else の両方に制御フロー
|
||||
- 多段ネスト if
|
||||
- 変数更新が複数経路に分散
|
||||
|
||||
### パターン A-4: Loop + early return
|
||||
|
||||
**テスト**: `loop_break_and_early_return_edge_copy`
|
||||
**ValueId**: 40
|
||||
|
||||
**コード構造**:
|
||||
```hako
|
||||
i = 0
|
||||
acc = 0
|
||||
loop(i < 6) {
|
||||
i = i + 1
|
||||
if (i == 5) { break } // ← break 経路
|
||||
if (i == 3) { return acc } // ← early return 経路
|
||||
acc = acc + i
|
||||
}
|
||||
return acc // ← ValueId(40)
|
||||
```
|
||||
|
||||
**特徴**:
|
||||
- break と early return の混在
|
||||
- 関数終了が複数経路
|
||||
- return 型推論が複雑
|
||||
|
||||
### パターン A-5: 単純 if-break
|
||||
|
||||
**テスト**: `vm_exec_break_inside_if`
|
||||
**ValueId**: 27
|
||||
|
||||
**コード構造**:
|
||||
```hako
|
||||
local i = 0
|
||||
loop(i < 10) {
|
||||
if (i == 3) { break } // ← if 内 break
|
||||
i = i + 1
|
||||
}
|
||||
return i // ← ValueId(27)
|
||||
```
|
||||
|
||||
**特徴**:
|
||||
- 最もシンプルな if-break パターン
|
||||
- これが解決できればベースケース成功
|
||||
|
||||
### パターン A-6: 3段ネスト if
|
||||
|
||||
**テスト**: `loop_if_three_level_merge_edge_copy`
|
||||
**ValueId**: 75
|
||||
|
||||
**コード構造**:
|
||||
```hako
|
||||
x = 0
|
||||
i = 0
|
||||
loop(i < 7) {
|
||||
i = i + 1
|
||||
if (i % 2 == 0) {
|
||||
if (i == 4) { continue } // ← 3段目 continue
|
||||
x = x + 2
|
||||
} else {
|
||||
if (i == 5) { break } // ← 3段目 break
|
||||
x = x + 1
|
||||
}
|
||||
}
|
||||
return x // ← ValueId(75)
|
||||
```
|
||||
|
||||
**特徴**:
|
||||
- 3段ネスト制御フロー
|
||||
- then/else の両方に制御フロー
|
||||
- 変数更新の分岐が複雑
|
||||
|
||||
## GroupB: 多段 PHI 型推論(2件)
|
||||
|
||||
### パターン B-1: static box + 複数 return
|
||||
|
||||
**テスト**: `mir_stage1_cli_emit_program_min_*`
|
||||
**ValueId**: 7
|
||||
|
||||
**コード構造**:
|
||||
```hako
|
||||
static box Stage1Cli {
|
||||
emit_program_json(source) {
|
||||
if source == null || source == "" { return null } // ← return 経路1
|
||||
return "{prog:" + source + "}" // ← return 経路2
|
||||
}
|
||||
|
||||
stage1_main(args) {
|
||||
if args == null { args = new ArrayBox() }
|
||||
local src = env.get("STAGE1_SOURCE")
|
||||
if src == null || src == "" { return 96 } // ← return 経路3
|
||||
|
||||
local prog = me.emit_program_json(src)
|
||||
if prog == null { return 96 } // ← return 経路4
|
||||
print(prog)
|
||||
return 0 // ← return 経路5
|
||||
}
|
||||
}
|
||||
|
||||
static box Main {
|
||||
main(args) {
|
||||
env.set("STAGE1_SOURCE", "apps/tests/stage1_using_minimal.hako")
|
||||
return Stage1Cli.stage1_main(args) // ← ValueId(7)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**MIR 構造(推測)**:
|
||||
```
|
||||
Function: Stage1Cli.emit_program_json
|
||||
Block1:
|
||||
%1 = PHI [null, string_concat_result]
|
||||
Return %1
|
||||
|
||||
Function: Stage1Cli.stage1_main
|
||||
Block1:
|
||||
%2 = Call Stage1Cli.emit_program_json
|
||||
Block2:
|
||||
%3 = PHI [%2, const_96, const_0]
|
||||
Return %3
|
||||
|
||||
Function: Main.main
|
||||
Block1:
|
||||
%4 = Call Stage1Cli.stage1_main
|
||||
Block2:
|
||||
%7 = PHI [%4] ← %4 の型が未解決(多段 PHI)
|
||||
Return %7
|
||||
```
|
||||
|
||||
**問題の本質**:
|
||||
- PHI(7) の incoming 値は PHI(3) の結果
|
||||
- PHI(3) の incoming 値は PHI(1) の結果
|
||||
- **3段 PHI チェーン** が発生
|
||||
|
||||
**解決策**:
|
||||
```rust
|
||||
// GenericTypeResolver::resolve_from_phi_recursive()
|
||||
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);
|
||||
|
||||
// PHI の incoming 値を再帰的に解決
|
||||
for (_, incoming_val) in phi_inputs {
|
||||
if let Some(ty) = resolve_from_phi_recursive(
|
||||
function, *incoming_val, types, visited
|
||||
) {
|
||||
return Some(ty);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
```
|
||||
|
||||
## GroupC: await 特殊パターン(1件)
|
||||
|
||||
### パターン C-1: await 式
|
||||
|
||||
**テスト**: `test_lowering_await_expression`
|
||||
**ValueId**: 2
|
||||
|
||||
**コード構造**:
|
||||
```rust
|
||||
// Rust AST 生成
|
||||
let ast = ASTNode::AwaitExpression {
|
||||
expression: Box::new(ASTNode::Literal {
|
||||
value: LiteralValue::Integer(1),
|
||||
span: crate::ast::Span::unknown(),
|
||||
}),
|
||||
span: crate::ast::Span::unknown(),
|
||||
};
|
||||
```
|
||||
|
||||
**MIR 構造(推測)**:
|
||||
```
|
||||
Block1:
|
||||
%1 = Const Integer(1)
|
||||
%2 = Await %1 ← await 命令の戻り値
|
||||
Return %2
|
||||
```
|
||||
|
||||
**問題の本質**:
|
||||
- await 式の型推論が未実装
|
||||
- 非同期システム(Safepoint/Checkpoint)が Phase 67+ 実装予定
|
||||
- 現在は MIR13 migration pending
|
||||
|
||||
**暫定対応**:
|
||||
```rust
|
||||
// lifecycle.rs に特殊ケース追加
|
||||
if is_await_expression {
|
||||
// await の戻り値型は Unknown で許容
|
||||
return MirType::Unknown;
|
||||
}
|
||||
```
|
||||
|
||||
**長期対応(Phase 67+)**:
|
||||
- async/await システム完全実装
|
||||
- type_hint による await 型推論
|
||||
- Safepoint/Checkpoint 命令統合
|
||||
|
||||
## 解決優先度
|
||||
|
||||
### 優先度1: GroupA(7件)
|
||||
|
||||
**理由**:
|
||||
- 最も頻出するパターン
|
||||
- Loop 制御フローは実用コードで必須
|
||||
- Edge Copy 追跡で一気に解決可能
|
||||
|
||||
**期待効果**: 9件 → 2件(78%削減)
|
||||
|
||||
### 優先度2: GroupB(2件)
|
||||
|
||||
**理由**:
|
||||
- static box は Stage1Cli で使用中
|
||||
- 多段メソッド呼び出しも実用的
|
||||
- 再帰的 PHI 推論で解決可能
|
||||
|
||||
**期待効果**: 2件 → 1件(50%削減)
|
||||
|
||||
### 優先度3: GroupC(1件)
|
||||
|
||||
**理由**:
|
||||
- await は実験的機能
|
||||
- 本格実装は Phase 67+ 予定
|
||||
- 暫定対応で十分
|
||||
|
||||
**期待効果**: 1件 → 0件(100%削減)
|
||||
|
||||
## 実装チェックリスト
|
||||
|
||||
### Phase 84-3: Edge Copy 追跡
|
||||
|
||||
- [ ] `GenericTypeResolver::resolve_from_phi_with_copy_trace()` 実装
|
||||
- [ ] `find_copy_src()` ヘルパー関数実装
|
||||
- [ ] `trace_copy_chain()` ヘルパー関数実装
|
||||
- [ ] lifecycle.rs 統合
|
||||
- [ ] テスト実行: GroupA の 7件を確認
|
||||
|
||||
### Phase 84-4: 多段 PHI 推論
|
||||
|
||||
- [ ] `GenericTypeResolver::resolve_from_phi_recursive()` 実装
|
||||
- [ ] 循環検出ロジック実装
|
||||
- [ ] lifecycle.rs 統合
|
||||
- [ ] テスト実行: GroupB の 2件を確認
|
||||
|
||||
### Phase 84-5: await 暫定対応
|
||||
|
||||
- [ ] lifecycle.rs に await 特殊ケース追加
|
||||
- [ ] テスト実行: GroupC の 1件を確認
|
||||
|
||||
## 完了確認
|
||||
|
||||
```bash
|
||||
# Phase 84-3 完了
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 期待: 2
|
||||
|
||||
# Phase 84-4 完了
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 期待: 1
|
||||
|
||||
# Phase 84-5 完了
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D"
|
||||
# 期待: 出力なし(0件)
|
||||
|
||||
# 最終確認
|
||||
cargo test --release --lib
|
||||
# 期待: test result: ok
|
||||
```
|
||||
@ -1,211 +0,0 @@
|
||||
# Phase 84-2: CopyTypePropagator 実装完了サマリー
|
||||
|
||||
## 成果
|
||||
|
||||
### 削減結果
|
||||
|
||||
```
|
||||
Before Phase 84-2: 12件の Case D 失敗
|
||||
After Phase 84-2: 9件の Case D 失敗
|
||||
|
||||
削減数: 3件 (25%削減)
|
||||
```
|
||||
|
||||
### 実装内容
|
||||
|
||||
**新規作成ファイル**:
|
||||
- `src/mir/phi_core/copy_type_propagator.rs` (125行)
|
||||
|
||||
**主要機能**:
|
||||
```rust
|
||||
pub struct CopyTypePropagator;
|
||||
|
||||
impl CopyTypePropagator {
|
||||
pub fn propagate(
|
||||
function: &MirFunction,
|
||||
types: &mut BTreeMap<ValueId, MirType>,
|
||||
) {
|
||||
// Copy 命令を走査して型を伝播
|
||||
for inst in all_copy_instructions(function) {
|
||||
if let Some(src_type) = types.get(&src) {
|
||||
types.insert(dst, src_type.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**統合箇所**:
|
||||
- `src/mir/builder/lifecycle.rs:371` - infer_type_from_phi() の直前に呼び出し
|
||||
|
||||
## 残り 9件の分類
|
||||
|
||||
### GroupA: Loop 制御フロー PHI(7件)
|
||||
|
||||
**パターン**: Loop + continue/break による Edge Copy 合流
|
||||
|
||||
**典型的なコード**:
|
||||
```hako
|
||||
i = 0
|
||||
sum = 0
|
||||
loop(i < 5) {
|
||||
i = i + 1
|
||||
if (i == 3) { break } // → edge copy
|
||||
if (i % 2 == 0) { continue } // → edge copy
|
||||
sum = sum + i
|
||||
}
|
||||
return sum // ← PHI の型が未解決
|
||||
```
|
||||
|
||||
**問題**: PHI の incoming 値が Edge Copy の dst で、src の型を遡れない
|
||||
|
||||
**テスト一覧**:
|
||||
1. `loop_with_continue_and_break_edge_copy_merge` - ValueId(56)
|
||||
2. `nested_loop_with_multi_continue_break_edge_copy_merge` - ValueId(135)
|
||||
3. `loop_inner_if_multilevel_edge_copy` - ValueId(74)
|
||||
4. `loop_break_and_early_return_edge_copy` - ValueId(40)
|
||||
5. `vm_exec_break_inside_if` - ValueId(27)
|
||||
6. `loop_if_three_level_merge_edge_copy` - ValueId(75)
|
||||
7. (GroupA 合計 7件)
|
||||
|
||||
### GroupB: 多段 PHI 型推論(2件)
|
||||
|
||||
**パターン**: 複数の PHI 命令が連鎖
|
||||
|
||||
**典型的なコード**:
|
||||
```hako
|
||||
static box Stage1Cli {
|
||||
stage1_main(args) {
|
||||
if cond1 { return 96 }
|
||||
if cond2 { return 96 }
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
static box Main {
|
||||
main(args) {
|
||||
return Stage1Cli.stage1_main(args) // ← 多段 PHI
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**問題**: PHI の incoming 値が別の PHI で、再帰的に解決できない
|
||||
|
||||
**テスト一覧**:
|
||||
1. `mir_stage1_cli_emit_program_min_exec_hits_type_error` - ValueId(7)
|
||||
2. `mir_stage1_cli_emit_program_min_compiles_and_verifies` - ValueId(7)
|
||||
|
||||
### GroupC: await 特殊パターン(1件)
|
||||
|
||||
**パターン**: await 式の MIR lowering
|
||||
|
||||
**コード**:
|
||||
```rust
|
||||
let ast = ASTNode::AwaitExpression {
|
||||
expression: Box::new(ASTNode::Literal {
|
||||
value: LiteralValue::Integer(1),
|
||||
...
|
||||
}),
|
||||
...
|
||||
};
|
||||
```
|
||||
|
||||
**問題**: await の型推論が未実装(非同期システム未完成)
|
||||
|
||||
**テスト**:
|
||||
1. `test_lowering_await_expression` - ValueId(2)
|
||||
|
||||
## Phase 84-3 実装推奨
|
||||
|
||||
### 目標: GroupA の 7件を解決
|
||||
|
||||
**新機能**: Edge Copy 追跡 PHI 型推論
|
||||
|
||||
**実装方針**:
|
||||
```rust
|
||||
// GenericTypeResolver に追加
|
||||
pub fn resolve_from_phi_with_copy_trace(
|
||||
function: &MirFunction,
|
||||
ret_val: ValueId,
|
||||
types: &BTreeMap<ValueId, MirType>,
|
||||
) -> Option<MirType> {
|
||||
// PHI の incoming 値から Copy を遡る
|
||||
for (_, incoming_val) in phi_inputs {
|
||||
// 1. 直接型取得を試みる
|
||||
if let Some(ty) = types.get(incoming_val) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2. Copy 命令を遡る
|
||||
if let Some(src) = find_copy_src(function, incoming_val) {
|
||||
if let Some(ty) = types.get(&src) {
|
||||
// src の型を使用
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 多段 Copy を再帰的に追跡
|
||||
if let Some(ty) = trace_copy_chain(function, incoming_val, types) {
|
||||
// チェーンを遡った型を使用
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**期待効果**:
|
||||
- 9件 → 2件に削減(GroupB + GroupC のみ残存)
|
||||
- Loop 制御フローの型推論が完全動作
|
||||
|
||||
### 実装ファイル
|
||||
|
||||
- `src/mir/join_ir/lowering/generic_type_resolver.rs` - 新関数追加
|
||||
- `src/mir/builder/lifecycle.rs` - 新関数呼び出し統合
|
||||
|
||||
### テスト検証
|
||||
|
||||
```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/5 展望
|
||||
|
||||
### Phase 84-4: 多段 PHI 型推論
|
||||
|
||||
**目標**: GroupB の 2件を解決
|
||||
|
||||
**実装**: `resolve_from_phi_recursive()` で PHI チェーンを再帰的に追跡
|
||||
|
||||
### Phase 84-5: await 暫定対応
|
||||
|
||||
**目標**: GroupC の 1件を解決
|
||||
|
||||
**実装**: lifecycle.rs に await 特殊ケース追加(暫定)
|
||||
|
||||
## 完了条件
|
||||
|
||||
```bash
|
||||
# 全 Case D 解決
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D"
|
||||
# 期待: 出力なし(0件)
|
||||
|
||||
# 最終確認
|
||||
cargo test --release --lib
|
||||
# 期待: test result: ok
|
||||
```
|
||||
|
||||
## タイムライン
|
||||
|
||||
- **Phase 84-2**: 完了 ✅ (12件 → 9件)
|
||||
- **Phase 84-3**: 推定 1-2日 (9件 → 2件)
|
||||
- **Phase 84-4**: 推定 1-2日 (2件 → 1件)
|
||||
- **Phase 84-5**: 推定 30分 (1件 → 0件)
|
||||
|
||||
**合計**: 2-4日で Case D 完全解決見込み
|
||||
|
||||
## 参考資料
|
||||
|
||||
- [Phase 84-2 詳細調査](./phase84-2-case-d-investigation.md)
|
||||
- [CopyTypePropagator 実装](../../../src/mir/phi_core/copy_type_propagator.rs)
|
||||
- [GenericTypeResolver](../../../src/mir/join_ir/lowering/generic_type_resolver.rs)
|
||||
- [lifecycle.rs 統合箇所](../../../src/mir/builder/lifecycle.rs:371)
|
||||
@ -1,120 +0,0 @@
|
||||
# Phase 84-2: Case D 残り 9件クイックリファレンス
|
||||
|
||||
## 一覧表
|
||||
|
||||
| # | Group | テスト名 | ValueId | ファイル | 行番号 |
|
||||
|---|-------|---------|---------|---------|-------|
|
||||
| 1 | C | `test_lowering_await_expression` | 2 | `src/mir/mod.rs` | 363 |
|
||||
| 2 | A | `loop_with_continue_and_break_edge_copy_merge` | 56 | `src/tests/loop_continue_break_no_phi_tests.rs` | 21 |
|
||||
| 3 | A | `nested_loop_with_multi_continue_break_edge_copy_merge` | 135 | `src/tests/loop_nested_no_phi_tests.rs` | 21 |
|
||||
| 4 | A | `loop_inner_if_multilevel_edge_copy` | 74 | `src/tests/loop_nested_no_phi_tests.rs` | 224 |
|
||||
| 5 | A | `loop_break_and_early_return_edge_copy` | 40 | `src/tests/loop_return_no_phi_tests.rs` | 22 |
|
||||
| 6 | A | `vm_exec_break_inside_if` | 27 | `src/tests/mir_ctrlflow_break_continue.rs` | 47 |
|
||||
| 7 | A | `loop_if_three_level_merge_edge_copy` | 75 | `src/tests/loop_return_no_phi_tests.rs` | 194 |
|
||||
| 8 | B | `mir_stage1_cli_emit_program_min_exec_hits_type_error` | 7 | `src/tests/mir_stage1_cli_emit_program_min.rs` | 97 |
|
||||
| 9 | B | `mir_stage1_cli_emit_program_min_compiles_and_verifies` | 7 | `src/tests/mir_stage1_cli_emit_program_min.rs` | 71 |
|
||||
|
||||
## グループ詳細
|
||||
|
||||
### GroupA: Loop 制御フロー PHI(7件)
|
||||
|
||||
**共通パターン**: Loop + continue/break
|
||||
|
||||
**テスト実行**:
|
||||
```bash
|
||||
# 個別テスト
|
||||
cargo test --release --lib loop_with_continue_and_break_edge_copy_merge
|
||||
|
||||
# GroupA 全体
|
||||
cargo test --release --lib loop_continue_break
|
||||
cargo test --release --lib loop_nested
|
||||
cargo test --release --lib loop_return
|
||||
cargo test --release --lib vm_exec_break
|
||||
```
|
||||
|
||||
**期待される解決策**: Edge Copy 追跡 PHI 型推論
|
||||
|
||||
### GroupB: 多段 PHI 型推論(2件)
|
||||
|
||||
**共通パターン**: static box + 複数 return 経路
|
||||
|
||||
**テスト実行**:
|
||||
```bash
|
||||
# GroupB 全体
|
||||
cargo test --release --lib mir_stage1_cli_emit_program_min
|
||||
```
|
||||
|
||||
**期待される解決策**: 再帰的 PHI 型推論
|
||||
|
||||
### GroupC: await 特殊パターン(1件)
|
||||
|
||||
**パターン**: await 式の MIR lowering
|
||||
|
||||
**テスト実行**:
|
||||
```bash
|
||||
cargo test --release --lib test_lowering_await_expression
|
||||
```
|
||||
|
||||
**期待される解決策**: await 特殊ケース処理(暫定)
|
||||
|
||||
## 実行コマンド集
|
||||
|
||||
### 全 Case D 確認
|
||||
|
||||
```bash
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep -B5 "Case D"
|
||||
```
|
||||
|
||||
### ValueId 一覧取得
|
||||
|
||||
```bash
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "ValueId:" | sort | uniq
|
||||
```
|
||||
|
||||
### グループ別実行
|
||||
|
||||
```bash
|
||||
# GroupA のみ
|
||||
cargo test --release --lib loop_ mir_ctrlflow_break
|
||||
|
||||
# GroupB のみ
|
||||
cargo test --release --lib mir_stage1_cli
|
||||
|
||||
# GroupC のみ
|
||||
cargo test --release --lib test_lowering_await
|
||||
```
|
||||
|
||||
## デバッグ用環境変数
|
||||
|
||||
```bash
|
||||
# MIR ダンプ
|
||||
NYASH_DUMP_MIR=1 cargo test --release --lib <test_name>
|
||||
|
||||
# 詳細ログ
|
||||
RUST_LOG=debug cargo test --release --lib <test_name>
|
||||
|
||||
# バックトレース
|
||||
RUST_BACKTRACE=1 cargo test --release --lib <test_name>
|
||||
```
|
||||
|
||||
## 次のステップ
|
||||
|
||||
1. **Phase 84-3**: GroupA の 7件を解決
|
||||
- `GenericTypeResolver::resolve_from_phi_with_copy_trace()` 実装
|
||||
- Edge Copy 追跡ロジック追加
|
||||
- 期待: 9件 → 2件
|
||||
|
||||
2. **Phase 84-4**: GroupB の 2件を解決
|
||||
- `GenericTypeResolver::resolve_from_phi_recursive()` 実装
|
||||
- 再帰的 PHI 型推論
|
||||
- 期待: 2件 → 1件
|
||||
|
||||
3. **Phase 84-5**: GroupC の 1件を解決
|
||||
- await 特殊ケース追加
|
||||
- 期待: 1件 → 0件
|
||||
|
||||
## 参考資料
|
||||
|
||||
- [詳細調査](./phase84-2-case-d-investigation.md)
|
||||
- [サマリー](./phase84-2-summary.md)
|
||||
- [CopyTypePropagator 実装](../../../src/mir/phi_core/copy_type_propagator.rs)
|
||||
@ -1,297 +0,0 @@
|
||||
# Phase 84-3: PhiTypeResolver 実装完了報告書
|
||||
|
||||
**日付**: 2025-12-02
|
||||
**作業者**: Claude
|
||||
**レビュー者**: User (tomoaki)
|
||||
|
||||
## エグゼクティブサマリー
|
||||
|
||||
Phase 84-3 で PhiTypeResolver を実装した結果、**Case D を 9件 → 4件に削減**しました(**56%削減達成**)。
|
||||
|
||||
特に、Loop 制御フロー関連の複雑な PHI パターン(GroupA)を **5件完全解決**し、箱理論に基づく型推論システムの有効性を実証しました。
|
||||
|
||||
## 成果指標
|
||||
|
||||
| 指標 | 目標 | 実績 | 達成率 |
|
||||
|-----|------|------|--------|
|
||||
| Case D 削減件数 | 5件以上 | 5件 | 100% |
|
||||
| Case D 残存件数 | 5件以下 | 4件 | 120%(目標超過) |
|
||||
| 削減率 | 40%以上 | 56% | 140%(目標超過) |
|
||||
| GroupA 解決率 | 80%以上 | 100% | 125%(目標超過) |
|
||||
|
||||
## 削減詳細
|
||||
|
||||
### Phase 84-3 で解決された 5件
|
||||
|
||||
| # | テスト名 | ValueId | パターン | 検証結果 |
|
||||
|---|---------|---------|---------|---------|
|
||||
| 1 | `loop_with_continue_and_break_edge_copy_merge` | ValueId(56) | Loop + continue/break | ✅ 解決 |
|
||||
| 2 | `nested_loop_with_multi_continue_break_edge_copy_merge` | ValueId(135) | Nested loop | ✅ 解決 |
|
||||
| 3 | `loop_inner_if_multilevel_edge_copy` | ValueId(74) | Loop + 多段 if | ✅ 解決 |
|
||||
| 4 | `loop_break_and_early_return_edge_copy` | ValueId(40) | Loop + early return | ✅ 解決 |
|
||||
| 5 | `vm_exec_break_inside_if` | ValueId(27) | Loop + if-break | ✅ 解決確認済み |
|
||||
|
||||
**検証コマンド**:
|
||||
```bash
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib vm_exec_break_inside_if
|
||||
# 結果: test ... ok ✅
|
||||
```
|
||||
|
||||
### 残り 4件の分類
|
||||
|
||||
| # | テスト名 | ValueId | パターン | 解決方法 |
|
||||
|---|---------|---------|---------|---------|
|
||||
| 1 | `test_lowering_await_expression` | ValueId(2) | await 特殊構文 | Phase 84-4-C |
|
||||
| 2 | `mir_lowering_of_qmark_propagate` | ValueId(7) | QMark 特殊構文 | Phase 84-4-B |
|
||||
| 3 | `mir_stage1_cli_emit_program_min_compiles_and_verifies` | ValueId(7) | Stage1Cli 型推論 | Phase 84-4-B |
|
||||
| 4 | `mir_stage1_cli_emit_program_min_exec_hits_type_error` | ValueId(7) | Stage1Cli 型推論 | Phase 84-4-B |
|
||||
|
||||
## 技術的成果
|
||||
|
||||
### PhiTypeResolver の実装
|
||||
|
||||
**ファイル**: `src/mir/phi_core/phi_type_resolver.rs`(新規作成)
|
||||
|
||||
**責務**: PHI + Copy グラフを辿って、安全に型を決められるときだけ MirType を返す
|
||||
|
||||
**コア機能**:
|
||||
|
||||
```rust
|
||||
pub struct PhiTypeResolver<'f> {
|
||||
func: &'f MirFunction,
|
||||
value_types: &'f BTreeMap<ValueId, MirType>,
|
||||
}
|
||||
|
||||
impl<'f> PhiTypeResolver<'f> {
|
||||
pub fn resolve(&self, root: ValueId) -> Option<MirType> {
|
||||
// DFS でグラフ探索
|
||||
// Copy → src へ進む
|
||||
// Phi → incoming 値へ進む
|
||||
// base 定義 → value_types から型取得
|
||||
// 全ての base 型が一致すれば返す
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**安全装置**:
|
||||
- visited セットで循環検出(無限ループ防止)
|
||||
- 探索上限(max_visits)でタイムアウト防止
|
||||
- Unknown/Void の除外による型安全性確保
|
||||
|
||||
### 解決メカニズム
|
||||
|
||||
**GroupA(Loop 制御フロー)の典型的パターン**:
|
||||
|
||||
```
|
||||
Block1 (loop_header):
|
||||
%sum_header = PHI [%sum_init, %sum_loop, %sum_updated]
|
||||
|
||||
Block2 (break):
|
||||
%sum_final = Copy %sum_header ← value_types に IntegerBox 登録済み
|
||||
Jump after_loop
|
||||
|
||||
Block3 (continue):
|
||||
%sum_loop = Copy %sum_header ← value_types に IntegerBox 登録済み
|
||||
Jump loop_header
|
||||
|
||||
Block4 (after_loop):
|
||||
%56 = PHI [%sum_final] ← PhiTypeResolver で型推論成功!
|
||||
Return %56
|
||||
```
|
||||
|
||||
**PhiTypeResolver の探索経路**:
|
||||
```
|
||||
%56 (PHI) → %sum_final (Copy) → %sum_header (PHI) → %sum_init (Const/IntegerBox)
|
||||
→ %sum_loop (Copy) → ...
|
||||
→ %sum_updated (BinOp/IntegerBox)
|
||||
```
|
||||
|
||||
**結果**: 全ての base 型が IntegerBox → %56 の型は IntegerBox と推論成功
|
||||
|
||||
## 残存 4件の根本原因
|
||||
|
||||
**統一された問題**: 「base 定義(BoxCall/Await)の戻り値型が value_types に未登録」
|
||||
|
||||
### なぜ PhiTypeResolver で解決できないか
|
||||
|
||||
PhiTypeResolver の設計原則:
|
||||
- **責務**: 既に登録された型を「伝播」する
|
||||
- **制約**: base 定義の型が未登録の場合は None を返す(正しい動作)
|
||||
|
||||
BoxCall/Await 命令の問題:
|
||||
- lowering 時に戻り値型を value_types に登録していない
|
||||
- PhiTypeResolver が探索しても型情報が存在しない
|
||||
|
||||
**解決策**: BoxCall/Await の lowering 時に型情報を登録する(Phase 84-4)
|
||||
|
||||
## Phase 84-4 への推奨
|
||||
|
||||
### 実装優先度
|
||||
|
||||
1. **Phase 84-4-A**: dev フォールバック(0.5日)
|
||||
- 目的: 開発環境の即座のアンブロック
|
||||
- 環境変数: `NYASH_PHI_DEV_FALLBACK=1`
|
||||
- 対象: 全 4件(暫定)
|
||||
|
||||
2. **Phase 84-4-B**: BoxCall 型情報登録(1-2日)
|
||||
- 目的: 根本解決
|
||||
- 実装箇所: `src/mir/builder/builder_calls.rs`
|
||||
- 対象: 3件(GroupB 2件 + GroupD 1件)
|
||||
|
||||
3. **Phase 84-4-C**: Await 型情報特殊処理(0.5日)
|
||||
- 目的: 暫定解決
|
||||
- 実装箇所: `src/mir/builder/stmts.rs`
|
||||
- 対象: 1件(GroupC)
|
||||
|
||||
### 期待成果
|
||||
|
||||
```bash
|
||||
# Phase 84-4-A 完了後
|
||||
NYASH_PHI_DEV_FALLBACK=1 NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib
|
||||
# 期待: Case D = 0件(dev 環境のみ)
|
||||
|
||||
# Phase 84-4-B 完了後
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 期待: 1件(await のみ残存)
|
||||
|
||||
# Phase 84-4-C 完了後
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 期待: 0件(完全解決)
|
||||
```
|
||||
|
||||
## Phase 82-84 の累積成果
|
||||
|
||||
| Phase | 実装内容 | 削減件数 | 残存件数 | 削減率 | 累積削減率 |
|
||||
|-------|---------|---------|---------|--------|-----------|
|
||||
| Phase 82 | フォールバック検出 | - | 12件 | - | - |
|
||||
| Phase 84-2 | CopyTypePropagator | 3件 | 9件 | 25% | 25% |
|
||||
| **Phase 84-3** | **PhiTypeResolver** | **5件** | **4件** | **56%** | **67%** |
|
||||
| Phase 84-4(目標) | BoxCall/Await 型登録 | 4件 | 0件 | 100% | 100% |
|
||||
|
||||
## 箱理論の実現
|
||||
|
||||
Phase 84-3 により、型推論システムの箱化が明確化されました:
|
||||
|
||||
```
|
||||
[型生成レイヤー] - 型を作る
|
||||
├─ emit_const() ✅ 実装済み
|
||||
├─ emit_box_call() 🎯 Phase 84-4-B で型登録追加
|
||||
└─ build_await_expression() 🎯 Phase 84-4-C で型登録追加
|
||||
|
||||
[型伝播レイヤー] - 型を広げる
|
||||
├─ CopyTypePropagator ✅ Phase 84-2 実装済み
|
||||
└─ PhiTypeResolver ✅ Phase 84-3 実装済み
|
||||
|
||||
[統合レイヤー] - 全体を調整
|
||||
└─ GenericTypeResolver ✅ 既存実装
|
||||
|
||||
[レガシー] - 削除予定
|
||||
└─ if_phi.rs フォールバック 🗑️ Phase 84-5 で削除
|
||||
```
|
||||
|
||||
## リスクと軽減策
|
||||
|
||||
### リスク1: GroupD(QMark)が新規出現
|
||||
|
||||
**リスク**: PhiTypeResolver 実装の副作用で、以前は隠蔽されていた型推論の欠陥が顕在化
|
||||
|
||||
**軽減策**:
|
||||
- ✅ 根本原因を特定済み(BoxCall 型情報の未登録)
|
||||
- ✅ Phase 84-4-B で根本解決予定
|
||||
|
||||
**ポジティブな側面**: 以前は偶然動いていた部分を明示的に修正できる
|
||||
|
||||
### リスク2: dev フォールバックの濫用
|
||||
|
||||
**リスク**: Phase 84-4-A の dev フォールバックが常用され、根本解決が遅延
|
||||
|
||||
**軽減策**:
|
||||
- ✅ 環境変数による明示的制御(`NYASH_PHI_DEV_FALLBACK=1`)
|
||||
- ✅ production 環境(CI)では依然として厳格
|
||||
- ✅ 警告ログで問題箇所を明示
|
||||
|
||||
### リスク3: Phase 84-4 の実装時間超過
|
||||
|
||||
**リスク**: BoxCall 型情報登録が予想より複雑で 1-2日を超過
|
||||
|
||||
**軽減策**:
|
||||
- ✅ ビルトイン Box のハードコード型情報で最小実装
|
||||
- ✅ Phase 26-A の slot_registry 統合は将来拡張として分離
|
||||
- ✅ Unknown 型での暫定登録も許容
|
||||
|
||||
## 今後のマイルストーン
|
||||
|
||||
### Phase 84-4(予定: 2-3日)
|
||||
|
||||
**目標**: BoxCall/Await 型情報登録による根本解決
|
||||
|
||||
**成果物**:
|
||||
- `src/mir/builder/lifecycle.rs` - dev フォールバック追加
|
||||
- `src/mir/builder/builder_calls.rs` - BoxCall 型登録追加
|
||||
- `src/mir/builder/stmts.rs` - Await 型登録追加
|
||||
|
||||
**完了条件**:
|
||||
```bash
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 期待: 0
|
||||
```
|
||||
|
||||
### Phase 84-5(予定: 1日)
|
||||
|
||||
**目標**: if_phi.rs レガシーフォールバック完全削除
|
||||
|
||||
**成果物**:
|
||||
- `src/mir/join_ir/lowering/if_phi.rs` 削除(約 300行)
|
||||
- `GenericTypeResolver` の if_phi 呼び出し削除
|
||||
- `lifecycle.rs` の Case D 処理削除
|
||||
|
||||
**完了条件**:
|
||||
```bash
|
||||
# if_phi.rs が存在しない
|
||||
ls src/mir/join_ir/lowering/if_phi.rs
|
||||
# 期待: No such file or directory
|
||||
|
||||
# レガシーフォールバック呼び出しが存在しない
|
||||
grep -r "infer_type_from_phi_fallback" src/
|
||||
# 期待: 出力なし
|
||||
```
|
||||
|
||||
## 謝辞
|
||||
|
||||
Phase 84-3 の成功は、以下の要因によるものです:
|
||||
|
||||
1. **ChatGPT Pro の設計**: PHI + Copy グラフ型推論という明確な責務分離
|
||||
2. **箱理論の適用**: 単一責務の徹底による保守性向上
|
||||
3. **段階的実装**: Phase 84-2 の CopyTypePropagator という土台
|
||||
4. **詳細な調査**: Phase 84-1/2 の失敗パターン分析
|
||||
|
||||
## まとめ
|
||||
|
||||
**Phase 84-3 の成果**:
|
||||
- ✅ PhiTypeResolver 実装完了(新規ファイル作成)
|
||||
- ✅ 56%削減達成(9件 → 4件)
|
||||
- ✅ GroupA(Loop 制御フロー)100%解決
|
||||
- ✅ 箱理論に基づく型推論システムの明確化
|
||||
|
||||
**残り 4件の本質**:
|
||||
- 全て「BoxCall/Await の型情報未登録」という同一問題
|
||||
- PhiTypeResolver の責務外(設計上正しい制約)
|
||||
|
||||
**Phase 84-4 への期待**:
|
||||
- 🎯 BoxCall/Await 型情報登録(2-3日)
|
||||
- 🎯 残り 4件の完全解決(67% → 100%)
|
||||
- 🎯 if_phi.rs レガシー削除準備完了
|
||||
|
||||
**Phase 84 プロジェクトの最終ゴール**:
|
||||
- 🎯 型推論システムの完全箱化
|
||||
- 🎯 レガシーフォールバック根絶
|
||||
- 🎯 保守性・拡張性・パフォーマンスの飛躍的向上
|
||||
|
||||
---
|
||||
|
||||
**次のアクション**: Phase 84-4 実装推奨ドキュメントを参照して、BoxCall/Await 型情報登録を開始してください。
|
||||
|
||||
**参考ドキュメント**:
|
||||
- [Phase 84-4 実装推奨](phase84-4-implementation-recommendation.md)
|
||||
- [Phase 84-3 残り 4件の完全調査](phase84-3-remaining-4-analysis.md)
|
||||
- [Phase 84 インデックス](phase84-index.md)
|
||||
@ -1,520 +0,0 @@
|
||||
# Phase 84-3: 残り 4件 Case D の完全調査
|
||||
|
||||
## 概要
|
||||
|
||||
Phase 84-3 で PhiTypeResolver を実装した結果、Case D は **9件 → 4件に削減**されました(**56%削減達成!**)。
|
||||
|
||||
本ドキュメントは残り 4件の詳細分析と、Phase 84-4 での完全削除ロードマップを提示します。
|
||||
|
||||
## 削減実績サマリー
|
||||
|
||||
| Phase | 実装内容 | Case D 件数 | 削減率 |
|
||||
|-------|---------|------------|--------|
|
||||
| Phase 84-1 (Initial) | フォールバック検出実装 | 12件 | - |
|
||||
| Phase 84-2 | CopyTypePropagator 実装 | 9件 | 25% |
|
||||
| **Phase 84-3** | **PhiTypeResolver 実装** | **4件** | **56%** |
|
||||
|
||||
## 残り 4件の一覧
|
||||
|
||||
| # | テスト名 | ValueId | 変更 |
|
||||
|---|---------|---------|------|
|
||||
| 1 | `test_lowering_await_expression` | ValueId(2) | 継続 |
|
||||
| 2 | `mir_lowering_of_qmark_propagate` | ValueId(7) | **新規** |
|
||||
| 3 | `mir_stage1_cli_emit_program_min_compiles_and_verifies` | ValueId(7) | 継続 |
|
||||
| 4 | `mir_stage1_cli_emit_program_min_exec_hits_type_error` | ValueId(7) | 継続 |
|
||||
|
||||
### Phase 84-3 で解決された 5件(GroupA ループ系)
|
||||
|
||||
PhiTypeResolver により以下が解決されました:
|
||||
|
||||
- ✅ `loop_with_continue_and_break_edge_copy_merge` - ValueId(56)
|
||||
- ✅ `nested_loop_with_multi_continue_break_edge_copy_merge` - ValueId(135)
|
||||
- ✅ `loop_inner_if_multilevel_edge_copy` - ValueId(74)
|
||||
- ✅ `loop_break_and_early_return_edge_copy` - ValueId(40)
|
||||
- ✅ `vm_exec_break_inside_if` - ValueId(27)
|
||||
|
||||
**削減原因**: Copy → PHI → Copy チェーンを DFS で遡り、base 型定義を発見する能力
|
||||
|
||||
## 残り 4件の詳細分析
|
||||
|
||||
### 1. test_lowering_await_expression (GroupC: await 特殊構文)
|
||||
|
||||
**テストファイル**: `src/mir/mod.rs:363-384`
|
||||
|
||||
**コード**:
|
||||
```rust
|
||||
let ast = ASTNode::AwaitExpression {
|
||||
expression: Box::new(ASTNode::Literal {
|
||||
value: LiteralValue::Integer(1),
|
||||
span: crate::ast::Span::unknown(),
|
||||
}),
|
||||
span: crate::ast::Span::unknown(),
|
||||
};
|
||||
```
|
||||
|
||||
**Lowering 実装**: `src/mir/builder/stmts.rs:388-401`
|
||||
```rust
|
||||
pub(super) fn build_await_expression(
|
||||
&mut self,
|
||||
expression: ASTNode,
|
||||
) -> Result<ValueId, String> {
|
||||
let future_value = self.build_expression(expression)?;
|
||||
self.emit_instruction(MirInstruction::Safepoint)?;
|
||||
let result_id = self.next_value_id();
|
||||
self.emit_instruction(MirInstruction::Await {
|
||||
dst: result_id,
|
||||
future: future_value,
|
||||
})?;
|
||||
self.emit_instruction(MirInstruction::Safepoint)?;
|
||||
Ok(result_id)
|
||||
}
|
||||
```
|
||||
|
||||
**問題の本質**:
|
||||
- `Await { dst: ValueId(2), future: ValueId(1) }` 命令の戻り値型が未登録
|
||||
- `ValueId(1)` は `Integer(1)` の型 (IntegerBox) が登録済み
|
||||
- しかし、`Await` 命令の戻り値型は **Future の解決値の型** であり、
|
||||
現在の MIR では型情報が失われている
|
||||
|
||||
**なぜ PhiTypeResolver で解決できないか**:
|
||||
- `ValueId(2)` は `Await` 命令の dst(base 定義)
|
||||
- value_types に型が登録されていない
|
||||
- PHI/Copy チェーンではないため、探索しても型が見つからない
|
||||
|
||||
**解決策**:
|
||||
1. **短期**: Await 命令の戻り値を Unknown として許容
|
||||
2. **中期**: Await 命令 lowering 時に future の型から戻り値型を推論
|
||||
3. **長期**: Phase 67+ async/await 型システム実装
|
||||
|
||||
### 2. mir_lowering_of_qmark_propagate (GroupD: QMark 特殊構文) **新規失敗**
|
||||
|
||||
**テストファイル**: `src/tests/mir_qmark_lower.rs:5-33`
|
||||
|
||||
**コード**:
|
||||
```rust
|
||||
let ast = ASTNode::QMarkPropagate {
|
||||
expression: Box::new(ASTNode::New {
|
||||
class: "StringBox".to_string(),
|
||||
arguments: vec![ASTNode::Literal {
|
||||
value: crate::ast::LiteralValue::String("ok".to_string()),
|
||||
span: Span::unknown(),
|
||||
}],
|
||||
type_arguments: vec![],
|
||||
span: Span::unknown(),
|
||||
}),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
```
|
||||
|
||||
**Lowering 実装**: `src/mir/builder/exprs_qmark.rs:6-42`
|
||||
```rust
|
||||
pub(super) fn build_qmark_propagate_expression(
|
||||
&mut self,
|
||||
expression: ASTNode,
|
||||
) -> Result<ValueId, String> {
|
||||
let res_val = self.build_expression_impl(expression)?;
|
||||
let res_local = self.local_ssa_ensure(res_val, 0);
|
||||
let ok_id = self.next_value_id();
|
||||
self.emit_instruction(super::MirInstruction::BoxCall {
|
||||
dst: Some(ok_id),
|
||||
box_val: res_local,
|
||||
method: "isOk".to_string(),
|
||||
args: vec![],
|
||||
method_id: None,
|
||||
effects: super::EffectMask::PURE,
|
||||
})?;
|
||||
let then_block = self.block_gen.next();
|
||||
let else_block = self.block_gen.next();
|
||||
let ok_local = self.local_ssa_ensure(ok_id, 4);
|
||||
crate::mir::builder::emission::branch::emit_conditional(
|
||||
self, ok_local, then_block, else_block,
|
||||
)?;
|
||||
self.start_new_block(then_block)?;
|
||||
self.emit_instruction(super::MirInstruction::Return {
|
||||
value: Some(res_local),
|
||||
})?;
|
||||
self.start_new_block(else_block)?;
|
||||
let val_id = self.next_value_id();
|
||||
self.emit_instruction(super::MirInstruction::BoxCall {
|
||||
dst: Some(val_id),
|
||||
box_val: res_local,
|
||||
method: "getValue".to_string(),
|
||||
args: vec![],
|
||||
method_id: None,
|
||||
effects: super::EffectMask::PURE,
|
||||
})?;
|
||||
Ok(val_id)
|
||||
}
|
||||
```
|
||||
|
||||
**制御フロー構造**:
|
||||
```
|
||||
Block1:
|
||||
%res = new StringBox("ok")
|
||||
%ok = BoxCall(%res, "isOk")
|
||||
br %ok, then_block, else_block
|
||||
|
||||
Block2 (then_block):
|
||||
ret %res
|
||||
|
||||
Block3 (else_block):
|
||||
%val = BoxCall(%res, "getValue") ← ValueId(7) の型が未登録
|
||||
// 暗黙の return %val
|
||||
```
|
||||
|
||||
**問題の本質**:
|
||||
- `BoxCall { dst: ValueId(7), method: "getValue" }` の戻り値型が未登録
|
||||
- `getValue()` の戻り値型は **Result<T> の T 型** だが、型情報が失われている
|
||||
- main 関数の return 型を推論する際に ValueId(7) の型が必要
|
||||
|
||||
**なぜ PhiTypeResolver で解決できないか**:
|
||||
- `ValueId(7)` は `BoxCall` 命令の dst(base 定義)
|
||||
- value_types に型が登録されていない
|
||||
- PHI/Copy チェーンではないため、探索しても型が見つからない
|
||||
|
||||
**Phase 84-2 で失敗していなかった理由**:
|
||||
- 以前の調査文書には記載なし → **PhiTypeResolver 実装の副作用で新たに顕在化**
|
||||
- 可能性1: 以前は別の型推論経路で偶然解決していた
|
||||
- 可能性2: テスト自体が無効化されていた(要調査)
|
||||
|
||||
**解決策**:
|
||||
1. **短期**: BoxCall の戻り値型を Unknown として許容(dev 環境のみ)
|
||||
2. **中期**: BoxCall 命令 lowering 時にメソッド型情報から戻り値型を登録
|
||||
3. **長期**: Phase 26-A ValueKind 型安全化で BoxCall 戻り値型を完全追跡
|
||||
|
||||
### 3-4. mir_stage1_cli_emit_program_min_* (GroupB: Stage1Cli 複雑型推論)
|
||||
|
||||
**テストファイル**: `src/tests/mir_stage1_cli_emit_program_min.rs:71-138`
|
||||
|
||||
**コード**: 138行の複雑な static box 定義
|
||||
```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 が複数の経路から合流するが、**BoxCall の戻り値型が未登録**
|
||||
|
||||
**なぜ PhiTypeResolver で解決できないか**:
|
||||
- `ValueId(7)` は `BoxCall { method: "stage1_main" }` の dst(base 定義)
|
||||
- value_types に型が登録されていない
|
||||
- PHI/Copy チェーンではないため、探索しても型が見つからない
|
||||
|
||||
**デバッグ情報**:
|
||||
```
|
||||
[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 合流が複雑であることを示唆。
|
||||
|
||||
**解決策**:
|
||||
1. **短期**: BoxCall の戻り値型を Unknown として許容(dev 環境のみ)
|
||||
2. **中期**: BoxCall 命令 lowering 時にメソッド型情報から戻り値型を登録
|
||||
3. **長期**: Phase 26-A ValueKind 型安全化で BoxCall 戻り値型を完全追跡
|
||||
|
||||
## パターン分類の再整理
|
||||
|
||||
Phase 84-3 の結果を踏まえ、パターン分類を更新:
|
||||
|
||||
### GroupA: Loop 制御フロー PHI(5件 → 0件) ✅ 完全解決
|
||||
|
||||
**PhiTypeResolver で解決**: Copy → PHI → Copy チェーンを DFS で遡る能力
|
||||
|
||||
### GroupB: Stage1Cli 複雑型推論(2件 → 2件) ⚠️ 継続
|
||||
|
||||
**根本原因**: BoxCall 戻り値型の未登録(base 定義の型情報欠落)
|
||||
|
||||
### GroupC: await 特殊構文(1件 → 1件) ⚠️ 継続
|
||||
|
||||
**根本原因**: Await 戻り値型の未登録(base 定義の型情報欠落)
|
||||
|
||||
### GroupD: QMark 特殊構文(0件 → 1件) ⚠️ 新規出現
|
||||
|
||||
**根本原因**: BoxCall 戻り値型の未登録(getValue メソッドの型情報欠落)
|
||||
|
||||
## Phase 84-4 で必要な機能の推奨
|
||||
|
||||
### 推奨1: BoxCall 戻り値型の実行時登録(優先度: 最高)
|
||||
|
||||
**対象**: GroupB(2件)、GroupD(1件)
|
||||
|
||||
**問題の統一化**:
|
||||
- 全て「BoxCall の dst が value_types に未登録」という同一問題
|
||||
- PhiTypeResolver では base 定義の型を発見できない
|
||||
|
||||
**解決策(2段階)**:
|
||||
|
||||
#### Phase 84-4-A: 暫定フォールバック(dev 環境専用)
|
||||
|
||||
**実装箇所**: `src/mir/builder/lifecycle.rs`
|
||||
|
||||
```rust
|
||||
// lifecycle.rs の infer_type_from_phi() 内
|
||||
if should_enable_dev_fallback() {
|
||||
// dev 環境専用: BoxCall/Await の戻り値型を Unknown として許容
|
||||
if is_boxcall_or_await_result(function, ret_val) {
|
||||
eprintln!(
|
||||
"[phase84/dev_fallback] BoxCall/Await result {} → Unknown (dev only)",
|
||||
ret_val
|
||||
);
|
||||
return Ok(MirType::Unknown);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**環境変数制御**:
|
||||
```rust
|
||||
fn should_enable_dev_fallback() -> bool {
|
||||
std::env::var("NYASH_PHI_DEV_FALLBACK").ok().as_deref() == Some("1")
|
||||
}
|
||||
```
|
||||
|
||||
**期待効果**:
|
||||
- 3件 → 1件(await のみ残存)
|
||||
- dev 環境でのビルド通過
|
||||
- production 環境では依然として厳格なエラー
|
||||
|
||||
#### Phase 84-4-B: BoxCall 型情報の実行時登録(根本解決)
|
||||
|
||||
**実装箇所**: `src/mir/builder/builder_calls.rs`
|
||||
|
||||
```rust
|
||||
// emit_box_call() 内に追加
|
||||
pub fn emit_box_call(
|
||||
&mut self,
|
||||
box_val: ValueId,
|
||||
method: &str,
|
||||
args: Vec<ValueId>,
|
||||
) -> Result<ValueId, String> {
|
||||
let dst = self.next_value_id();
|
||||
|
||||
// 既存の BoxCall 命令生成
|
||||
self.emit_instruction(MirInstruction::BoxCall {
|
||||
dst: Some(dst),
|
||||
box_val,
|
||||
method: method.to_string(),
|
||||
args,
|
||||
method_id: None,
|
||||
effects: EffectMask::UNKNOWN,
|
||||
})?;
|
||||
|
||||
// **新機能**: メソッド型情報から戻り値型を推論して登録
|
||||
if let Some(method_ty) = self.infer_boxcall_return_type(box_val, method, &args) {
|
||||
self.value_types.insert(dst, method_ty);
|
||||
}
|
||||
|
||||
Ok(dst)
|
||||
}
|
||||
|
||||
fn infer_boxcall_return_type(
|
||||
&self,
|
||||
box_val: ValueId,
|
||||
method: &str,
|
||||
args: &[ValueId],
|
||||
) -> Option<MirType> {
|
||||
// 1. box_val の型を取得
|
||||
let box_ty = self.value_types.get(&box_val)?;
|
||||
|
||||
// 2. method の型情報を slot_registry から取得
|
||||
if let Some(slot_id) = self.current_slot_registry
|
||||
.as_ref()
|
||||
.and_then(|reg| reg.resolve_method(box_ty, method))
|
||||
{
|
||||
// 3. slot_id からメソッドシグネチャを取得
|
||||
// (Phase 26-A で実装予定)
|
||||
return Some(MirType::Unknown); // 暫定
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
```
|
||||
|
||||
**期待効果**:
|
||||
- 3件 → 1件(await のみ残存)
|
||||
- production 環境でも安全に動作
|
||||
- 型情報の追跡可能性向上
|
||||
|
||||
### 推奨2: Await 型情報の特殊処理(優先度: 中)
|
||||
|
||||
**対象**: GroupC(1件)
|
||||
|
||||
**短期対応**: Phase 84-4-A の dev フォールバックで対応(Unknown として許容)
|
||||
|
||||
**長期対応**: Phase 67+ async/await 型システム実装
|
||||
```rust
|
||||
// build_await_expression() 内に追加
|
||||
pub(super) fn build_await_expression(
|
||||
&mut self,
|
||||
expression: ASTNode,
|
||||
) -> Result<ValueId, String> {
|
||||
let future_value = self.build_expression(expression)?;
|
||||
self.emit_instruction(MirInstruction::Safepoint)?;
|
||||
|
||||
let result_id = self.next_value_id();
|
||||
|
||||
// **新機能**: Future の型から戻り値型を推論
|
||||
if let Some(future_ty) = self.value_types.get(&future_value) {
|
||||
if let MirType::Box { name } = future_ty {
|
||||
if name.contains("Future") {
|
||||
// Future<T> の T を抽出(Phase 67+ で実装)
|
||||
let resolved_ty = extract_future_inner_type(name);
|
||||
self.value_types.insert(result_id, resolved_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.emit_instruction(MirInstruction::Await {
|
||||
dst: result_id,
|
||||
future: future_value,
|
||||
})?;
|
||||
self.emit_instruction(MirInstruction::Safepoint)?;
|
||||
Ok(result_id)
|
||||
}
|
||||
```
|
||||
|
||||
## Phase 84-4 実装ロードマップ
|
||||
|
||||
### Phase 84-4-A: dev フォールバック実装(0.5日)
|
||||
|
||||
**目標**: 開発環境でのビルド通過
|
||||
|
||||
**ステップ**:
|
||||
1. `lifecycle.rs` に `is_boxcall_or_await_result()` 実装
|
||||
2. `should_enable_dev_fallback()` 環境変数チェック実装
|
||||
3. dev フォールバック警告ログ追加
|
||||
4. テスト実行: `NYASH_PHI_DEV_FALLBACK=1` で 4件 → 0件 確認
|
||||
|
||||
**成果**:
|
||||
- dev 環境での即座のアンブロック
|
||||
- production 環境は依然として厳格
|
||||
|
||||
### Phase 84-4-B: BoxCall 型情報登録(1-2日)
|
||||
|
||||
**目標**: BoxCall 戻り値型の根本解決
|
||||
|
||||
**ステップ**:
|
||||
1. `builder_calls.rs` に `infer_boxcall_return_type()` 実装
|
||||
2. `emit_box_call()` 内で戻り値型を value_types に登録
|
||||
3. slot_registry とのインテグレーション
|
||||
4. テスト実行: 3件 → 1件(await のみ残存)確認
|
||||
|
||||
**成果**:
|
||||
- GroupB(2件)完全解決
|
||||
- GroupD(1件)完全解決
|
||||
- production 環境でも安全
|
||||
|
||||
### Phase 84-4-C: Await 型情報特殊処理(0.5日)
|
||||
|
||||
**目標**: Await 戻り値型の暫定対応
|
||||
|
||||
**ステップ**:
|
||||
1. `build_await_expression()` に Future 型チェック追加
|
||||
2. Unknown 型での暫定登録
|
||||
3. テスト実行: 1件 → 0件 確認
|
||||
|
||||
**成果**:
|
||||
- GroupC(1件)暫定解決
|
||||
- Phase 67+ 実装までの橋渡し
|
||||
|
||||
## 完了条件
|
||||
|
||||
```bash
|
||||
# Phase 84-4-A 完了
|
||||
NYASH_PHI_DEV_FALLBACK=1 NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 期待: 0(dev フォールバックで全件通過)
|
||||
|
||||
# Phase 84-4-B 完了
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 期待: 1(await のみ残存)
|
||||
|
||||
# Phase 84-4-C 完了
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 期待: 0(全件解決)
|
||||
```
|
||||
|
||||
## if_phi.rs レガシー削除ロードマップ
|
||||
|
||||
### Phase 84-5: レガシーフォールバック完全削除(1日)
|
||||
|
||||
**前提条件**: Phase 84-4-C 完了(Case D = 0件)
|
||||
|
||||
**ステップ**:
|
||||
1. `src/mir/join_ir/lowering/if_phi.rs` 完全削除
|
||||
2. `GenericTypeResolver` の if_phi 呼び出し削除
|
||||
3. `lifecycle.rs` の Case D 処理を全て削除
|
||||
4. 全テスト実行: Case D panic が 0件であることを確認
|
||||
5. ドキュメント更新: Phase 82-84 完了宣言
|
||||
|
||||
**期待成果**:
|
||||
- if_phi.rs(約 300行)完全削除
|
||||
- 型推論システムの完全箱化達成
|
||||
- レガシーフォールバック根絶
|
||||
|
||||
### 削除による技術的利点
|
||||
|
||||
1. **箱理論の完全実現**:
|
||||
- PhiTypeResolver: PHI + Copy グラフ専用箱
|
||||
- CopyTypePropagator: Copy 型伝播専用箱
|
||||
- GenericTypeResolver: 統合調整箱
|
||||
- if_phi.rs: 削除(レガシー汚染源の根絶)
|
||||
|
||||
2. **保守性向上**:
|
||||
- 型推論ロジックが 3箱に明確分離
|
||||
- 各箱の責務が単一明確
|
||||
- 新規型推論パターン追加が容易
|
||||
|
||||
3. **パフォーマンス改善**:
|
||||
- if_phi.rs の非効率な全探索削除
|
||||
- PhiTypeResolver の DFS による効率的探索
|
||||
- value_types キャッシュの最適化
|
||||
|
||||
## まとめ
|
||||
|
||||
**Phase 84-3 の成果**:
|
||||
- PhiTypeResolver 実装により 9件 → 4件(56%削減)
|
||||
- GroupA(Loop 制御フロー)5件を完全解決
|
||||
|
||||
**残り 4件の本質**:
|
||||
- 全て「base 定義(BoxCall/Await)の型情報欠落」という同一問題
|
||||
- PhiTypeResolver では解決不可能(設計上正しい制約)
|
||||
|
||||
**Phase 84-4 の戦略**:
|
||||
1. **Phase 84-4-A**: dev フォールバック実装(0.5日)
|
||||
2. **Phase 84-4-B**: BoxCall 型情報登録(1-2日)
|
||||
3. **Phase 84-4-C**: Await 型情報特殊処理(0.5日)
|
||||
|
||||
**Phase 84-5 の目標**:
|
||||
- if_phi.rs レガシーフォールバック完全削除
|
||||
- 型推論システムの完全箱化達成
|
||||
- Phase 82-84 完全達成宣言
|
||||
|
||||
**総削減見込み**:
|
||||
- 12件(初期)→ 0件(Phase 84-5 完了時)
|
||||
- **100%削減達成!**
|
||||
@ -1,208 +0,0 @@
|
||||
# Phase 84-3: PhiTypeResolver 実装完了サマリー
|
||||
|
||||
## 🎉 成果
|
||||
|
||||
**Case D 削減実績**: 9件 → 4件(**56%削減達成!**)
|
||||
|
||||
### Phase 82-84 の累積削減
|
||||
|
||||
| Phase | 実装内容 | Case D 件数 | 削減率 | 累積削減率 |
|
||||
|-------|---------|------------|--------|-----------|
|
||||
| Phase 82 | フォールバック検出実装 | 12件 | - | - |
|
||||
| Phase 84-2 | CopyTypePropagator 実装 | 9件 | 25% | 25% |
|
||||
| **Phase 84-3** | **PhiTypeResolver 実装** | **4件** | **56%** | **67%** |
|
||||
|
||||
## Phase 84-3 で解決された 5件
|
||||
|
||||
### GroupA: Loop 制御フロー PHI(完全解決)
|
||||
|
||||
PhiTypeResolver の DFS 探索により、以下のパターンが解決されました:
|
||||
|
||||
1. ✅ `loop_with_continue_and_break_edge_copy_merge` - ValueId(56)
|
||||
2. ✅ `nested_loop_with_multi_continue_break_edge_copy_merge` - ValueId(135)
|
||||
3. ✅ `loop_inner_if_multilevel_edge_copy` - ValueId(74)
|
||||
4. ✅ `loop_break_and_early_return_edge_copy` - ValueId(40)
|
||||
5. ✅ `vm_exec_break_inside_if` - ValueId(27)
|
||||
|
||||
**解決メカニズム**:
|
||||
```
|
||||
Copy → PHI → Copy → PHI → ... → base 型定義
|
||||
^ ^
|
||||
| |
|
||||
DFS 探索 value_types から型取得
|
||||
```
|
||||
|
||||
**技術的ポイント**:
|
||||
- 循環検出(visited セット)により無限ループ防止
|
||||
- 探索上限(max_visits)によるタイムアウト防止
|
||||
- base_types 収集と型一致性検証による安全な型推論
|
||||
|
||||
## 残り 4件の分類
|
||||
|
||||
| # | テスト名 | ValueId | パターン分類 |
|
||||
|---|---------|---------|------------|
|
||||
| 1 | `test_lowering_await_expression` | ValueId(2) | GroupC: await 特殊構文 |
|
||||
| 2 | `mir_lowering_of_qmark_propagate` | ValueId(7) | **GroupD: QMark 特殊構文(新規)** |
|
||||
| 3 | `mir_stage1_cli_emit_program_min_compiles_and_verifies` | ValueId(7) | GroupB: Stage1Cli 複雑型推論 |
|
||||
| 4 | `mir_stage1_cli_emit_program_min_exec_hits_type_error` | ValueId(7) | GroupB: Stage1Cli 複雑型推論 |
|
||||
|
||||
### 残存理由の統一
|
||||
|
||||
**全て同一問題**: 「base 定義(BoxCall/Await)の戻り値型が value_types に未登録」
|
||||
|
||||
PhiTypeResolver の設計上、base 定義の型が未登録の場合は None を返す(正しい動作)。
|
||||
これは PhiTypeResolver の責務外であり、**BoxCall/Await 命令の lowering 時に型情報を登録すべき**。
|
||||
|
||||
## Phase 84-4 への推奨
|
||||
|
||||
### 優先度1: BoxCall 型情報登録(3件解決)
|
||||
|
||||
**対象**:
|
||||
- GroupB(2件): Stage1Cli テスト
|
||||
- GroupD(1件): QMark テスト(新規出現)
|
||||
|
||||
**実装箇所**: `src/mir/builder/builder_calls.rs`
|
||||
|
||||
**実装内容**:
|
||||
```rust
|
||||
pub fn emit_box_call(
|
||||
&mut self,
|
||||
box_val: ValueId,
|
||||
method: &str,
|
||||
args: Vec<ValueId>,
|
||||
) -> Result<ValueId, String> {
|
||||
let dst = self.next_value_id();
|
||||
|
||||
// 既存の BoxCall 命令生成
|
||||
self.emit_instruction(MirInstruction::BoxCall { ... })?;
|
||||
|
||||
// **新機能**: メソッド戻り値型を推論して登録
|
||||
if let Some(ret_ty) = self.infer_boxcall_return_type(box_val, method, &args) {
|
||||
self.value_types.insert(dst, ret_ty);
|
||||
}
|
||||
|
||||
Ok(dst)
|
||||
}
|
||||
```
|
||||
|
||||
**期待効果**: 4件 → 1件(await のみ残存)
|
||||
|
||||
### 優先度2: Await 型情報特殊処理(1件解決)
|
||||
|
||||
**対象**: GroupC(1件)- await 特殊構文
|
||||
|
||||
**実装箇所**: `src/mir/builder/stmts.rs`
|
||||
|
||||
**実装内容**:
|
||||
```rust
|
||||
pub(super) fn build_await_expression(
|
||||
&mut self,
|
||||
expression: ASTNode,
|
||||
) -> Result<ValueId, String> {
|
||||
let future_value = self.build_expression(expression)?;
|
||||
self.emit_instruction(MirInstruction::Safepoint)?;
|
||||
|
||||
let result_id = self.next_value_id();
|
||||
|
||||
// **新機能**: Future の型から戻り値型を推論(暫定: Unknown)
|
||||
self.value_types.insert(result_id, MirType::Unknown);
|
||||
|
||||
self.emit_instruction(MirInstruction::Await { ... })?;
|
||||
self.emit_instruction(MirInstruction::Safepoint)?;
|
||||
Ok(result_id)
|
||||
}
|
||||
```
|
||||
|
||||
**期待効果**: 1件 → 0件(全件解決)
|
||||
|
||||
### 優先度3: dev フォールバック(即座のアンブロック)
|
||||
|
||||
**実装箇所**: `src/mir/builder/lifecycle.rs`
|
||||
|
||||
**環境変数**: `NYASH_PHI_DEV_FALLBACK=1`
|
||||
|
||||
**用途**: 開発環境での即座のアンブロック(production 環境は依然として厳格)
|
||||
|
||||
## Phase 84-5 への準備
|
||||
|
||||
### 完了条件
|
||||
|
||||
```bash
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 期待: 0
|
||||
```
|
||||
|
||||
### if_phi.rs 削除準備完了
|
||||
|
||||
Phase 84-4 完了後、以下が可能になります:
|
||||
|
||||
1. ✅ `src/mir/join_ir/lowering/if_phi.rs` 完全削除(約 300行)
|
||||
2. ✅ `GenericTypeResolver` の if_phi 呼び出し削除
|
||||
3. ✅ `lifecycle.rs` の Case D 処理を全て削除
|
||||
4. ✅ レガシーフォールバック根絶
|
||||
|
||||
## 技術的洞察
|
||||
|
||||
### PhiTypeResolver の設計原則(箱理論)
|
||||
|
||||
1. **単一責務**: PHI + Copy グラフ追跡のみ
|
||||
2. **探索限定**: Copy / Phi / base 定義 の 3 種類だけ
|
||||
3. **安全条件**: 1 種類の型に収束する場合のみ Some を返す
|
||||
|
||||
### なぜ base 定義の型推論は PhiTypeResolver の責務外か
|
||||
|
||||
**設計上の分離**:
|
||||
- **PhiTypeResolver**: 既に登録された型を「伝播」するレイヤー
|
||||
- **emit_box_call/emit_await**: 型を「生成」するレイヤー
|
||||
|
||||
**箱理論の実現**:
|
||||
```
|
||||
[型生成レイヤー]
|
||||
├─ emit_const() → MirType::Integer 等を登録
|
||||
├─ emit_box_call() → メソッド戻り値型を登録(Phase 84-4-B で実装)
|
||||
└─ build_await_expression() → Future 戻り値型を登録(Phase 84-4-C で実装)
|
||||
|
||||
[型伝播レイヤー]
|
||||
├─ CopyTypePropagator → Copy 命令で型伝播
|
||||
└─ PhiTypeResolver → PHI + Copy グラフで型伝播
|
||||
|
||||
[統合レイヤー]
|
||||
└─ GenericTypeResolver → 全ての型推論箱を調整
|
||||
```
|
||||
|
||||
### GroupD(QMark)が新規出現した理由
|
||||
|
||||
**仮説**: 以前は別の型推論経路(if_phi.rs のレガシーフォールバック)で偶然解決していた
|
||||
|
||||
**検証方法**:
|
||||
```bash
|
||||
# Phase 84-2 の状態に戻して確認
|
||||
git checkout <phase-84-2-commit>
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib mir_lowering_of_qmark_propagate
|
||||
# 結果: Case D で失敗するはず
|
||||
```
|
||||
|
||||
**意義**: PhiTypeResolver 実装により、以前は隠蔽されていた型推論の欠陥が顕在化
|
||||
→ 根本解決(BoxCall 型登録)の必要性が明確化
|
||||
|
||||
## まとめ
|
||||
|
||||
**Phase 84-3 の成果**:
|
||||
- ✅ PhiTypeResolver 実装完了
|
||||
- ✅ 9件 → 4件(56%削減)
|
||||
- ✅ GroupA(Loop 制御フロー)完全解決
|
||||
- ✅ 箱理論に基づく型推論システムの明確化
|
||||
|
||||
**Phase 84-4 への道筋**:
|
||||
- 🎯 BoxCall 型情報登録(3件解決)
|
||||
- 🎯 Await 型情報特殊処理(1件解決)
|
||||
- 🎯 dev フォールバック(即座のアンブロック)
|
||||
|
||||
**Phase 84-5 の目標**:
|
||||
- 🎯 if_phi.rs レガシー削除
|
||||
- 🎯 型推論システムの完全箱化達成
|
||||
- 🎯 Phase 82-84 完全達成宣言
|
||||
|
||||
**総削減見込み**:
|
||||
- 12件(初期)→ 0件(Phase 84-5 完了時)
|
||||
- **100%削減達成へ!**
|
||||
@ -1,352 +0,0 @@
|
||||
# Phase 84-4: BoxCall型情報登録 完了報告書
|
||||
|
||||
**日付**: 2025-12-02
|
||||
**作業者**: Claude
|
||||
**レビュー者**: User (tomoaki)
|
||||
|
||||
## 🎉 歴史的成果サマリー
|
||||
|
||||
**Phase 84-4-B で Case D を 4件 → 0件に削減(100%完全解決達成!)**
|
||||
|
||||
当初の予想(4件 → 1件、await 残存)を大幅に超え、**全件完全解決**を達成しました。
|
||||
|
||||
## 成果指標
|
||||
|
||||
| 指標 | Phase 84-3 目標 | Phase 84-4 実績 | 達成率 |
|
||||
|-----|----------------|----------------|--------|
|
||||
| Case D 削減件数 | 4件(全件) | 4件 | 100% |
|
||||
| Case D 残存件数 | 0件 | 0件 | 100%✅ |
|
||||
| 削減率 | 100% | 100% | 100%✅ |
|
||||
| 型推論成功率 | 90%以上 | 100% | 111%(目標超過) |
|
||||
|
||||
## Phase 84 全体の累積削減
|
||||
|
||||
| Phase | 実装内容 | 削減件数 | 残存件数 | 削減率 | 累積削減率 |
|
||||
|-------|---------|---------|---------|--------|--------------|
|
||||
| Phase 82 | フォールバック検出 | - | 15件 | - | - |
|
||||
| Phase 84-1 | Const 型注釈 | 3件 | 12件 | 20% | 20% |
|
||||
| Phase 84-2 | CopyTypePropagator | 3件 | 9件 | 25% | 40% |
|
||||
| Phase 84-3 | PhiTypeResolver | 5件 | 4件 | 56% | 73% |
|
||||
| **Phase 84-4-B** | **BoxCall 型情報登録** | **4件** | **0件** | **100%** | **100%** ✅ |
|
||||
|
||||
## Phase 84-4-B 実装詳細
|
||||
|
||||
### 新規実装ファイル
|
||||
|
||||
なし(既存 `src/mir/builder/utils.rs` に追加)
|
||||
|
||||
### 実装内容
|
||||
|
||||
#### 1. `infer_boxcall_return_type()` ヘルパー関数
|
||||
|
||||
**責務**: ビルトイン Box のメソッド戻り値型をハードコード推論
|
||||
|
||||
```rust
|
||||
/// Phase 84-4-B: BoxCall のメソッド戻り値型を推論
|
||||
///
|
||||
/// 責務: ビルトイン Box のメソッド戻り値型をハードコードで返す
|
||||
/// - plugin_method_sigs に登録されていないメソッドの型推論
|
||||
/// - PhiTypeResolver が依存する base 定義の型情報を提供
|
||||
fn infer_boxcall_return_type(
|
||||
&self,
|
||||
box_val: ValueId,
|
||||
method: &str,
|
||||
) -> Option<MirType>
|
||||
```
|
||||
|
||||
**対応 Box メソッド**:
|
||||
|
||||
```rust
|
||||
// StringBox: 8メソッド
|
||||
"upper", "lower", "length", "concat", "substring", "replace", "trim", "split"
|
||||
|
||||
// IntegerBox: 3メソッド
|
||||
"abs", "min", "max"
|
||||
|
||||
// BoolBox: 3メソッド
|
||||
"not", "and", "or"
|
||||
|
||||
// ArrayBox: 4メソッド
|
||||
"length", "get", "push", "pop"
|
||||
|
||||
// MapBox: 4メソッド
|
||||
"get", "set", "has", "keys"
|
||||
|
||||
// Result-like Box (QMark 対応): 2メソッド
|
||||
"isOk", "getValue"
|
||||
|
||||
// Stage1CliBox (暫定): 3メソッド
|
||||
"parse", "compile", "execute"
|
||||
|
||||
// 未知のメソッド: Unknown 型として登録(PhiTypeResolver 有効化)
|
||||
```
|
||||
|
||||
#### 2. `emit_box_or_plugin_call()` 型登録ロジック強化
|
||||
|
||||
**変更箇所**: `src/mir/builder/utils.rs:320-332`
|
||||
|
||||
**変更内容**:
|
||||
- `plugin_method_sigs` ルックアップ失敗時のフォールバック追加
|
||||
- `infer_boxcall_return_type()` 呼び出し
|
||||
- `value_types.insert()` による型情報登録
|
||||
- `NYASH_BOXCALL_TYPE_TRACE=1` デバッグ出力
|
||||
|
||||
```rust
|
||||
if let Some(bt) = recv_box {
|
||||
if let Some(mt) = self.plugin_method_sigs.get(&(bt.clone(), method.clone())) {
|
||||
self.value_types.insert(d, mt.clone());
|
||||
} else {
|
||||
// Phase 84-4-B: ビルトイン Box のメソッド戻り値型推論
|
||||
// plugin_method_sigs に登録されていない場合のフォールバック
|
||||
if let Some(ret_ty) = self.infer_boxcall_return_type(box_val, &method) {
|
||||
self.value_types.insert(d, ret_ty.clone());
|
||||
|
||||
if std::env::var("NYASH_BOXCALL_TYPE_TRACE").ok().as_deref() == Some("1") {
|
||||
eprintln!(
|
||||
"[boxcall_type] registered %{} = BoxCall(%{}, {}) → {:?}",
|
||||
d.0, box_val.0, method, ret_ty
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 解決された 4件の詳細
|
||||
|
||||
### 1. `mir_lowering_of_qmark_propagate` (GroupD)
|
||||
|
||||
**ValueId**: ValueId(7)
|
||||
**パターン**: QMark (?) 特殊構文
|
||||
**解決方法**: `isOk()` / `getValue()` の戻り値型を Unknown として登録
|
||||
|
||||
**検証結果**: ✅ 型推論成功(Case D panic なし)
|
||||
**副作用**: テスト期待値が古い(PluginInvoke 想定 → Call 生成で正常)
|
||||
|
||||
### 2-3. `mir_stage1_cli_emit_program_min_*` (GroupB)
|
||||
|
||||
**ValueId**: ValueId(7)
|
||||
**パターン**: Stage1Cli 複雑型推論
|
||||
**解決方法**: Stage1CliBox メソッドの戻り値型を Unknown として登録
|
||||
|
||||
**検証結果**: ✅ 型推論成功(Case D panic なし)
|
||||
**副作用**: テスト期待値の問題(Call 命令生成で正常)
|
||||
|
||||
### 4. `test_lowering_await_expression` (GroupC)
|
||||
|
||||
**ValueId**: ValueId(2)
|
||||
**パターン**: await 特殊構文
|
||||
**解決方法**: **BoxCall 経路で解決済み**(Await 専用実装不要)
|
||||
|
||||
**検証結果**: ✅ 型推論成功(Case D panic なし)
|
||||
**驚きの発見**: await が内部的に BoxCall 経路を使用していた
|
||||
|
||||
## 技術的洞察
|
||||
|
||||
### なぜ Phase 84-4-C(Await 型登録)が不要だったか
|
||||
|
||||
**仮説**: Await 命令が内部的に BoxCall と同じ型推論経路を通過
|
||||
|
||||
**証拠**:
|
||||
1. Phase 84-4-B 実装のみで await テストが解決
|
||||
2. `infer_boxcall_return_type()` に Await 専用ロジックなし
|
||||
3. 4件全て BoxCall 型推論で解決
|
||||
|
||||
**推論**:
|
||||
- Await → Future メソッド呼び出し → BoxCall 経路
|
||||
- または MirBuilder が Await を BoxCall として lowering
|
||||
|
||||
### 箱理論の完全実現
|
||||
|
||||
Phase 84-4-B により、型推論システムの 3層構造が完成しました:
|
||||
|
||||
```
|
||||
[型生成レイヤー] - 型を作る
|
||||
├─ emit_const() ✅ Phase 84-1 実装済み
|
||||
├─ emit_box_call() ✅ Phase 84-4-B 実装済み
|
||||
└─ build_await_expression() ✅ BoxCall 経路で解決(実装不要)
|
||||
|
||||
[型伝播レイヤー] - 型を広げる
|
||||
├─ CopyTypePropagator ✅ Phase 84-2 実装済み
|
||||
└─ PhiTypeResolver ✅ Phase 84-3 実装済み
|
||||
|
||||
[統合レイヤー] - 全体を調整
|
||||
└─ GenericTypeResolver ✅ 既存実装
|
||||
|
||||
[レガシー] - 削除準備完了
|
||||
└─ if_phi.rs フォールバック 🗑️ Phase 84-5 で削除可能
|
||||
```
|
||||
|
||||
### Unknown 型の戦略的利用
|
||||
|
||||
**設計判断**: 未知のメソッド → `None` ではなく `Some(MirType::Unknown)` を返す
|
||||
|
||||
**理由**:
|
||||
- PhiTypeResolver が動作するには base 定義の型情報が必要
|
||||
- `None` を返すと PhiTypeResolver が無効化される
|
||||
- `Unknown` を登録すれば PHI 探索が継続可能
|
||||
|
||||
**効果**:
|
||||
- 型情報が不完全でも型伝播が機能
|
||||
- ランタイム型検証でエラー検出
|
||||
- 開発体験の向上(panic より実行時エラー)
|
||||
|
||||
## 検証結果
|
||||
|
||||
### Case D panic 完全解消
|
||||
|
||||
```bash
|
||||
# Phase 84-3 ベースライン
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 結果: 9件(Phase 84-3 前)→ 4件(Phase 84-3 後)
|
||||
|
||||
# Phase 84-4-B 完了後
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 結果: 0件 ✅
|
||||
```
|
||||
|
||||
### テスト結果比較
|
||||
|
||||
| 状態 | passed | failed | Case D panic |
|
||||
|-----|--------|--------|--------------|
|
||||
| Phase 84-3 ベースライン | 504 | 30 | 4件 |
|
||||
| Phase 84-4-B 完了後 | 497 | 37 | **0件** ✅ |
|
||||
|
||||
**変化の理由**:
|
||||
- -7 passed / +7 failed は型推論問題ではない
|
||||
- 以前 Case D panic していたテストが実行完了
|
||||
- テスト期待値の問題(PluginInvoke → Call 命令)
|
||||
|
||||
### デバッグ環境変数
|
||||
|
||||
**型推論トレース有効化**:
|
||||
```bash
|
||||
NYASH_BOXCALL_TYPE_TRACE=1 cargo test --release --lib mir_lowering_of_qmark_propagate
|
||||
|
||||
# 期待される出力:
|
||||
# [boxcall_type] registered %3 = BoxCall(%1, isOk) → Box(BoolBox)
|
||||
# [boxcall_type] registered %7 = BoxCall(%1, getValue) → Unknown
|
||||
```
|
||||
|
||||
**未知メソッドデバッグ**:
|
||||
```bash
|
||||
NYASH_BOXCALL_TYPE_DEBUG=1 ./target/release/nyash program.hako
|
||||
|
||||
# 出力例:
|
||||
# [boxcall_type] unknown method UserBox.customMethod → Unknown
|
||||
```
|
||||
|
||||
## 残存課題と将来の拡張
|
||||
|
||||
### 残存課題
|
||||
|
||||
**なし** - Phase 84 の目標(Case D 完全解決)を 100%達成
|
||||
|
||||
### 将来の拡張(Phase 26-A 等)
|
||||
|
||||
1. **slot_registry 統合**
|
||||
- ビルトイン Box の型情報を動的に取得
|
||||
- ハードコード型情報の削減
|
||||
|
||||
2. **ユーザー定義 Box 対応**
|
||||
- Box 定義から自動的にメソッド型推論
|
||||
- 型注釈の完全活用
|
||||
|
||||
3. **ジェネリック型推論**
|
||||
- `ArrayBox<T>` の要素型推論
|
||||
- `Result<T>` の T 型推論
|
||||
|
||||
## Phase 84-5 への準備
|
||||
|
||||
### 完了条件
|
||||
|
||||
```bash
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 期待: 0 ✅ 達成済み
|
||||
```
|
||||
|
||||
### if_phi.rs 削除準備完了
|
||||
|
||||
Phase 84-4-B 完了により、以下が可能になりました:
|
||||
|
||||
1. ✅ `src/mir/join_ir/lowering/if_phi.rs` 完全削除(約 300行)
|
||||
2. ✅ `GenericTypeResolver` の if_phi 呼び出し削除
|
||||
3. ✅ `lifecycle.rs` の Case D 処理を全て削除
|
||||
4. ✅ レガシーフォールバック根絶
|
||||
|
||||
### 削除可能なコード
|
||||
|
||||
```rust
|
||||
// lifecycle.rs の Case D セクション(全削除可能)
|
||||
// Case D: GenericTypeResolver も失敗 → if_phi フォールバックが必要
|
||||
eprintln!("[phase82/phi_fallback] Case D triggered for {}", ret_val);
|
||||
|
||||
if std::env::var("NYASH_PHI_FALLBACK_DISABLED").is_ok() {
|
||||
panic!(
|
||||
"[phase82/phi_fallback] Case D: GenericTypeResolver failed for {}, ..."
|
||||
);
|
||||
}
|
||||
|
||||
// if_phi.rs 呼び出し(全削除可能)
|
||||
if let Some(mt) = infer_type_from_phi_fallback(...) {
|
||||
return Ok(mt);
|
||||
}
|
||||
```
|
||||
|
||||
## リスク評価
|
||||
|
||||
### リスク1: テスト期待値の更新
|
||||
|
||||
**リスク**: 4件のテストが PluginInvoke → Call 命令変更により失敗
|
||||
|
||||
**影響**: ✅ 軽微(型推論は成功、テスト期待値のみ古い)
|
||||
|
||||
**軽減策**: テスト期待値を Call 命令に更新(別タスク)
|
||||
|
||||
### リスク2: Unknown 型の乱用
|
||||
|
||||
**リスク**: Unknown 型が多用されると型安全性が低下
|
||||
|
||||
**影響**: ⚠️ 中程度(ランタイムエラーの可能性)
|
||||
|
||||
**軽減策**:
|
||||
- ✅ ビルトイン Box は厳密な型情報を提供
|
||||
- ✅ Unknown は最後の手段として使用
|
||||
- ✅ 将来的に slot_registry で Unknown を削減
|
||||
|
||||
### リスク3: ハードコード型情報の保守負担
|
||||
|
||||
**リスク**: Box メソッド追加時に手動更新が必要
|
||||
|
||||
**影響**: ⚠️ 中程度(保守負担)
|
||||
|
||||
**軽減策**:
|
||||
- ✅ Phase 26-A で slot_registry 統合予定
|
||||
- ✅ 現時点では 27 メソッドのみ(管理可能)
|
||||
|
||||
## まとめ
|
||||
|
||||
**Phase 84-4-B の成果**:
|
||||
- ✅ BoxCall 型情報登録実装完了
|
||||
- ✅ Case D 4件 → 0件(**100%完全解決**)
|
||||
- ✅ Phase 84-4-C(Await 型登録)不要(BoxCall 経路で解決)
|
||||
- ✅ 箱理論に基づく型推論システムの完全箱化達成
|
||||
|
||||
**Phase 84 プロジェクト全体の成果**:
|
||||
- ✅ 15件 → 0件(**100%削減達成**)
|
||||
- ✅ 型生成・型伝播・型統合の 3層構造完成
|
||||
- ✅ レガシーフォールバック削除準備完了
|
||||
|
||||
**Phase 84-5 への期待**:
|
||||
- 🎯 if_phi.rs レガシーフォールバック完全削除
|
||||
- 🎯 約 300行のコード削減
|
||||
- 🎯 型推論システムの保守性・拡張性・パフォーマンス飛躍的向上
|
||||
|
||||
---
|
||||
|
||||
**次のアクション**: Phase 84-5 実装計画を確認し、if_phi.rs 削除を開始してください。
|
||||
|
||||
**参考ドキュメント**:
|
||||
- [Phase 84-3 完了報告](phase84-3-final-report.md)
|
||||
- [Phase 84-4 実装推奨](phase84-4-implementation-recommendation.md)
|
||||
- [Phase 84 インデックス](phase84-index.md)
|
||||
@ -1,410 +0,0 @@
|
||||
# Phase 84-4: 実装推奨 — BoxCall 型情報登録による根本解決
|
||||
|
||||
## 実装優先順位
|
||||
|
||||
### 🎯 Phase 84-4-A: dev フォールバック(推奨: 即実装)
|
||||
|
||||
**目的**: 開発環境の即座のアンブロック
|
||||
|
||||
**実装時間**: 0.5日
|
||||
|
||||
**実装箇所**: `src/mir/builder/lifecycle.rs`
|
||||
|
||||
```rust
|
||||
// lifecycle.rs の infer_type_from_phi() の Case D セクション内
|
||||
|
||||
// 既存のコード:
|
||||
// Case D: GenericTypeResolver も失敗 → if_phi フォールバックが必要
|
||||
eprintln!("[phase82/phi_fallback] Case D triggered for {}", ret_val);
|
||||
|
||||
// ↓ 以下を追加 ↓
|
||||
|
||||
// Phase 84-4-A: dev 環境専用フォールバック
|
||||
if should_enable_dev_fallback() {
|
||||
if is_base_definition_with_missing_type(self.current_function(), ret_val) {
|
||||
eprintln!(
|
||||
"[phase84/dev_fallback] {} is base definition with missing type → Unknown (dev only)",
|
||||
ret_val
|
||||
);
|
||||
return Ok(MirType::Unknown);
|
||||
}
|
||||
}
|
||||
|
||||
// 既存の panic 処理
|
||||
if std::env::var("NYASH_PHI_FALLBACK_DISABLED").is_ok() {
|
||||
panic!(...);
|
||||
}
|
||||
```
|
||||
|
||||
**ヘルパー関数**:
|
||||
```rust
|
||||
/// Phase 84-4-A: dev 環境専用フォールバック判定
|
||||
fn should_enable_dev_fallback() -> bool {
|
||||
std::env::var("NYASH_PHI_DEV_FALLBACK").ok().as_deref() == Some("1")
|
||||
}
|
||||
|
||||
/// base 定義(BoxCall/Await/etc)で型が未登録かチェック
|
||||
fn is_base_definition_with_missing_type(
|
||||
func: &MirFunction,
|
||||
val: ValueId,
|
||||
) -> bool {
|
||||
// val を定義する命令を探索
|
||||
for bb in func.blocks.values() {
|
||||
for inst in bb.instructions.iter().chain(bb.terminator.iter()) {
|
||||
match inst {
|
||||
MirInstruction::BoxCall { dst: Some(d), .. }
|
||||
| MirInstruction::Await { dst: d, .. }
|
||||
| MirInstruction::PluginInvoke { dst: Some(d), .. }
|
||||
| MirInstruction::ExternCall { dst: Some(d), .. }
|
||||
if *d == val =>
|
||||
{
|
||||
return true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
```
|
||||
|
||||
**使用方法**:
|
||||
```bash
|
||||
# dev 環境での作業
|
||||
NYASH_PHI_DEV_FALLBACK=1 cargo test --release --lib
|
||||
|
||||
# production 環境(CI)
|
||||
# 環境変数なし → 依然として厳格なエラー
|
||||
cargo test --release --lib
|
||||
```
|
||||
|
||||
**利点**:
|
||||
- ✅ 開発者の作業を即座にアンブロック
|
||||
- ✅ production 環境は依然として厳格(CI で検出可能)
|
||||
- ✅ 警告ログで問題箇所を明示
|
||||
|
||||
**欠点**:
|
||||
- ⚠️ 根本解決ではない(暫定措置)
|
||||
- ⚠️ dev 環境で型エラーが隠蔽される可能性
|
||||
|
||||
---
|
||||
|
||||
### 🔥 Phase 84-4-B: BoxCall 型情報登録(推奨: 根本解決)
|
||||
|
||||
**目的**: BoxCall 戻り値型の完全追跡
|
||||
|
||||
**実装時間**: 1-2日
|
||||
|
||||
**実装箇所**: `src/mir/builder/builder_calls.rs`
|
||||
|
||||
#### ステップ1: 型情報取得インフラ整備
|
||||
|
||||
```rust
|
||||
// builder_calls.rs に追加
|
||||
|
||||
/// BoxCall のメソッド戻り値型を推論(Phase 84-4-B)
|
||||
fn infer_boxcall_return_type(
|
||||
&self,
|
||||
box_val: ValueId,
|
||||
method: &str,
|
||||
_args: &[ValueId],
|
||||
) -> Option<MirType> {
|
||||
// 1. box_val の型を取得
|
||||
let box_ty = self.value_types.get(&box_val)?;
|
||||
|
||||
// 2. Box 型名を取得
|
||||
let box_name = match box_ty {
|
||||
MirType::Box { name } => name,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
// 3. ビルトイン Box の型情報(ハードコード)
|
||||
match (box_name.as_str(), method) {
|
||||
// StringBox
|
||||
("StringBox", "upper") => Some(MirType::Box {
|
||||
name: "StringBox".to_string(),
|
||||
}),
|
||||
("StringBox", "lower") => Some(MirType::Box {
|
||||
name: "StringBox".to_string(),
|
||||
}),
|
||||
("StringBox", "length") => Some(MirType::Box {
|
||||
name: "IntegerBox".to_string(),
|
||||
}),
|
||||
|
||||
// IntegerBox
|
||||
("IntegerBox", "abs") => Some(MirType::Box {
|
||||
name: "IntegerBox".to_string(),
|
||||
}),
|
||||
|
||||
// BoolBox
|
||||
("BoolBox", "not") => Some(MirType::Box {
|
||||
name: "BoolBox".to_string(),
|
||||
}),
|
||||
|
||||
// ArrayBox
|
||||
("ArrayBox", "length") => Some(MirType::Box {
|
||||
name: "IntegerBox".to_string(),
|
||||
}),
|
||||
("ArrayBox", "get") => Some(MirType::Unknown), // 要素型は実行時決定
|
||||
|
||||
// Result-like Box (QMark 用)
|
||||
(_, "isOk") => Some(MirType::Box {
|
||||
name: "BoolBox".to_string(),
|
||||
}),
|
||||
(_, "getValue") => Some(MirType::Unknown), // Result<T> の T
|
||||
|
||||
// 未知のメソッド
|
||||
_ => {
|
||||
if std::env::var("NYASH_BOXCALL_TYPE_DEBUG").is_ok() {
|
||||
eprintln!(
|
||||
"[boxcall_type] unknown method {}.{} → Unknown",
|
||||
box_name, method
|
||||
);
|
||||
}
|
||||
Some(MirType::Unknown)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### ステップ2: emit_box_call() への統合
|
||||
|
||||
```rust
|
||||
// builder_calls.rs の emit_box_call() を修正
|
||||
|
||||
pub fn emit_box_call(
|
||||
&mut self,
|
||||
box_val: ValueId,
|
||||
method: &str,
|
||||
args: Vec<ValueId>,
|
||||
) -> Result<ValueId, String> {
|
||||
let dst = self.next_value_id();
|
||||
|
||||
// 既存の BoxCall 命令生成
|
||||
self.emit_instruction(MirInstruction::BoxCall {
|
||||
dst: Some(dst),
|
||||
box_val,
|
||||
method: method.to_string(),
|
||||
args: args.clone(),
|
||||
method_id: None,
|
||||
effects: EffectMask::UNKNOWN,
|
||||
})?;
|
||||
|
||||
// **Phase 84-4-B 新機能**: 戻り値型を推論して登録
|
||||
if let Some(ret_ty) = self.infer_boxcall_return_type(box_val, method, &args) {
|
||||
self.value_types.insert(dst, ret_ty);
|
||||
|
||||
if std::env::var("NYASH_BOXCALL_TYPE_TRACE").is_ok() {
|
||||
eprintln!(
|
||||
"[boxcall_type] registered {} = BoxCall({}, {}) → {:?}",
|
||||
dst, box_val, method, ret_ty
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(dst)
|
||||
}
|
||||
```
|
||||
|
||||
#### ステップ3: テスト実行
|
||||
|
||||
```bash
|
||||
# 型推論トレース有効化
|
||||
NYASH_BOXCALL_TYPE_TRACE=1 cargo test --release --lib mir_lowering_of_qmark_propagate
|
||||
|
||||
# 期待される出力:
|
||||
# [boxcall_type] registered %3 = BoxCall(%1, isOk) → Box(BoolBox)
|
||||
# [boxcall_type] registered %7 = BoxCall(%1, getValue) → Unknown
|
||||
|
||||
# Case D チェック
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 期待: 1(await のみ残存)
|
||||
```
|
||||
|
||||
**利点**:
|
||||
- ✅ 3件(GroupB 2件 + GroupD 1件)を根本解決
|
||||
- ✅ production 環境でも安全
|
||||
- ✅ 型情報の追跡可能性向上
|
||||
|
||||
**将来の拡張**:
|
||||
- Phase 26-A で slot_registry から動的に型情報取得
|
||||
- ユーザー定義 Box のメソッド戻り値型も追跡可能
|
||||
|
||||
---
|
||||
|
||||
### ⚡ Phase 84-4-C: Await 型情報特殊処理(推奨: 暫定対応)
|
||||
|
||||
**目的**: Await 戻り値型の暫定登録
|
||||
|
||||
**実装時間**: 0.5日
|
||||
|
||||
**実装箇所**: `src/mir/builder/stmts.rs`
|
||||
|
||||
```rust
|
||||
// stmts.rs の build_await_expression() を修正
|
||||
|
||||
pub(super) fn build_await_expression(
|
||||
&mut self,
|
||||
expression: ASTNode,
|
||||
) -> Result<ValueId, String> {
|
||||
let future_value = self.build_expression(expression)?;
|
||||
self.emit_instruction(MirInstruction::Safepoint)?;
|
||||
|
||||
let result_id = self.next_value_id();
|
||||
|
||||
// **Phase 84-4-C 新機能**: Future の型から戻り値型を推論
|
||||
if let Some(future_ty) = self.value_types.get(&future_value) {
|
||||
match future_ty {
|
||||
MirType::Box { name } if name.contains("Future") => {
|
||||
// Future<T> の T を抽出(Phase 67+ で完全実装予定)
|
||||
// 現時点では Unknown として登録
|
||||
self.value_types.insert(result_id, MirType::Unknown);
|
||||
|
||||
if std::env::var("NYASH_AWAIT_TYPE_TRACE").is_ok() {
|
||||
eprintln!(
|
||||
"[await_type] registered {} = Await({}) → Unknown (temp)",
|
||||
result_id, future_value
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// Future 型でない場合も Unknown で登録(エラー防止)
|
||||
self.value_types.insert(result_id, MirType::Unknown);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// future_value の型が不明でも Unknown で登録
|
||||
self.value_types.insert(result_id, MirType::Unknown);
|
||||
}
|
||||
|
||||
self.emit_instruction(MirInstruction::Await {
|
||||
dst: result_id,
|
||||
future: future_value,
|
||||
})?;
|
||||
self.emit_instruction(MirInstruction::Safepoint)?;
|
||||
Ok(result_id)
|
||||
}
|
||||
```
|
||||
|
||||
**テスト実行**:
|
||||
```bash
|
||||
# 型推論トレース有効化
|
||||
NYASH_AWAIT_TYPE_TRACE=1 cargo test --release --lib test_lowering_await_expression
|
||||
|
||||
# Case D チェック
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 期待: 0(全件解決)
|
||||
```
|
||||
|
||||
**利点**:
|
||||
- ✅ GroupC(1件)を暫定解決
|
||||
- ✅ Phase 67+ 実装までの橋渡し
|
||||
|
||||
**長期対応**:
|
||||
- Phase 67+ で Future<T> の T 型を正確に抽出
|
||||
- async/await 型システムの完全実装
|
||||
|
||||
---
|
||||
|
||||
## 実装順序の推奨
|
||||
|
||||
### パターン1: 最速アンブロック(推奨: 即実装)
|
||||
|
||||
```
|
||||
Phase 84-4-A (0.5日)
|
||||
↓
|
||||
開発作業継続可能
|
||||
↓
|
||||
Phase 84-4-B (1-2日) + Phase 84-4-C (0.5日)
|
||||
↓
|
||||
Phase 84-5: if_phi.rs 削除
|
||||
```
|
||||
|
||||
**利点**:
|
||||
- ✅ 即座に開発環境アンブロック
|
||||
- ✅ 根本解決と並行作業可能
|
||||
|
||||
**欠点**:
|
||||
- ⚠️ dev 環境で型エラーが一時的に隠蔽
|
||||
|
||||
### パターン2: 完璧主義(推奨: 時間に余裕がある場合)
|
||||
|
||||
```
|
||||
Phase 84-4-B (1-2日) + Phase 84-4-C (0.5日)
|
||||
↓
|
||||
Phase 84-5: if_phi.rs 削除
|
||||
```
|
||||
|
||||
**利点**:
|
||||
- ✅ dev フォールバック不要
|
||||
- ✅ 最初から根本解決
|
||||
|
||||
**欠点**:
|
||||
- ⚠️ 実装完了まで開発ブロック(1-2日)
|
||||
|
||||
---
|
||||
|
||||
## 完了条件と検証方法
|
||||
|
||||
### Phase 84-4-A 完了
|
||||
|
||||
```bash
|
||||
# dev 環境での全テスト通過
|
||||
NYASH_PHI_DEV_FALLBACK=1 NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D"
|
||||
# 期待: 出力なし(全件通過)
|
||||
|
||||
# production 環境では依然としてエラー
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 期待: 4(依然として厳格)
|
||||
```
|
||||
|
||||
### Phase 84-4-B 完了
|
||||
|
||||
```bash
|
||||
# BoxCall 型登録の確認
|
||||
NYASH_BOXCALL_TYPE_TRACE=1 cargo test --release --lib mir_lowering_of_qmark_propagate 2>&1 | grep "boxcall_type"
|
||||
# 期待: [boxcall_type] registered ... の出力
|
||||
|
||||
# Case D 削減確認
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 期待: 1(await のみ残存)
|
||||
```
|
||||
|
||||
### Phase 84-4-C 完了
|
||||
|
||||
```bash
|
||||
# Await 型登録の確認
|
||||
NYASH_AWAIT_TYPE_TRACE=1 cargo test --release --lib test_lowering_await_expression 2>&1 | grep "await_type"
|
||||
# 期待: [await_type] registered ... の出力
|
||||
|
||||
# Case D 完全解決確認
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 期待: 0(全件解決)
|
||||
```
|
||||
|
||||
### Phase 84-5 準備完了
|
||||
|
||||
```bash
|
||||
# if_phi.rs 削除前の最終確認
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib
|
||||
# 期待: 全テスト通過(Case D panic なし)
|
||||
|
||||
# レガシーフォールバック使用確認
|
||||
cargo test --release --lib 2>&1 | grep "infer_type_from_phi_fallback"
|
||||
# 期待: 出力なし(もう使われていない)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## まとめ
|
||||
|
||||
**推奨実装パス**: Phase 84-4-A → Phase 84-4-B → Phase 84-4-C
|
||||
|
||||
**総実装時間**: 2-3日
|
||||
|
||||
**期待成果**:
|
||||
- ✅ Case D 4件 → 0件(100%削減)
|
||||
- ✅ if_phi.rs レガシーフォールバック削除準備完了
|
||||
- ✅ 型推論システムの完全箱化達成
|
||||
|
||||
**次のステップ**: Phase 84-5(if_phi.rs 完全削除)
|
||||
@ -1,375 +0,0 @@
|
||||
# Phase 84: Case D 詳細分析レポート
|
||||
|
||||
## 概要
|
||||
|
||||
Phase 83 で Case D が 20 件 → **15 件** に減少(MethodReturnHintBox 実装)。
|
||||
その後 Phase 84-1(Const 命令型アノテーション追加)で **12 件**、Phase 84-2(CopyTypePropagator 導入)で **9 件** まで削減された。
|
||||
|
||||
本レポート自体は「24 件あった調査時点」の分析ログとして残しつつ、
|
||||
現在は Const 欠如グループと単純な Copy チェーンは解消され、残りは主に PHI を含む複雑なパターンであることが判明している。
|
||||
|
||||
**重要な発見(当時)**: 主要な原因は **Const命令の型アノテーション欠如** である。
|
||||
**補足(現在)**: Const 命令については 40dfbc68 で修正済み、Copy 伝播については CopyTypePropagator(Phase 84-2)で整理済み。
|
||||
|
||||
---
|
||||
|
||||
## 実行環境
|
||||
|
||||
```bash
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1
|
||||
```
|
||||
|
||||
**テスト結果(当時)**: 471 passed; **52 failed** (うち Case D は24件)
|
||||
|
||||
---
|
||||
|
||||
## Case D 失敗一覧(24件)
|
||||
|
||||
| # | Test Name | Function | ValueId | 推測される原因 |
|
||||
|---|-----------|----------|---------|--------------|
|
||||
| 1 | test_lowering_await_expression | main | ValueId(2) | Await式の戻り値型 |
|
||||
| 2 | test_try_catch_compilation | main | ValueId(7) | Try-Catch式の戻り値型 |
|
||||
| 3 | loop_break_and_early_return_edge_copy | main | ValueId(50) | Loop exit後の型 |
|
||||
| 4 | loop_with_continue_and_break_edge_copy_merge | main | ValueId(56) | Loop exit後の型 |
|
||||
| 5 | vm_exec_break_inside_if | main | ValueId(27) | Loop break後の型 |
|
||||
| 6 | **mir_locals_uninitialized** | main | **ValueId(1)** | **return 0 の型** |
|
||||
| 7 | loop_inner_if_multilevel_edge_copy | main | ValueId(74) | Loop exit後の型 |
|
||||
| 8 | nested_loop_with_multi_continue_break_edge_copy_merge | main | ValueId(135) | Loop exit後の型 |
|
||||
| 9 | mir13_no_phi_if_merge_inserts_edge_copies_for_return | main | ValueId(17) | If merge後の型 |
|
||||
| 10 | loop_if_three_level_merge_edge_copy | main | ValueId(75) | Loop exit後の型 |
|
||||
| 11 | nested_if_inside_loop_edges_copy_from_exiting_blocks | main | ValueId(6) | Loop exit後の型 |
|
||||
| 12 | nested_loops_break_continue_mixed | main | ValueId(8) | Loop exit後の型 |
|
||||
| 13 | mir_funcscanner_skip_ws_min_verify_and_vm | main | ValueId(76) | 複雑な制御フロー |
|
||||
| 14-20 | mir_stageb_like_*_verifies | main | ValueId(1) | **return 系の型** |
|
||||
| 21 | mir_stage1_cli_emit_program_min_compiles_and_verifies | main | ValueId(7) | Stage-1パターン |
|
||||
| 22 | mir_stage1_cli_emit_program_min_exec_hits_type_error | main | ValueId(7) | Stage-1パターン |
|
||||
| 23 | mir_jsonscanbox_like_seek_array_end_verifies | main | ValueId(2) | 複雑なメソッド |
|
||||
| 24 | mir_stage1_cli_entry_like_pattern_verifies | main | ValueId(1) | **return 系の型** |
|
||||
|
||||
---
|
||||
|
||||
## パターン別分類
|
||||
|
||||
### GroupA: **Const命令型アノテーション欠如**(推定 14-16件)
|
||||
|
||||
#### 根本原因
|
||||
|
||||
`src/mir/builder/emission/constant.rs` で、**Integer/Bool/Float/Null/Void 定数は `value_types` に登録されない**:
|
||||
|
||||
```rust
|
||||
// ❌ 型アノテーションなし
|
||||
pub fn emit_integer(b: &mut MirBuilder, val: i64) -> ValueId {
|
||||
let dst = b.next_value_id();
|
||||
let _ = b.emit_instruction(MirInstruction::Const {
|
||||
dst,
|
||||
value: ConstValue::Integer(val),
|
||||
});
|
||||
dst // ← value_types に何も登録していない!
|
||||
}
|
||||
|
||||
// ✅ String のみ型アノテーションあり
|
||||
pub fn emit_string<S: Into<String>>(b: &mut MirBuilder, s: S) -> ValueId {
|
||||
let dst = b.next_value_id();
|
||||
let _ = b.emit_instruction(MirInstruction::Const {
|
||||
dst,
|
||||
value: ConstValue::String(s.into()),
|
||||
});
|
||||
// 🎯 Phase 3-A: String constant type annotation
|
||||
b.value_types.insert(dst, MirType::Box("StringBox".to_string()));
|
||||
b.value_origin_newbox.insert(dst, "StringBox".to_string());
|
||||
dst
|
||||
}
|
||||
```
|
||||
|
||||
#### 影響範囲
|
||||
|
||||
- `return 0` のような整数リテラル return
|
||||
- `return true`/`return false` のような真偽値 return
|
||||
- `return 3.14` のような浮動小数点 return
|
||||
- `return null` や `return void`
|
||||
|
||||
#### 該当テスト
|
||||
|
||||
- #6: mir_locals_uninitialized (`return 0`)
|
||||
- #14-20: mir_stageb_like_*_verifies (全て `return` 系)
|
||||
- #24: mir_stage1_cli_entry_like_pattern_verifies
|
||||
|
||||
---
|
||||
|
||||
### GroupB: **Copy命令型伝播不足**(推定 6-8件)
|
||||
|
||||
#### 根本原因
|
||||
|
||||
`Copy` 命令で値がコピーされた際、型情報が伝播しないケースがある。
|
||||
|
||||
`src/mir/builder/metadata/propagate.rs` には型伝播機能があるが、**すべての Copy 命令で呼ばれるわけではない**:
|
||||
|
||||
```rust
|
||||
// Phase 3: 型伝播(一部のケースのみ)
|
||||
if let Some(t) = builder.value_types.get(&src).cloned() {
|
||||
builder.value_types.insert(dst, t);
|
||||
}
|
||||
```
|
||||
|
||||
#### 影響範囲
|
||||
|
||||
- Loop exit 後の edge copy
|
||||
- If merge 後の edge copy
|
||||
- PHI 命令からの Copy
|
||||
|
||||
#### 該当テスト
|
||||
|
||||
- #3-5, #7-8, #10-12: Loop break/continue 後の edge copy
|
||||
- #9: If merge 後の edge copy
|
||||
- #11: Loop 内 If の edge copy
|
||||
|
||||
---
|
||||
|
||||
### GroupC: **PHI命令型推論不足**(推定 4-6件)
|
||||
|
||||
#### 根本原因
|
||||
|
||||
`GenericTypeResolver::resolve_from_phi()` は以下のケースで失敗する:
|
||||
|
||||
1. **ret_val が PHI の出力ではない**
|
||||
2. **PHI の incoming 値の型が不一致**
|
||||
3. **incoming 値の型が `value_types` に未登録**
|
||||
|
||||
```rust
|
||||
pub fn resolve_from_phi(
|
||||
function: &MirFunction,
|
||||
ret_val: ValueId,
|
||||
types: &BTreeMap<ValueId, MirType>,
|
||||
) -> Option<MirType> {
|
||||
for (_bid, bb) in function.blocks.iter() {
|
||||
for inst in bb.instructions.iter() {
|
||||
if let MirInstruction::Phi { dst, inputs, .. } = inst {
|
||||
if *dst == ret_val {
|
||||
let mut it = inputs.iter().filter_map(|(_, v)| types.get(v));
|
||||
if let Some(first) = it.next() {
|
||||
if it.all(|mt| mt == first) {
|
||||
return Some(first.clone()); // ← 全て同じ型の時のみ成功
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None // ← PHI が見つからない、または型不一致
|
||||
}
|
||||
```
|
||||
|
||||
#### 影響範囲
|
||||
|
||||
- 複雑な制御フロー(Await/Try-Catch)
|
||||
- 多段 PHI チェーン(PHI → Copy → PHI)
|
||||
- 型が異なる incoming 値を持つ PHI
|
||||
|
||||
#### 該当テスト
|
||||
|
||||
- #1: test_lowering_await_expression (Await式)
|
||||
- #2: test_try_catch_compilation (Try-Catch式)
|
||||
- #13: mir_funcscanner_skip_ws_min_verify_and_vm
|
||||
- #21-22: Stage-1 CLI パターン
|
||||
|
||||
---
|
||||
|
||||
### GroupD: **その他の命令型**(推定 2-4件)
|
||||
|
||||
#### 可能性のある原因
|
||||
|
||||
- **BoxCall/Call 命令の戻り値型** が未登録
|
||||
- **NewBox 命令の戻り値型** が未登録(稀)
|
||||
- **TypeOp 命令の戻り値型** が未登録
|
||||
- **UnaryOp/BinOp 命令の戻り値型** が一部未登録
|
||||
|
||||
#### 該当テスト
|
||||
|
||||
- #23: mir_jsonscanbox_like_seek_array_end_verifies (複雑なメソッド)
|
||||
|
||||
---
|
||||
|
||||
## 解決策の優先順位
|
||||
|
||||
### Phase 84-1: **Const命令型アノテーション追加**(最優先・最大効果)
|
||||
|
||||
**期待される効果**: 14-16件のテストが修正される(58-67%)
|
||||
|
||||
**実装箇所**: `src/mir/builder/emission/constant.rs`
|
||||
|
||||
```rust
|
||||
// ✅ 修正案
|
||||
pub fn emit_integer(b: &mut MirBuilder, val: i64) -> ValueId {
|
||||
let dst = b.next_value_id();
|
||||
let _ = b.emit_instruction(MirInstruction::Const {
|
||||
dst,
|
||||
value: ConstValue::Integer(val),
|
||||
});
|
||||
b.value_types.insert(dst, MirType::Integer); // ← 追加
|
||||
dst
|
||||
}
|
||||
|
||||
pub fn emit_bool(b: &mut MirBuilder, val: bool) -> ValueId {
|
||||
let dst = b.next_value_id();
|
||||
let _ = b.emit_instruction(MirInstruction::Const {
|
||||
dst,
|
||||
value: ConstValue::Bool(val),
|
||||
});
|
||||
b.value_types.insert(dst, MirType::Bool); // ← 追加
|
||||
dst
|
||||
}
|
||||
|
||||
pub fn emit_float(b: &mut MirBuilder, val: f64) -> ValueId {
|
||||
let dst = b.next_value_id();
|
||||
let _ = b.emit_instruction(MirInstruction::Const {
|
||||
dst,
|
||||
value: ConstValue::Float(val),
|
||||
});
|
||||
b.value_types.insert(dst, MirType::Float); // ← 追加
|
||||
dst
|
||||
}
|
||||
|
||||
pub fn emit_null(b: &mut MirBuilder) -> ValueId {
|
||||
let dst = b.next_value_id();
|
||||
let _ = b.emit_instruction(MirInstruction::Const {
|
||||
dst,
|
||||
value: ConstValue::Null,
|
||||
});
|
||||
b.value_types.insert(dst, MirType::Null); // ← 追加
|
||||
dst
|
||||
}
|
||||
|
||||
pub fn emit_void(b: &mut MirBuilder) -> ValueId {
|
||||
let dst = b.next_value_id();
|
||||
let _ = b.emit_instruction(MirInstruction::Const {
|
||||
dst,
|
||||
value: ConstValue::Void,
|
||||
});
|
||||
b.value_types.insert(dst, MirType::Void); // ← 追加
|
||||
dst
|
||||
}
|
||||
```
|
||||
|
||||
**リスク**: 極めて低い(String は既に実装済み)
|
||||
|
||||
---
|
||||
|
||||
### Phase 84-2: **Copy命令型伝播の徹底**(次点・中効果)
|
||||
|
||||
**期待される効果**: 6-8件のテストが修正される(25-33%)
|
||||
|
||||
**実装箇所**:
|
||||
- `src/mir/builder/ssa/local.rs` - Local変数のCopy
|
||||
- `src/mir/builder/metadata/propagate.rs` - 一般的な型伝播
|
||||
- `src/mir/phi_core/loop_phi.rs` - Loop exit edge copy
|
||||
- `src/mir/phi_core/if_phi.rs` - If merge edge copy
|
||||
|
||||
**実装方針**:
|
||||
1. すべての `emit_copy()` 呼び出し箇所を洗い出す
|
||||
2. 型伝播が欠けている箇所に `propagate_type()` を追加
|
||||
3. Edge copy 生成時に元の ValueId の型を継承
|
||||
|
||||
```rust
|
||||
// ✅ 修正案(例:loop_phi.rs)
|
||||
fn emit_edge_copy(builder: &mut MirBuilder, src: ValueId) -> ValueId {
|
||||
let dst = builder.next_value_id();
|
||||
builder.emit_instruction(MirInstruction::Copy { dst, src });
|
||||
|
||||
// 型伝播を追加
|
||||
if let Some(ty) = builder.value_types.get(&src).cloned() {
|
||||
builder.value_types.insert(dst, ty);
|
||||
}
|
||||
|
||||
dst
|
||||
}
|
||||
```
|
||||
|
||||
**リスク**: 中程度(既存の型伝播ロジックとの整合性確認が必要)
|
||||
|
||||
---
|
||||
|
||||
### Phase 84-3: **PHI型推論の強化**(長期・小効果)
|
||||
|
||||
**期待される効果**: 4-6件のテストが修正される(17-25%)
|
||||
|
||||
**実装方針**:
|
||||
1. **多段PHIチェーン対応**: PHI → Copy → PHI の解析
|
||||
2. **型不一致PHI対応**: 共通の上位型(例: Integer | Null → Any)
|
||||
3. **await/try-catch専用**: 特殊構文用の型ヒント
|
||||
|
||||
**実装箇所**: `src/mir/join_ir/lowering/generic_type_resolver.rs`
|
||||
|
||||
```rust
|
||||
// ✅ 拡張案
|
||||
pub fn resolve_from_phi_recursive(
|
||||
function: &MirFunction,
|
||||
ret_val: ValueId,
|
||||
types: &BTreeMap<ValueId, MirType>,
|
||||
depth: usize, // 再帰深度制限
|
||||
) -> Option<MirType> {
|
||||
if depth > 5 {
|
||||
return None; // 無限ループ防止
|
||||
}
|
||||
|
||||
// 1. 直接 PHI を探す
|
||||
if let Some(ty) = resolve_from_phi(function, ret_val, types) {
|
||||
return Some(ty);
|
||||
}
|
||||
|
||||
// 2. Copy 経由で PHI を探す
|
||||
for (_bid, bb) in function.blocks.iter() {
|
||||
for inst in bb.instructions.iter() {
|
||||
if let MirInstruction::Copy { dst, src } = inst {
|
||||
if *dst == ret_val {
|
||||
return resolve_from_phi_recursive(function, *src, types, depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
```
|
||||
|
||||
**リスク**: 高(再帰的解析のパフォーマンスと正確性)
|
||||
|
||||
---
|
||||
|
||||
## アクションアイテム
|
||||
|
||||
### 即座に実装すべき項目
|
||||
|
||||
1. **Phase 84-1 実装** (最優先)
|
||||
- `constant.rs` の 5 関数に型アノテーション追加
|
||||
- テスト実行して 14-16 件の修正を確認
|
||||
- 期待: Case D が 24件 → 8-10件に削減
|
||||
|
||||
2. **Phase 84-2 実装** (次点)
|
||||
- Copy 命令の型伝播を徹底
|
||||
- Edge copy 専用のヘルパー関数を作成
|
||||
- 期待: Case D が 8-10件 → 2-4件に削減
|
||||
|
||||
### 後回しでも良い項目
|
||||
|
||||
3. **Phase 84-3 検討** (長期)
|
||||
- 多段 PHI チェーンが本当に必要か検証
|
||||
- await/try-catch の型推論を専用実装で対応
|
||||
- 期待: Case D が 2-4件 → 0件(完全解決)
|
||||
|
||||
---
|
||||
|
||||
## まとめ
|
||||
|
||||
**Case D の主要原因**:
|
||||
1. **Const命令の型アノテーション欠如** (58-67%)
|
||||
2. **Copy命令の型伝播不足** (25-33%)
|
||||
3. **PHI型推論の限界** (17-25%)
|
||||
|
||||
**推奨アプローチ**:
|
||||
- Phase 84-1 を即座に実装(1-2時間で完了、大幅改善)
|
||||
- Phase 84-2 を段階的に実装(1-2日で完了、ほぼ完全解決)
|
||||
- Phase 84-3 は残存ケースを見てから判断
|
||||
|
||||
**期待される最終結果**:
|
||||
- Case D: 24件 → **0-2件**(90-100%解決)
|
||||
- テスト成功率: 471/523 (90%) → **519-521/523 (99-100%)**
|
||||
@ -1,237 +0,0 @@
|
||||
# Phase 84: Case D 完全解決ロードマップ
|
||||
|
||||
## 現在の状況
|
||||
|
||||
```
|
||||
Phase 84-2 完了: 12件 → 9件(25%削減)
|
||||
残り: 9件
|
||||
|
||||
内訳:
|
||||
- GroupA (Loop 制御フロー): 7件
|
||||
- GroupB (多段 PHI): 2件
|
||||
- GroupC (await 特殊): 1件
|
||||
```
|
||||
|
||||
## ドキュメント一覧
|
||||
|
||||
### 📊 サマリー
|
||||
|
||||
- **[Phase 84-2 サマリー](./phase84-2-summary.md)** - 実装完了報告と次のステップ
|
||||
- **[Phase 84-2 テスト一覧](./phase84-2-test-list.md)** - クイックリファレンス表
|
||||
|
||||
### 📖 詳細分析
|
||||
|
||||
- **[Phase 84-2 詳細調査](./phase84-2-case-d-investigation.md)** - 9件の分類と解決策提案
|
||||
- **[Phase 84-2 失敗パターン](./phase84-2-failure-patterns.md)** - 各パターンのコード例と MIR 構造
|
||||
|
||||
### 🔧 実装資料
|
||||
|
||||
- **[CopyTypePropagator 実装](../../../src/mir/phi_core/copy_type_propagator.rs)** - Phase 84-2 で実装
|
||||
- **[GenericTypeResolver](../../../src/mir/join_ir/lowering/generic_type_resolver.rs)** - Phase 84-3/4 で拡張予定
|
||||
- **[lifecycle.rs](../../../src/mir/builder/lifecycle.rs)** - 型推論統合箇所
|
||||
|
||||
## クイックリンク
|
||||
|
||||
### 🎯 次のタスク
|
||||
|
||||
**Phase 84-3: Edge Copy 追跡 PHI 型推論**
|
||||
- 目標: GroupA の 7件を解決
|
||||
- 期待: 9件 → 2件(78%削減)
|
||||
- 期間: 1-2日
|
||||
|
||||
**実装内容**:
|
||||
```rust
|
||||
// GenericTypeResolver に追加
|
||||
pub fn resolve_from_phi_with_copy_trace(
|
||||
function: &MirFunction,
|
||||
ret_val: ValueId,
|
||||
types: &BTreeMap<ValueId, MirType>,
|
||||
) -> Option<MirType> {
|
||||
// PHI の incoming 値から Copy を遡る
|
||||
for (_, incoming_val) in phi_inputs {
|
||||
if let Some(src) = find_copy_src(function, incoming_val) {
|
||||
if let Some(ty) = types.get(&src) {
|
||||
return Some(ty.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
```
|
||||
|
||||
### 🧪 テスト実行
|
||||
|
||||
```bash
|
||||
# 全 Case D 確認
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D"
|
||||
|
||||
# GroupA のみ
|
||||
cargo test --release --lib loop_continue_break
|
||||
cargo test --release --lib loop_nested
|
||||
cargo test --release --lib loop_return
|
||||
cargo test --release --lib vm_exec_break
|
||||
|
||||
# GroupB のみ
|
||||
cargo test --release --lib mir_stage1_cli
|
||||
|
||||
# GroupC のみ
|
||||
cargo test --release --lib test_lowering_await
|
||||
```
|
||||
|
||||
## 完了条件
|
||||
|
||||
### Phase 84-3 完了
|
||||
|
||||
```bash
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 期待: 2 (GroupB のみ残存)
|
||||
```
|
||||
|
||||
### Phase 84-4 完了
|
||||
|
||||
```bash
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 期待: 1 (GroupC のみ残存)
|
||||
```
|
||||
|
||||
### Phase 84-5 完了
|
||||
|
||||
```bash
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D"
|
||||
# 期待: 出力なし(0件)
|
||||
|
||||
cargo test --release --lib
|
||||
# 期待: test result: ok
|
||||
```
|
||||
|
||||
## タイムライン
|
||||
|
||||
| Phase | 目標 | 期間 | 削減数 | 残存数 |
|
||||
|-------|-----|-----|-------|-------|
|
||||
| 84-1 | PHI Fallback 無効化テスト | 完了 | - | 12件 |
|
||||
| 84-2 | CopyTypePropagator 実装 | 完了 ✅ | 3件 | 9件 |
|
||||
| 84-3 | Edge Copy 追跡 PHI 型推論 | 1-2日 | 7件 | 2件 |
|
||||
| 84-4 | 多段 PHI 型推論 | 1-2日 | 2件 | 1件 |
|
||||
| 84-5 | await 暫定対応 | 30分 | 1件 | 0件 |
|
||||
|
||||
**合計**: 2-4日で Case D 完全解決見込み
|
||||
|
||||
## グループ別詳細
|
||||
|
||||
### GroupA: Loop 制御フロー PHI(7件)
|
||||
|
||||
**パターン**: Loop + continue/break による Edge Copy 合流
|
||||
|
||||
**テスト一覧**:
|
||||
1. `loop_with_continue_and_break_edge_copy_merge` (ValueId 56)
|
||||
2. `nested_loop_with_multi_continue_break_edge_copy_merge` (ValueId 135)
|
||||
3. `loop_inner_if_multilevel_edge_copy` (ValueId 74)
|
||||
4. `loop_break_and_early_return_edge_copy` (ValueId 40)
|
||||
5. `vm_exec_break_inside_if` (ValueId 27)
|
||||
6. `loop_if_three_level_merge_edge_copy` (ValueId 75)
|
||||
7. (7件合計)
|
||||
|
||||
**解決策**: Edge Copy 追跡 PHI 型推論(Phase 84-3)
|
||||
|
||||
**詳細**: [失敗パターン - GroupA](./phase84-2-failure-patterns.md#groupa-loop-制御フロー-phi7件)
|
||||
|
||||
### GroupB: 多段 PHI 型推論(2件)
|
||||
|
||||
**パターン**: 複数の PHI 命令が連鎖
|
||||
|
||||
**テスト一覧**:
|
||||
1. `mir_stage1_cli_emit_program_min_exec_hits_type_error` (ValueId 7)
|
||||
2. `mir_stage1_cli_emit_program_min_compiles_and_verifies` (ValueId 7)
|
||||
|
||||
**解決策**: 再帰的 PHI 型推論(Phase 84-4)
|
||||
|
||||
**詳細**: [失敗パターン - GroupB](./phase84-2-failure-patterns.md#groupb-多段-phi-型推論2件)
|
||||
|
||||
### GroupC: await 特殊パターン(1件)
|
||||
|
||||
**パターン**: await 式の MIR lowering
|
||||
|
||||
**テスト**:
|
||||
1. `test_lowering_await_expression` (ValueId 2)
|
||||
|
||||
**解決策**: await 特殊ケース処理(Phase 84-5)
|
||||
|
||||
**詳細**: [失敗パターン - GroupC](./phase84-2-failure-patterns.md#groupc-await-特殊パターン1件)
|
||||
|
||||
## ChatGPT Pro 設計相談ポイント
|
||||
|
||||
### 相談1: Edge Copy 追跡の最適化
|
||||
|
||||
- Copy チェーンの追跡深度は 10 で十分か?
|
||||
- 循環 Copy 検出は必要か?
|
||||
- パフォーマンス最適化(キャッシュ戦略)
|
||||
|
||||
### 相談2: 多段 PHI の循環検出
|
||||
|
||||
- 循環 PHI は実際に発生するか?
|
||||
- 発生する場合の処理方法(エラー or Unknown)
|
||||
- visited セットの最適なデータ構造
|
||||
|
||||
### 相談3: await 型推論の長期戦略
|
||||
|
||||
- Phase 67+ async/await システムの型推論設計
|
||||
- Safepoint/Checkpoint 命令の型情報統合方法
|
||||
- 現在の暫定対応が将来の実装を妨げないか
|
||||
|
||||
## 実装チェックリスト
|
||||
|
||||
### Phase 84-3: Edge Copy 追跡
|
||||
|
||||
- [ ] `GenericTypeResolver::resolve_from_phi_with_copy_trace()` 実装
|
||||
- [ ] `find_copy_src()` ヘルパー関数実装
|
||||
- [ ] `trace_copy_chain()` ヘルパー関数実装
|
||||
- [ ] lifecycle.rs 統合(371行目付近)
|
||||
- [ ] テスト実行: GroupA の 7件を確認
|
||||
- [ ] ドキュメント更新
|
||||
|
||||
### Phase 84-4: 多段 PHI 推論
|
||||
|
||||
- [ ] `GenericTypeResolver::resolve_from_phi_recursive()` 実装
|
||||
- [ ] 循環検出ロジック実装(HashSet<ValueId>)
|
||||
- [ ] lifecycle.rs 統合
|
||||
- [ ] テスト実行: GroupB の 2件を確認
|
||||
- [ ] ドキュメント更新
|
||||
|
||||
### Phase 84-5: await 暫定対応
|
||||
|
||||
- [ ] lifecycle.rs に await 特殊ケース追加
|
||||
- [ ] テスト実行: GroupC の 1件を確認
|
||||
- [ ] ドキュメント更新
|
||||
- [ ] Phase 67+ 長期計画メモ作成
|
||||
|
||||
## 関連リソース
|
||||
|
||||
### 過去の分析
|
||||
|
||||
- [Phase 84-1 Case D 分析](./phase84-case-d-detailed-analysis.md) - 最初の 12件分析
|
||||
|
||||
### 実装ファイル
|
||||
|
||||
- `src/mir/phi_core/copy_type_propagator.rs` - Phase 84-2 実装
|
||||
- `src/mir/join_ir/lowering/generic_type_resolver.rs` - 拡張予定
|
||||
- `src/mir/builder/lifecycle.rs` - 型推論統合箇所(371行目)
|
||||
|
||||
### テストファイル
|
||||
|
||||
- `src/tests/loop_continue_break_no_phi_tests.rs` - GroupA-1
|
||||
- `src/tests/loop_nested_no_phi_tests.rs` - GroupA-2,3
|
||||
- `src/tests/loop_return_no_phi_tests.rs` - GroupA-4,6
|
||||
- `src/tests/mir_ctrlflow_break_continue.rs` - GroupA-5
|
||||
- `src/tests/mir_stage1_cli_emit_program_min.rs` - GroupB
|
||||
- `src/mir/mod.rs:363` - GroupC
|
||||
|
||||
## まとめ
|
||||
|
||||
Phase 84-2 の CopyTypePropagator により 12件 → 9件に削減成功。
|
||||
残り 9件は 3つのパターンに分類され、各々に明確な解決策が提案済み。
|
||||
|
||||
Phase 84-3/4/5 の実装により、**Case D を完全解決** できる見込み。
|
||||
|
||||
---
|
||||
|
||||
**次のアクション**: Phase 84-3 の Edge Copy 追跡 PHI 型推論を実装
|
||||
@ -1,184 +0,0 @@
|
||||
# Phase 84: Case D 分析サマリー(エグゼクティブサマリー)
|
||||
|
||||
## TL;DR
|
||||
|
||||
**現状**: Case D 失敗 0 件(Phase 83〜84-4 実装後、dev ガード付きテストで panic なし)
|
||||
|
||||
**主要原因(解消済み)**:
|
||||
- Const 命令の型アノテーション欠如(Phase 84-1 で修正)
|
||||
- Copy チェーンでの型伝播不足(Phase 84-2 で修正)
|
||||
- PHI + Copy グラフ上の型集約不足(Phase 84-3 で PhiTypeResolver 導入)
|
||||
- BoxCall/Await/QMark の戻り値型未登録(Phase 84-4-B で修正)
|
||||
|
||||
**対応状況**:
|
||||
- Phase 83: MethodReturnHintBox(P3-D)実装で 20 件 → 15 件
|
||||
- Phase 84-1: Const 命令型アノテーション追加で 15 件 → 12 件
|
||||
- Phase 84-2: CopyTypePropagator 導入で 12 件 → 9 件
|
||||
- Phase 84-3: PhiTypeResolver 導入で 9 件 → 4 件
|
||||
- Phase 84-4-B: BoxCall 戻り値型登録で 4 件 → 0 件
|
||||
|
||||
**次タスク候補**: if_phi フォールバックの完全削除(Phase 84-5 / Phase 82 最終仕上げ)
|
||||
|
||||
---
|
||||
|
||||
## 問題の核心
|
||||
|
||||
### (初期段階)Const 命令の型アノテーション欠如
|
||||
|
||||
```rust
|
||||
// Integer/Bool/Float/Null/Void は型を登録しない
|
||||
pub fn emit_integer(b: &mut MirBuilder, val: i64) -> ValueId {
|
||||
let dst = b.next_value_id();
|
||||
b.emit_instruction(MirInstruction::Const {
|
||||
dst,
|
||||
value: ConstValue::Integer(val),
|
||||
});
|
||||
dst // ← value_types に何も登録していない!
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ 修正版
|
||||
|
||||
```rust
|
||||
pub fn emit_integer(b: &mut MirBuilder, val: i64) -> ValueId {
|
||||
let dst = b.next_value_id();
|
||||
b.emit_instruction(MirInstruction::Const {
|
||||
dst,
|
||||
value: ConstValue::Integer(val),
|
||||
});
|
||||
b.value_types.insert(dst, MirType::Integer); // ← この1行を追加
|
||||
dst
|
||||
}
|
||||
```
|
||||
|
||||
**同様の修正を `emit_bool`/`emit_float`/`emit_null`/`emit_void` にも適用**
|
||||
|
||||
---
|
||||
|
||||
## 影響範囲
|
||||
|
||||
### 修正されるテスト(推定 14-16 件)
|
||||
|
||||
- `mir_locals_uninitialized` - `return 0` の型
|
||||
- `mir_stageb_like_*_verifies` (7件) - 全て return 系
|
||||
- `mir_stage1_cli_entry_like_pattern_verifies` - return 系
|
||||
- 他の return リテラルを含むテスト
|
||||
|
||||
### 残存する問題(Phase 84 終了時点)
|
||||
|
||||
- Case D panic は dev ガード付きテストでも 0 件。
|
||||
- 残っている課題は「if_phi フォールバックそのものの削除」と、その前提となる `infer_type_from_phi*` callsite の整理のみ。
|
||||
|
||||
---
|
||||
|
||||
## 実装計画
|
||||
|
||||
### Phase 84-1: Const命令型アノテーション(完了)
|
||||
|
||||
**Status**: ✅ 実装完了(40dfbc68)
|
||||
|
||||
**ファイル**: `src/mir/builder/emission/constant.rs`
|
||||
|
||||
**変更箇所**: 5 関数 × 1 行 = **5 行追加**
|
||||
|
||||
**効果**: Case D が 15 件 → 12 件(Const 欠如グループは解消)
|
||||
|
||||
**所要時間**: 1-2 時間(テスト含む)
|
||||
|
||||
**リスク**: 極めて低い(String は既に実装済み)
|
||||
|
||||
### Phase 84-2: Copy命令型伝播(完了)
|
||||
|
||||
**Status**: ✅ 実装完了(CopyTypePropagator 導入)
|
||||
|
||||
**ファイル**:
|
||||
- `src/mir/phi_core/copy_type_propagator.rs`(新規箱)
|
||||
- `src/mir/phi_core/mod.rs`
|
||||
- `src/mir/builder/lifecycle.rs`
|
||||
|
||||
**内容**:
|
||||
- `CopyTypePropagator` が MIR 関数内の `Copy { dst, src }` を固定点ループで走査し、
|
||||
`value_types[src]` の型を `value_types[dst]` に伝播(Unknown のみ上書き)。
|
||||
- `finalize_module` 内で return 型推論の前に実行。
|
||||
|
||||
**効果**:
|
||||
- ベースラインテスト: 489 passed, 34 failed → 494 passed, 33 failed(+5/-1)。
|
||||
- Case D: 12 件 → 9 件(約 25% 削減)。
|
||||
|
||||
**箱理論チェック**:
|
||||
- 単一責務(Copy の型伝播のみ)、副作用は `value_types` 更新に限定、PHI/JoinIR には非依存。
|
||||
|
||||
### Phase 84-3: PHI型推論強化(長期)
|
||||
|
||||
**Status**: ✅ PhiTypeResolver 導入完了(PHI + Copy グラフの安全な型推論)
|
||||
|
||||
**内容**:
|
||||
- `PhiTypeResolver` が `Copy`/`Phi` グラフを DFS/BFS で辿り、末端の base 定義型が 1 種類に揃う場合にのみ MirType を返す。
|
||||
- lifecycle.rs の return 型推論フローに統合し、P3-D/Const/CopyTypePropagator で埋まらないケースの一部を吸収。
|
||||
|
||||
**効果**:
|
||||
- Case D: 9 件 → 4 件(約 56% 削減)。
|
||||
- 残り 4 件は BoxCall/Await/QMark 戻り値型が `value_types` に登録されていないため、PhiTypeResolver から見ても「base 型が不明」のケースとして扱われている。
|
||||
|
||||
### Phase 84-4: BoxCall/Await/QMark 戻り値型登録(完了)
|
||||
|
||||
**Status**: ✅ 実装完了(Phase 84-4-B)
|
||||
|
||||
**ファイル**:
|
||||
- `src/mir/builder/utils.rs`(新規)
|
||||
- `infer_boxcall_return_type()` ヘルパー関数を追加(約 75 行)
|
||||
- 27 個のビルトイン Box メソッドに対する戻り値型マッピングを集約
|
||||
- BoxCall lowering 呼び出し元(`emit_box_or_plugin_call` 相当)で、戻り値型を `value_types` に登録
|
||||
|
||||
**対応メソッド**(抜粋):
|
||||
- StringBox / IntegerBox / BoolBox / ArrayBox / MapBox / Result-like(QMark 相当)/ Stage1CliBox など、計 27 メソッド。
|
||||
|
||||
**効果**:
|
||||
- `NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib` 実行時の Case D panic が 4 件 → 0 件に。
|
||||
- Await/QMark 系テストは BoxCall 経路の型登録で全て解消され、追加の Await 専用実装は不要となった。
|
||||
|
||||
---
|
||||
|
||||
## 推奨アクション
|
||||
|
||||
1. **Phase 84-1 は完了済み**
|
||||
- Const 命令の型アノテーション欠如グループは解消済み。
|
||||
|
||||
2. **Phase 84-2 も完了済み**
|
||||
- Copy チェーンだけで説明できる Case D は削減済みで、残りは PHI 主体の複雑ケースに集中。
|
||||
|
||||
3. **Phase 84-3(PhiTypeResolver)は導入済み**
|
||||
- PHI + Copy グラフ上で安全に決められるケースは吸収済みで、残り 4 件は「base 定義側に型がない」という別レイヤの問題に集約された。
|
||||
|
||||
---
|
||||
|
||||
## 期待される最終結果
|
||||
|
||||
| Phase | Case D 件数 | 修正率 | 備考 |
|
||||
|--------------|------------|--------|-----|
|
||||
| Phase 82 終了時 | 20 件 | - | lifecycle 修正後 |
|
||||
| Phase 83 後 | 15 件 | 25% | MethodReturnHintBox(P3-D) |
|
||||
| Phase 84-1 後 | 12 件 | 40% | Const 型アノテーション |
|
||||
| Phase 84-2 後 | 9 件 | 55% | CopyTypePropagator |
|
||||
| Phase 84-3 後 | 4 件 | 80% | PhiTypeResolver(PHI + Copy グラフ) |
|
||||
| Phase 84-4 後 | 0 件 | 100% | BoxCall/Await/QMark 型登録 |
|
||||
|
||||
**最終目標**: Case D を 0 件にし、`infer_type_from_phi*` を本線から外せる状態を達成済み。次ステップで if_phi フォールバック(約 300 行)を構造的に削除する。
|
||||
|
||||
---
|
||||
|
||||
## Phase 84-4 方針(案)
|
||||
|
||||
- Phase 84-4-A: dev フォールバック
|
||||
- 開発時のみ PHI fallback を許可するガードを追加し、自分用のデバッグラインを確保。
|
||||
- Phase 84-4-B: BoxCall 戻り値型の登録
|
||||
- BoxCall lowering で戻り値型を `value_types` に登録し、Stage1 CLI 系 2 テストを根本解決。
|
||||
- Phase 84-4-C: Await/QMark 戻り値型の処理
|
||||
- await/QMark lowering で中間値の型を登録し、await/QMark テスト 2 件を解消。
|
||||
|
||||
---
|
||||
|
||||
## 詳細分析
|
||||
|
||||
完全な分析レポートは以下を参照:
|
||||
- [phase84-case-d-detailed-analysis.md](./phase84-case-d-detailed-analysis.md)
|
||||
@ -1,427 +0,0 @@
|
||||
# Phase 84: PHI 型推論完全箱化プロジェクト — 完全ガイド
|
||||
|
||||
## 📚 ドキュメント索引
|
||||
|
||||
### 🎉 Phase 84-4 完了報告(最新)✅
|
||||
|
||||
1. **[Phase 84-4 完了報告書](phase84-4-completion-report.md)** ⭐⭐⭐ **必読**
|
||||
- **Case D: 4件 → 0件(100%完全解決!)**
|
||||
- BoxCall 型情報登録実装完了
|
||||
- Phase 84-4-C(Await)不要(BoxCall 経路で解決)
|
||||
- 型推論システムの完全箱化達成
|
||||
|
||||
### Phase 84-3 完了報告(参考)
|
||||
|
||||
2. **[Phase 84-3 サマリー](phase84-3-summary.md)**
|
||||
- 削減実績: 9件 → 4件(56%削減)
|
||||
- PhiTypeResolver 実装成果
|
||||
- Phase 84-4 への推奨
|
||||
|
||||
3. **[残り 4件の完全調査](phase84-3-remaining-4-analysis.md)**
|
||||
- 各テストの詳細分析
|
||||
- 失敗パターン分類
|
||||
- なぜ PhiTypeResolver で解決できないか
|
||||
|
||||
4. **[Phase 84-4 実装推奨](phase84-4-implementation-recommendation.md)**
|
||||
- BoxCall 型情報登録の実装方法
|
||||
- dev フォールバック実装
|
||||
- Await 型情報特殊処理
|
||||
|
||||
### Phase 84-2 記録(参考)
|
||||
|
||||
4. **[Case D 残り 9件の調査](phase84-2-case-d-investigation.md)**
|
||||
- Phase 84-2 時点の分析
|
||||
- GroupA/B/C 分類
|
||||
- CopyTypePropagator 実装提案
|
||||
|
||||
5. **[Phase 84-2 詳細分析](phase84-case-d-detailed-analysis.md)**
|
||||
- 12件 → 9件削減の詳細
|
||||
- テスト別失敗パターン
|
||||
|
||||
### 初期調査(アーカイブ)
|
||||
|
||||
6. **[Case D インデックス](phase84-case-d-index.md)**
|
||||
- Phase 84-1 の初期調査
|
||||
- 12件の失敗パターン発見
|
||||
|
||||
## 🎯 Phase 84 の全体像
|
||||
|
||||
### 目標
|
||||
|
||||
**if_phi.rs レガシーフォールバックの完全削除** ✅ **達成済み**
|
||||
|
||||
- 初期状態: 15件の Case D 失敗
|
||||
- **Phase 84-4 完了: 0件(100%削減達成!)** ✅
|
||||
- 最終目標: 0件(100%削減) ✅ **達成**
|
||||
|
||||
### 実装ロードマップ
|
||||
|
||||
```
|
||||
Phase 82: フォールバック検出実装
|
||||
↓ (Case D: 15件検出)
|
||||
Phase 84-1: 初期調査・パターン分類
|
||||
↓ (15件 → 12件, 20%削減)
|
||||
Phase 84-2: CopyTypePropagator 実装
|
||||
↓ (12件 → 9件, 25%削減)
|
||||
Phase 84-3: PhiTypeResolver 実装 ✅ 完了
|
||||
↓ (9件 → 4件, 56%削減)
|
||||
Phase 84-4: BoxCall 型情報登録 ✅ 完了
|
||||
↓ (4件 → 0件, 100%削減達成!)
|
||||
Phase 84-5: if_phi.rs 完全削除 ✅ 完了
|
||||
↓
|
||||
✨ 型推論システム完全箱化達成 ✅
|
||||
```
|
||||
|
||||
## 📊 削減実績の詳細
|
||||
|
||||
### Phase 別削減内訳
|
||||
|
||||
| Phase | 実装内容 | 削減件数 | 残存件数 | 削減率 | 累積削減率 |
|
||||
|-------|---------|---------|---------|--------|-----------|
|
||||
| Phase 82 | 初期検出 | - | 15件 | - | - |
|
||||
| Phase 84-1 | Const 型注釈 | 3件 | 12件 | 20% | 20% |
|
||||
| Phase 84-2 | CopyTypePropagator | 3件 | 9件 | 25% | 40% |
|
||||
| Phase 84-3 | PhiTypeResolver | 5件 | 4件 | 56% | 73% |
|
||||
| **Phase 84-4** | **BoxCall 型情報登録** | **4件** | **0件** ✅ | **100%** | **100%** ✅ |
|
||||
|
||||
### パターン別解決状況
|
||||
|
||||
| パターン | 件数(初期) | Phase 84-2 後 | Phase 84-3 後 | Phase 84-4 実績 |
|
||||
|---------|------------|--------------|--------------|----------------|
|
||||
| GroupA: Loop 制御フロー | 7件 | 7件 | **0件** ✅ | **0件** ✅ |
|
||||
| GroupB: Stage1Cli 複雑型推論 | 2件 | 2件 | 2件 | **0件** ✅ |
|
||||
| GroupC: await 特殊構文 | 1件 | 1件 | 1件 | **0件** ✅ |
|
||||
| GroupD: QMark 特殊構文 | 0件 | 0件 | 1件(新規) | **0件** ✅ |
|
||||
| **合計** | **10件** | **10件** | **4件** | **0件** ✅ |
|
||||
|
||||
## 🔬 技術的成果
|
||||
|
||||
### Phase 84-3 で実装した箱
|
||||
|
||||
**PhiTypeResolver** (`src/mir/phi_core/phi_type_resolver.rs`)
|
||||
|
||||
**責務**: PHI + Copy グラフを辿って、安全に型を決められるときだけ MirType を返す
|
||||
|
||||
**アルゴリズム**:
|
||||
1. DFS/BFS で root から探索開始
|
||||
2. Copy → src へ進む
|
||||
3. Phi → 各 incoming ValueId へ進む
|
||||
4. それ以外(Const/Call/BoxCall/NewBox...)は base 定義
|
||||
5. base_types 集合を収集し、1 種類なら返す
|
||||
|
||||
**安全装置**:
|
||||
- visited セットで同じ ValueId を 2 回以上辿らない(ループ防止)
|
||||
- 探索上限で打ち切り(max_visits)
|
||||
|
||||
### 箱理論の実現
|
||||
|
||||
```
|
||||
[型生成レイヤー] - 型を作る
|
||||
├─ emit_const()
|
||||
├─ emit_box_call() ← Phase 84-4-B で型登録を追加
|
||||
└─ build_await_expression() ← Phase 84-4-C で型登録を追加
|
||||
|
||||
[型伝播レイヤー] - 型を広げる
|
||||
├─ CopyTypePropagator ← Phase 84-2
|
||||
└─ PhiTypeResolver ← Phase 84-3 ✅
|
||||
|
||||
[統合レイヤー] - 全体を調整
|
||||
└─ GenericTypeResolver
|
||||
|
||||
[レガシー] - 削除予定
|
||||
└─ if_phi.rs フォールバック ← Phase 84-5 で削除
|
||||
```
|
||||
|
||||
## 🎯 Phase 84-4 実装ガイド
|
||||
|
||||
### 推奨実装順序
|
||||
|
||||
#### ステップ1: dev フォールバック(0.5日)
|
||||
|
||||
**目的**: 開発環境の即座のアンブロック
|
||||
|
||||
**実装**: `src/mir/builder/lifecycle.rs`
|
||||
```rust
|
||||
if should_enable_dev_fallback() {
|
||||
if is_base_definition_with_missing_type(function, ret_val) {
|
||||
return Ok(MirType::Unknown);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**環境変数**: `NYASH_PHI_DEV_FALLBACK=1`
|
||||
|
||||
#### ステップ2: BoxCall 型情報登録(1-2日)
|
||||
|
||||
**目的**: GroupB(2件)+ GroupD(1件)の根本解決
|
||||
|
||||
**実装**: `src/mir/builder/builder_calls.rs`
|
||||
```rust
|
||||
pub fn emit_box_call(...) -> Result<ValueId, String> {
|
||||
let dst = self.next_value_id();
|
||||
self.emit_instruction(MirInstruction::BoxCall { ... })?;
|
||||
|
||||
// 新機能: 戻り値型を推論して登録
|
||||
if let Some(ret_ty) = self.infer_boxcall_return_type(box_val, method, &args) {
|
||||
self.value_types.insert(dst, ret_ty);
|
||||
}
|
||||
|
||||
Ok(dst)
|
||||
}
|
||||
```
|
||||
|
||||
#### ステップ3: Await 型情報特殊処理(0.5日)
|
||||
|
||||
**目的**: GroupC(1件)の暫定解決
|
||||
|
||||
**実装**: `src/mir/builder/stmts.rs`
|
||||
```rust
|
||||
pub(super) fn build_await_expression(...) -> Result<ValueId, String> {
|
||||
let result_id = self.next_value_id();
|
||||
|
||||
// 新機能: Unknown として型登録
|
||||
self.value_types.insert(result_id, MirType::Unknown);
|
||||
|
||||
self.emit_instruction(MirInstruction::Await { ... })?;
|
||||
Ok(result_id)
|
||||
}
|
||||
```
|
||||
|
||||
### 検証方法
|
||||
|
||||
```bash
|
||||
# ステップ1 完了確認
|
||||
NYASH_PHI_DEV_FALLBACK=1 NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D"
|
||||
# 期待: 出力なし
|
||||
|
||||
# ステップ2 完了確認
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 期待: 1(await のみ)
|
||||
|
||||
# ステップ3 完了確認
|
||||
NYASH_PHI_FALLBACK_DISABLED=1 cargo test --release --lib 2>&1 | grep "Case D" | wc -l
|
||||
# 期待: 0(全件解決)
|
||||
```
|
||||
|
||||
## 📝 関連ファイル
|
||||
|
||||
### 実装ファイル
|
||||
|
||||
- `src/mir/phi_core/phi_type_resolver.rs` - Phase 84-3 実装
|
||||
- `src/mir/phi_core/copy_type_propagator.rs` - Phase 84-2 実装
|
||||
- `src/mir/join_ir/lowering/generic_type_resolver.rs` - 統合調整
|
||||
- `src/mir/builder/lifecycle.rs` - 型推論エントリーポイント
|
||||
- `src/mir/join_ir/lowering/if_phi.rs` - 削除予定レガシー
|
||||
|
||||
### Phase 84-4 で修正するファイル
|
||||
|
||||
- `src/mir/builder/lifecycle.rs` - dev フォールバック追加
|
||||
- `src/mir/builder/builder_calls.rs` - BoxCall 型登録追加
|
||||
- `src/mir/builder/stmts.rs` - Await 型登録追加
|
||||
|
||||
## 🚀 次のアクション
|
||||
|
||||
### 優先度1: Phase 84-4-A 実装(即実装推奨)
|
||||
|
||||
**目的**: 開発環境の即座のアンブロック
|
||||
|
||||
**実装時間**: 0.5日
|
||||
|
||||
**参考**: [Phase 84-4 実装推奨](phase84-4-implementation-recommendation.md#phase-84-4-a-dev-フォールバック推奨-即実装)
|
||||
|
||||
### 優先度2: Phase 84-4-B 実装(根本解決)
|
||||
|
||||
**目的**: BoxCall 型情報の完全追跡
|
||||
|
||||
**実装時間**: 1-2日
|
||||
|
||||
**参考**: [Phase 84-4 実装推奨](phase84-4-implementation-recommendation.md#phase-84-4-b-boxcall-型情報登録推奨-根本解決)
|
||||
|
||||
### 優先度3: Phase 84-4-C 実装(完全解決)
|
||||
|
||||
**目的**: Await 型情報の暫定対応
|
||||
|
||||
**実装時間**: 0.5日
|
||||
|
||||
**参考**: [Phase 84-4 実装推奨](phase84-4-implementation-recommendation.md#phase-84-4-c-await-型情報特殊処理推奨-暫定対応)
|
||||
|
||||
### Phase 84-5: if_phi.rs 削除(最終ゴール)
|
||||
|
||||
**前提条件**: Phase 84-4 完了(Case D = 0件)
|
||||
|
||||
**実装内容**:
|
||||
1. `src/mir/join_ir/lowering/if_phi.rs` 完全削除(約 300行)
|
||||
2. `GenericTypeResolver` の if_phi 呼び出し削除
|
||||
3. `lifecycle.rs` の Case D 処理を全て削除
|
||||
4. ドキュメント更新: Phase 82-84 完了宣言
|
||||
|
||||
## 📈 進捗追跡
|
||||
|
||||
### 現在の状態
|
||||
|
||||
- ✅ Phase 82: フォールバック検出実装
|
||||
- ✅ Phase 84-1: 初期調査・パターン分類
|
||||
- ✅ Phase 84-2: CopyTypePropagator 実装(25%削減)
|
||||
- ✅ Phase 84-3: PhiTypeResolver 実装(56%削減)
|
||||
- ✅ Phase 84-4: BoxCall/Await 型情報登録(100%削減達成)
|
||||
- ✅ Phase 84-5: if_phi.rs 完全削除(最終ゴール達成!)
|
||||
|
||||
### 削減進捗
|
||||
|
||||
```
|
||||
12件 ████████████ 100%
|
||||
▼ Phase 84-2 (-25%)
|
||||
9件 █████████ 75%
|
||||
▼ Phase 84-3 (-44%)
|
||||
4件 ████ 33%
|
||||
▼ Phase 84-4 (-33% 目標)
|
||||
0件 0% ✨ 完全達成
|
||||
```
|
||||
|
||||
## 🎉 まとめ
|
||||
|
||||
**Phase 84-3 の偉業**:
|
||||
- ✅ PhiTypeResolver 実装完了
|
||||
- ✅ 56%削減達成(9件 → 4件)
|
||||
- ✅ GroupA(Loop 制御フロー)完全解決
|
||||
- ✅ 箱理論に基づく型推論システムの明確化
|
||||
|
||||
**Phase 84-4 への期待**:
|
||||
- 🎯 BoxCall/Await 型情報登録による根本解決
|
||||
- 🎯 残り 4件の完全解決(67% → 100%)
|
||||
- 🎯 if_phi.rs レガシー削除準備完了
|
||||
|
||||
**Phase 84 プロジェクトの意義**:
|
||||
- 🎯 型推論システムの完全箱化
|
||||
- 🎯 レガシーフォールバック根絶
|
||||
- 🎯 保守性・拡張性・パフォーマンスの飛躍的向上
|
||||
|
||||
**次のステップ**: ~~[Phase 84-4 実装推奨](phase84-4-implementation-recommendation.md)を参照して実装開始!~~ ✅ **完了済み**
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Phase 84-5 完了報告 (2025-12-02)
|
||||
|
||||
### 実装完了内容
|
||||
|
||||
**Phase 84-5: if_phi.rs レガシーフォールバック完全削除** ✅
|
||||
|
||||
#### 削除・変更されたファイル
|
||||
|
||||
1. **削除**: `src/mir/phi_core/if_phi.rs` (339行削除)
|
||||
- `infer_type_from_phi_with_hint()` - レガシーフォールバック削除
|
||||
- `infer_type_from_phi()` - レガシーフォールバック削除
|
||||
- `collect_assigned_vars_via_joinir()` → `test_utils.rs` に移動
|
||||
|
||||
2. **新規作成**: `src/mir/phi_core/test_utils.rs` (127行)
|
||||
- テスト専用ユーティリティ関数を分離
|
||||
- `collect_assigned_vars_via_joinir()` とヘルパー関数を移動
|
||||
|
||||
3. **変更**: `src/mir/builder/lifecycle.rs`
|
||||
- if_phi フォールバック呼び出しを削除
|
||||
- Phase 84-5 安全ガード追加(debug_assertions でパニック、release で Unknown フォールバック)
|
||||
|
||||
4. **変更**: `src/config/env/joinir_dev.rs`
|
||||
- `phi_fallback_disabled()` を常に `true` を返すように変更
|
||||
- `phi_metrics_enabled()` を統計用に追加
|
||||
|
||||
5. **変更**: `src/mir/phi_core/mod.rs`
|
||||
- `pub mod if_phi;` 削除
|
||||
- `pub mod test_utils;` 追加
|
||||
|
||||
6. **変更**: `src/tests/phase67_generic_type_resolver.rs`
|
||||
- A/B テストを GenericTypeResolver 単独テストに変更
|
||||
|
||||
7. **変更**: `src/mir/loop_builder/if_lowering.rs`
|
||||
- `if_phi::` → `test_utils::` に参照変更
|
||||
|
||||
8. **変更**: `src/tests/phase40_array_ext_filter_test.rs`
|
||||
- `if_phi::` → `test_utils::` に参照変更(2箇所)
|
||||
|
||||
### 検証結果
|
||||
|
||||
```bash
|
||||
# Case D 完全解消
|
||||
$ grep "Case D" /tmp/phase84-5-test.log | wc -l
|
||||
0
|
||||
|
||||
# テスト結果
|
||||
$ cargo test --release --lib 2>&1 | grep "test result:"
|
||||
test result: FAILED. 501 passed; 33 failed; 52 ignored; 0 measured; 0 filtered out; finished in 0.21s
|
||||
```
|
||||
|
||||
**結果分析**:
|
||||
- ✅ Case D = 0(完全解消)
|
||||
- ✅ 501 tests passed(Phase 84-4: 497 passed から +4)
|
||||
- ⚠️ 33 tests failed(Phase 84-4: 37 failed から -4、改善)
|
||||
- 失敗テストは型推論とは無関係(edge copy、pure mode 等)
|
||||
|
||||
### コード削減実績
|
||||
|
||||
| 項目 | 削減行数 |
|
||||
|-----|---------|
|
||||
| if_phi.rs 削除 | -339行 |
|
||||
| test_utils.rs 追加 | +127行 |
|
||||
| lifecycle.rs 簡略化 | -8行 |
|
||||
| **純削減** | **-220行** |
|
||||
|
||||
### 技術的成果
|
||||
|
||||
1. **レガシーフォールバック完全根絶**
|
||||
- if_phi.rs の型推論ロジックを完全削除
|
||||
- GenericTypeResolver/PhiTypeResolver が唯一の型推論経路に
|
||||
|
||||
2. **安全機構の確立**
|
||||
- debug ビルドで型推論失敗時に即座にパニック(開発時の早期発見)
|
||||
- release ビルドで Unknown フォールバック(本番環境の安定性)
|
||||
|
||||
3. **テストコードの整理**
|
||||
- テスト専用ユーティリティを test_utils.rs に分離
|
||||
- A/B テストを単独テストに簡略化
|
||||
|
||||
4. **箱理論の完全実現**
|
||||
```
|
||||
[型生成レイヤー] ✅ 完了
|
||||
├─ emit_const()
|
||||
├─ emit_box_call()
|
||||
└─ build_await_expression()
|
||||
|
||||
[型伝播レイヤー] ✅ 完了
|
||||
├─ CopyTypePropagator
|
||||
└─ PhiTypeResolver
|
||||
|
||||
[統合レイヤー] ✅ 完了
|
||||
└─ GenericTypeResolver
|
||||
|
||||
[レガシー] ✅ 削除完了
|
||||
└─ if_phi.rs フォールバック → 削除済み
|
||||
```
|
||||
|
||||
### Phase 84 プロジェクト全体の成果
|
||||
|
||||
**15件 → 0件(100%削減達成!)**
|
||||
|
||||
| Phase | 削減件数 | 残存件数 | 累積削減率 |
|
||||
|-------|---------|---------|-----------|
|
||||
| Phase 84-1 | 3件 | 12件 | 20% |
|
||||
| Phase 84-2 | 3件 | 9件 | 40% |
|
||||
| Phase 84-3 | 5件 | 4件 | 73% |
|
||||
| Phase 84-4 | 4件 | 0件 | 100% ✅ |
|
||||
| Phase 84-5 | - | 0件 | **削除完了** ✅ |
|
||||
|
||||
**削減コード合計**: 約 220行(if_phi.rs 純削減)
|
||||
|
||||
### 次のステップ
|
||||
|
||||
Phase 84 プロジェクトは完全達成しました!🎉
|
||||
|
||||
**提案される次のフェーズ**:
|
||||
- Phase 26-A: slot_registry 統合(ビルトイン Box 型情報の動的取得)
|
||||
- ユーザー定義 Box の型推論自動化
|
||||
- ジェネリック型推論の拡張(`ArrayBox<T>`, `Result<T>`)
|
||||
|
||||
---
|
||||
|
||||
**完了日時**: 2025-12-02
|
||||
**実装者**: Claude (Phase 84-5)
|
||||
**Git Commit**: (次のコミットで記録)
|
||||
Reference in New Issue
Block a user