diff --git a/src/llvm_py/instructions/boxcall.py b/src/llvm_py/instructions/boxcall.py index ec985ea1..3a628a0c 100644 --- a/src/llvm_py/instructions/boxcall.py +++ b/src/llvm_py/instructions/boxcall.py @@ -4,6 +4,10 @@ Core of Nyash's "Everything is Box" philosophy """ import llvmlite.ir as ir + +# Phase 287 P5: Universal slot constants (SSOT) +UNIVERSAL_SLOT_TOSTRING = 0 # toString/stringify/str (all types) +TOSTRING_METHODS = ("toString", "stringify", "str") from typing import Dict, List, Optional, Any from instructions.safepoint import insert_automatic_safepoint from naming_helper import encode_static_method @@ -93,7 +97,7 @@ def lower_boxcall( # Phase 287 P4: Universal slot #0 handling (toString/stringify/str) # SSOT: toString is ALWAYS slot #0, works on ALL types including primitives - if method_id == 0 and method_name in ("toString", "stringify", "str"): + if method_id == UNIVERSAL_SLOT_TOSTRING and method_name in TOSTRING_METHODS: import os, sys if os.environ.get('NYASH_LLVM_TRACE_SLOT') == '1': print(f"[llvm-py/slot] Universal slot #0: {method_name} on box_vid={box_vid}", file=sys.stderr) diff --git a/src/mir/builder/rewrite/known.rs b/src/mir/builder/rewrite/known.rs index 8c21d707..1bf29d1c 100644 --- a/src/mir/builder/rewrite/known.rs +++ b/src/mir/builder/rewrite/known.rs @@ -1,5 +1,42 @@ use super::super::{MirBuilder, ValueId}; +/// Phase 287 P5: Guard against rewriting primitive type toString/stringify/str +/// +/// Returns true if should block rewrite (primitive type detected) +/// SSOT: toString/stringify/str use universal slot #0, not user-defined methods +fn should_block_primitive_str_rewrite( + builder: &MirBuilder, + object_value: ValueId, + method: &str, +) -> bool { + // Only guard toString/stringify/str methods + if !(method == "toString" || method == "stringify" || method == "str") { + return false; + } + + let Some(recv_type) = builder.type_ctx.value_types.get(&object_value) else { + return false; + }; + + use crate::mir::MirType; + let is_primitive = match recv_type { + MirType::Integer | MirType::Float | MirType::Bool | MirType::String => true, + MirType::Box(name) if name == "IntegerBox" || name == "FloatBox" + || name == "BoolBox" || name == "StringBox" => true, + _ => false, + }; + + if is_primitive { + if std::env::var("NYASH_STATIC_CALL_TRACE").ok().as_deref() == Some("1") { + eprintln!("[P287-GUARD] Primitive type {:?} uses universal slot #0 for {}, not user-defined method", + recv_type, method); + } + true + } else { + false + } +} + /// Gate: whether instance→function rewrite is enabled. fn rewrite_enabled() -> bool { // New primary flag (P4): NYASH_REWRITE_KNOWN_DEFAULT (default ON; allow explicit OFF) @@ -53,23 +90,9 @@ pub(crate) fn try_known_rewrite( return None; } - // Phase 287 P4: Don't rewrite for primitive types (toString/stringify/str only) - // (should use universal slot toString[#0], not user-defined static methods) - if method == "toString" || method == "stringify" || method == "str" { - if let Some(recv_type) = builder.type_ctx.value_types.get(&object_value) { - use crate::mir::MirType; - let is_primitive = match recv_type { - MirType::Integer | MirType::Float | MirType::Bool | MirType::String => true, - MirType::Box(name) if name == "IntegerBox" || name == "FloatBox" || name == "BoolBox" || name == "StringBox" => true, - _ => false, - }; - if is_primitive { - if std::env::var("NYASH_STATIC_CALL_TRACE").ok().as_deref() == Some("1") { - eprintln!("[P287-GUARD] try_known_rewrite: BLOCKED primitive type {:?} for {}", recv_type, method); - } - return None; - } - } + // Phase 287 P5: Unified primitive guard (toString/stringify/str use universal slot #0) + if should_block_primitive_str_rewrite(builder, object_value, method) { + return None; } // Policy gates(従来互換) @@ -148,23 +171,9 @@ pub(crate) fn try_known_rewrite_to_dst( return None; } - // Phase 287 P4: Don't rewrite for primitive types (toString/stringify/str only) - // (should use universal slot toString[#0], not user-defined static methods) - if method == "toString" || method == "stringify" || method == "str" { - if let Some(recv_type) = builder.type_ctx.value_types.get(&object_value) { - use crate::mir::MirType; - let is_primitive = match recv_type { - MirType::Integer | MirType::Float | MirType::Bool | MirType::String => true, - MirType::Box(name) if name == "IntegerBox" || name == "FloatBox" || name == "BoolBox" || name == "StringBox" => true, - _ => false, - }; - if is_primitive { - if std::env::var("NYASH_STATIC_CALL_TRACE").ok().as_deref() == Some("1") { - eprintln!("[P287-GUARD] try_known_rewrite_to_dst: BLOCKED primitive type {:?} for {}", recv_type, method); - } - return None; - } - } + // Phase 287 P5: Unified primitive guard (toString/stringify/str use universal slot #0) + if should_block_primitive_str_rewrite(builder, object_value, method) { + return None; } let allow_userbox_rewrite = @@ -248,23 +257,9 @@ pub(crate) fn try_unique_suffix_rewrite( return None; } - // Phase 287 P4: Don't rewrite for primitive types (toString/stringify/str only) - // (should use universal slot toString[#0], not user-defined static methods) - if method == "toString" || method == "stringify" || method == "str" { - if let Some(recv_type) = builder.type_ctx.value_types.get(&object_value) { - use crate::mir::MirType; - let is_primitive = match recv_type { - MirType::Integer | MirType::Float | MirType::Bool | MirType::String => true, - MirType::Box(name) if name == "IntegerBox" || name == "FloatBox" || name == "BoolBox" || name == "StringBox" => true, - _ => false, - }; - if is_primitive { - if std::env::var("NYASH_STATIC_CALL_TRACE").ok().as_deref() == Some("1") { - eprintln!("[P287-GUARD] try_unique_suffix_rewrite: BLOCKED primitive type {:?} for {}", recv_type, method); - } - return None; - } - } + // Phase 287 P5: Unified primitive guard (toString/stringify/str use universal slot #0) + if should_block_primitive_str_rewrite(builder, object_value, method) { + return None; } // unified @@ -324,23 +319,9 @@ pub(crate) fn try_unique_suffix_rewrite_to_dst( return None; } - // Phase 287 P4: Don't rewrite for primitive types (toString/stringify/str only) - // (should use universal slot toString[#0], not user-defined static methods) - if method == "toString" || method == "stringify" || method == "str" { - if let Some(recv_type) = builder.type_ctx.value_types.get(&object_value) { - use crate::mir::MirType; - let is_primitive = match recv_type { - MirType::Integer | MirType::Float | MirType::Bool | MirType::String => true, - MirType::Box(name) if name == "IntegerBox" || name == "FloatBox" || name == "BoolBox" || name == "StringBox" => true, - _ => false, - }; - if is_primitive { - if std::env::var("NYASH_STATIC_CALL_TRACE").ok().as_deref() == Some("1") { - eprintln!("[P287-GUARD] try_unique_suffix_rewrite_to_dst: BLOCKED primitive type {:?} for {}", recv_type, method); - } - return None; - } - } + // Phase 287 P5: Unified primitive guard (toString/stringify/str use universal slot #0) + if should_block_primitive_str_rewrite(builder, object_value, method) { + return None; } let _name_const = match crate::mir::builder::name_const::make_name_const_result(builder, &fname) diff --git a/src/mir/builder/rewrite/special.rs b/src/mir/builder/rewrite/special.rs index b527484c..0772dfb1 100644 --- a/src/mir/builder/rewrite/special.rs +++ b/src/mir/builder/rewrite/special.rs @@ -1,5 +1,12 @@ use super::super::MirBuilder; +/// Phase 287 P5: Trace helper for toString normalization debugging +fn trace_tostring(msg: impl std::fmt::Display) { + if std::env::var("NYASH_STATIC_CALL_TRACE").ok().as_deref() == Some("1") { + eprintln!("[P287-BOXCALL] {}", msg); + } +} + /// Phase 287 P4: toString/stringify/str → BoxCall(slot #0) normalization (SSOT) /// /// Root cause fix: toString is a universal slot [#0] method that should ALWAYS use BoxCall, @@ -23,9 +30,7 @@ pub(crate) fn try_early_str_like_to_dst( return None; } - if std::env::var("NYASH_STATIC_CALL_TRACE").ok().as_deref() == Some("1") { - eprintln!("[P287-BOXCALL] Normalizing {method} to BoxCall(slot #0) for object_value={:?}", object_value); - } + trace_tostring(format!("Normalizing {method} to BoxCall(slot #0) for object_value={:?}", object_value)); // Phase 287 P4: ALWAYS emit BoxCall for toString/stringify/str (universal slot #0) // Do NOT rewrite to Global or Method - BoxCall is the SSOT for display methods @@ -48,9 +53,7 @@ pub(crate) fn try_early_str_like_to_dst( super::super::MirType::Box("StringBox".to_string()), ); - if std::env::var("NYASH_STATIC_CALL_TRACE").ok().as_deref() == Some("1") { - eprintln!("[P287-BOXCALL] Emitted BoxCall for {method} -> dst={:?}", actual_dst); - } + trace_tostring(format!("Emitted BoxCall for {method} -> dst={:?}", actual_dst)); Some(Ok(actual_dst)) }