From 74271f3c5b338969947ca2cb2928a35bf6c93db1 Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Fri, 21 Nov 2025 14:00:09 +0900 Subject: [PATCH] =?UTF-8?q?test(mir):=20Phase=2025.1=20StaticCompiler=20re?= =?UTF-8?q?ceiver=E5=9B=9E=E5=B8=B0=E9=98=B2=E6=AD=A2=E3=83=86=E3=82=B9?= =?UTF-8?q?=E3=83=88=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## テスト内容 1. MIR compile & verify(SSA検証) 2. VM実行でRC=0(receiver捏造バグ検出) 3. StringBox正規化確認(ParserBox→StringBox) ## 検証項目 - ✅ StringHelpers.skip_ws/2 呼び出し成功 - ✅ receiver型推論正常動作 - ✅ 文字列メソッド正規化動作確認 Co-Authored-By: ChatGPT5 --- .../mir_stage1_staticcompiler_receiver.rs | 136 ++++++++++++++++++ src/tests/mod.rs | 1 + 2 files changed, 137 insertions(+) create mode 100644 src/tests/mir_stage1_staticcompiler_receiver.rs diff --git a/src/tests/mir_stage1_staticcompiler_receiver.rs b/src/tests/mir_stage1_staticcompiler_receiver.rs new file mode 100644 index 00000000..1eb002a6 --- /dev/null +++ b/src/tests/mir_stage1_staticcompiler_receiver.rs @@ -0,0 +1,136 @@ +/*! + * Phase 25.1 StaticCompiler receiver型推論バグ回帰防止テスト + * + * ## 問題再現 + * - StringHelpers.skip_ws/2 呼び出しで receiver 型情報なし + * - ParserBox.length が Global("ParserBox.length") に変換されてVM落ち + * + * ## 修正内容 + * - Phase 1: guard.rs でreceiver型なし→Global変換 + * - Phase 2: unified_emitter.rs で guard→materialization 順序反転 + * - Phase 3-A: emit_string型注釈追加 + * - Phase 3-B: BinOp(Add)型注釈強化 + * - Phase 3-C: StaticCompiler文字列メソッド→StringBox正規化 + * + * ## 検証項目 + * 1. MIR compile + verify が通る + * 2. VM実行でRC=0(エラー落ちしない) + * 3. StringBox.length に正規化されている + */ + +use crate::ast::ASTNode; +use crate::backend::VM; +use crate::mir::{instruction::MirInstruction, MirCompiler, MirVerifier}; +use crate::parser::NyashParser; + +fn ensure_stage3_env() { + std::env::set_var("NYASH_PARSER_STAGE3", "1"); + std::env::set_var("HAKO_PARSER_STAGE3", "1"); + std::env::set_var("NYASH_ENABLE_USING", "1"); + std::env::set_var("HAKO_ENABLE_USING", "1"); +} + +/// Stage1Cli + StringHelpers.skip_ws テスト用フィクスチャ +fn stage1_staticcompiler_fixture_src() -> String { + let stage1_cli_src = include_str!("../../lang/src/runner/stage1_cli.hako"); + let test_main_src = r#" +using lang.src.runner.stage1_cli as Stage1Cli + +static box Main { + main(args) { + env.set("STAGE1_SOURCE_TEXT", "static box Main { main() { return StringHelpers.skip_ws(\" a\", 0) } }") + local prog = Stage1Cli.emit_program_json_from_text() + print("[stage1_staticcompiler_receiver] prog=" + ("" + prog)) + return 0 + } +} +"#; + format!("{stage1_cli_src}\n\n{test_main_src}") +} + +/// Test 1: MIR compile & verify が通ることを確認 +#[test] +fn mir_stage1_staticcompiler_receiver_compiles_and_verifies() { + ensure_stage3_env(); + let src = stage1_staticcompiler_fixture_src(); + + let 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 mut verifier = MirVerifier::new(); + if let Err(errors) = verifier.verify_module(&cr.module) { + for e in &errors { + eprintln!("[rust-mir-verify] {}", e); + } + panic!("MIR verification failed for stage1_staticcompiler_receiver"); + } +} + +/// Test 2: VM実行でRC=0(receiver捏造バグがないことを確認) +#[test] +fn mir_stage1_staticcompiler_receiver_exec_succeeds() { + ensure_stage3_env(); + std::env::set_var("NYASH_DISABLE_PLUGINS", "1"); // Plugin依存を排除 + + let src = stage1_staticcompiler_fixture_src(); + + let 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 mut verifier = MirVerifier::new(); + verifier.verify_module(&cr.module).expect("verify"); + + // VM実行 + let mut vm = VM::new(); + let result = vm.execute_module(&cr.module); + + // RC=0 を期待(receiver捏造バグがあると "Unknown: ParserBox.length" で落ちる) + assert!( + result.is_ok(), + "VM should execute successfully without receiver fabrication error" + ); +} + +/// Test 3: StringBox正規化が行われていることを確認(MIR検証) +#[test] +fn mir_stage1_staticcompiler_receiver_normalizes_to_stringbox() { + ensure_stage3_env(); + let src = stage1_staticcompiler_fixture_src(); + + let ast: ASTNode = NyashParser::parse_from_string(&src).expect("parse ok"); + let mut mc = MirCompiler::with_options(false); + let cr = mc.compile(ast).expect("compile"); + + // StringHelpers.skip_ws 内の .length() 呼び出しを探す + let mut found_stringbox_length = false; + + for (fname, func) in cr.module.functions.iter() { + if fname.contains("StringHelpers") { + for (bb_id, block) in &func.blocks { + for inst in &block.instructions { + if let MirInstruction::Call { callee, .. } = inst { + if let Some(crate::mir::Callee::Method { + box_name, method, .. + }) = callee + { + if box_name == "StringBox" && method == "length" { + found_stringbox_length = true; + eprintln!( + "[test] Found StringBox.length in {} bb={:?}", + fname, bb_id + ); + } + } + } + } + } + } + } + + assert!( + found_stringbox_length, + "Expected StaticCompiler string methods to be normalized to StringBox" + ); +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 53d22c18..4fe97a28 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -15,6 +15,7 @@ pub mod mir_loopform_exit_phi; pub mod mir_loopform_complex; pub mod mir_static_box_naming; pub mod mir_stage1_cli_emit_program_min; +pub mod mir_stage1_staticcompiler_receiver; // Phase 25.1: StaticCompiler receiver型推論バグ回帰防止 pub mod mir_stage1_using_resolver_verify; pub mod stage1_cli_entry_ssa_smoke; pub mod mir_stageb_like_args_length;