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

@ -699,7 +699,28 @@ impl super::MirBuilder {
}
// 4. Build object value for remaining cases
let object_value = self.build_expression(object)?;
let object_value = self.build_expression(object.clone())?;
// CRITICAL DEBUG: Track receiver ValueId for parameter variables
if std::env::var("NYASH_DEBUG_PARAM_RECEIVER").ok().as_deref() == Some("1") {
use crate::ast::ASTNode;
if let ASTNode::Variable { name, .. } = &object {
eprintln!("[DEBUG/param-recv] build_method_call receiver '{}' → ValueId({})",
name, object_value.0);
if let Some(origin) = self.value_origin_newbox.get(&object_value) {
eprintln!("[DEBUG/param-recv] origin: {}", origin);
}
if let Some(&mapped_id) = self.variable_map.get(name) {
eprintln!("[DEBUG/param-recv] variable_map['{}'] = ValueId({})", name, mapped_id.0);
if mapped_id != object_value {
eprintln!("[DEBUG/param-recv] ⚠️ MISMATCH! build_expression returned different ValueId!");
}
} else {
eprintln!("[DEBUG/param-recv] ⚠️ '{}' NOT FOUND in variable_map!", name);
}
eprintln!("[DEBUG/param-recv] current_block: {:?}", self.current_block);
}
}
// 5. Handle TypeOp methods: value.is("Type") / value.as("Type")
// Note: This was duplicated in original code - now unified!

View File

@ -70,7 +70,9 @@ impl super::MirBuilder {
/// Start a new basic block and set as current
pub(crate) fn start_new_block(&mut self, block_id: BasicBlockId) -> Result<(), String> {
if let Some(ref mut function) = self.current_function {
function.add_block(BasicBlock::new(block_id));
if !function.blocks.contains_key(&block_id) {
function.add_block(BasicBlock::new(block_id));
}
self.current_block = Some(block_id);
// Local SSA cache is per-block; clear on block switch
self.local_ssa_map.clear();

View File

@ -98,6 +98,9 @@ impl MirFunction {
/// Add a new basic block
pub fn add_block(&mut self, block: BasicBlock) -> BasicBlockId {
let id = block.id;
if self.blocks.contains_key(&id) && std::env::var("NYASH_LOCAL_SSA_TRACE").ok().as_deref() == Some("1") {
eprintln!("[mir-function] replacing existing block {:?}", id);
}
self.blocks.insert(id, block);
id
}