Files
hakorune/docs/development/current/main/mir-nested-if-loop-bug.md
nyash-codex d5b065e5c4 docs(phase173): Phase 173 Task 1-3 complete - investigation, spec, and JsonParserBox bugfix
📚 Phase 173 前半完了(Task 1-3)!

 Task 1: 名前解決経路調査
- UsingResolverBox / CalleeResolverBox 構造把握
- 3つの重大問題発見:
  1. 静的 Box が InstanceBox として扱われる
  2. JsonParserBox _parse_number 無限ループ
  3. new Alias.BoxName() 構文未サポート

 Task 2: 仕様固定(docs)
- using.md: +179行(静的 Box 使用例)
- LANGUAGE_REFERENCE_2025.md: +54行(static box ライブラリ方針)

 Task 3: JsonParserBox バグ修正
- MIR Nested-If-in-Loop Bug 発見・回避
- while → loop() 構文統一(10箇所)
- ネスト if-else のフラット化

📋 成果物:
- phase173_task1_investigation.md(220行)
- phase173_using_static_box_resolution.md
- phase173-2_using_resolver_mir_lowering.md(後半指示書)
- mir-nested-if-loop-bug.md(バグ分析)
- json_parser_min.hako(テストファイル)

🎯 次: Task 4-6(using resolver + MIR lowering 統合)

🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 17:47:19 +09:00

4.3 KiB

MIR Nested-If-in-Loop Bug (Critical)

Date: 2025-12-04 Severity: Critical Status: Workaround Applied, Root Fix Needed

🐛 Problem Summary

Symptom: Infinite loop when using nested if-else statements inside loop() blocks.

Error Message:

[ERROR] VM error: vm step budget exceeded (max_steps=1000000, steps=1000001)

📊 Root Cause Analysis

MIR Lowering Bug

The MIR builder generates incorrect control flow for nested if-else statements inside loops:

// ❌ Causes infinite loop
loop(condition) {
    if expr1 {
        if expr2 {
            // code
        } else {
            break
        }
    } else {
        break
    }
}

Control Flow Issue

Generated MIR:

bb4: loop header (PHI)
bb6: unconditional jump to bb4
bb11: unconditional jump to bb6

Jump chain: bb11 → bb6 → bb4 → ... (infinite)

Problem: The PHI node in bb4 never gets updated because the execution gets stuck in the bb11→bb6→bb4 jump chain.

🔬 Reproduction Case

Minimal Test Case

static box Main {
  main() {
    local i = 0

    loop(i < 3) {
      local x = 1

      if x == 1 {
        if x == 1 {
          i = i + 1
        } else {
          break
        }
      } else {
        break
      }
    }

    return 0
  }
}

Result: vm step budget exceeded at bb6

MIR Dump Analysis

bb6:
    1: br label bb4

bb11:
    1: br label bb6

Infinite unconditional jump chain with no PHI update.

Workaround

Strategy: Flatten Nested Ifs

Before (infinite loop):

loop(p < s.length()) {
    local ch = s.substring(p, p+1)
    if ch >= "0" && ch <= "9" {
        num_str = num_str + ch
        p = p + 1
    } else {
        break
    }
}

After (fixed):

local parsing_done = 0
loop(p < s.length()) {
    if parsing_done == 1 { break }

    local ch = s.substring(p, p+1)
    local digits = "0123456789"
    local digit_pos = digits.indexOf(ch)

    if digit_pos >= 0 {
        num_str = num_str + ch
        p = p + 1
    } else {
        parsing_done = 1
    }
}

Patterns to Avoid

  1. Nested if-else in loop:

    loop(cond) {
        if a {
            if b { ... } else { break }
        } else { break }
    }
    
  2. && operator in loop condition:

    loop(cond) {
        if x >= "0" && x <= "9" { ... }
    }
    

Safe Patterns

  1. Flatten with flags:

    local done = 0
    loop(cond) {
        if done == 1 { break }
        // single-level if statements
    }
    
  2. Use indexOf instead of range check:

    local digits = "0123456789"
    if digits.indexOf(ch) >= 0 { ... }
    

📋 Affected Code

Fixed Files

  1. tools/hako_shared/json_parser.hako:

    • _parse_number(): Used indexOf() workaround
    • _parse_string(): Flattened escape sequence check
    • _unescape_string(): Flattened ch == "\\" && i + 1 < s.length()
  2. Converted whileloop() (10 occurrences):

    • All while loops converted to loop() syntax per language spec

Commit

  • Commit: 608693af
  • Title: fix(json_parser): Fix infinite loop by working around MIR nested-if bug
  • Files Changed: 1 file, +45/-23 lines

🎯 Root Fix Needed

MIR Builder Issue

Location: src/mir/builder/ (control flow lowering)

Problem: When lowering nested if-else inside loops, the builder creates:

  • Unreachable PHI nodes
  • Unconditional jump chains
  • Missing latch block updates

Solution Required:

  1. Fix control flow graph generation for nested conditionals
  2. Ensure PHI nodes are properly connected
  3. Add test cases for nested if-else in loops

Test Coverage

Add comprehensive tests for:

  • Nested if-else in loops (2+ levels)
  • && and || operators in loop conditions
  • break and continue in nested contexts
  • Phase 173 Task 3: JsonParserBox bug fix (completed with workaround)
  • CLAUDE.md: whileloop() syntax migration
  • Loop Builder: src/mir/loop_builder.rs (potential fix location)

🔗 References

  • Test Case: test_nested_if_loop.hako (reproduces bug)
  • JSON Parser: tools/hako_shared/json_parser.hako (workaround applied)
  • CURRENT_TASK.md: Phase 173 tracking

Status: Workaround deployed, root fix tracked for future MIR lowering improvements.