mir/vm: SSA pin+PHI + short-circuit; user-defined method calls → functions; entry single-pred PHIs; compare-operand pin; VM BoxCall fallback to InstanceBox methods; docs: update CURRENT_TASK (plan + acceptance)
- Lower And/Or to branch+PHI (RHS not evaluated) - Always slotify compare operands (dominance safety) - Insert single-predecessor PHIs at then/else/short-circuit entries - pin_to_slot now logs (NYASH_PIN_TRACE) and participates in PHI - Rewrite user-defined instance method calls to Box.method/Arity (builder) - VM fallback: BoxCall on InstanceBox dispatches to lowered functions with 'me'+args - Keep plugin/BoxCall path for core boxes (String/Array/Map) - Add env-gated pre-pin for if/loop (NYASH_MIR_PREPIN) - CURRENT_TASK: add SSA/userbox plan, debug steps, acceptance criteria
This commit is contained in:
@ -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 の未実装は許容)。
|
||||
|
||||
@ -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. 実践的ガイドライン
|
||||
|
||||
|
||||
@ -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<ValueId, String> {
|
||||
// ローカルコピーでブロック内にマテリアライズ
|
||||
// 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<ValueId, String> {
|
||||
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協働開発において技術的能力以上に重要なのは、人間の深層的価値観を理解し、それに基づく長期的判断を支援する能力であることである。**
|
||||
@ -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<T> = 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[抽象度: 最高<br/>Everything is Loop] -->|実装困難| B[抽象度: 高<br/>Loop State Unification]
|
||||
B -->|実装困難| C[抽象度: 中<br/>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: 三段階進化による設計空間の完全探索
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**「ループに始まりループに終わる」— この言葉は、単なる設計思想ではなく、創造的思考の本質的構造を表現している。理想から現実への収束は、敗北ではなく、設計者の成熟の証なのである。**
|
||||
@ -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::<crate::instance_v2::InstanceBox>() {
|
||||
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<VMValue> = 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(),
|
||||
|
||||
@ -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)),
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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(); }
|
||||
|
||||
@ -57,8 +57,44 @@ impl super::MirBuilder {
|
||||
args: Vec<ValueId>,
|
||||
) -> 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<String> = 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) => {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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<String> = 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<String> = 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),
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -25,6 +25,8 @@ impl MirBuilder {
|
||||
then_map_end,
|
||||
else_map_end_opt,
|
||||
);
|
||||
use std::collections::HashSet;
|
||||
let changed_set: HashSet<String> = 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.
|
||||
|
||||
@ -32,8 +32,9 @@ 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.
|
||||
// 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<String> = self.variable_map.keys().cloned().collect();
|
||||
for name in names {
|
||||
if !name.starts_with("__pin$") { continue; }
|
||||
@ -43,6 +44,9 @@ impl super::MirBuilder {
|
||||
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<super::ValueId, String> {
|
||||
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<super::ValueId, String> {
|
||||
self.pin_to_slot(v, hint)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<String> = 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<Vec<ASTNode>>,
|
||||
) -> Result<ValueId, String> {
|
||||
// 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<String> = 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<String> = 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<HashMap<String, ValueId>> = None;
|
||||
if let Some(es) = else_body.clone() {
|
||||
for s in es.into_iter() {
|
||||
|
||||
Reference in New Issue
Block a user