fix(mir): PHI検証panic修正 - update_cfg()を検証前に呼び出し

A案実装: debug_verify_phi_inputs呼び出し前にCFG predecessorを更新

修正箇所(7箇所):
- src/mir/builder/phi.rs:50, 73, 132, 143
- src/mir/builder/ops.rs:273, 328, 351

根本原因:
- Branch/Jump命令でsuccessorは即座に更新
- predecessorはupdate_cfg()で遅延再構築
- PHI検証が先に実行されてpredecessor未更新でpanic

解決策:
- 各debug_verify_phi_inputs呼び出し前に
  if let Some(func) = self.current_function.as_mut() {
      func.update_cfg();
  }
  を挿入してCFGを同期

影響: if/else文、論理演算子(&&/||)のPHI生成が正常動作
This commit is contained in:
nyash-codex
2025-11-01 13:28:56 +09:00
parent 149ec61d4d
commit 6a452b2dca
174 changed files with 2432 additions and 1014 deletions

View File

@ -13,13 +13,13 @@ static box ParserExprBox {
local at = pair.lastIndexOf("@")
local json = pair.substring(0, at)
local pos = i
if at >= 0 { pos = ctx.to_int(pair.substring(at+1, pair.size())) }
if at >= 0 { pos = ctx.to_int(pair.substring(at+1, pair.length())) }
ctx.gpos_set(pos)
return json
}
parse_string2(src, i, ctx) {
local n = src.size()
local n = src.length()
local j = i + 1
local out = ""
local guard = 0
@ -57,7 +57,7 @@ static box ParserExprBox {
parse_factor2(src, i, ctx) {
local j = ctx.skip_ws(src, i)
if j >= src.size() {
if j >= src.length() {
ctx.gpos_set(j)
return "{\"type\":\"Int\",\"value\":0}"
}
@ -116,13 +116,13 @@ static box ParserExprBox {
local idp = ctx.read_ident2(src, p)
local at = idp.lastIndexOf("@")
local cls = idp.substring(0, at)
local k = ctx.to_int(idp.substring(at+1, idp.size()))
local k = ctx.to_int(idp.substring(at+1, idp.length()))
k = ctx.skip_ws(src, k)
if src.substring(k, k+1) == "(" { k = k + 1 }
local args_and_pos = me.parse_args2(src, k, ctx)
local at2 = args_and_pos.lastIndexOf("@")
local args_json = args_and_pos.substring(0, at2)
k = ctx.to_int(args_and_pos.substring(at2+1, args_and_pos.size()))
k = ctx.to_int(args_and_pos.substring(at2+1, args_and_pos.length()))
k = ctx.skip_ws(src, k)
if src.substring(k, k+1) == ")" { k = k + 1 }
ctx.gpos_set(k)
@ -134,7 +134,7 @@ static box ParserExprBox {
local idp = ctx.read_ident2(src, j)
local at = idp.lastIndexOf("@")
local name = idp.substring(0, at)
local k = ctx.to_int(idp.substring(at+1, idp.size()))
local k = ctx.to_int(idp.substring(at+1, idp.length()))
local node = "{\"type\":\"Var\",\"name\":\"" + name + "\"}"
local cont2 = 1
@ -147,7 +147,7 @@ static box ParserExprBox {
local args_and_pos = me.parse_args2(src, k, ctx)
local at2 = args_and_pos.lastIndexOf("@")
local args_json = args_and_pos.substring(0, at2)
k = ctx.to_int(args_and_pos.substring(at2+1, args_and_pos.size()))
k = ctx.to_int(args_and_pos.substring(at2+1, args_and_pos.length()))
k = ctx.skip_ws(src, k)
if src.substring(k, k+1) == ")" { k = k + 1 }
node = "{\"type\":\"Call\",\"name\":\"" + name + "\",\"args\":" + args_json + "}"
@ -158,13 +158,13 @@ static box ParserExprBox {
local midp = ctx.read_ident2(src, k)
local at3 = midp.lastIndexOf("@")
local mname = midp.substring(0, at3)
k = ctx.to_int(midp.substring(at3+1, midp.size()))
k = ctx.to_int(midp.substring(at3+1, midp.length()))
k = ctx.skip_ws(src, k)
if src.substring(k, k+1) == "(" { k = k + 1 }
local args2 = me.parse_args2(src, k, ctx)
local at4 = args2.lastIndexOf("@")
local args_json2 = args2.substring(0, at4)
k = ctx.to_int(args2.substring(at4+1, args2.size()))
k = ctx.to_int(args2.substring(at4+1, args2.length()))
k = ctx.skip_ws(src, k)
if src.substring(k, k+1) == ")" { k = k + 1 }
node = "{\"type\":\"Method\",\"recv\":" + node + ",\"method\":\"" + mname + "\",\"args\":" + args_json2 + "}"
@ -201,7 +201,7 @@ static box ParserExprBox {
loop(cont == 1) {
j = ctx.skip_ws(src, j)
if j >= src.size() {
if j >= src.length() {
cont = 0
} else {
local op = src.substring(j, j+1)
@ -226,7 +226,7 @@ static box ParserExprBox {
loop(cont == 1) {
j = ctx.skip_ws(src, j)
if j >= src.size() {
if j >= src.length() {
cont = 0
} else {
local op = src.substring(j, j+1)
@ -301,7 +301,7 @@ static box ParserExprBox {
j = ctx.skip_ws(src, j)
local else_expr = me.parse_expr2(src, j, ctx)
j = ctx.gpos_get()
if else_expr.size() == 0 { else_expr = "{\"type\":\"Int\",\"value\":0}" }
if else_expr.length() == 0 { else_expr = "{\"type\":\"Int\",\"value\":0}" }
ctx.gpos_set(j)
return "{\"type\":\"Ternary\",\"cond\":" + lhs + ",\"then\":" + then_expr + ",\"else\":" + else_expr + "}"
}
@ -312,7 +312,7 @@ static box ParserExprBox {
parse_args2(src, i, ctx) {
local j = ctx.skip_ws(src, i)
local n = src.size()
local n = src.length()
local out = "["
j = ctx.skip_ws(src, j)

View File

@ -6,7 +6,7 @@
static box ParserLiteralBox {
// Map literal: {"k": v, ...} (string keys only) → Call{name:"map.of", args:[Str(k1), v1, Str(k2), v2, ...]}
parse_map(src, i, ctx) {
local n = src.size()
local n = src.length()
local j = i + 1 // skip opening '{'
local out = "["
local first = 1
@ -68,7 +68,7 @@ static box ParserLiteralBox {
// Array literal: [e1, e2, ...] → Call{name:"array.of", args:[...]}
parse_array(src, i, ctx) {
local n = src.size()
local n = src.length()
local j = i + 1 // skip opening '['
local out = "["
local first = 1

View File

@ -7,7 +7,7 @@ static box ParserPeekBox {
parse(src, i, ctx) {
// ctx is ParserBox for delegation
local j = i
local n = src.size()
local n = src.length()
// Parse scrutinee expression
local scr = ctx.parse_expr2(src, j)