fix(builder): BoxCompilationContext clear()アプローチ確立

🎯 箱理論: swap累積バグを修正し、clear()で完全独立化を実現

## 問題
- swap実装は ctx に変数が累積され、次のメソッドで汚染される
- StageBArgsBox.resolve_src で ValueId(21) 未定義エラー

## 解決策
- swap → clear() に変更(開始時・終了時両方)
- context_active mode: clear() のみ(完全独立)
- legacy mode: saved_var_map で従来の挙動維持

## 成果
 StageBArgsBox.resolve_src - 成功!
 StageBBodyExtractorBox.build_body_src - 次の問題箇所(進展!)

## 実装
- src/mir/builder/builder_calls.rs:
  - 開始時: context_active なら clear()(swap削除)
  - 終了時: context_active なら clear()(swap back削除)
  - legacy mode: saved_var_map で復元

🤖 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 15:57:34 +09:00
parent 757b0fcfc9
commit c27f6466e8
3 changed files with 39 additions and 29 deletions

View File

@ -860,18 +860,6 @@ impl super::MirBuilder {
params: Vec<String>,
body: Vec<ASTNode>,
) -> Result<(), String> {
// 🎯 箱理論: コンテキスト分離(開始)
// compilation_contextがある場合、その内容を既存のフィールドとswap
// これにより、既存のコードを変更せずにコンテキスト分離を実現
let context_active = self.compilation_context.is_some();
if context_active {
if let Some(ref mut ctx) = self.compilation_context {
std::mem::swap(&mut self.variable_map, &mut ctx.variable_map);
std::mem::swap(&mut self.value_origin_newbox, &mut ctx.value_origin_newbox);
std::mem::swap(&mut self.value_types, &mut ctx.value_types);
}
}
// Derive static box context from function name prefix, e.g., "BoxName.method/N"
let saved_static_ctx = self.current_static_box.clone();
if let Some(pos) = func_name.find('.') {
@ -880,6 +868,26 @@ impl super::MirBuilder {
self.current_static_box = Some(box_name.to_string());
}
}
// 🎯 箱理論: BoxCompilationContext と saved_var_map をモード別に管理
// context_active = true の場合BoxCompilationContext mode:
// - clear() で完全独立化(各メソッドが汚染されない)
// - swap は不要(累積バグの原因)
// context_active = false の場合Legacy mode:
// - saved_var_map に退避して空から開始し、終了時に復元
let context_active = self.compilation_context.is_some();
let saved_var_map = if !context_active {
Some(std::mem::take(&mut self.variable_map))
} else {
None
};
if context_active {
// 🎯 箱理論: 完全独立化clear のみ、swap 不要)
self.variable_map.clear();
self.value_origin_newbox.clear();
self.value_types.clear();
}
let signature = function_lowering::prepare_static_method_signature(
func_name,
&params,
@ -890,7 +898,6 @@ impl super::MirBuilder {
let function = super::MirFunction::new(signature, entry);
let saved_function = self.current_function.take();
let saved_block = self.current_block.take();
let saved_var_map = std::mem::take(&mut self.variable_map);
self.current_function = Some(function);
self.current_block = Some(entry);
self.ensure_block_exists(entry)?;
@ -952,20 +959,22 @@ impl super::MirBuilder {
}
self.current_function = saved_function;
self.current_block = saved_block;
self.variable_map = saved_var_map;
// 🎯 箱理論: モード別に状態を復元
if context_active {
// 🎯 BoxCompilationContext mode: clear のみ(次回も完全独立)
// swap は不要(累積バグを防ぐ)
self.variable_map.clear();
self.value_origin_newbox.clear();
self.value_types.clear();
} else if let Some(saved) = saved_var_map {
// 従来モード: Main.main 側の variable_map を元に戻す
self.variable_map = saved;
}
// Restore static box context
self.current_static_box = saved_static_ctx;
// 🎯 箱理論: コンテキスト分離(終了)
// swap backでコンテキストに変更を保存
if context_active {
if let Some(ref mut ctx) = self.compilation_context {
std::mem::swap(&mut self.variable_map, &mut ctx.variable_map);
std::mem::swap(&mut self.value_origin_newbox, &mut ctx.value_origin_newbox);
std::mem::swap(&mut self.value_types, &mut ctx.value_types);
}
}
Ok(())
}
}

View File

@ -70,7 +70,7 @@ static box Stage1UsingResolverMini {
/// Verify MIR/SSA for ParserBox.parse_program2 in isolation by compiling a small wrapper.
#[test]
fn mir_parserbox_parse_program2_verifies() {
fn mir_parserbox_parse_program2_harness_parses_minimal_source() {
// Minimal wrapper that brings ParserBox into scope and calls parse_program2.
let src = r#"
using lang.compiler.parser.parser_box as ParserBox
@ -84,15 +84,16 @@ static box ParserBoxHarness {
}
"#;
let ast: ASTNode = NyashParser::parse_from_string(src).expect("parse ok");
// Stage3 構文キーワード `local` を含む最小ソースを ParserBoxHarness でパースする
let harness_ast: ASTNode = NyashParser::parse_from_string(src).expect("parse ok");
let mut mc = MirCompiler::with_options(false);
let cr = mc.compile(ast).expect("compile");
let cr = mc.compile(harness_ast).expect("compile");
let mut verifier = MirVerifier::new();
if let Err(errors) = verifier.verify_module(&cr.module) {
for e in &errors {
eprintln!("[mir-verify] {}", e);
}
panic!("MIR verification failed for ParserBoxHarness.parse_program2");
panic!("MIR verification failed for ParserBoxHarness");
}
}