debug(mir): add comprehensive receiver tracing and block overwrite protection

This commit investigates ValueId(21) undefined error in Stage-B compilation.

Changes:
- src/mir/builder/builder_calls.rs:
  - Add NYASH_DEBUG_PARAM_RECEIVER=1 trace for method call receivers
  - Track variable_map lookups and ValueId mismatches
  - Log receiver origin and current_block context

- src/mir/builder/utils.rs:
  - Fix start_new_block() to avoid overwriting existing blocks
  - Check if block exists before calling add_block()
  - Prevents Copy instructions from being lost

- src/mir/function.rs:
  - Add warning log when replacing existing block
  - Helps detect block overwrite issues

- lang/src/mir/builder/ (Hako files):
  - Add debug prints for method lowering paths
  - These were not used (Stage-B uses Rust MIR Builder)
  - Kept for future Hako MIR Builder debugging

Key Discovery:
- Stage-B compilation uses Rust MIR Builder, not Hako MIR Builder
- ValueId(21) is undefined receiver in StageBArgsBox.resolve_src/1
- MIR shows: call_method ParserBox.length() [recv: %21] but %21 has no definition
- Likely caused by LocalSSA Copy emission failure or block overwrite

Next: Fix LocalSSA to ensure receiver Copy is properly emitted and preserved

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-11-17 09:39:26 +09:00
parent f7d218190e
commit 6bfaaaf445
5 changed files with 59 additions and 5 deletions

View File

@ -37,8 +37,12 @@ static box FuncBodyBasicLowerBox {
// 2) Try simple Return(Method ...) patternparams ベースの receiver のみ)
{
print("[builder/funcs:return_method] trying func=" + func_name + " box=" + box_name)
local mret = me._try_lower_return_method(func_name, box_name, params_arr, s)
if mret != null { return mret }
if mret != null {
print("[builder/funcs:return_method] SUCCESS via _try_lower_return_method")
return mret
}
}
// 3) Non-Loop processing: Local/If/Return パターンのみ
@ -48,7 +52,14 @@ static box FuncBodyBasicLowerBox {
s = me._inline_local_ints(s)
// Try minimal lowers (same order as MirBuilderMinBox, restricted set)
{ local out = LowerReturnMethodArrayMapBox.try_lower(s); if out != null { return me._rebind(out, func_name, box_name, params_arr, "[funcs/basic:return.method.arraymap]") } }
{
print("[builder/funcs] trying LowerReturnMethodArrayMapBox (LEGACY, const 0 receiver)")
local out = LowerReturnMethodArrayMapBox.try_lower(s)
if out != null {
print("[builder/funcs] SUCCESS via LowerReturnMethodArrayMapBox (WARNING: uses const 0 receiver!)")
return me._rebind(out, func_name, box_name, params_arr, "[funcs/basic:return.method.arraymap]")
}
}
{ local out = LowerReturnBinOpVarIntBox.try_lower(s); if out != null { return me._rebind(out, func_name, box_name, params_arr, "[funcs/basic:return.binop.varint]") } }
{ local out = LowerReturnBinOpVarVarBox.try_lower(s); if out != null { return me._rebind(out, func_name, box_name, params_arr, "[funcs/basic:return.binop.varvar]") } }
{ local out = LowerReturnBinOpBox.try_lower(s); if out != null { return me._rebind(out, func_name, box_name, params_arr, "[funcs/basic:return.binop.intint]") } }

View File

@ -12,16 +12,33 @@ static box LowerReturnMethodArrayMapBox {
local k_m = JsonFragBox.index_of_from(s, "\"type\":\"Method\"", k_ret); if k_m < 0 { return null }
// receiver must be Var(name)
local k_recv = JsonFragBox.index_of_from(s, "\"recv\":{\"type\":\"Var\"", k_m); if k_recv < 0 { return null }
// Extract receiver variable name
local recv_name = null
{
local kn = JsonFragBox.index_of_from(s, "\"name\":\"", k_recv)
if kn >= 0 {
recv_name = JsonFragBox.read_string_after(s, kn + 8)
}
}
local method = null
{ local km = JsonFragBox.index_of_from(s, "\"method\":\"", k_m); if km < 0 { return null } method = JsonFragBox.read_string_after(s, km + 9) }
// Standardize: generate 'size' (len/length are accepted aliases at receiver)
method = MethodAliasPolicy.normalize_size(method)
// Allow basic methods
if !(method == "size" || method == "length" || method == "len" || method == "get" || method == "set" || method == "push") { return null }
// Dev trace: show what we matched (always print for now)
print("[builder/arraymap] matched return method pattern")
print("[builder/arraymap] method=" + method)
print("[builder/arraymap] recv_name=" + recv_name)
// Parse up to two Int args with actual values
// Prepare instruction JSON text (avoid Box allocations in VM)
local insts = ""
// Receiver placeholder: const 0 -> r1Var 解決は未実装なので 0 を受信者に置く)
// FIXME: Receiver placeholder: const 0 -> r1Var 解決は未実装なので 0 を受信者に置く)
// TODO: Use recv_name to find actual parameter slot instead of hardcoded 0
insts = insts + "{\\\"op\\\":\\\"const\\\",\\\"dst\\\":1,\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":0}}"
local k_args = JsonFragBox.index_of_from(s, "\"args\":", k_m)
local next_id = 2