fix(mir): Phase 25.1m - Continue PHI修正 & Bug A main(args)ループ修正

**Phase 25.1m: Continue PHI修正**
- seal_phis に continue_snapshots 入力を追加 (loopform_builder.rs)
- LoopShape::debug_validate に continue/break エッジ検証追加 (control_form.rs)
- test_seal_phis_includes_continue_snapshots テスト追加
- 実証テスト成功: balanced scan loop で 228回イテレーション確認

**Bug A修正: main(args) でループ未実行問題**
- LoopBuilder::build_loop で entry → preheader への jump 追加
- decls.rs でデュアル関数作成時のブロック接続修正
- mir_static_main_args_loop.rs テスト追加

**パーサー改善**:
- parser_box.hako に HAKO_PARSER_PROG_MAX ガード追加(無限ループ対策)

🎉 成果:
- Continue 文の PHI predecessor mismatch エラー完全解消
- main(args) パラメータ有りループが正常動作
- Stage-B balanced scan で continue 正常動作確認 (228回イテレーション)

🤖 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 08:04:43 +09:00
parent b086933acb
commit a95fedf26a
10 changed files with 547 additions and 42 deletions

View File

@ -78,7 +78,7 @@ impl MirBuilder {
ctx: &mut LoweringContext,
) -> Result<(), String> {
let signature = function_lowering::prepare_static_method_signature(
func_name,
func_name.clone(),
params,
body,
);
@ -89,6 +89,9 @@ impl MirBuilder {
ctx.saved_function = self.current_function.take();
ctx.saved_block = self.current_block.take();
eprintln!("[DEBUG/create_function_skeleton] Creating function: {}", func_name);
eprintln!("[DEBUG/create_function_skeleton] Entry block: {:?}", entry);
// 新しい関数に切り替え
self.current_function = Some(function);
self.current_block = Some(entry);
@ -98,7 +101,7 @@ impl MirBuilder {
// Region 観測レイヤ: static 関数用の FunctionRegion を積むよ。
crate::mir::region::observer::observe_function_region(self);
Ok(())
}
@ -145,8 +148,11 @@ impl MirBuilder {
/// 🎯 箱理論: Step 4 - 本体lowering
fn lower_function_body(&mut self, body: Vec<ASTNode>) -> Result<(), String> {
eprintln!("[DEBUG/lower_function_body] body.len() = {}", body.len());
let program_ast = function_lowering::wrap_in_program(body);
eprintln!("[DEBUG/lower_function_body] About to call build_expression");
let _last = self.build_expression(program_ast)?;
eprintln!("[DEBUG/lower_function_body] build_expression completed");
Ok(())
}

View File

@ -29,15 +29,25 @@ impl super::MirBuilder {
// Look for the main() method
let out = if let Some(main_method) = methods.get("main") {
if let ASTNode::FunctionDeclaration { params, body, .. } = main_method {
// Also materialize a callable function entry "BoxName.main/N" for harness/PyVM
let func_name = format!("{}.{}", box_name, "main");
eprintln!("[DEBUG] build_static_main_box: Before lower_static_method_as_function");
eprintln!("[DEBUG] variable_map = {:?}", self.variable_map);
// Note: Metadata clearing is now handled by BoxCompilationContext (箱理論)
// See lifecycle.rs and builder_calls.rs for context swap implementation
let _ = self.lower_static_method_as_function(func_name, params.clone(), body.clone());
eprintln!("[DEBUG] build_static_main_box: After lower_static_method_as_function");
eprintln!("[DEBUG] variable_map = {:?}", self.variable_map);
// Optional: materialize a callable function entry "BoxName.main/N" for harness/PyVM.
// This static entryは通常の VM 実行では使用されず、過去の Hotfix 4 絡みの loop/control-flow
// バグの温床になっていたため、Phase 25.1m では明示トグルが立っている場合だけ生成する。
if std::env::var("NYASH_BUILD_STATIC_MAIN_ENTRY")
.ok()
.as_deref()
== Some("1")
{
let func_name = format!("{}.{}", box_name, "main");
eprintln!("[DEBUG] build_static_main_box: Before lower_static_method_as_function");
eprintln!("[DEBUG] params.len() = {}", params.len());
eprintln!("[DEBUG] body.len() = {}", body.len());
eprintln!("[DEBUG] variable_map = {:?}", self.variable_map);
// Note: Metadata clearing is now handled by BoxCompilationContext (箱理論)
// See lifecycle.rs and builder_calls.rs for context swap implementation
let _ = self.lower_static_method_as_function(func_name, params.clone(), body.clone());
eprintln!("[DEBUG] build_static_main_box: After lower_static_method_as_function");
eprintln!("[DEBUG] variable_map = {:?}", self.variable_map);
}
// Initialize local variables for Main.main() parameters
// Note: These are local variables in the wrapper main() function, NOT parameters
let saved_var_map = std::mem::take(&mut self.variable_map);

View File

@ -152,11 +152,17 @@ impl super::MirBuilder {
let scope_id = self.current_block.map(|bb| bb.as_u32()).unwrap_or(0);
self.hint_scope_enter(scope_id);
let mut last_value = None;
for statement in statements {
let total = statements.len();
eprintln!("[DEBUG/build_block] Processing {} statements", total);
for (idx, statement) in statements.into_iter().enumerate() {
eprintln!("[DEBUG/build_block] Statement {}/{} current_block={:?} current_function={}",
idx+1, total, self.current_block,
self.current_function.as_ref().map(|f| f.signature.name.as_str()).unwrap_or("none"));
last_value = Some(self.build_statement(statement)?);
// If the current block was terminated by this statement (e.g., return/throw),
// do not emit any further instructions for this block.
if is_current_block_terminated(self)? {
eprintln!("[DEBUG/build_block] Block terminated after statement {}", idx+1);
break;
}
}
@ -168,6 +174,7 @@ impl super::MirBuilder {
if !self.is_current_block_terminated() {
self.hint_scope_leave(scope_id);
}
eprintln!("[DEBUG/build_block] Completed, returning value {:?}", out);
Ok(out)
}