Hotfix 5: Pre-populate params vector in MirFunction::new()

📦 箱理論: Parameter ValueId完全予約システム確立

## 🎯 根本原因
Hotfix 4でnext_value_id counterは予約したが、paramsベクトルが空のまま。
setup_function_params()が新規ValueIdをインクリメント済みcounterから割り当て。
結果: シグネチャは%0だが本体は%2を使用するミスマッチ発生。

##  修正内容

### 1. src/mir/function.rs - MirFunction::new()
```rust
// 🔥 Hotfix 5: Pre-populate params vector with reserved ValueIds
let mut pre_params = Vec::new();
for i in 0..total_value_ids {
    pre_params.push(ValueId::new(i));
}
// ...
params: pre_params,  //  Pre-populate instead of empty Vec
```

### 2. src/mir/builder/calls/lowering.rs - setup_function_params()
```rust
// 📦 Hotfix 5: Use pre-populated params from MirFunction::new()
let receiver_offset = if f.params.is_empty() { 0 } else {
    if f.params.len() > params.len() { 1 } else { 0 }
};

for (idx, p) in params.iter().enumerate() {
    let param_idx = receiver_offset + idx;
    let pid = if param_idx < f.params.len() {
        f.params[param_idx]  // Use pre-allocated ValueId
    } else {
        let new_pid = f.next_value_id();
        f.params.push(new_pid);
        new_pid
    };
    // ...
}
```

## 📊 テスト結果
-  mir_parserbox_parse_program2_harness_parses_minimal_source: PASS
-  mir_stage1_using_resolver_full_collect_entries_verifies: PASS
- ⚠️ mir_stage1_using_resolver_min_fragment_verifies: 別問題(dominator violation)

## 🎉 成果
- **Parameter ValueId問題完全解決**: 0/3 → 2/3 tests passing
- **Counter予約とVector実体の完全一致**: シグネチャと本体の整合性確保
- **Static method receiver完全対応**: 暗黙receiverも正しく予約

## 🔧 次のステップ
残り1テストのdominator violation調査(LoopForm Exit PHI生成問題)

Co-Authored-By: task先生 <task@anthropic.com>
This commit is contained in:
nyash-codex
2025-11-18 07:56:47 +09:00
parent 461c7d196d
commit fa087eeeea
2 changed files with 29 additions and 6 deletions

View File

@ -94,9 +94,24 @@ impl MirBuilder {
fn setup_function_params(&mut self, params: &[String]) {
self.function_param_names.clear();
if let Some(ref mut f) = self.current_function {
for p in params {
let pid = f.next_value_id();
f.params.push(pid);
// 📦 Hotfix 5: Use pre-populated params from MirFunction::new()
// Static methods have implicit receiver at params[0], so actual parameters start at offset
let receiver_offset = if f.params.is_empty() { 0 } else {
// If params already populated (by Hotfix 4+5), use them
if f.params.len() > params.len() { 1 } else { 0 }
};
for (idx, p) in params.iter().enumerate() {
let param_idx = receiver_offset + idx;
let pid = if param_idx < f.params.len() {
// Use pre-allocated ValueId from MirFunction::new()
f.params[param_idx]
} else {
// Allocate new ValueId (fallback for non-static methods)
let new_pid = f.next_value_id();
f.params.push(new_pid);
new_pid
};
self.variable_map.insert(p.clone(), pid);
self.function_param_names.insert(p.clone());
}

View File

@ -104,9 +104,17 @@ impl MirFunction {
let total_value_ids = param_count + receiver_count;
let initial_counter = total_value_ids.max(1); // At least 1 to reserve ValueId(0) as sentinel
// 🔥 Hotfix 5: Pre-populate params vector with reserved ValueIds
// Without this, setup_function_params() will allocate NEW ValueIds starting from
// the already-incremented counter, causing signature/body mismatch.
let mut pre_params = Vec::new();
for i in 0..total_value_ids {
pre_params.push(ValueId::new(i));
}
if std::env::var("NYASH_LOOPFORM_DEBUG").is_ok() {
eprintln!("[MirFunction::new] fn='{}' params={}, receiver={}, total={}, initial_counter={}",
signature.name, param_count, receiver_count, total_value_ids, initial_counter);
eprintln!("[MirFunction::new] fn='{}' params={}, receiver={}, total={}, initial_counter={}, pre_params={:?}",
signature.name, param_count, receiver_count, total_value_ids, initial_counter, pre_params);
}
Self {
@ -114,7 +122,7 @@ impl MirFunction {
blocks,
entry_block,
locals: Vec::new(),
params: Vec::new(),
params: pre_params, // ✅ Pre-populate instead of empty Vec
next_value_id: initial_counter,
metadata: FunctionMetadata::default(),
}