feat(joinir): Phase 259 P0 - Pattern8 BoolPredicateScan + Copy binding fix

Pattern8 (Boolean Predicate Scan) implementation for is_integer/1:
- New pattern detection for `loop + if not predicate() { return false }`
- JoinIR lowerer with main/loop_step/k_exit structure
- Me receiver passed as param (by-name 禁止)

Key fixes:
1. expr_result = Some(join_exit_value) (Pattern7 style)
2. Tail-call: dst: None (no extra Ret instruction)
3. instruction_rewriter: Add `&& is_loop_header_with_phi` check
   - Pattern8 has no carriers → no PHIs → MUST generate Copy bindings
   - Without this, ValueId(103/104/105) were undefined

Status: Copy instructions now generated correctly, but exit block
creation issue remains (next step: Step A-C in指示書).

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-21 02:40:07 +09:00
parent e4f57ea83d
commit a767f0f3a9
10 changed files with 913 additions and 5 deletions

View File

@ -22,8 +22,42 @@ Related:
## Proposed Approach (P0)
方針: preludenested-ifは既存 lowering のまま、loop 部分だけを scan パターンへ寄せる(構造で解決)。
**P0 Design Decision: Pattern8新規採用**
P0 の狙い:
- loop の core は “scan until mismatch” で、Pattern6scanと近い
- ただし return 値が `i/-1` ではなく `true/false` なので、scan パターンの “return payload” を一般化する必要がある可能性がある
### Why Pattern8?
Pattern6index_of系は "見つける" scan返り値: 整数 i or -1で、is_integer は "全部検証する" predicate scan返り値: 真偽値 true/false。役割が異なるため、Pattern8 として分離した。
### Pattern8 vs Pattern6
| | Pattern6 (index_of系) | Pattern8 (is_integer系) |
|---|---|---|
| 役割 | "見つける" scan | "全部検証する" predicate scan |
| Match形 | `substring(...) == needle` | `not predicate(ch)` → early exit |
| 返り値 | Integer (i or -1) | Boolean (true/false) |
| Exit PHI | `i`(ループ状態変数) | `ret_bool`(検証結果) |
| Carriers | [i] (LoopState) | [] (empty, expr_result のみ) |
### JoinIR Contract
- **jump_args_layout**: ExprResultPlusCarrierscarriers=0
- **expr_result**: Some(join_exit_value) - ret_bool from k_exit (pipeline handling)
- **exit_bindings**: Emptycarriers なし)
- **SSOT**: `join_inputs = entry_func.params.clone()`
- **Me receiver**: Passed as param [i, me, s] (by-name 禁止)
### 受理形P0固定
```nyash
loop(i < s.length()) {
if not this.is_digit(s.substring(i, i + 1)) {
return false
}
i = i + 1
}
return true
```
- prelude の start 計算は許可(ただし i_init = start で渡す)
- predicate は Me method callthis.is_digitのみ
- step は 1 固定