fix(mir): Hotfix 6+7 - Instance method receiver完全修正

問題箇所1 (Hotfix 6):
- setup_method_params が next_value_id() で新規 ValueId 生成
- でも MirFunction::new() で既に予約済み
- → パラメータマッピングがずれる(%2,%3 vs %0,%1)

修正1:
- 予約済み ValueId(0), ValueId(1), ... を直接使用
- setup_function_params と同じロジックに統一

問題箇所2 (Hotfix 7):
- emit_unified_call_impl で Callee::Method の receiver が args に含まれない
- finalize_call_operands は receiver を Callee 側に保持
- → VM の exec_function_inner で args = [] → ValueId(0) = Void

修正2:
- Callee::Method { receiver: Some(recv), .. } の場合に
  args_local.insert(0, *recv) で receiver を先頭に追加
- VM のパラメータバインディングが正しく動作するように

検証:
- 手動テスト: ng → ok 
- 各種環境変数組み合わせでも動作確認済み

既知問題:
- userbox_birth_to_string_vm.sh スモークテストは依然失敗
  → 別調査が必要(手動では動作するので環境依存の可能性)

🤖 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-19 04:01:02 +09:00
parent c0fb1ccff8
commit 5c5e1bd099
2 changed files with 39 additions and 10 deletions

View File

@ -268,21 +268,42 @@ impl MirBuilder {
let mut slot_regs: Vec<(String, Option<MirType>)> = Vec::new();
if let Some(ref mut f) = self.current_function {
// 📦 Hotfix 6: Use pre-reserved ValueIds instead of generating new ones
// MirFunction::new() already reserved ValueIds 0..N for parameters
// First parameter is always 'me' at ValueId(0)
let me_id = ValueId(0);
f.params.push(me_id);
// 📦 Hotfix 6 改訂版:
// MirFunction::new() が既に 0..N の ValueId を params 用に予約しているので、
// ここではそれを「上書き使用」するだけにして、push で二重定義しないようにするよ。
//
// params レイアウト:
// index 0: me (box<MyBox>)
// index 1..: 通常パラメータ
if f.params.is_empty() {
// 安全弁: 何らかの理由で pre-populate されていない場合は従来どおり new する
let me_id = ValueId(0);
f.params.push(me_id);
for i in 0..params.len() {
f.params.push(ValueId((i + 1) as u32));
}
}
// me
let me_id = f.params[0];
self.variable_map.insert("me".to_string(), me_id);
self.value_origin_newbox.insert(me_id, box_name.to_string());
slot_regs.push(("me".to_string(), None));
// Then regular parameters at ValueId(1), ValueId(2), ...
// 通常パラメータ
for (idx, p) in params.iter().enumerate() {
let pid = ValueId((idx + 1) as u32);
f.params.push(pid);
self.variable_map.insert(p.clone(), pid);
slot_regs.push((p.clone(), None));
let param_idx = idx + 1;
if param_idx < f.params.len() {
let pid = f.params[param_idx];
self.variable_map.insert(p.clone(), pid);
slot_regs.push((p.clone(), None));
} else {
// 念のため足りない場合は新規に確保(互換用)
let pid = f.next_value_id();
f.params.push(pid);
self.variable_map.insert(p.clone(), pid);
slot_regs.push((p.clone(), None));
}
}
}

View File

@ -177,6 +177,14 @@ impl UnifiedCallEmitterBox {
let mut args_local: Vec<ValueId> = args;
crate::mir::builder::emit_guard::finalize_call_operands(builder, &mut callee, &mut args_local);
// 📦 Hotfix 7: Include receiver in args for Callee::Method
// VM's exec_function_inner expects receiver as the first parameter (ValueId(0))
// but finalize_call_operands keeps receiver in Callee, not in args.
// We must add it to args_local here so VM can bind it correctly.
if let Callee::Method { receiver: Some(recv), .. } = &callee {
args_local.insert(0, *recv);
}
// Create MirCall instruction using the new module (pure data composition)
let mir_call = call_unified::create_mir_call(dst, callee.clone(), args_local.clone());