//! Static box naming tests (Main._nop/0 canonicalization) //! //! Repro: apps/tests/minimal_to_i64_void.hako //! - static box Main { _nop(); main(args) { me._nop(); ... } } //! - VM runtime reported Unknown: main._nop/0 //! This test compiles the fixture and inspects the MIR module to ensure: //! 1) Static methods are materialized as canonical names (Main._nop/0) //! 2) Calls inside Main.main use the canonical/global name use crate::ast::ASTNode; use crate::mir::instruction::MirInstruction; use crate::mir::{definitions::Callee, MirCompiler}; use crate::parser::NyashParser; fn load_fixture_with_string_helpers() -> String { // Bundle StringHelpers directly to avoid relying on using resolution in this unit test. let string_helpers = include_str!("../../lang/src/shared/common/string_helpers.hako"); let fixture = std::fs::read_to_string("apps/tests/minimal_to_i64_void.hako").expect("read fixture"); format!("{}\n\n{}", string_helpers, fixture) } /// Compile minimal_to_i64_void.hako and assert Main._nop/0 exists and is targeted. /// The test now accepts either: /// - Global(Main._nop/0) call (methodization OFF), or /// - Method(Main._nop, receiver=singleton) call (methodization ON: default) /// Methodization is ON by default (HAKO_MIR_BUILDER_METHODIZE=1). #[test] fn mir_static_main_box_emits_canonical_static_methods() { // Enable Stage‑3 + using for the fixture. std::env::set_var("NYASH_FEATURES", "stage3"); std::env::set_var("NYASH_FEATURES", "stage3"); std::env::set_var("NYASH_PARSER_ALLOW_SEMICOLON", "1"); std::env::set_var("NYASH_ENABLE_USING", "1"); std::env::set_var("HAKO_ENABLE_USING", "1"); let src = load_fixture_with_string_helpers(); let ast: ASTNode = NyashParser::parse_from_string(&src).expect("parse"); let mut mc = MirCompiler::with_options(false); let compiled = mc.compile(ast).expect("compile"); // 1) Ensure Main._nop/0 is materialized in the function table. let mut fn_names: Vec = compiled.module.functions.keys().cloned().collect(); fn_names.sort(); assert!( fn_names.iter().any(|n| n == "Main._nop/0"), "Main._nop/0 missing. Functions:\n{}", fn_names.join("\n") ); // 2) At least keep the static method materialized (methodization may inline calls away). assert!( fn_names.iter().any(|n| n == "Main._nop/0"), "Main._nop/0 should remain materialized even if calls are optimized away" ); } /// Execute the minimal fixture with Void-returning _nop() and confirm it lowers without SSA/arity drift. #[test] fn mir_static_main_box_executes_void_path_with_guard() { std::env::set_var("NYASH_FEATURES", "stage3"); std::env::set_var("NYASH_FEATURES", "stage3"); std::env::set_var("NYASH_PARSER_ALLOW_SEMICOLON", "1"); std::env::set_var("NYASH_ENABLE_USING", "1"); std::env::set_var("HAKO_ENABLE_USING", "1"); // Accept Void inputs as 0 for this execution path. std::env::set_var("NYASH_TO_I64_FORCE_ZERO", "1"); let src = load_fixture_with_string_helpers(); let ast: ASTNode = NyashParser::parse_from_string(&src).expect("parse"); let mut mc = MirCompiler::with_options(false); let compiled = mc.compile(ast).expect("compile"); // Just ensure the symbol exists; methodization may optimize away the actual call. assert!( compiled.module.functions.keys().any(|k| k == "Main._nop/0"), "Main._nop/0 should remain defined" ); }