## 修正内容 ### 1. Stage-B パーサー修正(偶然の回避) - **ファイル**: - `lang/src/compiler/parser/expr/parser_expr_box.hako` - `lang/src/compiler/parser/stmt/parser_control_box.hako` - **問題**: ネストループで gpos が正しく進まず、loop の cond/body が壊れる - **回避策**: new 式のメソッドチェーン処理追加で別ループを導入 - **結果**: MIR 生成が変わって VM gpos バグを回避 ### 2. delegate パス動作確認 - **テスト**: `/tmp/loop_min.hako` → rc=10 ✅ - **MIR構造**: 正しい PHI/compare/binop を生成 - **チェーン**: hakorune parser → Rust delegate → LLVM EXE 完動 ### 3. ドキュメント追加 - `docs/development/analysis/` - delegate 分析 - `docs/development/guides/` - ループテストガイド - `docs/development/testing/` - Stage-B 検証報告 ### 4. カナリーテスト追加 - `tools/smokes/v2/profiles/quick/core/phase2100/` 配下に複数追加 - emit_boxcall_length_canary_vm.sh - stageb_parser_loop_json_canary_vm.sh - 他 ### 受け入れ基準 - ✅ delegate パス: rc=10 返す - ✅ FORCE パス: rc=10 返す(既存) - ✅ MIR 構造: 正しい PHI incoming と compare - ✅ 既定挙動: 不変(dev トグルのみ) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
5.9 KiB
Delegate Loop Lowering Analysis
Executive Summary
Root Cause: The delegate path loop lowering issue is NOT a bug in the Rust lowering code (src/runner/json_v0_bridge/lowering/loop_.rs). The actual problem is in the Stage-B self-hosting compiler (lang/src/compiler/entry/compiler_stageb.hako and lang/src/compiler/parser/parser_box.hako) which produces malformed Program JSON v0.
Status: The Rust delegate lowering code is correct. The Stage-B parser is producing incorrect output.
Problem Description
Test Case
static box Main { method main(){
local n=10; local i=0;
loop(i<n){ i=i+1 }
return i
} }
Expected: Returns 10 Actual (delegate): Returns 0 Actual (FORCE): Returns 10 ✅
Investigation Findings
1. Malformed Program JSON v0
The Stage-B compiler produces this Program JSON:
{
"body": [
{"type":"Local","name":"n","expr":{"type":"Int","value":10}},
{"type":"Local","name":"i","expr":{"type":"Int","value":0}},
{"type":"Loop","cond":{"type":"Compare","op":"<","lhs":{"type":"Var","name":"i"},"rhs":{"type":"Int","value":0}},"body":[]},
...
]
}
Two Critical Bugs:
- Empty loop body:
"body":[]instead of[{"type":"Local","name":"i","expr":{"type":"Binary",...}}] - Wrong condition: Compares
i < 0instead ofi < n(rhs is{"type":"Int","value":0}instead of{"type":"Var","name":"n"})
2. Delegate MIR Structure (Incorrect)
The delegate path produces this MIR:
Block 1 (Header):
{
"op": "phi", "dst": 3, "incoming": [[2,0],[2,2]] // Wrong: both from reg 2
},
{
"op": "phi", "dst": 5, "incoming": [[4,0],[4,2]] // Wrong: both from reg 4
},
{
"op": "compare", "operation": "<", "lhs": 5, "rhs": 6 // Wrong: compares i < 0
}
Block 2 (Body):
{
"op": "jump", "target": 1 // Empty body - no i=i+1!
}
3. FORCE MIR Structure (Correct)
The FORCE path (using selfhost-first with JsonFrag) produces correct MIR:
Block 1 (Header):
{
"op": "phi", "dst": 6, "incoming": [[2,0],[6,2]] // Correct: n from preheader/itself
},
{
"op": "phi", "dst": 3, "incoming": [[1,0],[5,2]] // Correct: i from 0/updated
},
{
"op": "compare", "operation": "<", "lhs": 3, "rhs": 6 // Correct: i < n
}
Block 2 (Body):
{
"op": "const", "dst": 10, "value": {"type":"i64","value":1}
},
{
"op": "binop", "operation": "+", "lhs": 3, "rhs": 10, "dst": 5 // Correct: i+1
},
{
"op": "jump", "target": 1
}
Rust Delegate Lowering Code Analysis
The Rust lowering code in src/runner/json_v0_bridge/lowering/loop_.rs is CORRECT:
- Line 109-111: Correctly prepares loop PHIs with preheader seeds
- Line 115-116: Correctly lowers condition and sets up branch
- Line 117-123: Correctly clones vars and lowers body
- Line 133: Correctly saves
body_varsafter body execution - Line 145-152: Correctly seals PHIs with latch values
The code correctly implements:
- PHI preparation with preheader copies
- Body variable tracking
- PHI sealing with latch values
- Exit PHI generation
The problem is garbage-in, garbage-out: When the Program JSON has an empty body and wrong condition, the lowering correctly processes that incorrect input.
Verification
Test Results
FORCE Path (✅ Works):
HAKO_SELFHOST_BUILDER_FIRST=1 \
HAKO_MIR_BUILDER_LOOP_FORCE_JSONFRAG=1 \
bash tools/hakorune_emit_mir.sh /tmp/loop_min.hako /tmp/loop_min_force.json
# Result: MIR with correct structure, EXE returns 10
Delegate Path (❌ Broken):
NYASH_JSON_ONLY=1 \
bash tools/hakorune_emit_mir.sh /tmp/loop_min.hako /tmp/loop_min_delegate.json
# Result: MIR with empty body and wrong condition, EXE returns 0
Root Cause Location
The bug is in the Stage-B self-hosting compiler:
Entry Point: lang/src/compiler/entry/compiler_stageb.hako line 341
local ast_json = p.parse_program2(body_src)
Parser: lang/src/compiler/parser/parser_box.hako
- Likely in loop parsing logic
- Incorrectly handles loop body extraction
- Incorrectly handles loop condition parsing
Recommendations
Short-Term (Immediate)
-
Use FORCE path for production:
export HAKO_SELFHOST_BUILDER_FIRST=1 export HAKO_MIR_BUILDER_LOOP_FORCE_JSONFRAG=1 -
Document delegate path limitation:
- Add warning in tools/hakorune_emit_mir.sh
- Update phase documentation
Medium-Term (Fix)
-
Debug Stage-B parser:
- Add instrumentation to
parser_box.hako - Trace loop parsing logic
- Fix body extraction and condition parsing
- Add instrumentation to
-
Add Stage-B tests:
- Create test suite for Program JSON v0 output
- Include loop test cases
- Verify against expected JSON structure
Long-Term (Architecture)
-
Phase out Stage-B for critical paths:
- Keep FORCE path as primary
- Use delegate only for verified constructs
- Consider Rust-based parser for reliability
-
Improve JsonFrag robustness:
- The FORCE path already works correctly
- Focus optimization efforts there
Conclusion
The delegate loop lowering code is correct. The bug is upstream in the Stage-B self-hosting compiler which produces malformed Program JSON v0. The FORCE path works because it bypasses the buggy Stage-B parser and uses the JsonFrag-based MirBuilder implementation.
Immediate Action: Use FORCE path (HAKO_SELFHOST_BUILDER_FIRST=1) for all loop-related development and testing until the Stage-B parser is fixed.
Files Analyzed
- ✅
src/runner/json_v0_bridge/lowering/loop_.rs- Correct implementation - ✅
src/mir/phi_core/loop_phi.rs- Correct PHI management - ❌
lang/src/compiler/entry/compiler_stageb.hako- Calls buggy parser - ❌
lang/src/compiler/parser/parser_box.hako- Contains loop parsing bug - ✅
tools/hakorune_emit_mir.sh- Script wrapper (works as designed)
Date: 2025-11-11 Analyst: Claude (Sonnet 4.5) Context: Phase 21.5 Delegate Loop Lowering Investigation