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:
@ -5,14 +5,14 @@ static box Main {
|
||||
if a.isEmpty() != 1 { print("FAIL: empty array not empty") return 1 }
|
||||
a.push(1)
|
||||
if a.isEmpty() != 0 { print("FAIL: non-empty array empty") return 1 }
|
||||
if a.size() != 1 { print("FAIL: array size!=1") return 1 }
|
||||
if a.length() != 1 { print("FAIL: array size!=1") return 1 }
|
||||
|
||||
// Map
|
||||
local m = new MapBox()
|
||||
if m.isEmpty() != 1 { print("FAIL: empty map not empty") return 1 }
|
||||
m.set("k", 10)
|
||||
if m.isEmpty() != 0 { print("FAIL: non-empty map empty") return 1 }
|
||||
if m.size() != 1 { print("FAIL: map size!=1") return 1 }
|
||||
if m.length() != 1 { print("FAIL: map size!=1") return 1 }
|
||||
|
||||
print("OK: Array/Map size/isEmpty")
|
||||
return 0
|
||||
|
||||
@ -39,9 +39,9 @@ static box Main {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Test 5: ArrayBox.size()
|
||||
// Test 5: ArrayBox.length()
|
||||
local test5 = me._test_array_size()
|
||||
print("[Test 5] ArrayBox.size() - result: " + StringHelpers.int_to_str(test5))
|
||||
print("[Test 5] ArrayBox.length() - result: " + StringHelpers.int_to_str(test5))
|
||||
if test5 != 0 {
|
||||
print("[FAIL] Test 5: expected 0, got " + StringHelpers.int_to_str(test5))
|
||||
return 1
|
||||
@ -55,9 +55,9 @@ static box Main {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Test 7: MapBox.size()
|
||||
// Test 7: MapBox.length()
|
||||
local test7 = me._test_map_size()
|
||||
print("[Test 7] MapBox.size() - result: " + StringHelpers.int_to_str(test7))
|
||||
print("[Test 7] MapBox.length() - result: " + StringHelpers.int_to_str(test7))
|
||||
if test7 != 0 {
|
||||
print("[FAIL] Test 7: expected 0, got " + StringHelpers.int_to_str(test7))
|
||||
return 1
|
||||
@ -164,9 +164,9 @@ static box Main {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Test 5: ArrayBox.size()
|
||||
// Test 5: ArrayBox.length()
|
||||
_test_array_size() {
|
||||
// MIR JSON: newbox ArrayBox -> v%2, const 10 -> v%3, boxcall v%2.push(v%3) -> v%4, const 20 -> v%5, boxcall v%2.push(v%5) -> v%6, boxcall v%2.size() -> v%1, ret v%1
|
||||
// MIR JSON: newbox ArrayBox -> v%2, const 10 -> v%3, boxcall v%2.push(v%3) -> v%4, const 20 -> v%5, boxcall v%2.push(v%5) -> v%6, boxcall v%2.length() -> v%1, ret v%1
|
||||
local mir_json = "{\"functions\":[{\"name\":\"Main.main\",\"blocks\":[{\"id\":0,\"instructions\":[{\"op\":\"newbox\",\"dst\":2,\"box_type\":\"ArrayBox\",\"args\":[]},{\"op\":\"const\",\"dst\":3,\"value\":{\"Integer\":10}},{\"op\":\"boxcall\",\"dst\":4,\"box\":2,\"method\":\"push\",\"args\":[3]},{\"op\":\"const\",\"dst\":5,\"value\":{\"Integer\":20}},{\"op\":\"boxcall\",\"dst\":6,\"box\":2,\"method\":\"push\",\"args\":[5]},{\"op\":\"boxcall\",\"dst\":1,\"box\":2,\"method\":\"size\",\"args\":[]},{\"op\":\"copy\",\"dst\":7,\"src\":1}],\"terminator\":{\"op\":\"ret\",\"value\":7}}]}]}"
|
||||
|
||||
local vm_result = HakoruneVmCore.run(mir_json)
|
||||
@ -206,9 +206,9 @@ static box Main {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Test 7: MapBox.size()
|
||||
// Test 7: MapBox.length()
|
||||
_test_map_size() {
|
||||
// MIR JSON: newbox MapBox -> v%2, const "key1" -> v%3, const 100 -> v%4, boxcall v%2.set(v%3, v%4) -> v%5, const "key2" -> v%6, const 200 -> v%7, boxcall v%2.set(v%6, v%7) -> v%8, boxcall v%2.size() -> v%1, ret v%1
|
||||
// MIR JSON: newbox MapBox -> v%2, const "key1" -> v%3, const 100 -> v%4, boxcall v%2.set(v%3, v%4) -> v%5, const "key2" -> v%6, const 200 -> v%7, boxcall v%2.set(v%6, v%7) -> v%8, boxcall v%2.length() -> v%1, ret v%1
|
||||
local mir_json = "{\"functions\":[{\"name\":\"Main.main\",\"blocks\":[{\"id\":0,\"instructions\":[{\"op\":\"newbox\",\"dst\":2,\"box_type\":\"MapBox\",\"args\":[]},{\"op\":\"const\",\"dst\":3,\"value\":{\"String\":\"key1\"}},{\"op\":\"const\",\"dst\":4,\"value\":{\"Integer\":100}},{\"op\":\"boxcall\",\"dst\":5,\"box\":2,\"method\":\"set\",\"args\":[3,4]},{\"op\":\"const\",\"dst\":6,\"value\":{\"String\":\"key2\"}},{\"op\":\"const\",\"dst\":7,\"value\":{\"Integer\":200}},{\"op\":\"boxcall\",\"dst\":8,\"box\":2,\"method\":\"set\",\"args\":[6,7]},{\"op\":\"boxcall\",\"dst\":1,\"box\":2,\"method\":\"size\",\"args\":[]},{\"op\":\"copy\",\"dst\":9,\"src\":1}],\"terminator\":{\"op\":\"ret\",\"value\":9}}]}]}"
|
||||
|
||||
local vm_result = HakoruneVmCore.run(mir_json)
|
||||
@ -250,7 +250,7 @@ static box Main {
|
||||
|
||||
// Test 9: MapBox.keys()
|
||||
_test_map_keys() {
|
||||
// MIR JSON: newbox MapBox -> v%2, const "a" -> v%3, const 1 -> v%4, boxcall v%2.set(v%3, v%4) -> v%5, const "b" -> v%6, const 2 -> v%7, boxcall v%2.set(v%6, v%7) -> v%8, boxcall v%2.keys() -> v%1, boxcall v%1.size() -> v%9, ret v%9
|
||||
// MIR JSON: newbox MapBox -> v%2, const "a" -> v%3, const 1 -> v%4, boxcall v%2.set(v%3, v%4) -> v%5, const "b" -> v%6, const 2 -> v%7, boxcall v%2.set(v%6, v%7) -> v%8, boxcall v%2.keys() -> v%1, boxcall v%1.length() -> v%9, ret v%9
|
||||
local mir_json = "{\"functions\":[{\"name\":\"Main.main\",\"blocks\":[{\"id\":0,\"instructions\":[{\"op\":\"newbox\",\"dst\":2,\"box_type\":\"MapBox\",\"args\":[]},{\"op\":\"const\",\"dst\":3,\"value\":{\"String\":\"a\"}},{\"op\":\"const\",\"dst\":4,\"value\":{\"Integer\":1}},{\"op\":\"boxcall\",\"dst\":5,\"box\":2,\"method\":\"set\",\"args\":[3,4]},{\"op\":\"const\",\"dst\":6,\"value\":{\"String\":\"b\"}},{\"op\":\"const\",\"dst\":7,\"value\":{\"Integer\":2}},{\"op\":\"boxcall\",\"dst\":8,\"box\":2,\"method\":\"set\",\"args\":[6,7]},{\"op\":\"boxcall\",\"dst\":1,\"box\":2,\"method\":\"keys\",\"args\":[]},{\"op\":\"boxcall\",\"dst\":9,\"box\":1,\"method\":\"size\",\"args\":[]},{\"op\":\"copy\",\"dst\":10,\"src\":9}],\"terminator\":{\"op\":\"ret\",\"value\":10}}]}]}"
|
||||
|
||||
local vm_result = HakoruneVmCore.run(mir_json)
|
||||
|
||||
@ -13,7 +13,7 @@ static box Main {
|
||||
// mir_call new ArrayBox() → v1
|
||||
// const 42 → v2
|
||||
// mir_call v1.push(v2) → null
|
||||
// mir_call v1.size() → v3
|
||||
// mir_call v1.length() → v3
|
||||
// ret v3
|
||||
local mir1 = r#"{"functions":[{"name":"test","blocks":[{"id":0,"instructions":[{"op":"mir_call","dst":1,"mir_call":{"callee":{"type":"Constructor","box_type":"ArrayBox"},"args":[],"effects":["alloc"],"flags":{}}},{"op":"const","dst":2,"value":{"type":"i64","value":42}},{"op":"mir_call","dst":null,"mir_call":{"callee":{"type":"Method","receiver":1,"method":"push"},"args":[2],"effects":[],"flags":{}}},{"op":"mir_call","dst":3,"mir_call":{"callee":{"type":"Method","receiver":1,"method":"size"},"args":[],"effects":[],"flags":{}}},{"op":"ret","value":3}],"terminator":{"op":"ret","value":3}}]}]}"#
|
||||
|
||||
@ -29,7 +29,7 @@ static box Main {
|
||||
// Test 2: new MapBox() - birth()なしConstructor
|
||||
// Block 0:
|
||||
// mir_call new MapBox() → v1
|
||||
// mir_call v1.size() → v2
|
||||
// mir_call v1.length() → v2
|
||||
// ret v2
|
||||
local mir2 = r#"{"functions":[{"name":"test","blocks":[{"id":0,"instructions":[{"op":"mir_call","dst":1,"mir_call":{"callee":{"type":"Constructor","box_type":"MapBox"},"args":[],"effects":["alloc"],"flags":{}}},{"op":"mir_call","dst":2,"mir_call":{"callee":{"type":"Method","receiver":1,"method":"size"},"args":[],"effects":[],"flags":{}}},{"op":"ret","value":2}],"terminator":{"op":"ret","value":2}}]}]}"#
|
||||
|
||||
@ -50,8 +50,8 @@ static box Main {
|
||||
// mir_call new ArrayBox() → v3
|
||||
// const 20 → v4
|
||||
// mir_call v3.push(v4) → null
|
||||
// mir_call v1.size() → v5
|
||||
// mir_call v3.size() → v6
|
||||
// mir_call v1.length() → v5
|
||||
// mir_call v3.length() → v6
|
||||
// binop Add v5+v6 → v7
|
||||
// ret v7
|
||||
local mir3 = r#"{"functions":[{"name":"test","blocks":[{"id":0,"instructions":[{"op":"mir_call","dst":1,"mir_call":{"callee":{"type":"Constructor","box_type":"ArrayBox"},"args":[],"effects":["alloc"],"flags":{}}},{"op":"const","dst":2,"value":{"type":"i64","value":10}},{"op":"mir_call","dst":null,"mir_call":{"callee":{"type":"Method","receiver":1,"method":"push"},"args":[2],"effects":[],"flags":{}}},{"op":"mir_call","dst":3,"mir_call":{"callee":{"type":"Constructor","box_type":"ArrayBox"},"args":[],"effects":["alloc"],"flags":{}}},{"op":"const","dst":4,"value":{"type":"i64","value":20}},{"op":"mir_call","dst":null,"mir_call":{"callee":{"type":"Method","receiver":3,"method":"push"},"args":[4],"effects":[],"flags":{}}},{"op":"mir_call","dst":5,"mir_call":{"callee":{"type":"Method","receiver":1,"method":"size"},"args":[],"effects":[],"flags":{}}},{"op":"mir_call","dst":6,"mir_call":{"callee":{"type":"Method","receiver":3,"method":"size"},"args":[],"effects":[],"flags":{}}},{"op":"binop","op_kind":"Add","dst":7,"lhs":5,"rhs":6},{"op":"ret","value":7}],"terminator":{"op":"ret","value":7}}]}]}"#
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
// test_mircall_phase2_method.hako — MirCall Phase 2 tests (Method)
|
||||
// Expected: Method calls (array.size(), string.substring(), etc.) work correctly
|
||||
// Expected: Method calls (array.length(), string.substring(), etc.) work correctly
|
||||
|
||||
using "lang/src/vm/hakorune-vm/hakorune_vm_core.hako" as HakoruneVmCore
|
||||
using "lang/src/shared/common/string_helpers.hako" as StringHelpers
|
||||
@ -8,23 +8,23 @@ static box Main {
|
||||
main() {
|
||||
print("=== MirCall Phase 2 Tests (Method) ===")
|
||||
|
||||
// Test 1: Array.size() - no arguments
|
||||
// Test 1: Array.length() - no arguments
|
||||
// Block 0:
|
||||
// newbox ArrayBox → v1
|
||||
// const 42 → v2
|
||||
// boxcall v1.push(v2) → null
|
||||
// mir_call v1.size() → v3
|
||||
// mir_call v1.length() → v3
|
||||
// ret v3
|
||||
local mir1 = r#"{"functions":[{"name":"test","blocks":[{"id":0,"instructions":[{"op":"newbox","dst":1,"box_type":"ArrayBox","args":[]},{"op":"const","dst":2,"value":{"type":"i64","value":42}},{"op":"boxcall","dst":null,"box":1,"method":"push","args":[2]},{"op":"mir_call","dst":3,"mir_call":{"callee":{"type":"Method","receiver":1,"method":"size"},"args":[],"effects":[],"flags":{}}},{"op":"ret","value":3}],"terminator":{"op":"ret","value":3}}]}]}"#
|
||||
|
||||
print("[Test 1] Array.size() - no arguments (expect 1)")
|
||||
print("[Test 1] Array.length() - no arguments (expect 1)")
|
||||
local result1 = HakoruneVmCore.run(mir1)
|
||||
print("Test 1 result: " + StringHelpers.int_to_str(result1))
|
||||
if result1 != 1 {
|
||||
print("[FAIL] Test 1: expected 1 (array size), got " + StringHelpers.int_to_str(result1))
|
||||
return 1
|
||||
}
|
||||
print("[PASS] Test 1: Array.size() works")
|
||||
print("[PASS] Test 1: Array.length() works")
|
||||
|
||||
// Test 2: Array.get(index) - single argument
|
||||
// Block 0:
|
||||
@ -51,7 +51,7 @@ static box Main {
|
||||
// const 1 → v2
|
||||
// const 4 → v3
|
||||
// mir_call v1.substring(v2, v3) → v4
|
||||
// boxcall v4.size() → v5
|
||||
// boxcall v4.length() → v5
|
||||
// ret v5
|
||||
local mir3 = r#"{"functions":[{"name":"test","blocks":[{"id":0,"instructions":[{"op":"const","dst":1,"value":{"String":"hello"}},{"op":"const","dst":2,"value":{"type":"i64","value":1}},{"op":"const","dst":3,"value":{"type":"i64","value":4}},{"op":"mir_call","dst":4,"mir_call":{"callee":{"type":"Method","receiver":1,"method":"substring"},"args":[2,3],"effects":[],"flags":{}}},{"op":"boxcall","dst":5,"box":4,"method":"size","args":[]},{"op":"ret","value":5}],"terminator":{"op":"ret","value":5}}]}]}"#
|
||||
|
||||
@ -64,7 +64,7 @@ static box Main {
|
||||
}
|
||||
print("[PASS] Test 3: String.substring(start, end) works")
|
||||
|
||||
// Test 4: Map.size() - method chaining pattern
|
||||
// Test 4: Map.length() - method chaining pattern
|
||||
// Block 0:
|
||||
// newbox MapBox → v1
|
||||
// const "key1" → v2
|
||||
@ -73,15 +73,15 @@ static box Main {
|
||||
// const "key2" → v4
|
||||
// const "value2" → v5
|
||||
// boxcall v1.set(v4, v5) → null
|
||||
// mir_call v1.size() → v6
|
||||
// mir_call v1.length() → v6
|
||||
// ret v6
|
||||
local mir4 = r#"{"functions":[{"name":"test","blocks":[{"id":0,"instructions":[{"op":"newbox","dst":1,"box_type":"MapBox","args":[]},{"op":"const","dst":2,"value":{"String":"key1"}},{"op":"const","dst":3,"value":{"String":"value1"}},{"op":"boxcall","dst":null,"box":1,"method":"set","args":[2,3]},{"op":"const","dst":4,"value":{"String":"key2"}},{"op":"const","dst":5,"value":{"String":"value2"}},{"op":"boxcall","dst":null,"box":1,"method":"set","args":[4,5]},{"op":"mir_call","dst":6,"mir_call":{"callee":{"type":"Method","receiver":1,"method":"size"},"args":[],"effects":[],"flags":{}}},{"op":"ret","value":6}],"terminator":{"op":"ret","value":6}}]}]}"#
|
||||
|
||||
// Test 4 & 5: Skipped (Map methods have implementation gaps in Hakorune VM)
|
||||
// Note: Method calling mechanism WORKS - verified by Tests 1-3
|
||||
// Issue: Map.set()/Map.size() not fully functional in current Hakorune VM
|
||||
// Issue: Map.set()/Map.length() not fully functional in current Hakorune VM
|
||||
// This is a VM limitation, not a Method calling issue
|
||||
print("[Test 4] SKIPPED: Map.size() (VM limitation)")
|
||||
print("[Test 4] SKIPPED: Map.length() (VM limitation)")
|
||||
print("[Test 5] SKIPPED: Map.isEmpty() (VM limitation)")
|
||||
|
||||
print("=== MirCall Phase 2 (Method) CORE tests PASSED! (3/3 core) ===")
|
||||
|
||||
@ -29,7 +29,7 @@ static box Main {
|
||||
// Block 0:
|
||||
// const 0 → v1
|
||||
// mir_call StringHelpers.int_to_str(v1) → v2
|
||||
// boxcall v2.size() → v3
|
||||
// boxcall v2.length() → v3
|
||||
// ret v3
|
||||
local mir2 = r#"{"functions":[{"name":"test","blocks":[{"id":0,"instructions":[{"op":"const","dst":1,"value":{"type":"i64","value":0}},{"op":"mir_call","dst":2,"mir_call":{"callee":{"type":"ModuleFunction","name":"StringHelpers.int_to_str"},"args":[1],"effects":[],"flags":{}}},{"op":"boxcall","dst":3,"box":2,"method":"size","args":[]},{"op":"ret","value":3}],"terminator":{"op":"ret","value":3}}]}]}"#
|
||||
|
||||
@ -46,7 +46,7 @@ static box Main {
|
||||
// Block 0:
|
||||
// const 100 → v1
|
||||
// mir_call StringHelpers.int_to_str(v1) → v2
|
||||
// boxcall v2.size() → v3
|
||||
// boxcall v2.length() → v3
|
||||
// ret v3
|
||||
local mir3 = r#"{"functions":[{"name":"test","blocks":[{"id":0,"instructions":[{"op":"const","dst":1,"value":{"type":"i64","value":100}},{"op":"mir_call","dst":2,"mir_call":{"callee":{"type":"ModuleFunction","name":"StringHelpers.int_to_str"},"args":[1],"effects":[],"flags":{}}},{"op":"boxcall","dst":3,"box":2,"method":"size","args":[]},{"op":"ret","value":3}],"terminator":{"op":"ret","value":3}}]}]}"#
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
static box Main {
|
||||
main() {
|
||||
local s = "Nyash"
|
||||
if s.size() != 5 { print("FAIL: size!=5") return 1 }
|
||||
if s.length() != 5 { print("FAIL: size!=5") return 1 }
|
||||
if s.isEmpty() { print("FAIL: isEmpty on non-empty") return 1 }
|
||||
if s.substring(0, 2) != "Ny" { print("FAIL: substring") return 1 }
|
||||
if s.charAt(2) != "a" { print("FAIL: charAt") return 1 }
|
||||
|
||||
Reference in New Issue
Block a user