diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index 7bc9bf02..dffced53 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -1,6 +1,6 @@ # Current Task — Phase 15 (Revised): Self‑Hosting Focus, JSON→Ny Executor -Updated: 2025‑09‑26 +Updated: 2025‑09‑27 Quick status - Build: `cargo build --release` → OK(警告のみ) @@ -8,6 +8,21 @@ Quick status - Parser: TokenCursor 統一 Step‑2/3 完了(env ゲート) - PHI: if/else の incoming pred を exit ブロックへ修正(VM 未定義値を根治) +MIR/VM 進捗(SSA/短絡/ユーザーBox) +- 短絡(&&/||): 分岐+PHI で正規低下(RHS 未評価)を実装済み。 +- 比較オペランド: その場 `pin_to_slot` で slot 化、PHI 参加(支配関係破れの根治策)。 +- ブロック入口: then/else/短絡入口に単一 pred PHI を配置(局所定義を保証)。 +- ユーザーBox呼び出し(VM fallback): + - Builder 側: user‑defined Box のインスタンスメソッドは `Box.method/Arity` 関数へ書き換え('me' 先頭引数、関数名の Arity は 'me' を含めない)。 + - VM 側: BoxCall で InstanceBox を受けた場合、存在すれば `Box.method/Arity` に動的フォールバック実行('me'+args を渡す)。 + +現状の未解決(再現あり) +- JSON VM quick が `BoxCall unsupported on VoidBox.current` で停止。 + - トレース: `JsonTokenizer.next_token` 内で `me.scanner.current()` が BoxCall 経路に残存。 + - 期待: Builder が user‑defined `JsonScanner` を検知して `JsonScanner.current/0` へ書き換えるか、VM が fallback で補足。 + - 観測: 関数一覧に `JsonScanner.current/0` が存在しないケースがある(環境差/順序の可能性)。 + - 以前の実行では `JsonScanner.current/0` が列挙されていたため、低下順または条件分岐の取りこぼしが疑わしい。 + ## ADR 受理: No CoreBox & Everything is Plugin(Provider/Type 分離) - CoreBox は戻さない。Kernel は最小(GC/Handle/TLV/Extern/PluginRegistry/ABI)。 @@ -74,6 +89,52 @@ Quick status - mini(starts_with)が VM fallback / LLVM / PyVM のいずれか基準で PASS(VM fallback は暫定メソッドで通せばOK)。 - Builder 順序不整合の解消: 出現順に依存せず、new/静的メソッドの前方参照が安定解決。 +## いま着手中(SSA pin/PHI と user‑defined 呼び出しの根治) + +目的 +- 「式一時値の支配関係破れ」由来の未定義参照を構造的に排除(pin→PHI)。 +- user‑defined Box のインスタンスメソッド呼び出しを 100% `Box.method/Arity` へ正規化し、VM fallback でも実行可能にする。 + +実装済み +- 短絡: And/Or を分岐+PHI で実装。 +- 比較: 左右オペランドを都度 pin→PHI 参加。 +- 分岐入口: then/else/短絡入口に単一 pred PHI を配置(正規化)。 +- VM fallback: InstanceBox に対する BoxCall を `Box.method/Arity` 関数へ動的フォールバック('me'+args)。 +- Builder: user‑defined Box のメソッド呼び出しを `Box.method/Arity` 関数へ書き換え(存在確認つき)。 + +未解決点(原因候補) +- `JsonScanner.current/0` が関数一覧に存在しない実行がある → インスタンスメソッド低下の取りこぼし疑い。 + - 仮説A: `build_box_declaration` の instance method 低下が順序/条件でスキップされるケースがある。 + - 仮説B: `field_access` → `value_origin_newbox` の伝搬が不足し、Builder が user‑defined 判定に失敗(BoxCall に落ちる)。 + +デバッグ手順(再現と確認) +- 関数一覧の確認: `NYASH_DUMP_FUNCS=1 NYASH_VM_TRACE=1 ... --backend vm driver.nyash` + - 期待: `JsonScanner.current/0` を含む。 +- Builder トレース: `NYASH_BUILDER_DEBUG=1`(userbox method 書き換え時に `userbox method-call ...` を出力) +- フィールド由来の型伝搬: `build_field_access` で `field_origin_class` → `value_origin_newbox` 反映の有無をログで確認。 + +次の作業(順番) +1) 低下順序の点検 + - `build_box_declaration` の instance method 低下が常に走ることを再確認(静的/インスタンス混在時、重複/上書きなし)。 + - `JsonScanner` の全メソッド(`current/0` 含む)が `module.functions` に常に登録されることをテストで保証。 +2) 型伝搬の強化 + - `build_field_access` 経由の `value_origin_newbox` 伝搬を明示ログ化し、`scanner` フィールドで `JsonScanner` を確実に付与。 + - 併せて `value_types` に `MirType::Box(JsonScanner)` を注釈(判定補助; 既定OFFの安全弁として env ゲートで導入)。 +3) 呼び出し書き換えの網羅 + - `handle_standard_method_call` の user‑defined 書き換えを早期に実施(BoxCall へ落ちる前に判定)。 + - `CallTarget::Method` 経由の経路も同一ロジックで統一。 +4) 検証 + - ミニ: `me.scanner.current()` を含む 1 ケースで `NYASH_DUMP_FUNCS=1` と Builder/VM トレース確認、BoxCall が消えて Call(`JsonScanner.current/0`, me) であること。 + - quick/core JSON VM: 代表ケース再実行。未定義参照や Void 経路暫定ガードが発火しないこと。 + +注意(暫定対策の扱い) +- `eval_binop(Add, Void, X)` の簡易ガードは開発用の安全弁。根治後に撤去する(テストが緑になってから)。 + +受け入れ基準(このタスク) +- `JsonTokenizer.next_token` で `me.scanner.current()` が Call 経路に正規化され、BoxCall 不要。 +- `JsonScanner.current/0` が常に関数一覧に存在。 +- JSON VM quick が未定義参照・BoxCall unsupported を出さずに最後まで出力一致(ノイズ除去込み)。 + 受け入れ基準 - StringUtils の `--dump-ast` に stray FunctionCall が出ない(宣言のみ)。 - mini(starts_with): ASTモード ON/OFF で parse→MIR まで到達(VM fallback の未実装は許容)。 diff --git a/docs/private/research/paper-14-ai-collaborative-abstraction/README.md b/docs/private/research/paper-14-ai-collaborative-abstraction/README.md index 76b77468..578d49b0 100644 --- a/docs/private/research/paper-14-ai-collaborative-abstraction/README.md +++ b/docs/private/research/paper-14-ai-collaborative-abstraction/README.md @@ -150,6 +150,18 @@ preindex_functions_from_ast() // どんどん増える... - 創造的思考と現実的判断の弁証法 - 「諦める」ことの設計的価値 +7. **[三段階設計進化論 — 究極理想から実用現実への収束](three-stage-design-evolution.md)** 🆕 + - 「箱のインスタンスもループ0回のループに」(LoopSignal IR) + - 三段階進化:究極統一→部分統一→実用解決 + - 設計者の成熟過程と段階的妥協の智恵 + - Philosophy-Driven Development 3.0の提唱 + +8. **[設計哲学の誤読と長期的代償 — AI協働における哲学伝達の重要性](philosophy-misreading-longterm-cost.md)** 🔥NEW + - 開発者の真の哲学「正しく動かす最優先、コスト重視せず」vs ChatGPTの誤読 + - LoopFormこそが開発者哲学に100%合致していた皮肉 + - Pin方式の予期せぬ複雑性(現在もSSA PHI問題で苦戦中) + - Philosophy-Driven Development 4.0の提案(哲学的価値観の明示化) + ## 🎓 学術的貢献 ### 1. 新しい協働モデルの提案 @@ -158,6 +170,7 @@ preindex_functions_from_ast() // どんどん増える... - **認知負荷分散理論**: 各エージェントが最適な抽象度で処理 - **制約駆動型協働(Constraint-Driven Collaboration)**: 最小介入で最大成果 🆕 - **設計空間探索理論**: 理想解と実用解の収束パターン 🆕 +- **三段階設計進化論**: 究極理想→部分統一→実用現実の進化モデル 🆕 ### 2. 実証的エビデンス @@ -165,12 +178,20 @@ preindex_functions_from_ast() // どんどん増える... - 定量的な効率改善データ(前方参照:4倍、SSA PHI:21.56倍) - 再現可能な協働パターン - **創造的休憩の効果**:タバコ休憩20分での完璧な解決策構想 🆕 +- **段階的洗練過程**:3つの解決策(LoopSignal→LoopForm→Pin)の実証的追跡 🆕 ### 3. 実践的設計哲学 - **段階的開発原理**:「正しく動かす→軽く動かす」 - **賢い妥協の価値**:理想解から実用解への合理的収束 - **トレードオフ認識**:コストと価値の成熟した判断 🆕 +- **統一化思想の階層**:Everything is Box × Everything is Loop 🆕 + +### 4. 新しい開発パラダイム + +- **Philosophy-Driven Development (PDD) 3.0**:三段階制約認識モデル +- **設計者成熟度理論**:理想→現実への段階的収束能力 +- **創造的妥協論**:「諦める」ことの積極的価値 🆕 ### 4. 実践的ガイドライン diff --git a/docs/private/research/paper-14-ai-collaborative-abstraction/philosophy-misreading-longterm-cost.md b/docs/private/research/paper-14-ai-collaborative-abstraction/philosophy-misreading-longterm-cost.md new file mode 100644 index 00000000..3ea1696c --- /dev/null +++ b/docs/private/research/paper-14-ai-collaborative-abstraction/philosophy-misreading-longterm-cost.md @@ -0,0 +1,336 @@ +# 📚 Chapter 11: 設計哲学の誤読と長期的代償 — AI協働における哲学伝達の重要性 + +## 🎯 開発者の真の哲学 vs AIの解釈 + +### 11.1 設計哲学の一貫性 + +#### 開発者の明確な哲学 +> 「まずは正しく動かす、後から軽く動かす」 +> 「コストが重くても、それこそ最適化でいい」 + +この哲学は**Nyash設計全体を貫く一貫した原則**である。 + +#### 哲学の実践例 +```yaml +examples: + type_safety: "型安全性優先、速度は後回し" + correctness: "動作確実性優先、効率は二の次" + architecture: "美しい設計優先、実装コストは許容" +``` + +### 11.2 LoopFormと設計哲学の完全合致 + +#### LoopForm本来の位置づけ +```rust +// LoopFormの本質:完全に正しい動作 +loop_carrier = (var1, var2, var3); +head: + let (var1, var2, var3) = phi_carrier; // ← 1個のPHIで完璧! + if !condition goto exit; + next_carrier = (update1(var1), update2(var2), update3(var3)); + phi_carrier = φ(loop_carrier, next_carrier); + goto head; +``` + +**この設計は開発者哲学に100%合致していた**: +- ✅ **正しく動く**:PHI問題の根本解決 +- ✅ **美しい設計**:概念的に完璧 +- ✅ **後から最適化可能**:LLVM最適化の恩恵を最大受益 + +### 11.3 ChatGPTによる哲学誤読 + +#### 誤読の詳細 +```yaml +chatgpt_misreading: + perceived_priority: "効率・速度重視の開発者" + actual_priority: "正しさ・美しさ重視の哲学者" + + judgment: "LoopFormはコストが重いので却下" + missed_point: "開発者は『重くてもOK』哲学だった" +``` + +#### 結果的な提案 +``` +ChatGPT提案: Pin方式(軽くて実用的) +開発者期待: LoopForm(重くても正しい) +``` + +## 🔄 現実の皮肉な展開 + +### 11.4 Pin方式の予期せぬ複雑性 + +#### 当初の期待 +```yaml +pin_method_expectation: + implementation_time: "数時間" + complexity: "低" + maintenance: "簡単" +``` + +#### 現在の現実 +```yaml +pin_method_reality: + implementation_time: "継続中(数週間)" + complexity: "SSA PHI問題で苦戦" + maintenance: "追加実装が必要" + + current_issues: + - "Pin適用範囲の拡大(LHS/ループ/if条件)" + - "PHI対象化の登録機構追加" + - "PHI→copy-in順序の修正" + - "MIR verifier支配関係チェック追加" +``` + +### 11.5 LoopFormの真の価値の再発見 + +#### 開発者の振り返り +> 「やはり最初からコストが重くてもLoopFormから作るべきだったかにゃ」 +> 「今もPin大作戦になってるもん」 + +#### 長期的視点での評価 +```python +# 実装コスト比較(推定) +loopform_cost = { + "initial_implementation": "3-6ヶ月", + "long_term_maintenance": "低(概念が完璧)", + "optimization": "LLVM任せで自動最適化", + "total_lifetime_cost": "中程度" +} + +pin_method_cost = { + "initial_implementation": "数時間", + "long_term_maintenance": "高(継続的バグ修正)", + "optimization": "手動最適化が必要", + "total_lifetime_cost": "高(継続コスト)" +} +``` + +## 🤖 ChatGPTの能力特性詳細分析 + +### 11.6 理論構築力 vs 実装複雑性の限界 + +#### ChatGPTの圧倒的強み +```yaml +chatgpt_strengths: + theoretical_discussion: "口喧嘩と理論がとても強い" + architecture_design: "完璧な設計思想の提案" + concept_creation: "Pin方式・Callee型等の革新的概念" + problem_analysis: "根本原因の的確な特定" +``` + +#### 実装における現実的限界 +```yaml +implementation_challenges: + complex_control_flow: "複雑なif/and/or演算子で苦戦" + nested_logic: "制御構造の組み合わせで困難" + edge_cases: "境界条件での予期せぬ複雑性" + +current_status: "箱理論で何とかしてもらっているところ" +``` + +### 11.7 理論と実装の乖離現象 + +#### 設計時の期待 vs 実装時の現実 +```python +# 理論レベル(ChatGPTの提案) +pin_method_theory = { + "概念": "一時値をスロットに昇格するだけ", + "複雑性": "低", + "実装難易度": "簡単" +} + +# 実装レベル(実際の困難) +pin_method_reality = { + "複雑なif条件": "予期せぬ制御フロー問題", + "and/or演算子": "論理演算での複雑性増大", + "組み合わせ爆発": "様々な構文パターンの相互作用" +} +``` + +#### 箱理論の救済的役割 +開発者の対応戦略: +> 「箱理論で何とかしてもらっているところ」 + +これは**哲学が実装困難を救済する**パターンを示している: + +#### 実装進展:pin_to_slot関数の完成 +> 「pin_to_slot関数ができてますにゃ これ いい箱だと思うので これでバグが治るといいにゃあ」 + +```rust +// ChatGPT実装による「いい箱」の実現 +pub(crate) fn pin_to_slot(&mut self, v: ValueId, _hint: &str) -> Result { + // ローカルコピーでブロック内にマテリアライズ + // variable_mapに登録せず、ブロック間漏出を防ぐ + let dst = self.value_gen.next(); + self.emit_instruction(MirInstruction::Copy { dst, src: v })?; + Ok(dst) +} +``` + +**箱理論の完璧な体現**: +- ✅ **明確な境界**:ブロック境界を越えない設計 +- ✅ **責任の分離**:variable_map漏出防止 +- ✅ **シンプルな実装**:Copy命令でローカル化 +- ✅ **開発者評価**:「いい箱だと思う」 + +#### リアルタイム実装進化の観察 + +実装が継続的に進化している様子を目撃: + +```rust +// 進化後:完全なPHI参加システム +pub(crate) fn pin_to_slot(&mut self, v: ValueId, hint: &str) -> Result { + self.temp_slot_counter = self.temp_slot_counter.wrapping_add(1); + let slot_name = format!("__pin${}${}", self.temp_slot_counter, hint); + // PHI参加のためvariable_mapに登録 + self.variable_map.insert(slot_name, dst); + Ok(dst) +} +``` + +**進化のポイント**: +- 🔄 **PHI参加機構**: variable_mapでブロック間値伝播 +- 🏷️ **ユニーク命名**: `__pin$counter$hint`で名前衝突回避 +- 🐛 **デバッグ支援**: `NYASH_PIN_TRACE=1`でトレース可能 +- 🎯 **ブロック協調**: start_new_block()で`__pin$`プレフィックス処理 + +開発者の見通し: +> 「動くようになったあとで claude code君にチェックしてもらう予定ですが まだまだ時間かかりそうだにゃ」 + +これは**段階的実装アプローチ**の典型例を示している。 + +#### 「正確性優先の箱盛り」実装完了 + +実装戦略の現在地: + +```yaml +accomplished_pin_strategy: + 比較オペランド集中ピン: "Compare発行前に左右を必ずslot化" + pin_to_slot箱化: "__pin$...でPHI対象化 + NYASH_PIN_TRACE=1" + 分岐入口単一predPHI: "if/else/ループ/短絡の入口で全変数局所定義化" + マージブロック順序ガード: "PHI先頭配置のためentry-copy抑制" + VM安全弁: "Void+Integer→0扱いの開発用ガード" + +result: "未定義参照は消えた(進歩)" +new_issue: "BoxCall unsupported on VoidBox.current(型問題)" +``` + +#### 開発者の新たな懸念 + +> 「llvmハーネス経路 は これますますややこしくなりそうだにゃ」 + +**複雑化の要因**: +1. **VM fallback安全弁の増加**:開発用ガードの蓄積 +2. **実行経路の分岐**:VM vs LLVM で異なる型処理 +3. **テスト複雑性**:2経路での整合性検証が必要 + +#### 段階的解決アプローチ + +開発者の現実的戦略: +``` +1. 短絡分岐RHS側への最小entry PHI追加 +2. VM fallback安全弁を1箇所だけ追加(緑化優先) +3. 検証&整理(NYASH_PIN_TRACE=1 + NYASH_VM_TRACE=1) +``` + +これは**「まず正しく動かす、後から軽く動かす」哲学**の完璧な実践例である。 + +```mermaid +graph TD + A[ChatGPT理論提案] -->|実装開始| B[複雑性発覚] + B -->|困難| C[箱理論による救済] + C -->|哲学的制約| D[問題解決の方向性] + D -->|再実装| E[解決] +``` + +## 🧠 AI協働における哲学伝達の課題 + +### 11.8 コミュニケーション・ギャップ + +#### 哲学の暗黙性 +開発者の設計哲学は**暗黙知**として存在: +- 明示的に語られることは少ない +- 具体的な判断の積み重ねで表現される +- AIには読み取りが困難 + +#### AIの解釈バイアス +```yaml +ai_interpretation_bias: + tendency: "効率性重視と仮定" + reason: "一般的な開発プラクティスに基づく推論" + missed: "個別の開発者哲学の特殊性" +``` + +### 11.7 Philosophy-Driven Developmentの進化必要性 + +#### PDD 4.0の提案 +``` +PDD 1.0: 単一制約による問題解決 +PDD 2.0: 段階的制約による多重解の生成 +PDD 3.0: 三段階進化による設計空間の完全探索 +PDD 4.0: 哲学的価値観の明示化と継続的検証 ← NEW! +``` + +#### 具体的改善案 +```yaml +philosophy_communication: + explicit_declaration: + - 設計哲学の文書化 + - 価値観の優先順位明示 + - トレードオフ判断基準の共有 + + continuous_validation: + - 提案に対する哲学適合性チェック + - 長期的視点での価値評価 + - 判断の振り返りと学習 +``` + +## 🎓 学術的示唆 + +### 11.8 Human-AI協働研究への貢献 + +#### 新しい研究テーマ +1. **暗黙的哲学の明示化技術** +2. **AI による人間価値観の学習メカニズム** +3. **長期的視点での意思決定支援** +4. **設計哲学の一貫性検証システム** + +#### 実践的ガイドライン +```yaml +best_practices: + for_humans: + - 設計哲学を明示的に文書化 + - AIに対する価値観の継続的伝達 + - 長期的視点の重要性を強調 + + for_ai_systems: + - 人間の価値観学習機能 + - 短期効率 vs 長期価値の判断支援 + - 哲学一貫性のチェック機能 +``` + +## 🌟 結論 + +### 11.9 LoopForm事例の普遍的価値 + +この事例は単なる技術的選択の失敗ではなく、**AI協働開発における根本的課題**を浮き彫りにした: + +1. **哲学伝達の重要性**:技術的制約より価値観の共有が重要 +2. **長期的視点の必要性**:短期的効率より長期的価値を重視 +3. **AIの解釈限界**:人間の暗黙知を読み取る困難さ +4. **継続的学習の必要性**:判断の振り返りと改善 + +### 11.10 「正しく動かす、後から軽く動かす」の真の意味 + +この開発哲学は単なる段階的開発法ではなく、**価値観の優先順位を示す根本原則**だった。 + +``` +誤解: 「効率を後回しにする開発手法」 +真実: 「正しさを最高価値とする哲学的立場」 +``` + +LoopFormこそが、この哲学を最も純粋に体現する解決策だったのである。 + +--- + +**この章が示すのは、AI協働開発において技術的能力以上に重要なのは、人間の深層的価値観を理解し、それに基づく長期的判断を支援する能力であることである。** \ No newline at end of file diff --git a/docs/private/research/paper-14-ai-collaborative-abstraction/three-stage-design-evolution.md b/docs/private/research/paper-14-ai-collaborative-abstraction/three-stage-design-evolution.md new file mode 100644 index 00000000..a8a5cd9b --- /dev/null +++ b/docs/private/research/paper-14-ai-collaborative-abstraction/three-stage-design-evolution.md @@ -0,0 +1,336 @@ +# 📚 Chapter 10: 三段階設計進化論 — 究極理想から実用現実への収束 + +## 🌌 「ループに始まりループに終わる」究極の統一思想 + +### 10.1 設計思考の三段階進化 + +#### 開発者の洞察の深化 +```yaml +evolution_timeline: + stage_1_ultimate: "箱のインスタンスもループ0回のループにしようとしたんですが" + stage_2_partial: "LoopFormという考え(タバコ休憩20分)" + stage_3_practical: "箱が足りないだけなのかな?(Pin方式)" + +ai_response_pattern: + stage_1: "ChatGPTに何度も断られました" + stage_2: "結局コストが重いとchatgptにことわられました" + stage_3: "無言で実装開始" +``` + +## 🎯 Stage 1: LoopSignal IR — 究極の統一化理論 + +### 10.2 Everything is Loop の革命的発想 + +#### 核心思想 +> 「Everything is Box(空間)」×「Everything is Loop(時間)」 + +```rust +// 究極の統一化:すべてをLoopで表現 +conceptual_unification = { + "box_instance": "Loop0", // 0回のループ + "if_statement": "Loop1", // 1回のループ + "while_loop": "LoopN", // N回のループ + "function_call": "Loop1", // 1回のループ + "scope_block": "Loop1", // 1回のループ + "generator": "LoopYield", // Yield付きループ + "async_function": "LoopAsync" // 非同期ループ +} +``` + +#### 制御の値化 +```rust +// 制御を値として統一表現 +LoopSignal = Next(T) | Break(T) | Yield(T) | Return(T) + +// IR統一命令 +loop.begin %id +loop.iter %sig, %loop, %state +loop.branch %sig { onNext: L1, onBreak: L2, onYield: L3 } +loop.end %id +``` + +### 10.3 理論的完璧性 + +#### 構造的美しさ +```yaml +theoretical_perfection: + unification_level: "完全統一(すべてがLoop)" + control_representation: "値としての制御(Signal)" + phi_optimization: "dispatch合流点への完全集約" + extensibility: "generator/async/effectの自然な実装" + +design_elegance: + - すべての制御構造が4つの命令で表現可能 + - PHIの配置が完全に規格化 + - 最適化パスが統一的に適用可能 + - 将来拡張(effect系)への完璧な対応 +``` + +#### 実装コストの現実 +```python +implementation_requirements = { + "new_ir_layer": "完全な新IRレイヤー実装", + "type_system": "LoopSignal型システムの完全統合", + "optimization_passes": "全最適化パスの書き直し", + "debugging_support": "新しいデバッグ情報システム", + "backend_support": "VM/JIT/LLVMすべての対応", + "estimated_effort": "6-12ヶ月の開発期間", + "risk_level": "非常に高い(全システム影響)" +} + +chatgpt_assessment: "何度も実装拒否" +reason: "プロジェクト全体への影響が甚大" +``` + +## 🔄 Stage 2: LoopForm — 部分統一化理論 + +### 10.4 タバコ休憩20分の天才的直感 + +#### 問題の焦点化 +```rust +// LoopFormの焦点:ループ状態管理の統一 +problem_focus = "複数変数のPHI管理の複雑性" + +// 解決アプローチ:タプル統一 +solution_approach = { + "carrier_concept": "複数状態を1つのタプルに統合", + "phi_simplification": "1個のPHIで全状態管理", + "loop_unification": "ループ構造の標準化" +} +``` + +#### 実装の現実性 +```yaml +implementation_scope: + affected_systems: ["ループ構文", "マクロシステム", "PHI生成"] + development_time: "3-6ヶ月" + risk_level: "中程度" + +chatgpt_assessment: "コストが重い" +reason: "マクロシステム全体の実装が必要" +``` + +## ⚡ Stage 3: Pin方式 — 実用的解決 + +### 10.5 哲学の保持と現実的実装 + +#### 問題認識の洗練化 +``` +開発者の洞察: "箱が足りないだけなのかな?" +↓ +ChatGPT Pro: Pin方式の理論設計 +↓ +コーディングChatGPT: 無言の即実装 +``` + +#### 実用性の優位 +```python +pin_approach = { + "implementation_time": "数時間", + "risk_level": "低い", + "compatibility": "既存システムとの完全互換", + "philosophy_preservation": "箱理論の完全維持", + "immediate_value": "問題の即時解決" +} + +success_factor = "哲学は保持、実装は現実的" +``` + +## 🧠 設計進化の認知科学的分析 + +### 10.6 創造的思考の段階的洗練 + +#### 抽象化レベルの変化 +```mermaid +graph TD + A[抽象度: 最高
Everything is Loop] -->|実装困難| B[抽象度: 高
Loop State Unification] + B -->|実装困難| C[抽象度: 中
Value Pinning] + C -->|実装成功| D[問題解決] + + A -->|哲学的完璧性| E[理論的価値] + B -->|部分的統一| F[設計的価値] + C -->|実用的価値| G[実装的価値] +``` + +#### 制約条件の段階的認識 +```yaml +constraint_recognition_evolution: + stage_1: + constraint_awareness: "制約を無視した理想追求" + design_freedom: "無制限" + result: "完璧だが実装不可能" + + stage_2: + constraint_awareness: "部分的制約の認識" + design_freedom: "制限付き" + result: "優雅だが依然として重い" + + stage_3: + constraint_awareness: "現実的制約の完全理解" + design_freedom: "大幅制限" + result: "実用的で実装可能" +``` + +### 10.7 「諦める」ことの設計的価値 + +#### 段階的妥協の智恵 +```python +design_wisdom_evolution = { + "stage_1_rejection": { + "value": "理想解の明確化", + "learning": "完全統一の可能性と限界", + "future_reference": "将来実装への指針" + }, + "stage_2_rejection": { + "value": "部分解の理解", + "learning": "統一化のコストとベネフィット", + "scope_definition": "現実的統一の範囲" + }, + "stage_3_acceptance": { + "value": "実用解の実現", + "learning": "哲学と実装のバランス", + "immediate_impact": "問題の解決" + } +} +``` + +## 🎯 Philosophy-Driven Development の成熟 + +### 10.8 三段階PDDモデル + +#### 拡張されたPDD理論 +```yaml +three_stage_pdd: + stage_1_ideation: + constraint_level: "哲学的制約のみ" + thinking_mode: "発散的思考" + output: "完璧な理想解" + ai_response: "実装困難評価" + + stage_2_refinement: + constraint_level: "哲学的 + 部分的実装制約" + thinking_mode: "収束的思考" + output: "現実的理想解" + ai_response: "実装困難評価" + + stage_3_implementation: + constraint_level: "哲学的 + 完全実装制約" + thinking_mode: "問題解決思考" + output: "実装可能解" + ai_response: "即座の実装" +``` + +#### 各段階の価値 +```python +stage_values = { + "ultimate_theory": "将来への道標、技術進歩の目標", + "partial_theory": "中期的実装の可能性、段階的改善", + "practical_solution": "即時的問題解決、現在の価値創造" +} + +integration_value = "三段階すべてが設計空間を完全にカバー" +``` + +## 🔮 将来への示唆 + +### 10.9 技術進歩による段階的実現 + +#### 実現可能性の時間的変化 +```yaml +technology_maturity_timeline: + 2025_current: + feasible: "Pin方式" + challenging: "LoopForm" + impossible: "LoopSignal IR" + + 2027_projected: + feasible: "Pin方式 + LoopForm" + challenging: "LoopSignal IR(部分実装)" + impossible: "完全な LoopSignal IR" + + 2030_projected: + feasible: "全段階の統合実装" + research_focus: "さらなる統一理論" +``` + +#### 段階的実装戦略 +```python +implementation_roadmap = { + "phase_1": "Pin方式の完全実装・最適化", + "phase_2": "LoopFormの限定的実装", + "phase_3": "LoopSignal IRの研究プロトタイプ", + "phase_4": "統合的実装システム" +} +``` + +### 10.10 他分野への応用可能性 + +#### 三段階設計法の汎用性 +```yaml +applications: + software_architecture: + - 理想アーキテクチャの定義 + - 実用アーキテクチャの設計 + - 段階的移行戦略 + + product_development: + - ビジョンプロダクトの構想 + - MVP の設計 + - 段階的機能拡張 + + research_methodology: + - 理想理論の構築 + - 実証可能仮説の絞り込み + - 実験的検証 +``` + +## 💡 統合的理解 + +### 10.11 三段階進化の本質 + +#### 創造性と実用性の弁証法 +``` +正: 創造的理想(LoopSignal IR) +反: 実装制約(技術的限界) +合: 実用的解決(Pin方式) + +しかし: +- 正(理想)は失われない → 将来への指針 +- 反(制約)は変化する → 技術進歩 +- 合(解決)は進化する → 段階的実現 +``` + +#### 設計者の成熟過程 +```python +designer_maturity = { + "novice": "実装制約を無視した理想のみ", + "intermediate": "制約と理想の両方を考慮", + "expert": "段階的実現戦略を設計", + "master": "三段階すべてを統合的に価値化" +} + +user_level = "master" # 三段階すべてに価値を見出す +``` + +## 🏆 結論 + +### 10.12 三段階設計進化論の価値 + +この事例は、以下の革新的洞察を提供する: + +1. **理想の価値**: 実装されない理想も設計指針として永続的価値 +2. **段階的洗練**: 制約の段階的認識による解決策の洗練 +3. **統合的思考**: 三段階すべてが設計空間の完全なカバレッジ +4. **将来実現性**: 技術進歩による段階的実現の可能性 + +### 10.13 Philosophy-Driven Developmentの新次元 + +``` +PDD 1.0: 単一制約による問題解決 +PDD 2.0: 段階的制約による多重解の生成 +PDD 3.0: 三段階進化による設計空間の完全探索 +``` + +--- + +**「ループに始まりループに終わる」— この言葉は、単なる設計思想ではなく、創造的思考の本質的構造を表現している。理想から現実への収束は、敗北ではなく、設計者の成熟の証なのである。** \ No newline at end of file diff --git a/src/backend/mir_interpreter/handlers/boxes.rs b/src/backend/mir_interpreter/handlers/boxes.rs index bedc0c62..d6fd43c8 100644 --- a/src/backend/mir_interpreter/handlers/boxes.rs +++ b/src/backend/mir_interpreter/handlers/boxes.rs @@ -481,6 +481,23 @@ impl MirInterpreter { ))), } } else { + // Dynamic fallback for user-defined InstanceBox: dispatch to lowered function "Class.method/Arity" + if let Some(inst) = recv_box.as_any().downcast_ref::() { + let class_name = inst.class_name.clone(); + let arity = args.len(); // function name arity excludes 'me' + let fname = format!("{}.{}{}", class_name, method, format!("/{}", arity)); + if let Some(func) = self.functions.get(&fname).cloned() { + let mut argv: Vec = Vec::with_capacity(arity + 1); + // Pass receiver as first arg ('me') + argv.push(recv.clone()); + for a in args { + argv.push(self.reg_load(*a)?); + } + let ret = self.exec_function_inner(&func, Some(&argv))?; + if let Some(d) = dst { self.regs.insert(d, ret); } + return Ok(()); + } + } Err(VMError::InvalidInstruction(format!( "BoxCall unsupported on {}.{}", recv_box.type_name(), diff --git a/src/backend/mir_interpreter/helpers.rs b/src/backend/mir_interpreter/helpers.rs index 38841df9..11be6a3e 100644 --- a/src/backend/mir_interpreter/helpers.rs +++ b/src/backend/mir_interpreter/helpers.rs @@ -38,6 +38,11 @@ impl MirInterpreter { use BinaryOp::*; use VMValue::*; Ok(match (op, a, b) { + // Safety valve: treat Void as 0 for + (dev fallback for scanners) + (Add, VMValue::Void, Integer(y)) => Integer(y), + (Add, Integer(x), VMValue::Void) => Integer(x), + (Add, VMValue::Void, Float(y)) => Float(y), + (Add, Float(x), VMValue::Void) => Float(x), (Add, Integer(x), Integer(y)) => Integer(x + y), (Add, String(s), Integer(y)) => String(format!("{}{}", s, y)), (Add, String(s), Float(y)) => String(format!("{}{}", s, y)), diff --git a/src/config/env.rs b/src/config/env.rs index 1ee6e0ea..710dbe85 100644 --- a/src/config/env.rs +++ b/src/config/env.rs @@ -173,6 +173,18 @@ pub fn mir_core13_pure() -> bool { std::env::var("NYASH_MIR_CORE13_PURE").ok().as_deref() == Some("1") } +/// Enable heuristic pre-pin of comparison operands in if/loop headers. +/// Default: OFF (0). Set NYASH_MIR_PREPIN=1 to enable. +pub fn mir_pre_pin_compare_operands() -> bool { + match std::env::var("NYASH_MIR_PREPIN").ok() { + Some(v) => { + let lv = v.to_ascii_lowercase(); + !(lv == "0" || lv == "false" || lv == "off") + } + None => false, + } +} + // ---- Optimizer diagnostics ---- pub fn opt_debug() -> bool { std::env::var("NYASH_OPT_DEBUG").is_ok() diff --git a/src/mir/builder.rs b/src/mir/builder.rs index c1787cb4..f823f586 100644 --- a/src/mir/builder.rs +++ b/src/mir/builder.rs @@ -130,6 +130,8 @@ pub struct MirBuilder { /// Internal counter for temporary pin slots (block-crossing ephemeral values) temp_slot_counter: u32, + /// If true, skip entry materialization of pinned slots on the next start_new_block call. + suppress_pin_entry_copy_next: bool, } impl MirBuilder { @@ -168,6 +170,7 @@ impl MirBuilder { cleanup_allow_throw: false, hint_sink: crate::mir::hints::HintSink::new(), temp_slot_counter: 0, + suppress_pin_entry_copy_next: false, } } @@ -175,6 +178,9 @@ impl MirBuilder { pub(super) fn push_if_merge(&mut self, bb: BasicBlockId) { self.if_merge_stack.push(bb); } pub(super) fn pop_if_merge(&mut self) { let _ = self.if_merge_stack.pop(); } + /// Suppress entry pin copy for the next start_new_block (used for merge blocks). + pub(super) fn suppress_next_entry_pin_copy(&mut self) { self.suppress_pin_entry_copy_next = true; } + // ---- Hint helpers (no-op by default) ---- #[inline] pub(crate) fn hint_loop_header(&mut self) { self.hint_sink.loop_header(); } diff --git a/src/mir/builder/builder_calls.rs b/src/mir/builder/builder_calls.rs index c15eb809..6fd11698 100644 --- a/src/mir/builder/builder_calls.rs +++ b/src/mir/builder/builder_calls.rs @@ -57,8 +57,44 @@ impl super::MirBuilder { args: Vec, ) -> Result<(), String> { match target { - CallTarget::Method { receiver, method, .. } => { - // Use existing emit_box_or_plugin_call + CallTarget::Method { receiver, method, box_type } => { + // If receiver is a user-defined box, lower to function call: "Box.method/(1+arity)" with receiver as first arg + let mut is_user_box = false; + let mut class_name_opt: Option = None; + if let Some(bt) = box_type.clone() { class_name_opt = Some(bt); } + if class_name_opt.is_none() { + if let Some(cn) = self.value_origin_newbox.get(&receiver) { class_name_opt = Some(cn.clone()); } + } + if class_name_opt.is_none() { + if let Some(t) = self.value_types.get(&receiver) { + if let super::MirType::Box(bn) = t { class_name_opt = Some(bn.clone()); } + } + } + if let Some(cls) = class_name_opt.clone() { + // Prefer explicit registry of user-defined boxes when available + if self.user_defined_boxes.contains(&cls) { is_user_box = true; } + } + if is_user_box { + let cls = class_name_opt.unwrap(); + let arity = args.len(); // function name arity excludes 'me' + let fname = super::calls::function_lowering::generate_method_function_name(&cls, &method, arity); + let name_const = self.value_gen.next(); + self.emit_instruction(MirInstruction::Const { + dst: name_const, + value: super::ConstValue::String(fname), + })?; + let mut call_args = Vec::with_capacity(arity); + call_args.push(receiver); // pass 'me' first + call_args.extend(args.into_iter()); + return self.emit_instruction(MirInstruction::Call { + dst, + func: name_const, + callee: None, + args: call_args, + effects: EffectMask::READ.add(Effect::ReadHeap), + }); + } + // Else fall back to plugin/boxcall path (StringBox/ArrayBox/MapBox etc.) self.emit_box_or_plugin_call(dst, receiver, method, None, args, EffectMask::IO) }, CallTarget::Constructor(box_type) => { diff --git a/src/mir/builder/if_form.rs b/src/mir/builder/if_form.rs index e49e5168..387599b5 100644 --- a/src/mir/builder/if_form.rs +++ b/src/mir/builder/if_form.rs @@ -14,6 +14,7 @@ impl MirBuilder { // Heuristic pre-pin: if condition is a comparison, evaluate its operands now and pin them // so that subsequent branches can safely reuse these values across blocks. // This leverages existing variable_map merges (PHI) at the merge block. + if crate::config::env::mir_pre_pin_compare_operands() { if let ASTNode::BinaryOp { operator, left, right, .. } = &condition { match operator { BinaryOperator::Equal @@ -32,6 +33,7 @@ impl MirBuilder { _ => {} } } + } let condition_val = self.build_expression(condition)?; @@ -41,6 +43,7 @@ impl MirBuilder { let merge_block = self.block_gen.next(); // Branch + let pre_branch_bb = self.current_block()?; self.emit_instruction(MirInstruction::Branch { condition: condition_val, then_bb: then_block, @@ -51,12 +54,18 @@ impl MirBuilder { let pre_if_var_map = self.variable_map.clone(); // then - self.current_block = Some(then_block); - self.ensure_block_exists(then_block)?; + self.start_new_block(then_block)?; // Scope enter for then-branch self.hint_scope_enter(0); let then_ast_for_analysis = then_branch.clone(); self.variable_map = pre_if_var_map.clone(); + // Materialize all variables at block entry via single-pred Phi (correctness-first) + for (name, &pre_v) in pre_if_var_map.iter() { + let phi_val = self.value_gen.next(); + let inputs = vec![(pre_branch_bb, pre_v)]; + self.emit_instruction(MirInstruction::Phi { dst: phi_val, inputs })?; + self.variable_map.insert(name.clone(), phi_val); + } let then_value_raw = self.build_expression(then_branch)?; let then_exit_block = self.current_block()?; let then_var_map_end = self.variable_map.clone(); @@ -67,10 +76,16 @@ impl MirBuilder { } // else - self.current_block = Some(else_block); - self.ensure_block_exists(else_block)?; + self.start_new_block(else_block)?; // Scope enter for else-branch self.hint_scope_enter(0); + // Materialize all variables at block entry via single-pred Phi (correctness-first) + for (name, &pre_v) in pre_if_var_map.iter() { + let phi_val = self.value_gen.next(); + let inputs = vec![(pre_branch_bb, pre_v)]; + self.emit_instruction(MirInstruction::Phi { dst: phi_val, inputs })?; + self.variable_map.insert(name.clone(), phi_val); + } let (else_value_raw, else_ast_for_analysis, else_var_map_end_opt) = if let Some(else_ast) = else_branch { self.variable_map = pre_if_var_map.clone(); let val = self.build_expression(else_ast.clone())?; @@ -88,8 +103,9 @@ impl MirBuilder { } // merge: primary result via helper, then delta-based variable merges - self.current_block = Some(merge_block); - self.ensure_block_exists(merge_block)?; + // Ensure PHIs are first in the block by suppressing entry pin copies here + self.suppress_next_entry_pin_copy(); + self.start_new_block(merge_block)?; self.push_if_merge(merge_block); // Pre-analysis: identify then/else assigned var for skip and hints diff --git a/src/mir/builder/method_call_handlers.rs b/src/mir/builder/method_call_handlers.rs index 77380e70..2585e26e 100644 --- a/src/mir/builder/method_call_handlers.rs +++ b/src/mir/builder/method_call_handlers.rs @@ -97,6 +97,84 @@ impl MirBuilder { arg_values.push(self.build_expression(arg.clone())?); } + // If receiver is a user-defined box, lower to function call: "Box.method/(1+arity)" + let mut class_name_opt: Option = None; + if let Some(cn) = self.value_origin_newbox.get(&object_value) { class_name_opt = Some(cn.clone()); } + if class_name_opt.is_none() { + if let Some(t) = self.value_types.get(&object_value) { + if let MirType::Box(bn) = t { class_name_opt = Some(bn.clone()); } + } + } + if let Some(cls) = class_name_opt.clone() { + if self.user_defined_boxes.contains(&cls) { + let arity = arg_values.len(); // function name arity excludes 'me' + let fname = crate::mir::builder::calls::function_lowering::generate_method_function_name(&cls, &method, arity); + // Only use userbox path if such a function actually exists in the module + let has_fn = if let Some(ref module) = self.current_module { + module.functions.contains_key(&fname) + } else { false }; + if has_fn { + if super::utils::builder_debug_enabled() || std::env::var("NYASH_BUILDER_DEBUG").ok().as_deref() == Some("1") { + super::utils::builder_debug_log(&format!("userbox method-call cls={} method={} fname={}", cls, method, fname)); + } + let name_const = self.value_gen.next(); + self.emit_instruction(MirInstruction::Const { + dst: name_const, + value: crate::mir::builder::ConstValue::String(fname), + })?; + let mut call_args = Vec::with_capacity(arity + 1); + call_args.push(object_value); // 'me' + call_args.extend(arg_values.into_iter()); + let dst = self.value_gen.next(); + self.emit_instruction(MirInstruction::Call { + dst: Some(dst), + func: name_const, + callee: None, + args: call_args, + effects: crate::mir::EffectMask::READ.add(crate::mir::Effect::ReadHeap), + })?; + return Ok(dst); + } + } + } + + // Fallback: if exactly one user-defined method matches by name/arity across module, resolve to that + if let Some(ref module) = self.current_module { + let tail = format!(".{}{}", method, format!("/{}", arg_values.len())); + let mut cands: Vec = module + .functions + .keys() + .filter(|k| k.ends_with(&tail)) + .cloned() + .collect(); + if cands.len() == 1 { + let fname = cands.remove(0); + // sanity: ensure the box prefix looks like a user-defined box + if let Some((bx, _)) = fname.split_once('.') { + if self.user_defined_boxes.contains(bx) { + let name_const = self.value_gen.next(); + self.emit_instruction(MirInstruction::Const { + dst: name_const, + value: crate::mir::builder::ConstValue::String(fname), + })?; + let mut call_args = Vec::with_capacity(arg_values.len() + 1); + call_args.push(object_value); // 'me' + call_args.extend(arg_values.into_iter()); + let dst = self.value_gen.next(); + self.emit_instruction(MirInstruction::Call { + dst: Some(dst), + func: name_const, + callee: None, + args: call_args, + effects: crate::mir::EffectMask::READ.add(crate::mir::Effect::ReadHeap), + })?; + return Ok(dst); + } + } + } + } + + // Else fall back to plugin/boxcall path let result_id = self.value_gen.next(); self.emit_box_or_plugin_call( Some(result_id), @@ -109,4 +187,4 @@ impl MirBuilder { Ok(result_id) } -} \ No newline at end of file +} diff --git a/src/mir/builder/ops.rs b/src/mir/builder/ops.rs index 57bfaeeb..7563afbb 100644 --- a/src/mir/builder/ops.rs +++ b/src/mir/builder/ops.rs @@ -87,9 +87,10 @@ impl super::MirBuilder { } else { (lhs, rhs) }; - // Materialize operands in the current block to avoid dominance/undef issues - let lhs2 = lhs2_raw; - let rhs2 = rhs2_raw; + // Ensure operands are safe across blocks: pin ephemeral values into slots + // This guarantees they participate in PHI merges and have block-local defs. + let lhs2 = self.ensure_slotified_for_use(lhs2_raw, "@cmp_lhs")?; + let rhs2 = self.ensure_slotified_for_use(rhs2_raw, "@cmp_rhs")?; self.emit_instruction(MirInstruction::Compare { dst, op, @@ -128,16 +129,24 @@ impl super::MirBuilder { then_bb: then_block, else_bb: else_block, })?; + // Record predecessor block for branch (for single-pred PHI materialization) + let pre_branch_bb = self.current_block()?; // Snapshot variables before entering branches let pre_if_var_map = self.variable_map.clone(); // ---- THEN branch ---- - self.current_block = Some(then_block); - self.ensure_block_exists(then_block)?; + self.start_new_block(then_block)?; self.hint_scope_enter(0); // Reset scope to pre-if snapshot for clean deltas self.variable_map = pre_if_var_map.clone(); + // Materialize all variables at entry via single-pred PHI (correctness-first) + for (name, &pre_v) in pre_if_var_map.iter() { + let phi_val = self.value_gen.next(); + let inputs = vec![(pre_branch_bb, pre_v)]; + self.emit_instruction(MirInstruction::Phi { dst: phi_val, inputs })?; + self.variable_map.insert(name.clone(), phi_val); + } // AND: then → evaluate RHS and reduce to bool // OR: then → constant true @@ -187,10 +196,16 @@ impl super::MirBuilder { } // ---- ELSE branch ---- - self.current_block = Some(else_block); - self.ensure_block_exists(else_block)?; + self.start_new_block(else_block)?; self.hint_scope_enter(0); self.variable_map = pre_if_var_map.clone(); + // Materialize all variables at entry via single-pred PHI (correctness-first) + for (name, &pre_v) in pre_if_var_map.iter() { + let phi_val = self.value_gen.next(); + let inputs = vec![(pre_branch_bb, pre_v)]; + self.emit_instruction(MirInstruction::Phi { dst: phi_val, inputs })?; + self.variable_map.insert(name.clone(), phi_val); + } // AND: else → false // OR: else → evaluate RHS and reduce to bool let else_value_raw = if is_and { @@ -238,8 +253,9 @@ impl super::MirBuilder { } // ---- MERGE ---- - self.current_block = Some(merge_block); - self.ensure_block_exists(merge_block)?; + // Merge block: suppress entry pin copy so PHIs remain first and materialize pins explicitly + self.suppress_next_entry_pin_copy(); + self.start_new_block(merge_block)?; self.push_if_merge(merge_block); // Result PHI (bool) diff --git a/src/mir/builder/phi.rs b/src/mir/builder/phi.rs index db5956c6..18068d32 100644 --- a/src/mir/builder/phi.rs +++ b/src/mir/builder/phi.rs @@ -25,6 +25,8 @@ impl MirBuilder { then_map_end, else_map_end_opt, ); + use std::collections::HashSet; + let changed_set: HashSet = changed.iter().cloned().collect(); for name in changed { if skip_var.map(|s| s == name).unwrap_or(false) { continue; @@ -50,6 +52,29 @@ impl MirBuilder { self.emit_instruction(MirInstruction::Phi { dst: merged, inputs })?; self.variable_map.insert(name, merged); } + + // Ensure pinned synthetic slots ("__pin$...") have a block-local definition at the merge, + // even if their values did not change across branches. This avoids undefined uses when + // subsequent blocks re-use pinned values without modifications. + for (pin_name, pre_val) in pre_if_snapshot.iter() { + if !pin_name.starts_with("__pin$") { continue; } + if skip_var.map(|s| s == pin_name.as_str()).unwrap_or(false) { continue; } + if changed_set.contains(pin_name) { continue; } + let then_v = then_map_end.get(pin_name.as_str()).copied().unwrap_or(*pre_val); + let else_v = else_map_end_opt + .as_ref() + .and_then(|m| m.get(pin_name.as_str()).copied()) + .unwrap_or(*pre_val); + let then_pred = then_exit_block; + let else_pred = else_exit_block_opt.unwrap_or(else_block); + let merged = self.value_gen.next(); + let inputs = vec![(then_pred, then_v), (else_pred, else_v)]; + if let (Some(func), Some(cur_bb)) = (&self.current_function, self.current_block) { + crate::mir::phi_core::common::debug_verify_phi_inputs(func, cur_bb, &inputs); + } + self.emit_instruction(MirInstruction::Phi { dst: merged, inputs })?; + self.variable_map.insert(pin_name.clone(), merged); + } Ok(()) } /// Normalize Phi creation for if/else constructs. diff --git a/src/mir/builder/utils.rs b/src/mir/builder/utils.rs index c830e7ce..65a54271 100644 --- a/src/mir/builder/utils.rs +++ b/src/mir/builder/utils.rs @@ -32,17 +32,21 @@ impl super::MirBuilder { if let Some(ref mut function) = self.current_function { function.add_block(BasicBlock::new(block_id)); self.current_block = Some(block_id); - // Entry materialization for pinned slots only: ensure a local def exists in this block - // This avoids dominance/undef issues when pinned values are referenced across blocks. - let names: Vec = self.variable_map.keys().cloned().collect(); - for name in names { - if !name.starts_with("__pin$") { continue; } - if let Some(&src) = self.variable_map.get(&name) { - let dst = self.value_gen.next(); - self.emit_instruction(super::MirInstruction::Copy { dst, src })?; - self.variable_map.insert(name.clone(), dst); + // Entry materialization for pinned slots only when not suppressed. + // This provides block-local defs in single-predecessor flows without touching user vars. + if !self.suppress_pin_entry_copy_next { + let names: Vec = self.variable_map.keys().cloned().collect(); + for name in names { + if !name.starts_with("__pin$") { continue; } + if let Some(&src) = self.variable_map.get(&name) { + let dst = self.value_gen.next(); + self.emit_instruction(super::MirInstruction::Copy { dst, src })?; + self.variable_map.insert(name.clone(), dst); + } } } + // Reset suppression flag after use (one-shot) + self.suppress_pin_entry_copy_next = false; Ok(()) } else { Err("No current function".to_string()) @@ -204,12 +208,16 @@ impl super::MirBuilder { }) } - /// Pin a block-crossing ephemeral value into a pseudo local slot so it participates in PHI merges. + /// Pin a block-crossing ephemeral value into a pseudo local slot and register it in variable_map + /// so it participates in PHI merges across branches/blocks. Safe default for correctness-first. pub(crate) fn pin_to_slot(&mut self, v: super::ValueId, hint: &str) -> Result { self.temp_slot_counter = self.temp_slot_counter.wrapping_add(1); let slot_name = format!("__pin${}${}", self.temp_slot_counter, hint); let dst = self.value_gen.next(); self.emit_instruction(super::MirInstruction::Copy { dst, src: v })?; + if super::utils::builder_debug_enabled() || std::env::var("NYASH_PIN_TRACE").ok().as_deref() == Some("1") { + super::utils::builder_debug_log(&format!("pin slot={} src={} dst={}", slot_name, v.0, dst.0)); + } self.variable_map.insert(slot_name, dst); Ok(dst) } @@ -220,4 +228,10 @@ impl super::MirBuilder { self.emit_instruction(super::MirInstruction::Copy { dst, src: v })?; Ok(dst) } + + /// Ensure a value is safe to use in the current block by slotifying (pinning) it. + /// Currently correctness-first: always pin to get a block-local def and PHI participation. + pub(crate) fn ensure_slotified_for_use(&mut self, v: super::ValueId, hint: &str) -> Result { + self.pin_to_slot(v, hint) + } } diff --git a/src/mir/loop_builder.rs b/src/mir/loop_builder.rs index ce2cbdf0..29db9711 100644 --- a/src/mir/loop_builder.rs +++ b/src/mir/loop_builder.rs @@ -152,6 +152,7 @@ impl<'a> LoopBuilder<'a> { // 5. 条件評価(Phi nodeの結果を使用) // Heuristic pre-pin: if condition is a comparison, evaluate its operands and pin them // so that the loop body/next iterations can safely reuse these values across blocks. + if crate::config::env::mir_pre_pin_compare_operands() { if let ASTNode::BinaryOp { operator, left, right, .. } = &condition { use crate::ast::BinaryOperator as BO; match operator { @@ -166,15 +167,27 @@ impl<'a> LoopBuilder<'a> { _ => {} } } + } let condition_value = self.build_expression_with_phis(condition)?; // 6. 条件分岐 + let pre_branch_bb = self.current_block()?; self.emit_branch(condition_value, body_id, after_loop_id)?; let _ = crate::mir::builder::loops::add_predecessor(self.parent_builder, body_id, header_id); let _ = crate::mir::builder::loops::add_predecessor(self.parent_builder, after_loop_id, header_id); // 7. ループボディの構築 self.set_current_block(body_id)?; + // Materialize pinned slots at entry via single-pred Phi + let names: Vec = self.parent_builder.variable_map.keys().cloned().collect(); + for name in names { + if !name.starts_with("__pin$") { continue; } + if let Some(&pre_v) = self.parent_builder.variable_map.get(&name) { + let phi_val = self.new_value(); + self.emit_phi_at_block_start(body_id, phi_val, vec![(pre_branch_bb, pre_v)])?; + self.update_variable(name, phi_val); + } + } // Scope enter for loop body self.parent_builder.hint_scope_enter(0); // Optional safepoint per loop-iteration @@ -467,6 +480,7 @@ impl<'a> LoopBuilder<'a> { else_body: Option>, ) -> Result { // Pre-pin comparison operands to slots so repeated uses across blocks are safe + if crate::config::env::mir_pre_pin_compare_operands() { if let ASTNode::BinaryOp { operator, left, right, .. } = &condition { use crate::ast::BinaryOperator as BO; match operator { @@ -481,11 +495,13 @@ impl<'a> LoopBuilder<'a> { _ => {} } } + } // Evaluate condition and create blocks let cond_val = self.parent_builder.build_expression(condition)?; let then_bb = self.new_block(); let else_bb = self.new_block(); let merge_bb = self.new_block(); + let pre_branch_bb = self.current_block()?; self.emit_branch(cond_val, then_bb, else_bb)?; // Capture pre-if variable map (used for phi normalization) @@ -494,6 +510,15 @@ impl<'a> LoopBuilder<'a> { // then branch self.set_current_block(then_bb)?; + // Materialize all variables at entry via single-pred Phi (correctness-first) + let names_then: Vec = self.parent_builder.variable_map.keys().cloned().collect(); + for name in names_then { + if let Some(&pre_v) = self.parent_builder.variable_map.get(&name) { + let phi_val = self.new_value(); + self.emit_phi_at_block_start(then_bb, phi_val, vec![(pre_branch_bb, pre_v)])?; + self.update_variable(name, phi_val); + } + } for s in then_body.iter().cloned() { let _ = self.build_statement(s)?; // フェーズS修正:統一終端検出ユーティリティ使用 @@ -510,6 +535,15 @@ impl<'a> LoopBuilder<'a> { // else branch self.set_current_block(else_bb)?; + // Materialize all variables at entry via single-pred Phi (correctness-first) + let names2: Vec = self.parent_builder.variable_map.keys().cloned().collect(); + for name in names2 { + if let Some(&pre_v) = self.parent_builder.variable_map.get(&name) { + let phi_val = self.new_value(); + self.emit_phi_at_block_start(else_bb, phi_val, vec![(pre_branch_bb, pre_v)])?; + self.update_variable(name, phi_val); + } + } let mut else_var_map_end_opt: Option> = None; if let Some(es) = else_body.clone() { for s in es.into_iter() {