2025-08-12 11:33:48 +00:00
/*!
* MIR Builder - Converts AST to MIR / SSA form
2025-09-17 07:43:07 +09:00
*
2025-08-12 11:33:48 +00:00
* Implements AST → MIR conversion with SSA construction
* /
2025-09-17 07:43:07 +09:00
use super ::slot_registry ::resolve_slot_by_type_name ;
2025-08-12 11:33:48 +00:00
use super ::{
2025-09-17 07:43:07 +09:00
BasicBlock , BasicBlockId , BasicBlockIdGenerator , CompareOp , ConstValue , Effect , EffectMask ,
FunctionSignature , MirFunction , MirInstruction , MirModule , MirType , ValueId , ValueIdGenerator ,
2025-08-12 11:33:48 +00:00
} ;
2025-11-24 14:17:02 +09:00
use crate ::ast ::{ ASTNode , LiteralValue , Span } ;
2025-09-26 14:34:42 +09:00
use crate ::mir ::builder ::builder_calls ::CallTarget ;
2025-11-21 06:25:17 +09:00
use crate ::mir ::region ::function_slot_registry ::FunctionSlotRegistry ;
use crate ::mir ::region ::RegionId ;
2025-08-21 01:18:25 +09:00
use std ::collections ::HashSet ;
2025-11-24 14:17:02 +09:00
use std ::collections ::{ BTreeMap , HashMap } ;
2025-09-03 01:37:38 +09:00
mod builder_calls ;
2025-09-24 01:05:44 +09:00
mod call_resolution ; // ChatGPT5 Pro: Type-safe call resolution utilities
2025-11-21 06:25:17 +09:00
mod calls ; // Call system modules (refactored from builder_calls)
2025-11-17 11:28:18 +09:00
mod context ; // BoxCompilationContext - 箱理論による静的Boxコンパイル時のコンテキスト分離
🎉 Phase 11.8/12.7: MIR Core-13 完全実装 + 糖衣構文ドキュメント更新
主要な変更:
- MIR Core-13命令セット確定(Load/Store削除の革命的設計)
- Const, BinOp, Compare(値・計算)
- Jump, Branch, Return, Phi(制御)
- Call, BoxCall, ExternCall(呼び出し)
- TypeOp, Safepoint, Barrier(メタ)
- Phase 12.7糖衣構文ドキュメント整理(超圧縮重視、可逆変換保証)
- MIRビルダーのモジュール分割完了
- vtableテストスイート拡充
- AI協調開発ツール追加(並列リファクタリング支援)
詳細:
- src/mir/instruction_introspection.rs: core13_instruction_names()追加
- MIRビルダー分割: decls.rs, exprs_*.rs, fields.rs
- plugin_loader_v2: errors.rs, host_bridge.rs分離
- 論文用データ: mir13-final.md作成
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-04 11:34:15 +09:00
mod decls ; // declarations lowering split
2025-09-17 07:43:07 +09:00
mod exprs ; // expression lowering split
2025-11-21 06:25:17 +09:00
mod exprs_call ;
mod method_call_handlers ; // Method call handler separation (Phase 3) // call(expr)
// include lowering removed (using is handled in runner)
mod control_flow ; // thin wrappers to centralize control-flow entrypoints
2025-09-17 07:43:07 +09:00
mod exprs_lambda ; // lambda lowering
mod exprs_peek ; // peek expression
mod exprs_qmark ; // ?-propagate
mod fields ; // field access/assignment lowering split
2025-11-21 06:25:17 +09:00
mod if_form ;
mod lifecycle ;
2025-11-28 20:59:54 +09:00
mod loop_frontend_binding ; // Phase 50: Loop Frontend Binding (JoinIR variable mapping)
2025-12-05 14:11:49 +09:00
mod joinir_id_remapper ; // Phase 189: JoinIR ID remapping (ValueId/BlockId translation)
mod joinir_inline_boundary_injector ; // Phase 189: JoinInlineBoundary Copy instruction injector
2025-09-17 07:43:07 +09:00
pub ( crate ) mod loops ;
mod ops ;
mod phi ;
2025-11-21 06:25:17 +09:00
mod phi_merge ; // Phase 25.1q: Unified PHI merge helper // prepare/lower_root/finalize split
// legacy large-match remains inline for now (planned extraction)
mod emission ; // emission::*( Const/Compare/Branch の薄い発行箱)
mod emit_guard ; // EmitGuardBox( emit直前の最終関所)
mod metadata ; // MetadataPropagationBox( type/originの伝播)
mod name_const ; // NameConstBox( 関数名Const生成)
2025-09-28 12:19:49 +09:00
mod observe ; // P0: dev-only observability helpers( ssa/resolve)
2025-11-21 06:25:17 +09:00
mod origin ; // P0: origin inference( me/Known) と PHI 伝播(軽量)
mod plugin_sigs ; // plugin signature loader
mod receiver ; // ReceiverMaterializationBox( Method recv の pin+LocalSSA 集約)
2025-09-28 12:19:49 +09:00
mod rewrite ; // P1: Known rewrite & special consolidation
2025-11-21 06:25:17 +09:00
mod router ; // RouterPolicyBox( Unified vs BoxCall)
2025-09-28 20:38:09 +09:00
mod schedule ; // BlockScheduleBox( 物理順序: PHI→materialize→body)
2025-11-21 06:25:17 +09:00
mod ssa ; // LocalSSA helpers (in-block materialization)
mod stmts ;
pub ( crate ) mod type_registry ;
mod types ; // types::annotation / inference( 型注釈/推論の箱: 推論は後段)
mod utils ;
mod vars ; // variables/scope helpers // small loop helpers (header/exit context) // TypeRegistryBox( 型情報管理の一元化)
2025-08-30 22:52:16 +09:00
2025-09-19 08:34:29 +09:00
// Unified member property kinds for computed/once/birth_once
#[ derive(Debug, Clone, PartialEq, Eq, Hash) ]
pub ( crate ) enum PropertyKind {
Computed ,
Once ,
BirthOnce ,
}
2025-08-12 11:33:48 +00:00
/// MIR builder for converting AST to SSA form
pub struct MirBuilder {
/// Current module being built
2025-08-18 23:36:40 +09:00
pub ( super ) current_module : Option < MirModule > ,
2025-09-17 07:43:07 +09:00
2025-08-12 11:33:48 +00:00
/// Current function being built
2025-08-18 23:36:40 +09:00
pub ( super ) current_function : Option < MirFunction > ,
2025-09-17 07:43:07 +09:00
2025-08-12 11:33:48 +00:00
/// Current basic block being built
2025-08-18 23:36:40 +09:00
pub ( super ) current_block : Option < BasicBlockId > ,
2025-09-17 07:43:07 +09:00
2025-08-12 11:33:48 +00:00
/// Value ID generator
2025-08-18 23:36:40 +09:00
pub ( super ) value_gen : ValueIdGenerator ,
2025-09-17 07:43:07 +09:00
2025-08-12 11:33:48 +00:00
/// Basic block ID generator
2025-08-18 23:36:40 +09:00
pub ( super ) block_gen : BasicBlockIdGenerator ,
2025-09-17 07:43:07 +09:00
2025-11-17 11:28:18 +09:00
/// 箱理論: Static boxコンパイル時のコンテキスト分離
/// Some(ctx)の場合、variable_map/value_origin_newbox/value_typesはctxから取得
/// Noneの場合、従来のフィールドを使用( 後方互換性)
pub ( super ) compilation_context : Option < context ::BoxCompilationContext > ,
2025-08-12 11:33:48 +00:00
/// Variable name to ValueId mapping (for SSA conversion)
2025-11-17 11:28:18 +09:00
/// 注意: compilation_contextがSomeの場合は使用されません
2025-11-22 05:33:40 +09:00
/// Phase 25.1: HashMap → BTreeMap( PHI生成の決定性確保)
pub ( super ) variable_map : BTreeMap < String , ValueId > ,
2025-09-17 07:43:07 +09:00
2025-08-12 11:33:48 +00:00
/// Pending phi functions to be inserted
2025-08-16 17:39:04 +09:00
#[ allow(dead_code) ]
2025-08-18 23:36:40 +09:00
pub ( super ) pending_phis : Vec < ( BasicBlockId , ValueId , String ) > ,
2025-08-20 20:56:08 +09:00
/// Origin tracking for simple optimizations (e.g., object.method after new)
/// Maps a ValueId to the class name if it was produced by NewBox of that class
2025-11-17 11:28:18 +09:00
/// 注意: compilation_contextがSomeの場合は使用されません
2025-11-22 05:33:40 +09:00
// Phase 25.1: HashMap → BTreeMap( 決定性確保)
pub ( super ) value_origin_newbox : BTreeMap < ValueId , String > ,
2025-08-21 01:18:25 +09:00
/// Names of user-defined boxes declared in the current module
pub ( super ) user_defined_boxes : HashSet < String > ,
2025-08-24 00:05:12 +09:00
/// Weak field registry: BoxName -> {weak field names}
pub ( super ) weak_fields_by_box : HashMap < String , HashSet < String > > ,
2025-09-19 08:34:29 +09:00
/// Unified members: BoxName -> {propName -> Kind}
pub ( super ) property_getters_by_box : HashMap < String , HashMap < String , PropertyKind > > ,
2025-08-24 00:05:12 +09:00
/// Remember class of object fields after assignments: (base_id, field) -> class_name
pub ( super ) field_origin_class : HashMap < ( ValueId , String ) , String > ,
2025-09-26 14:34:42 +09:00
/// Class-level field origin (cross-function heuristic): (BaseBoxName, field) -> FieldBoxName
pub ( super ) field_origin_by_box : HashMap < ( String , String ) , String > ,
2025-08-28 22:31:51 +09:00
/// Optional per-value type annotations (MIR-level): ValueId -> MirType
2025-11-17 11:28:18 +09:00
/// 注意: compilation_contextがSomeの場合は使用されません
2025-11-22 05:33:40 +09:00
// Phase 25.1: HashMap → BTreeMap( 決定性確保)
pub ( super ) value_types : BTreeMap < ValueId , super ::MirType > ,
2025-09-11 03:33:33 +09:00
2025-11-20 09:34:55 +09:00
/// Phase 26-A: ValueId型情報マップ( 型安全性強化)
/// ValueId -> MirValueKind のマッピング
/// - GUARDバグ予防: ValueId(0)がParameterかLocalか区別可能
/// - デフォルト: 未登録のValueIdはTemporary扱い
pub ( super ) value_kinds : HashMap < ValueId , super ::MirValueKind > ,
2025-11-19 03:28:58 +09:00
/// 関数スコープの SlotRegistry( 観測専用)
/// - current_function と同じライフサイクルを持つよ。
/// - 既存の variable_map/SSA には影響しない(メタデータのみ)。
pub ( super ) current_slot_registry : Option < FunctionSlotRegistry > ,
2025-11-17 23:13:57 +09:00
/// 🎯 箱理論: 型情報管理の一元化( TypeRegistryBox)
/// NYASH_USE_TYPE_REGISTRY=1 で有効化(段階的移行用)
pub ( super ) type_registry : type_registry ::TypeRegistry ,
2025-09-11 03:33:33 +09:00
/// Plugin method return type signatures loaded from nyash_box.toml
plugin_method_sigs : HashMap < ( String , String ) , super ::MirType > ,
2025-08-29 21:39:47 +09:00
/// Current static box name when lowering a static box body (e.g., "Main")
current_static_box : Option < String > ,
2025-09-25 10:23:14 +09:00
/// Index of static methods seen during lowering: name -> [(BoxName, arity)]
pub ( super ) static_method_index : std ::collections ::HashMap < String , Vec < ( String , usize ) > > ,
2025-08-30 23:47:08 +09:00
2025-11-17 05:24:07 +09:00
/// Function parameter names (for LoopForm PHI construction)
/// Tracks the original parameter names at function entry
pub ( super ) function_param_names : HashSet < String > ,
2025-09-28 12:19:49 +09:00
/// Fast lookup: method+arity tail → candidate function names (e.g., ".str/0" → ["JsonNode.str/0", ...])
pub ( super ) method_tail_index : std ::collections ::HashMap < String , Vec < String > > ,
/// Source size snapshot to detect when to rebuild the tail index
pub ( super ) method_tail_index_source_len : usize ,
2025-11-19 03:28:58 +09:00
/// Region 観測用のスタックだよ( FunctionRegion がルート)。
/// - NYASH_REGION_TRACE=1 のときだけ使われる開発用メタデータだよ。
pub ( super ) current_region_stack : Vec < RegionId > ,
2025-09-25 00:41:56 +09:00
// include guards removed
2025-09-15 22:14:42 +09:00
/// Loop context stacks for lowering break/continue inside nested control flow
/// Top of stack corresponds to the innermost active loop
pub ( super ) loop_header_stack : Vec < BasicBlockId > ,
pub ( super ) loop_exit_stack : Vec < BasicBlockId > ,
2025-09-16 23:49:36 +09:00
2025-09-19 02:07:38 +09:00
/// If/merge context stack (innermost first). Used to make merge targets explicit
/// when lowering nested conditionals and to simplify jump generation.
pub ( super ) if_merge_stack : Vec < BasicBlockId > ,
2025-09-23 07:25:58 +09:00
// フェーズM: no_phi_modeフィールド削除( 常にPHI使用)
2025-09-19 02:07:38 +09:00
// ---- Try/Catch/Cleanup lowering context ----
/// When true, `return` statements are deferred: they assign to `return_defer_slot`
/// and jump to `return_defer_target` (typically the cleanup/exit block).
pub ( super ) return_defer_active : bool ,
/// Slot value to receive deferred return values (edge-copy mode friendly).
pub ( super ) return_defer_slot : Option < ValueId > ,
/// Target block to jump to on deferred return.
pub ( super ) return_defer_target : Option < BasicBlockId > ,
/// Set to true when a deferred return has been emitted in the current context.
pub ( super ) return_deferred_emitted : bool ,
/// True while lowering the cleanup block.
pub ( super ) in_cleanup_block : bool ,
/// Policy flags (snapshotted at entry of try/catch lowering)
pub ( super ) cleanup_allow_return : bool ,
pub ( super ) cleanup_allow_throw : bool ,
2025-09-20 03:37:20 +09:00
/// Hint sink (zero-cost guidance; currently no-op)
pub ( super ) hint_sink : crate ::mir ::hints ::HintSink ,
2025-09-26 04:17:56 +09:00
/// Internal counter for temporary pin slots (block-crossing ephemeral values)
temp_slot_counter : u32 ,
2025-09-26 05:28:20 +09:00
/// If true, skip entry materialization of pinned slots on the next start_new_block call.
suppress_pin_entry_copy_next : bool ,
2025-09-28 01:33:58 +09:00
// ----------------------
// Debug scope context (dev only; zero-cost when unused)
// ----------------------
/// Stack of region identifiers like "loop#1/header" or "join#3/join".
debug_scope_stack : Vec < String > ,
2025-11-19 08:35:56 +09:00
/// Monotonic counter for region IDs (deterministic across a run).
2025-09-28 01:33:58 +09:00
debug_join_counter : u32 ,
2025-09-28 20:38:09 +09:00
/// Local SSA cache: ensure per-block materialization for critical operands (e.g., recv)
/// Key: (bb, original ValueId, kind) -> local ValueId
/// kind: 0=recv, 1+ reserved for future (args etc.)
pub ( super ) local_ssa_map : HashMap < ( BasicBlockId , ValueId , u8 ) , ValueId > ,
/// BlockSchedule cache: deduplicate materialize copies per (bb, src)
pub ( super ) schedule_mat_map : HashMap < ( BasicBlockId , ValueId ) , ValueId > ,
2025-11-19 02:44:40 +09:00
/// Mapping from ValueId to its pin slot name (e.g., "__pin$3$@recv")
/// Used by LocalSSA to redirect old pinned values to the latest slot value.
pub ( super ) pin_slot_names : HashMap < ValueId , String > ,
2025-11-17 17:31:09 +09:00
/// Guard flag to prevent re-entering emit_unified_call from BoxCall fallback.
/// Used when RouterPolicyBox in emit_unified_call has already decided to
/// route a given Method call to BoxCall; emit_box_or_plugin_call must not
/// bounce back into the unified path for the same call, otherwise an
/// infinite recursion (emit_unified_call → emit_box_or_plugin_call →
/// emit_unified_call …) can occur when routing decisions disagree.
pub ( super ) in_unified_boxcall_fallback : bool ,
2025-11-17 17:53:40 +09:00
/// Recursion depth counter for debugging stack overflow
/// Tracks the depth of build_expression calls to detect infinite loops
pub ( super ) recursion_depth : usize ,
2025-11-18 06:39:45 +09:00
2025-11-24 14:17:02 +09:00
/// Current AST span being lowered (used to annotate MIR instructions)
pub ( super ) current_span : Span ,
/// Optional source file hint for metadata/spans
pub ( super ) source_file : Option < String > ,
2025-11-18 06:39:45 +09:00
/// Root lowering mode: how to treat top-level Program
/// - None: not decided yet (lower_root not called)
/// - Some(true): App mode (static box Main.main is entry)
/// - Some(false): Script/Test mode (top-level Program runs sequentially)
pub ( super ) root_is_app_mode : Option < bool > ,
2025-11-22 00:00:51 +09:00
/// 🎯 Phase 21.7: Static box singleton instances for methodization
/// Maps BoxName → ValueId of singleton instance (created on demand)
/// Used when HAKO_MIR_BUILDER_METHODIZE=1 to convert Global("BoxName.method/arity")
/// to Method{receiver=singleton} calls
pub ( super ) static_box_singletons : HashMap < String , ValueId > ,
2025-08-12 11:33:48 +00:00
}
impl MirBuilder {
/// Create a new MIR builder
pub fn new ( ) -> Self {
2025-09-11 04:20:28 +09:00
let plugin_method_sigs = plugin_sigs ::load_plugin_method_sigs ( ) ;
2025-09-23 07:25:58 +09:00
// フェーズM: no_phi_mode初期化削除
2025-08-12 11:33:48 +00:00
Self {
current_module : None ,
current_function : None ,
current_block : None ,
value_gen : ValueIdGenerator ::new ( ) ,
block_gen : BasicBlockIdGenerator ::new ( ) ,
2025-11-24 14:17:02 +09:00
compilation_context : None , // 箱理論: デフォルトは従来モード
2025-11-22 05:33:40 +09:00
variable_map : BTreeMap ::new ( ) , // Phase 25.1: 決定性確保
2025-08-12 11:33:48 +00:00
pending_phis : Vec ::new ( ) ,
2025-11-22 05:33:40 +09:00
value_origin_newbox : BTreeMap ::new ( ) , // Phase 25.1: 決定性確保
2025-08-21 01:18:25 +09:00
user_defined_boxes : HashSet ::new ( ) ,
2025-08-24 00:05:12 +09:00
weak_fields_by_box : HashMap ::new ( ) ,
2025-09-19 08:34:29 +09:00
property_getters_by_box : HashMap ::new ( ) ,
2025-08-24 00:05:12 +09:00
field_origin_class : HashMap ::new ( ) ,
2025-09-26 14:34:42 +09:00
field_origin_by_box : HashMap ::new ( ) ,
2025-11-22 05:33:40 +09:00
value_types : BTreeMap ::new ( ) , // Phase 25.1: 決定性確保
2025-11-24 14:17:02 +09:00
value_kinds : HashMap ::new ( ) , // Phase 26-A: ValueId型安全化
2025-11-19 03:28:58 +09:00
current_slot_registry : None ,
2025-11-17 23:13:57 +09:00
type_registry : type_registry ::TypeRegistry ::new ( ) ,
2025-09-11 03:33:33 +09:00
plugin_method_sigs ,
2025-08-29 21:39:47 +09:00
current_static_box : None ,
2025-09-25 10:23:14 +09:00
static_method_index : std ::collections ::HashMap ::new ( ) ,
2025-11-17 05:24:07 +09:00
function_param_names : HashSet ::new ( ) ,
2025-09-28 12:19:49 +09:00
method_tail_index : std ::collections ::HashMap ::new ( ) ,
method_tail_index_source_len : 0 ,
2025-11-17 05:24:07 +09:00
2025-11-19 03:28:58 +09:00
current_region_stack : Vec ::new ( ) ,
2025-09-15 22:14:42 +09:00
loop_header_stack : Vec ::new ( ) ,
loop_exit_stack : Vec ::new ( ) ,
2025-09-19 02:07:38 +09:00
if_merge_stack : Vec ::new ( ) ,
2025-09-23 07:25:58 +09:00
// フェーズM: no_phi_modeフィールド削除
2025-09-19 02:07:38 +09:00
return_defer_active : false ,
return_defer_slot : None ,
return_defer_target : None ,
return_deferred_emitted : false ,
in_cleanup_block : false ,
cleanup_allow_return : false ,
cleanup_allow_throw : false ,
2025-09-20 03:37:20 +09:00
hint_sink : crate ::mir ::hints ::HintSink ::new ( ) ,
2025-09-26 04:17:56 +09:00
temp_slot_counter : 0 ,
2025-09-26 05:28:20 +09:00
suppress_pin_entry_copy_next : false ,
2025-09-28 01:33:58 +09:00
// Debug scope context
debug_scope_stack : Vec ::new ( ) ,
debug_join_counter : 0 ,
2025-09-28 20:38:09 +09:00
local_ssa_map : HashMap ::new ( ) ,
schedule_mat_map : HashMap ::new ( ) ,
2025-11-19 02:44:40 +09:00
pin_slot_names : HashMap ::new ( ) ,
2025-11-17 17:31:09 +09:00
in_unified_boxcall_fallback : false ,
2025-11-17 17:53:40 +09:00
recursion_depth : 0 ,
2025-11-24 14:17:02 +09:00
current_span : Span ::unknown ( ) ,
source_file : None ,
2025-11-18 06:39:45 +09:00
root_is_app_mode : None ,
2025-11-22 00:00:51 +09:00
static_box_singletons : HashMap ::new ( ) , // Phase 21.7: methodization support
2025-08-12 11:33:48 +00:00
}
}
2025-08-20 18:57:10 +09:00
2025-09-19 02:07:38 +09:00
/// Push/pop helpers for If merge context (best-effort; optional usage)
2025-11-21 06:25:17 +09:00
pub ( super ) fn push_if_merge ( & mut self , bb : BasicBlockId ) {
self . if_merge_stack . push ( bb ) ;
}
pub ( super ) fn pop_if_merge ( & mut self ) {
let _ = self . if_merge_stack . pop ( ) ;
}
2025-09-19 02:07:38 +09:00
2025-09-26 05:28:20 +09:00
/// Suppress entry pin copy for the next start_new_block (used for merge blocks).
2025-11-21 06:25:17 +09:00
pub ( super ) fn suppress_next_entry_pin_copy ( & mut self ) {
self . suppress_pin_entry_copy_next = true ;
}
2025-09-26 05:28:20 +09:00
2025-09-20 03:37:20 +09:00
// ---- Hint helpers (no-op by default) ----
#[ inline ]
2025-11-21 06:25:17 +09:00
pub ( crate ) fn hint_scope_enter ( & mut self , id : u32 ) {
self . hint_sink . scope_enter ( id ) ;
}
2025-09-20 03:37:20 +09:00
#[ inline ]
2025-11-21 06:25:17 +09:00
pub ( crate ) fn hint_scope_leave ( & mut self , id : u32 ) {
self . hint_sink . scope_leave ( id ) ;
}
2025-09-20 03:37:20 +09:00
#[ inline ]
2025-11-21 06:25:17 +09:00
pub ( crate ) fn hint_join_result < S : Into < String > > ( & mut self , var : S ) {
self . hint_sink . join_result ( var . into ( ) ) ;
}
2025-09-20 03:37:20 +09:00
2025-09-28 01:33:58 +09:00
// ----------------------
// Debug scope helpers (region_id for DebugHub events)
// ----------------------
#[ inline ]
pub ( crate ) fn debug_next_join_id ( & mut self ) -> u32 {
let id = self . debug_join_counter ;
self . debug_join_counter = self . debug_join_counter . saturating_add ( 1 ) ;
id
}
#[ inline ]
pub ( crate ) fn debug_push_region < S : Into < String > > ( & mut self , region : S ) {
self . debug_scope_stack . push ( region . into ( ) ) ;
}
#[ inline ]
pub ( crate ) fn debug_pop_region ( & mut self ) {
let _ = self . debug_scope_stack . pop ( ) ;
}
#[ inline ]
pub ( crate ) fn debug_current_region_id ( & self ) -> Option < String > {
self . debug_scope_stack . last ( ) . cloned ( )
}
2025-11-24 14:17:02 +09:00
/// Hint for downstream metadata: set the logical source file name/path for the next build.
pub fn set_source_file_hint < S : Into < String > > ( & mut self , source : S ) {
self . source_file = Some ( source . into ( ) ) ;
}
/// Clear the source file hint (used when reusing the builder across modules).
pub fn clear_source_file_hint ( & mut self ) {
self . source_file = None ;
}
/// Resolve current source file hint (builder field or env fallback).
fn current_source_file ( & self ) -> Option < String > {
self . source_file
. clone ( )
. or_else ( | | std ::env ::var ( " NYASH_SOURCE_FILE_HINT " ) . ok ( ) )
}
/// Create a new MirFunction with source metadata applied.
fn new_function_with_metadata (
& self ,
signature : FunctionSignature ,
entry_block : BasicBlockId ,
) -> MirFunction {
let mut f = MirFunction ::new ( signature , entry_block ) ;
f . metadata . source_file = self . current_source_file ( ) ;
f
}
2025-11-17 19:53:44 +09:00
// ----------------------
// Compile trace helpers (dev only; env-gated)
// ----------------------
#[ inline ]
pub ( super ) fn compile_trace_enabled ( ) -> bool {
2025-11-21 06:25:17 +09:00
std ::env ::var ( " NYASH_MIR_COMPILE_TRACE " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " )
2025-11-17 19:53:44 +09:00
}
#[ inline ]
pub ( super ) fn trace_compile < S : AsRef < str > > ( & self , msg : S ) {
if Self ::compile_trace_enabled ( ) {
eprintln! ( " [mir-compile] {} " , msg . as_ref ( ) ) ;
}
}
2025-09-28 12:19:49 +09:00
// ----------------------
// Method tail index (performance helper)
// ----------------------
fn rebuild_method_tail_index ( & mut self ) {
self . method_tail_index . clear ( ) ;
if let Some ( ref module ) = self . current_module {
for name in module . functions . keys ( ) {
if let ( Some ( dot ) , Some ( slash ) ) = ( name . rfind ( '.' ) , name . rfind ( '/' ) ) {
if slash > dot {
let tail = & name [ dot .. ] ;
self . method_tail_index
. entry ( tail . to_string ( ) )
. or_insert_with ( Vec ::new )
. push ( name . clone ( ) ) ;
}
}
}
self . method_tail_index_source_len = module . functions . len ( ) ;
} else {
self . method_tail_index_source_len = 0 ;
}
}
fn ensure_method_tail_index ( & mut self ) {
let need_rebuild = match self . current_module {
Some ( ref refmod ) = > self . method_tail_index_source_len ! = refmod . functions . len ( ) ,
None = > self . method_tail_index_source_len ! = 0 ,
} ;
if need_rebuild {
self . rebuild_method_tail_index ( ) ;
}
}
pub ( super ) fn method_candidates ( & mut self , method : & str , arity : usize ) -> Vec < String > {
self . ensure_method_tail_index ( ) ;
let tail = format! ( " . {} {} " , method , format! ( " / {} " , arity ) ) ;
self . method_tail_index
. get ( & tail )
. cloned ( )
. unwrap_or_default ( )
}
pub ( super ) fn method_candidates_tail < S : AsRef < str > > ( & mut self , tail : S ) -> Vec < String > {
self . ensure_method_tail_index ( ) ;
self . method_tail_index
. get ( tail . as_ref ( ) )
. cloned ( )
. unwrap_or_default ( )
}
2025-08-12 11:33:48 +00:00
/// Build a complete MIR module from AST
pub fn build_module ( & mut self , ast : ASTNode ) -> Result < MirModule , String > {
2025-09-17 07:29:28 +09:00
self . prepare_module ( ) ? ;
let result_value = self . lower_root ( ast ) ? ;
self . finalize_module ( result_value )
}
2025-08-12 11:33:48 +00:00
/// Build an expression and return its value ID
2025-08-18 23:36:40 +09:00
pub ( super ) fn build_expression ( & mut self , ast : ASTNode ) -> Result < ValueId , String > {
2025-09-04 06:27:39 +09:00
// Delegated to exprs.rs to keep this file lean
2025-11-17 17:53:40 +09:00
// Debug: Track recursion depth to detect infinite loops
const MAX_RECURSION_DEPTH : usize = 200 ;
self . recursion_depth + = 1 ;
if self . recursion_depth > MAX_RECURSION_DEPTH {
eprintln! ( " \n [FATAL] ============================================ " ) ;
2025-11-21 06:25:17 +09:00
eprintln! (
" [FATAL] Recursion depth exceeded {} in build_expression " ,
MAX_RECURSION_DEPTH
) ;
2025-11-17 17:53:40 +09:00
eprintln! ( " [FATAL] Current depth: {} " , self . recursion_depth ) ;
eprintln! ( " [FATAL] AST node type: {:?} " , std ::mem ::discriminant ( & ast ) ) ;
eprintln! ( " [FATAL] ============================================ \n " ) ;
2025-11-21 06:25:17 +09:00
return Err ( format! (
" Recursion depth exceeded: {} (possible infinite loop) " ,
self . recursion_depth
) ) ;
2025-11-17 17:53:40 +09:00
}
let result = self . build_expression_impl ( ast ) ;
self . recursion_depth - = 1 ;
result
2025-09-04 06:27:39 +09:00
}
2025-09-17 07:43:07 +09:00
2025-08-12 11:33:48 +00:00
/// Build a literal value
2025-09-04 06:27:39 +09:00
pub ( super ) fn build_literal ( & mut self , literal : LiteralValue ) -> Result < ValueId , String > {
2025-08-28 22:31:51 +09:00
// Determine type without moving literal
let ty_for_dst = match & literal {
LiteralValue ::Integer ( _ ) = > Some ( super ::MirType ::Integer ) ,
LiteralValue ::Float ( _ ) = > Some ( super ::MirType ::Float ) ,
LiteralValue ::Bool ( _ ) = > Some ( super ::MirType ::Bool ) ,
LiteralValue ::String ( _ ) = > Some ( super ::MirType ::String ) ,
_ = > None ,
} ;
2025-09-28 20:38:09 +09:00
// Emit via ConstantEmissionBox( 仕様不変の統一ルート)
let dst = match literal {
2025-11-21 06:25:17 +09:00
LiteralValue ::Integer ( n ) = > {
crate ::mir ::builder ::emission ::constant ::emit_integer ( self , n )
}
2025-09-28 20:38:09 +09:00
LiteralValue ::Float ( f ) = > crate ::mir ::builder ::emission ::constant ::emit_float ( self , f ) ,
2025-11-21 06:25:17 +09:00
LiteralValue ::String ( s ) = > {
crate ::mir ::builder ::emission ::constant ::emit_string ( self , s )
}
2025-09-28 20:38:09 +09:00
LiteralValue ::Bool ( b ) = > crate ::mir ::builder ::emission ::constant ::emit_bool ( self , b ) ,
LiteralValue ::Null = > crate ::mir ::builder ::emission ::constant ::emit_null ( self ) ,
LiteralValue ::Void = > crate ::mir ::builder ::emission ::constant ::emit_void ( self ) ,
2025-08-12 11:33:48 +00:00
} ;
2025-08-28 22:31:51 +09:00
// Annotate type
2025-09-17 07:43:07 +09:00
if let Some ( ty ) = ty_for_dst {
self . value_types . insert ( dst , ty ) ;
}
2025-08-12 11:33:48 +00:00
Ok ( dst )
}
2025-09-17 07:43:07 +09:00
2025-08-12 11:33:48 +00:00
/// Build variable access
2025-09-04 06:27:39 +09:00
pub ( super ) fn build_variable_access ( & mut self , name : String ) -> Result < ValueId , String > {
2025-11-20 16:10:56 +09:00
// Step 5-5-G: __pin$ variables should NEVER be accessed from variable_map
// They are transient temporaries created during expression building and
// should not persist across blocks. If we see one here, it's a compiler bug.
if name . starts_with ( " __pin$ " ) {
return Err ( format! (
" COMPILER BUG: Attempt to access __pin$ temporary '{}' from variable_map. \
__pin $ variables should only exist as direct SSA values , not as named variables . " ,
name
) ) ;
}
2025-08-12 11:33:48 +00:00
if let Some ( & value_id ) = self . variable_map . get ( & name ) {
Ok ( value_id )
} else {
2025-09-24 21:45:27 +09:00
// Enhance diagnostics using Using simple registry (Phase 1)
let mut msg = format! ( " Undefined variable: {} " , name ) ;
2025-11-14 13:36:20 +09:00
// Stage-3 keyword diagnostic (local/flow/try/catch/throw)
2025-11-30 14:30:28 +09:00
if name = = " local " & & ! crate ::config ::env ::parser_stage3_enabled ( ) {
msg . push_str ( " \n Hint: 'local' is a Stage-3 keyword. Prefer NYASH_FEATURES=stage3 (legacy: NYASH_PARSER_STAGE3=1 / HAKO_PARSER_STAGE3=1 for Stage-B). " ) ;
2025-11-14 13:36:20 +09:00
msg . push_str ( " \n For AotPrep verification, use tools/hakorune_emit_mir.sh which sets these automatically. " ) ;
} else if ( name = = " flow " | | name = = " try " | | name = = " catch " | | name = = " throw " )
2025-11-30 14:30:28 +09:00
& & ! crate ::config ::env ::parser_stage3_enabled ( )
2025-11-21 06:25:17 +09:00
{
2025-11-30 14:30:28 +09:00
msg . push_str ( & format! ( " \n Hint: ' {} ' is a Stage-3 keyword. Prefer NYASH_FEATURES=stage3 (legacy: NYASH_PARSER_STAGE3=1 / HAKO_PARSER_STAGE3=1 for Stage-B). " , name ) ) ;
2025-11-14 13:36:20 +09:00
}
2025-09-24 21:45:27 +09:00
let suggest = crate ::using ::simple_registry ::suggest_using_for_symbol ( & name ) ;
if ! suggest . is_empty ( ) {
msg . push_str ( " \n Hint: symbol appears in using module(s): " ) ;
msg . push_str ( & suggest . join ( " , " ) ) ;
2025-11-21 06:25:17 +09:00
msg . push_str (
" \n Consider adding 'using <module> [as Alias]' or check nyash.toml [using]. " ,
) ;
2025-09-24 21:45:27 +09:00
}
Err ( msg )
2025-08-12 11:33:48 +00:00
}
}
2025-09-17 07:43:07 +09:00
2025-08-12 11:33:48 +00:00
/// Build assignment
2025-09-17 07:43:07 +09:00
pub ( super ) fn build_assignment (
& mut self ,
var_name : String ,
value : ASTNode ,
) -> Result < ValueId , String > {
2025-11-20 15:53:06 +09:00
let value_id = self . build_expression ( value ) ? ;
// Step 5-5-E: FIX variable map corruption bug
// REMOVED pin_to_slot() call - it was causing __pin$ temporaries to overwrite
// real variable names in the variable map.
//
// Root cause: pin_to_slot(raw_value_id, "@assign") would sometimes return
// a ValueId from a previous __pin$ temporary (e.g., __pin$767$@binop_lhs),
// causing variable_map["m"] to point to the wrong ValueId.
//
// SSA + PHI merges work correctly without explicit pinning here.
// The expression building already creates necessary temporaries.
2025-09-17 07:43:07 +09:00
2025-11-20 16:10:56 +09:00
// Step 5-5-F: NEVER insert __pin$ temporaries into variable_map
// __pin$ variables are transient compiler-generated temporaries that should
// never be tracked as real variables. They are used only within expression
// building and should not persist across blocks or loops.
//
// BUG FIX: Previously, __pin$ variables would be inserted into variable_map,
// causing stale references after LoopForm transformation renumbers blocks.
// Result: VM would try to read undefined ValueIds (e.g., ValueId(270) at bb303).
if ! var_name . starts_with ( " __pin$ " ) {
// In SSA form, each assignment creates a new value
self . variable_map . insert ( var_name . clone ( ) , value_id ) ;
}
2025-09-17 07:43:07 +09:00
2025-08-12 11:33:48 +00:00
Ok ( value_id )
}
2025-09-17 07:43:07 +09:00
2025-08-12 11:33:48 +00:00
/// Emit an instruction to the current basic block
2025-08-18 23:36:40 +09:00
pub ( super ) fn emit_instruction ( & mut self , instruction : MirInstruction ) -> Result < ( ) , String > {
2025-08-12 11:33:48 +00:00
let block_id = self . current_block . ok_or ( " No current basic block " ) ? ;
2025-09-17 07:43:07 +09:00
2025-11-17 08:41:50 +09:00
// Make instruction mutable for potential receiver materialization
let mut instruction = instruction ;
2025-09-28 01:33:58 +09:00
// Precompute debug metadata to avoid borrow conflicts later
2025-11-18 18:56:35 +09:00
let _dbg_fn_name = self
2025-09-28 01:33:58 +09:00
. current_function
. as_ref ( )
. map ( | f | f . signature . name . clone ( ) ) ;
2025-11-18 18:56:35 +09:00
let _dbg_region_id = self . debug_current_region_id ( ) ;
2025-09-28 12:19:49 +09:00
// P0: PHI の軽量補強と観測は、関数ブロック取得前に実施して借用競合を避ける
2025-11-30 04:35:40 +09:00
if let MirInstruction ::Phi { dst , inputs , .. } = & instruction {
2025-09-28 12:19:49 +09:00
origin ::phi ::propagate_phi_meta ( self , * dst , inputs ) ;
observe ::ssa ::emit_phi ( self , * dst , inputs ) ;
}
2025-11-17 08:41:50 +09:00
// CRITICAL: Final receiver materialization for MethodCall
// This ensures the receiver has an in-block definition in the same block as the Call.
// Must happen BEFORE function mutable borrow to avoid borrowck conflicts.
2025-11-21 06:25:17 +09:00
if let MirInstruction ::Call {
callee : Some ( callee ) ,
dst ,
args ,
effects ,
..
} = & instruction
{
2025-11-17 08:41:50 +09:00
use crate ::mir ::definitions ::call_unified ::Callee ;
2025-11-21 06:25:17 +09:00
if let Callee ::Method {
box_name ,
method ,
receiver : Some ( r ) ,
certainty ,
box_kind ,
} = callee . clone ( )
{
2025-11-17 08:41:50 +09:00
// LocalSSA: ensure receiver has a Copy in current_block
let r_local = crate ::mir ::builder ::ssa ::local ::recv ( self , r ) ;
// Update instruction with materialized receiver
let new_callee = Callee ::Method {
box_name : box_name . clone ( ) ,
method : method . clone ( ) ,
receiver : Some ( r_local ) ,
2025-11-17 23:13:57 +09:00
certainty ,
box_kind ,
2025-11-17 08:41:50 +09:00
} ;
instruction = MirInstruction ::Call {
dst : * dst ,
2025-11-20 06:38:43 +09:00
func : crate ::mir ::ValueId ::INVALID , // Legacy dummy (not a real SSA use)
2025-11-17 08:41:50 +09:00
callee : Some ( new_callee ) ,
args : args . clone ( ) ,
effects : * effects ,
} ;
}
}
2025-08-12 11:33:48 +00:00
if let Some ( ref mut function ) = self . current_function {
2025-11-01 13:41:43 +09:00
// Pre-capture branch/jump targets for predecessor update after we finish
// mutably borrowing the current block.
let ( then_t , else_t , jump_t ) = match & instruction {
2025-11-21 06:25:17 +09:00
MirInstruction ::Branch {
then_bb , else_bb , ..
} = > ( Some ( * then_bb ) , Some ( * else_bb ) , None ) ,
2025-11-01 13:41:43 +09:00
MirInstruction ::Jump { target } = > ( None , None , Some ( * target ) ) ,
_ = > ( None , None , None ) ,
} ;
2025-11-17 03:19:03 +09:00
// Extract function name before mutable borrow to avoid borrowck error
let current_fn_name = function . signature . name . clone ( ) ;
2025-08-12 11:33:48 +00:00
if let Some ( block ) = function . get_block_mut ( block_id ) {
2025-11-17 08:41:50 +09:00
// CRITICAL: Copy専用トレース( LocalSSA調査用)
if let MirInstruction ::Copy { dst , src } = & instruction {
if std ::env ::var ( " NYASH_LOCAL_SSA_TRACE " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
eprintln! (
" [emit-inst] fn={} bb={:?} COPY %{} <- %{} " ,
current_fn_name ,
self . current_block . map ( | b | b . 0 ) . unwrap_or ( 0 ) ,
dst . 0 ,
src . 0
) ;
}
}
2025-11-13 16:40:58 +09:00
// Invariant: Call must always carry a Callee (unified path).
if let MirInstruction ::Call { callee , .. } = & instruction {
if callee . is_none ( ) {
return Err ( " builder invariant violated: MirInstruction::Call.callee must be Some (unified call) " . into ( ) ) ;
2025-11-17 08:41:50 +09:00
} else if std ::env ::var ( " NYASH_LOCAL_SSA_TRACE " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
use crate ::mir ::definitions ::call_unified ::Callee ;
2025-11-21 06:25:17 +09:00
if let Some ( Callee ::Method {
box_name ,
method ,
receiver : Some ( r ) ,
..
} ) = callee
{
2025-11-17 08:41:50 +09:00
eprintln! (
" [emit-inst] fn={} bb={:?} Call {}.{} recv=%{} " ,
current_fn_name ,
self . current_block . map ( | b | b . 0 ) . unwrap_or ( 0 ) ,
box_name ,
method ,
r . 0
) ;
}
2025-11-21 06:25:17 +09:00
} else if std ::env ::var ( " NYASH_BUILDER_TRACE_RECV " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " )
{
2025-11-17 03:19:03 +09:00
use crate ::mir ::definitions ::call_unified ::Callee ;
2025-11-21 06:25:17 +09:00
if let Some ( Callee ::Method {
box_name ,
method ,
receiver : Some ( r ) ,
..
} ) = callee
{
2025-11-17 03:19:03 +09:00
let names : Vec < String > = self
. variable_map
. iter ( )
. filter ( | ( _ , & vid ) | vid = = * r )
. map ( | ( k , _ ) | k . clone ( ) )
. collect ( ) ;
eprintln! (
" [builder/recv-trace] fn={} bb={:?} method={}.{} recv=%{} aliases={:?} " ,
current_fn_name ,
self . current_block ,
box_name ,
method ,
r . 0 ,
names
) ;
}
2025-11-13 16:40:58 +09:00
}
}
2025-09-03 05:04:56 +09:00
if utils ::builder_debug_enabled ( ) {
2025-09-17 07:43:07 +09:00
eprintln! (
" [BUILDER] emit @bb{} -> {} " ,
block_id ,
match & instruction {
MirInstruction ::TypeOp { dst , op , value , ty } = >
format! ( " typeop {:?} {} {:?} -> {} " , op , value , ty , dst ) ,
MirInstruction ::Print { value , .. } = > format! ( " print {} " , value ) ,
MirInstruction ::BoxCall {
box_val ,
method ,
method_id ,
args ,
dst ,
..
} = > {
if let Some ( mid ) = method_id {
format! (
" boxcall {}.{}[#{}]({:?}) -> {:?} " ,
box_val , method , mid , args , dst
)
} else {
format! (
" boxcall {}.{}({:?}) -> {:?} " ,
box_val , method , args , dst
)
}
2025-08-26 20:48:48 +09:00
}
2025-09-17 07:43:07 +09:00
MirInstruction ::Call {
func , args , dst , ..
} = > format! ( " call {} ( {:?} ) -> {:?} " , func , args , dst ) ,
MirInstruction ::NewBox {
dst ,
box_type ,
args ,
} = > format! ( " new {} ( {:?} ) -> {} " , box_type , args , dst ) ,
MirInstruction ::Const { dst , value } = >
format! ( " const {:?} -> {} " , value , dst ) ,
MirInstruction ::Branch {
condition ,
then_bb ,
else_bb ,
} = > format! ( " br {} , {} , {} " , condition , then_bb , else_bb ) ,
MirInstruction ::Jump { target } = > format! ( " br {} " , target ) ,
_ = > format! ( " {:?} " , instruction ) ,
}
) ;
2025-08-24 01:58:41 +09:00
}
2025-11-24 14:17:02 +09:00
block . add_instruction_with_span ( instruction , self . current_span ) ;
2025-11-01 13:41:43 +09:00
// Drop the mutable borrow of `block` before updating other blocks
2025-11-21 06:25:17 +09:00
}
2025-11-01 13:41:43 +09:00
// Update predecessor sets for branch/jump immediately so that
// debug_verify_phi_inputs can observe a consistent CFG without
// requiring a full function.update_cfg() pass.
if let Some ( t ) = then_t {
2025-11-21 06:25:17 +09:00
if let Some ( succ ) = function . get_block_mut ( t ) {
succ . add_predecessor ( block_id ) ;
}
2025-11-01 13:41:43 +09:00
}
if let Some ( t ) = else_t {
2025-11-21 06:25:17 +09:00
if let Some ( succ ) = function . get_block_mut ( t ) {
succ . add_predecessor ( block_id ) ;
}
2025-11-01 13:41:43 +09:00
}
if let Some ( t ) = jump_t {
2025-11-21 06:25:17 +09:00
if let Some ( succ ) = function . get_block_mut ( t ) {
succ . add_predecessor ( block_id ) ;
}
2025-08-12 11:33:48 +00:00
}
2025-11-01 13:41:43 +09:00
Ok ( ( ) )
2025-08-12 11:33:48 +00:00
} else {
2025-11-01 13:41:43 +09:00
Err ( format! ( " Basic block {} does not exist " , block_id ) )
2025-08-12 11:33:48 +00:00
}
}
2025-09-16 23:49:36 +09:00
2025-11-17 05:24:07 +09:00
/// Update an existing PHI instruction's inputs (for loop sealing)
/// Used by LoopFormBuilder to complete incomplete PHI nodes
pub ( super ) fn update_phi_instruction (
& mut self ,
block : BasicBlockId ,
phi_id : ValueId ,
new_inputs : Vec < ( BasicBlockId , ValueId ) > ,
) -> Result < ( ) , String > {
if let Some ( ref mut function ) = self . current_function {
if let Some ( block_data ) = function . get_block_mut ( block ) {
// Find PHI instruction with matching dst
for inst in & mut block_data . instructions {
2025-11-30 04:35:40 +09:00
if let MirInstruction ::Phi { dst , inputs , .. } = inst {
2025-11-17 05:24:07 +09:00
if * dst = = phi_id {
* inputs = new_inputs ;
return Ok ( ( ) ) ;
}
}
}
2025-11-21 06:25:17 +09:00
Err ( format! (
" PHI instruction {} not found in block {} " ,
phi_id , block
) )
2025-11-17 05:24:07 +09:00
} else {
Err ( format! ( " Block {} not found " , block ) )
}
} else {
Err ( " No current function " . to_string ( ) )
}
}
2025-09-23 07:25:58 +09:00
// フェーズM: is_no_phi_mode()メソッド削除
2025-09-16 23:49:36 +09:00
2025-09-23 07:25:58 +09:00
// フェーズM: insert_edge_copy()メソッド削除( no_phi_mode撤廃により不要)
2025-09-17 07:43:07 +09:00
2025-08-13 10:20:37 +00:00
/// Build new expression: new ClassName(arguments)
2025-09-17 07:43:07 +09:00
pub ( super ) fn build_new_expression (
& mut self ,
class : String ,
arguments : Vec < ASTNode > ,
) -> Result < ValueId , String > {
2025-08-20 17:58:51 +09:00
// Phase 9.78a: Unified Box creation using NewBox instruction
2025-09-07 07:28:53 +09:00
// Core-13 pure mode: emit ExternCall(env.box.new) with type name const only
if crate ::config ::env ::mir_core13_pure ( ) {
2025-09-28 20:38:09 +09:00
// Emit Const String for type name( ConstantEmissionBox)
let ty_id = crate ::mir ::builder ::emission ::constant ::emit_string ( self , class . clone ( ) ) ;
2025-09-07 07:28:53 +09:00
// Evaluate arguments (pass through to env.box.new shim)
let mut arg_vals : Vec < ValueId > = Vec ::with_capacity ( arguments . len ( ) ) ;
2025-09-17 07:43:07 +09:00
for a in arguments {
arg_vals . push ( self . build_expression ( a ) ? ) ;
}
2025-09-07 07:28:53 +09:00
// Build arg list: [type, a1, a2, ...]
let mut args : Vec < ValueId > = Vec ::with_capacity ( 1 + arg_vals . len ( ) ) ;
args . push ( ty_id ) ;
args . extend ( arg_vals ) ;
// Call env.box.new
2025-11-18 06:46:22 +09:00
// 📦 Hotfix 3: Use next_value_id() to respect function parameter reservation
let dst = self . next_value_id ( ) ;
2025-09-07 07:28:53 +09:00
self . emit_instruction ( MirInstruction ::ExternCall {
2025-09-17 07:43:07 +09:00
dst : Some ( dst ) ,
iface_name : " env.box " . to_string ( ) ,
method_name : " new " . to_string ( ) ,
args ,
effects : EffectMask ::PURE ,
2025-09-07 07:28:53 +09:00
} ) ? ;
// 型注釈(最小)
2025-09-17 07:43:07 +09:00
self . value_types
. insert ( dst , super ::MirType ::Box ( class . clone ( ) ) ) ;
2025-09-07 07:28:53 +09:00
return Ok ( dst ) ;
}
2025-09-17 07:43:07 +09:00
2025-08-30 22:52:16 +09:00
// Optimization: Primitive wrappers → emit Const directly when possible
if class = = " IntegerBox " & & arguments . len ( ) = = 1 {
2025-09-17 07:43:07 +09:00
if let ASTNode ::Literal {
value : LiteralValue ::Integer ( n ) ,
..
} = arguments [ 0 ] . clone ( )
{
2025-11-18 06:46:22 +09:00
// 📦 Hotfix 3: Use next_value_id() to respect function parameter reservation
let dst = self . next_value_id ( ) ;
2025-09-17 07:43:07 +09:00
self . emit_instruction ( MirInstruction ::Const {
dst ,
value : ConstValue ::Integer ( n ) ,
} ) ? ;
2025-08-30 22:52:16 +09:00
self . value_types . insert ( dst , super ::MirType ::Integer ) ;
return Ok ( dst ) ;
}
}
2025-09-17 07:43:07 +09:00
2025-08-20 17:58:51 +09:00
// First, evaluate all arguments to get their ValueIds
let mut arg_values = Vec ::new ( ) ;
for arg in arguments {
let arg_value = self . build_expression ( arg ) ? ;
arg_values . push ( arg_value ) ;
2025-08-18 19:29:24 +09:00
}
2025-09-17 07:43:07 +09:00
2025-08-20 17:58:51 +09:00
// Generate the destination ValueId
2025-11-18 06:46:22 +09:00
// 📦 Hotfix 3: Use next_value_id() to respect function parameter reservation
let dst = self . next_value_id ( ) ;
2025-09-17 07:43:07 +09:00
2025-08-20 17:58:51 +09:00
// Emit NewBox instruction for all Box types
// VM will handle optimization for basic types internally
self . emit_instruction ( MirInstruction ::NewBox {
2025-08-13 10:20:37 +00:00
dst ,
2025-08-20 20:56:08 +09:00
box_type : class . clone ( ) ,
2025-08-20 18:57:10 +09:00
args : arg_values . clone ( ) ,
} ) ? ;
2025-09-24 09:30:42 +09:00
// Phase 15.5: Unified box type handling
// All boxes (including former core boxes) are treated uniformly as Box types
self . value_types
. insert ( dst , super ::MirType ::Box ( class . clone ( ) ) ) ;
2025-08-20 18:57:10 +09:00
2025-08-20 20:56:08 +09:00
// Record origin for optimization: dst was created by NewBox of class
2025-08-26 20:48:48 +09:00
self . value_origin_newbox . insert ( dst , class . clone ( ) ) ;
2025-08-20 20:56:08 +09:00
2025-09-26 14:34:42 +09:00
// birth 呼び出し( Builder 正規化)
// 優先: 低下済みグローバル関数 `<Class>.birth/Arity`( Arity は me を含まない)
// 代替: 既存互換として BoxCall("birth")(プラグイン/ビルトインの初期化に対応)
2025-09-26 03:30:59 +09:00
if class ! = " StringBox " {
2025-09-26 14:34:42 +09:00
let arity = arg_values . len ( ) ;
2025-11-21 06:25:17 +09:00
let lowered =
crate ::mir ::builder ::calls ::function_lowering ::generate_method_function_name (
& class , " birth " , arity ,
) ;
2025-09-26 14:34:42 +09:00
let use_lowered = if let Some ( ref module ) = self . current_module {
module . functions . contains_key ( & lowered )
2025-11-21 06:25:17 +09:00
} else {
false
} ;
2025-09-26 14:34:42 +09:00
if use_lowered {
// Call Global("Class.birth/Arity") with argv = [me, args...]
let mut argv : Vec < ValueId > = Vec ::with_capacity ( 1 + arity ) ;
argv . push ( dst ) ;
argv . extend ( arg_values . iter ( ) . copied ( ) ) ;
self . emit_legacy_call ( None , CallTarget ::Global ( lowered ) , argv ) ? ;
} else {
2025-09-28 01:33:58 +09:00
// Fallback policy:
// - For user-defined boxes (no explicit constructor), do NOT emit BoxCall("birth").
// VM will treat plain NewBox as constructed; dev verify warns if needed.
// - For builtins/plugins, keep BoxCall("birth") fallback to preserve legacy init.
let is_user_box = self . user_defined_boxes . contains ( & class ) ;
2025-09-28 12:19:49 +09:00
// Dev safety: allow disabling birth() injection for builtins to avoid
// unified-call method dispatch issues while migrating. Off by default unless explicitly enabled.
2025-11-21 06:25:17 +09:00
let allow_builtin_birth = std ::env ::var ( " NYASH_DEV_BIRTH_INJECT_BUILTINS " )
. ok ( )
. as_deref ( )
= = Some ( " 1 " ) ;
2025-09-28 12:19:49 +09:00
if ! is_user_box & & allow_builtin_birth {
2025-09-28 01:33:58 +09:00
let birt_mid = resolve_slot_by_type_name ( & class , " birth " ) ;
self . emit_box_or_plugin_call (
None ,
dst ,
" birth " . to_string ( ) ,
birt_mid ,
arg_values ,
EffectMask ::READ . add ( Effect ::ReadHeap ) ,
) ? ;
}
2025-09-26 14:34:42 +09:00
}
2025-08-30 22:52:16 +09:00
}
2025-09-17 07:43:07 +09:00
2025-08-13 10:20:37 +00:00
Ok ( dst )
}
2025-09-17 07:43:07 +09:00
2025-08-13 07:13:53 +00:00
/// Check if the current basic block is terminated
fn is_current_block_terminated ( & self ) -> bool {
if let ( Some ( block_id ) , Some ( ref function ) ) = ( self . current_block , & self . current_function ) {
if let Some ( block ) = function . get_block ( block_id ) {
return block . is_terminated ( ) ;
}
}
false
}
2025-09-17 07:43:07 +09:00
2025-11-20 09:34:55 +09:00
// ============================================================================
// Phase 26-A: ValueId型安全化メソッド
// ============================================================================
2025-09-17 07:43:07 +09:00
2025-11-20 09:34:55 +09:00
/// 型付きValueIdを発行( 新API)
pub fn new_typed_value ( & mut self , kind : super ::MirValueKind ) -> super ::TypedValueId {
let id = self . value_gen . next ( ) ;
self . value_kinds . insert ( id , kind ) ;
super ::TypedValueId ::new ( id , kind )
}
2025-08-29 21:39:47 +09:00
2025-11-20 09:34:55 +09:00
/// 既存ValueIdの型情報を取得
pub fn get_value_kind ( & self , id : ValueId ) -> Option < super ::MirValueKind > {
self . value_kinds . get ( & id ) . copied ( )
}
2025-08-29 21:39:47 +09:00
2025-11-20 09:34:55 +09:00
/// 既存ValueIdに型情報を後付け( レガシー互換用)
pub fn register_value_kind ( & mut self , id : ValueId , kind : super ::MirValueKind ) {
self . value_kinds . insert ( id , kind ) ;
}
2025-09-17 07:43:07 +09:00
2025-11-20 09:34:55 +09:00
/// 型安全なパラメータ判定( ValueIdベース) - GUARD Bug Prevention
pub fn is_value_parameter ( & self , id : ValueId ) -> bool {
self . get_value_kind ( id )
. map ( | kind | kind . is_parameter ( ) )
. unwrap_or ( false )
}
/// 型安全なローカル変数判定( ValueIdベース)
pub fn is_value_local ( & self , id : ValueId ) -> bool {
self . get_value_kind ( id )
. map ( | kind | kind . is_local ( ) )
. unwrap_or ( false )
}
/// 型安全なLoopCarrier判定( ValueIdベース)
pub fn is_value_loop_carrier ( & self , id : ValueId ) -> bool {
self . get_value_kind ( id )
. map ( | kind | kind . is_loop_carrier ( ) )
. unwrap_or ( false )
}
2025-08-12 11:33:48 +00:00
}
impl Default for MirBuilder {
fn default ( ) -> Self {
Self ::new ( )
}
}