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-12-16 07:02:14 +09:00
mod binding_context ; // Phase 136 follow-up (Step 4/7): BindingContext extraction
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-12-15 22:12:33 +09:00
mod compilation_context ; // Phase 136 follow-up (Step 7/7): CompilationContext extraction
2025-11-17 11:28:18 +09:00
mod context ; // BoxCompilationContext - 箱理論による静的Boxコンパイル時のコンテキスト分離
2025-12-15 20:10:36 +09:00
mod core_context ; // Phase 136 follow-up (Step 2/7): CoreContext extraction
🎉 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 ;
2025-12-16 07:02:14 +09:00
mod metadata_context ; // Phase 136 follow-up (Step 6/7): MetadataContext extraction
mod method_call_handlers ;
mod variable_context ; // Phase 136 follow-up (Step 5/7): VariableContext extraction // Method call handler separation (Phase 3) // call(expr)
2025-12-16 07:09:22 +09:00
// include lowering removed (using is handled in runner)
2025-11-21 06:25:17 +09:00
mod control_flow ; // thin wrappers to centralize control-flow entrypoints
2025-12-16 07:09:22 +09:00
// Phase 140-P4-A: Re-export for loop_canonicalizer SSOT (crate-wide visibility)
pub ( crate ) use control_flow ::{ detect_skip_whitespace_pattern , SkipWhitespaceInfo } ;
2025-12-16 09:08:37 +09:00
// Phase 142-P1: Re-export continue pattern detection for loop_canonicalizer
pub ( crate ) use control_flow ::{ detect_continue_pattern , ContinuePatternInfo } ;
// Phase 143-P0: Re-export parse_number pattern detection for loop_canonicalizer
pub ( crate ) use control_flow ::{ detect_parse_number_pattern , ParseNumberInfo } ;
feat(mir): Phase 143 P1 - Add parse_string pattern to canonicalizer
Expand loop canonicalizer to recognize parse_string patterns with both
continue (escape handling) and return (quote found) statements.
## Implementation
### New Pattern Detection (ast_feature_extractor.rs)
- Add `detect_parse_string_pattern()` function
- Support nested continue detection using `has_continue_node()` helper
- Recognize both return and continue in same loop body
- Return ParseStringInfo { carrier_name, delta, body_stmts }
- ~120 lines added
### Canonicalizer Integration (canonicalizer.rs)
- Try parse_string pattern first (most specific)
- Build LoopSkeleton with HeaderCond, Body, Update steps
- Set ExitContract: has_continue=true, has_return=true
- Route to Pattern4Continue (both exits present)
- ~45 lines modified
### Export Chain
- Add re-exports through 7 module levels:
ast_feature_extractor → patterns → joinir → control_flow → builder → mir
- 10 lines total across 7 files
### Unit Test
- Add `test_parse_string_pattern_recognized()` in canonicalizer.rs
- Verify skeleton structure (3+ steps)
- Verify carrier (name="p", delta=1, role=Counter)
- Verify exit contract (continue=true, return=true, break=false)
- Verify routing decision (Pattern4Continue, no missing_caps)
- ~180 lines added
## Target Pattern
`tools/selfhost/test_pattern4_parse_string.hako`
Pattern structure:
- Check for closing quote → return
- Check for escape sequence → continue (nested inside another if)
- Regular character processing → p++
## Results
- ✅ Strict parity green: Pattern4Continue
- ✅ All 19 unit tests pass
- ✅ Nested continue detection working
- ✅ ExitContract correctly set (first pattern with both continue+return)
- ✅ Default behavior unchanged
## Technical Challenges
1. Nested continue detection required recursive search
2. First pattern with both has_continue=true AND has_return=true
3. Variable step updates (p++ vs p+=2) handled with base delta
## Statistics
- New patterns: 1 (parse_string)
- Total patterns: 4 (skip_whitespace, parse_number, continue, parse_string)
- New capabilities: 0 (uses existing ConstStep)
- Lines added: ~300
- Files modified: 9
- Parity status: Green ✅
Phase 143 P1: Complete
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 12:37:47 +09:00
pub ( crate ) use control_flow ::{ detect_parse_string_pattern , ParseStringInfo } ;
2025-12-16 14:36:32 +09:00
// Phase 91 P5b: Re-export escape skip pattern detection for loop_canonicalizer
pub ( crate ) use control_flow ::{ detect_escape_skip_pattern , EscapeSkipPatternInfo } ;
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 ;
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-12-11 20:54:33 +09:00
mod lifecycle ;
mod loop_frontend_binding ; // Phase 50: Loop Frontend Binding (JoinIR variable mapping)
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-12-16 07:02:14 +09:00
mod scope_context ; // Phase 136 follow-up (Step 3/7): ScopeContext extraction
2025-11-21 06:25:17 +09:00
mod ssa ; // LocalSSA helpers (in-block materialization)
mod stmts ;
2025-12-15 19:59:55 +09:00
mod type_context ; // Phase 136 follow-up: TypeContext extraction
2025-12-15 19:49:41 +09:00
mod type_facts ; // Phase 136 follow-up: Type inference facts box
2025-11-21 06:25:17 +09:00
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 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-12-15 20:10:36 +09:00
/// Phase 136 follow-up (Step 2/7): Core ID generation context
/// Consolidates value_gen, block_gen, next_binding_id, temp_slot_counter, debug_join_counter.
/// Direct field access for backward compatibility (migration in progress).
pub ( super ) core_ctx : core_context ::CoreContext ,
2025-12-15 19:59:55 +09:00
/// Phase 136 follow-up: Type information context
/// Consolidates value_types, value_kinds, value_origin_newbox for better organization.
/// Direct field access for backward compatibility (migration in progress).
pub ( super ) type_ctx : type_context ::TypeContext ,
2025-12-15 20:28:21 +09:00
/// Phase 136 follow-up (Step 3/7): Scope and control flow context
/// Consolidates lexical_scope_stack, loop stacks, if_merge_stack, current_function,
/// function_param_names, debug_scope_stack for better organization.
/// Direct field access for backward compatibility (migration in progress).
pub ( super ) scope_ctx : scope_context ::ScopeContext ,
2025-12-15 20:40:23 +09:00
/// Phase 136 follow-up (Step 4/7): Binding context
/// Consolidates binding_map (String -> BindingId mapping).
/// Direct field access for backward compatibility (migration in progress).
pub ( super ) binding_ctx : binding_context ::BindingContext ,
2025-12-15 21:50:50 +09:00
/// Phase 136 follow-up (Step 5/7): Variable context
/// Consolidates variable_map (String -> ValueId mapping for SSA conversion).
/// Direct field access for backward compatibility (migration in progress).
pub ( super ) variable_ctx : variable_context ::VariableContext ,
2025-12-15 22:03:34 +09:00
/// Phase 136 follow-up (Step 6/7): Metadata context
/// Consolidates current_span, source_file, hint_sink, current_region_stack.
/// Direct field access for backward compatibility (migration in progress).
pub ( super ) metadata_ctx : metadata_context ::MetadataContext ,
2025-12-15 22:12:33 +09:00
/// Phase 136 follow-up (Step 7/7): Compilation context
/// Consolidates compilation_context, current_static_box, user_defined_boxes, reserved_value_ids,
/// fn_body_ast, weak_fields_by_box, property_getters_by_box, field_origin_class, field_origin_by_box,
/// static_method_index, method_tail_index, type_registry, current_slot_registry, plugin_method_sigs.
/// Direct field access for backward compatibility (migration in progress).
pub ( super ) comp_ctx : compilation_context ::CompilationContext ,
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
2025-12-15 23:51:01 +09:00
// Phase 2-5: binding_map removed - use binding_ctx.binding_map instead
2025-12-13 05:34:56 +09:00
2025-09-25 00:41:56 +09:00
// include guards removed
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
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)
// ----------------------
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
/// 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-12-15 20:10:36 +09:00
let core_ctx = core_context ::CoreContext ::new ( ) ;
2025-12-15 22:12:33 +09:00
// Phase 136 Step 7/7: Compilation context (new SSOT)
2025-12-16 07:02:14 +09:00
let comp_ctx =
compilation_context ::CompilationContext ::with_plugin_sigs ( plugin_method_sigs . clone ( ) ) ;
2025-12-15 22:12:33 +09:00
2025-09-23 07:25:58 +09:00
// フェーズM: no_phi_mode初期化削除
2025-12-15 20:10:36 +09:00
#[ allow(deprecated) ]
2025-08-12 11:33:48 +00:00
Self {
current_module : None ,
current_block : None ,
2025-12-15 20:10:36 +09:00
// Phase 136 Step 2/7: Core context (new SSOT)
core_ctx ,
2025-12-15 19:59:55 +09:00
type_ctx : type_context ::TypeContext ::new ( ) , // Phase 136: Type context
2025-12-15 20:28:21 +09:00
scope_ctx : scope_context ::ScopeContext ::new ( ) , // Phase 136 Step 3/7: Scope context
2025-12-15 20:40:23 +09:00
binding_ctx : binding_context ::BindingContext ::new ( ) , // Phase 136 Step 4/7: Binding context
2025-12-15 21:50:50 +09:00
variable_ctx : variable_context ::VariableContext ::new ( ) , // Phase 136 Step 5/7: Variable context
2025-12-15 22:03:34 +09:00
metadata_ctx : metadata_context ::MetadataContext ::new ( ) , // Phase 136 Step 6/7: Metadata context
2025-12-15 22:12:33 +09:00
comp_ctx , // Phase 136 Step 7/7: Compilation context
2025-08-12 11:33:48 +00:00
pending_phis : Vec ::new ( ) ,
2025-11-19 03:28:58 +09:00
2025-12-15 23:51:01 +09:00
// Phase 2-5: binding_map initialization removed
2025-12-13 05:34:56 +09:00
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-26 05:28:20 +09:00
suppress_pin_entry_copy_next : false ,
2025-09-28 01:33:58 +09:00
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-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-12-15 23:51:01 +09:00
// Phase 2-5: BindingContext sync helpers removed - binding_ctx is now SSOT
2025-12-16 03:48:44 +09:00
// Phase 2-6: VariableContext sync helpers removed - variable_ctx is now SSOT
2025-12-15 21:50:50 +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 ) {
2025-12-16 03:33:56 +09:00
// Phase 2-4: Use scope_ctx only (legacy field removed)
2025-12-15 20:28:21 +09:00
self . scope_ctx . push_if_merge ( bb ) ;
2025-11-21 06:25:17 +09:00
}
pub ( super ) fn pop_if_merge ( & mut self ) {
2025-12-16 03:33:56 +09:00
// Phase 2-4: Use scope_ctx only (legacy field removed)
2025-12-15 20:28:21 +09:00
let _ = self . scope_ctx . pop_if_merge ( ) ;
2025-11-21 06:25:17 +09:00
}
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-12-13 05:34:56 +09:00
// ---- Phase 74: BindingId allocation ----
/// Allocate a new BindingId (parallel to ValueId allocation)
///
/// ## Parallel ValueId/BindingId Allocation
///
/// BindingId allocation is completely independent from ValueId allocation:
/// - `next_value_id()` increments `value_gen` counter
/// - `allocate_binding_id()` increments `next_binding_id` counter
///
/// This parallelism enables:
/// 1. **Stable binding identity** across SSA transformations
/// 2. **Independent shadowing tracking** separate from SSA renaming
/// 3. **Future ScopeManager migration** (Phase 75+) without breaking SSA
///
/// Example:
/// ```ignore
/// // local x = 1; <- allocate_binding_id() -> BindingId(0)
/// // next_value_id() -> ValueId(10)
/// // {
/// // local x = 2; <- allocate_binding_id() -> BindingId(1)
/// // next_value_id() -> ValueId(20)
/// // }
/// ```
pub fn allocate_binding_id ( & mut self ) -> super ::BindingId {
2025-12-15 23:05:36 +09:00
// Phase 136 Step 2/7 + Phase 2-2: Use core_ctx as SSOT (no sync needed)
self . core_ctx . next_binding ( )
2025-12-13 05:34:56 +09:00
}
2025-09-20 03:37:20 +09:00
// ---- Hint helpers (no-op by default) ----
2025-12-15 22:03:34 +09:00
// Phase 136 Step 6/7: Delegate to metadata_ctx with legacy sync
2025-09-20 03:37:20 +09:00
#[ inline ]
2025-11-21 06:25:17 +09:00
pub ( crate ) fn hint_scope_enter ( & mut self , id : u32 ) {
2025-12-15 22:03:34 +09:00
self . metadata_ctx . hint_scope_enter ( id ) ;
2025-11-21 06:25:17 +09:00
}
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 ) {
2025-12-15 22:03:34 +09:00
self . metadata_ctx . hint_scope_leave ( id ) ;
2025-11-21 06:25:17 +09:00
}
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 ) {
2025-12-15 22:44:38 +09:00
self . metadata_ctx . hint_join_result ( var ) ;
2025-11-21 06:25:17 +09:00
}
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 {
2025-12-15 23:05:36 +09:00
// Phase 136 Step 2/7 + Phase 2-2: Use core_ctx as SSOT (no sync needed)
self . core_ctx . next_debug_join ( )
2025-09-28 01:33:58 +09:00
}
#[ inline ]
pub ( crate ) fn debug_push_region < S : Into < String > > ( & mut self , region : S ) {
2025-12-16 03:33:56 +09:00
// Phase 2-4: Use scope_ctx only (legacy field removed)
2025-12-15 20:28:21 +09:00
let region = region . into ( ) ;
2025-12-16 03:33:56 +09:00
self . scope_ctx . debug_push_region ( region ) ;
2025-09-28 01:33:58 +09:00
}
#[ inline ]
pub ( crate ) fn debug_pop_region ( & mut self ) {
2025-12-16 03:33:56 +09:00
// Phase 2-4: Use scope_ctx only (legacy field removed)
2025-12-15 20:28:21 +09:00
self . scope_ctx . debug_pop_region ( ) ;
2025-09-28 01:33:58 +09:00
}
#[ inline ]
2025-12-15 20:28:21 +09:00
#[ allow(deprecated) ]
2025-09-28 01:33:58 +09:00
pub ( crate ) fn debug_current_region_id ( & self ) -> Option < String > {
2025-12-15 20:28:21 +09:00
// Phase 136 Step 3/7: Read from scope_ctx (SSOT)
self . scope_ctx . debug_current_region_id ( )
2025-09-28 01:33:58 +09:00
}
2025-11-24 14:17:02 +09:00
/// Hint for downstream metadata: set the logical source file name/path for the next build.
2025-12-15 22:44:38 +09:00
/// Phase 136 Step 6/7: Delegate to metadata_ctx
2025-11-24 14:17:02 +09:00
pub fn set_source_file_hint < S : Into < String > > ( & mut self , source : S ) {
2025-12-15 22:44:38 +09:00
self . metadata_ctx . set_source_file ( source ) ;
2025-11-24 14:17:02 +09:00
}
/// Clear the source file hint (used when reusing the builder across modules).
2025-12-15 22:44:38 +09:00
/// Phase 136 Step 6/7: Delegate to metadata_ctx
2025-11-24 14:17:02 +09:00
pub fn clear_source_file_hint ( & mut self ) {
2025-12-15 22:03:34 +09:00
self . metadata_ctx . clear_source_file ( ) ;
2025-11-24 14:17:02 +09:00
}
/// Resolve current source file hint (builder field or env fallback).
2025-12-15 22:03:34 +09:00
/// Phase 136 Step 6/7: Delegate to metadata_ctx
2025-11-24 14:17:02 +09:00
fn current_source_file ( & self ) -> Option < String > {
2025-12-15 22:03:34 +09:00
self . metadata_ctx
. current_source_file ( )
2025-11-24 14:17:02 +09:00
. 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 ) {
2025-12-16 04:07:17 +09:00
self . comp_ctx . method_tail_index . clear ( ) ;
2025-09-28 12:19:49 +09:00
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 .. ] ;
2025-12-16 07:02:14 +09:00
self . comp_ctx
. method_tail_index
2025-09-28 12:19:49 +09:00
. entry ( tail . to_string ( ) )
. or_insert_with ( Vec ::new )
. push ( name . clone ( ) ) ;
}
}
}
2025-12-16 04:07:17 +09:00
self . comp_ctx . method_tail_index_source_len = module . functions . len ( ) ;
2025-09-28 12:19:49 +09:00
} else {
2025-12-16 04:07:17 +09:00
self . comp_ctx . method_tail_index_source_len = 0 ;
2025-09-28 12:19:49 +09:00
}
}
fn ensure_method_tail_index ( & mut self ) {
let need_rebuild = match self . current_module {
2025-12-16 07:02:14 +09:00
Some ( ref refmod ) = > {
self . comp_ctx . method_tail_index_source_len ! = refmod . functions . len ( )
}
2025-12-16 04:07:17 +09:00
None = > self . comp_ctx . method_tail_index_source_len ! = 0 ,
2025-09-28 12:19:49 +09:00
} ;
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 ) ) ;
2025-12-16 07:02:14 +09:00
self . comp_ctx
. method_tail_index
2025-09-28 12:19:49 +09:00
. 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 ( ) ;
2025-12-16 07:02:14 +09:00
self . comp_ctx
. method_tail_index
2025-09-28 12:19:49 +09:00
. 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 {
2025-12-15 23:27:24 +09:00
self . type_ctx . value_types . insert ( dst , ty ) ;
2025-09-17 07:43:07 +09:00
}
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-12-16 03:48:44 +09:00
if let Some ( & value_id ) = self . variable_ctx . variable_map . get ( & name ) {
2025-08-12 11:33:48 +00:00
Ok ( value_id )
} else {
2025-12-13 01:30:04 +09:00
Err ( self . undefined_variable_message ( & name ) )
}
}
2025-11-14 13:36:20 +09:00
2025-12-13 01:30:04 +09:00
pub ( in crate ::mir ::builder ) fn undefined_variable_message ( & self , name : & str ) -> String {
// Enhance diagnostics using Using simple registry (Phase 1)
let mut msg = format! ( " Undefined variable: {} " , name ) ;
// Stage-3 keyword diagnostic (local/flow/try/catch/throw)
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). " ) ;
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 " )
& & ! crate ::config ::env ::parser_stage3_enabled ( )
{
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-08-12 11:33:48 +00:00
}
2025-12-13 01:30:04 +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-12-16 07:02:14 +09:00
msg . push_str (
" \n Consider adding 'using <module> [as Alias]' or check nyash.toml [using]. " ,
) ;
2025-12-13 01:30:04 +09:00
}
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-12-13 01:30:04 +09:00
// SSOT (LANGUAGE_REFERENCE_2025 / syntax-cheatsheet):
// - Assignment to an undeclared name is an error.
// - Use `local name = ...` (or `local name; name = ...`) to declare.
vars ::assignment_resolver ::AssignmentResolverBox ::ensure_declared ( self , & var_name ) ? ;
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
2025-12-16 07:02:14 +09:00
self . variable_ctx
. variable_map
. insert ( var_name . clone ( ) , value_id ) ;
2025-11-20 16:10:56 +09:00
}
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-12-16 07:02:14 +09:00
. scope_ctx
. current_function
2025-09-28 01:33:58 +09:00
. 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-12-16 03:33:56 +09:00
if let Some ( ref mut function ) = self . scope_ctx . 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
2025-12-16 07:02:14 +09:00
. variable_ctx
. variable_map
2025-11-17 03:19:03 +09:00
. 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-12-15 22:03:34 +09:00
// Phase 136 Step 6/7: Use metadata_ctx for span
2025-12-16 07:02:14 +09:00
block . add_instruction_with_span (
instruction . clone ( ) ,
self . metadata_ctx . 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
2025-12-10 00:01:53 +09:00
#[ allow(dead_code) ]
2025-11-17 05:24:07 +09:00
pub ( super ) fn update_phi_instruction (
& mut self ,
block : BasicBlockId ,
phi_id : ValueId ,
new_inputs : Vec < ( BasicBlockId , ValueId ) > ,
) -> Result < ( ) , String > {
2025-12-16 03:33:56 +09:00
if let Some ( ref mut function ) = self . scope_ctx . current_function {
2025-11-17 05:24:07 +09:00
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-12-16 07:02:14 +09:00
self . type_ctx
. value_types
2025-09-17 07:43:07 +09:00
. 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-12-16 07:02:14 +09:00
self . type_ctx
. value_types
. insert ( dst , super ::MirType ::Integer ) ;
2025-08-30 22:52:16 +09:00
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
2025-12-16 07:02:14 +09:00
self . type_ctx
. value_types
2025-09-24 09:30:42 +09:00
. 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-12-15 23:27:24 +09:00
self . type_ctx . 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.
2025-12-16 04:07:17 +09:00
let is_user_box = self . comp_ctx . 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 {
2025-12-16 07:02:14 +09:00
if let ( Some ( block_id ) , Some ( ref function ) ) =
( self . current_block , & self . scope_ctx . current_function )
{
2025-08-13 07:13:53 +00:00
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)
2025-12-15 19:37:30 +09:00
/// Phase 136 P0: Use SSOT allocator (next_value_id) to respect function context
2025-11-20 09:34:55 +09:00
pub fn new_typed_value ( & mut self , kind : super ::MirValueKind ) -> super ::TypedValueId {
2025-12-15 19:37:30 +09:00
let id = self . next_value_id ( ) ;
2025-12-15 23:27:24 +09:00
self . type_ctx . value_kinds . insert ( id , kind ) ;
2025-11-20 09:34:55 +09:00
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 > {
2025-12-15 23:27:24 +09:00
self . type_ctx . value_kinds . get ( & id ) . copied ( )
2025-11-20 09:34:55 +09:00
}
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 ) {
2025-12-15 23:27:24 +09:00
self . type_ctx . value_kinds . insert ( id , kind ) ;
2025-11-20 09:34:55 +09:00
}
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 ( )
}
}
2025-12-13 05:34:56 +09:00
2025-12-13 07:05:30 +09:00
// Phase 79: BindingMapProvider implementation
// Centralizes feature-gated binding_map access for promoters
use crate ::mir ::loop_pattern_detection ::BindingMapProvider ;
impl BindingMapProvider for MirBuilder {
#[ cfg(feature = " normalized_dev " ) ]
2025-12-16 07:02:14 +09:00
fn get_binding_map (
& self ,
) -> Option < & std ::collections ::BTreeMap < String , crate ::mir ::BindingId > > {
2025-12-15 20:40:23 +09:00
// Phase 136 Step 4/7: Use binding_ctx (SSOT)
Some ( self . binding_ctx . binding_map ( ) )
2025-12-13 07:05:30 +09:00
}
#[ cfg(not(feature = " normalized_dev " )) ]
2025-12-16 07:02:14 +09:00
fn get_binding_map (
& self ,
) -> Option < & std ::collections ::BTreeMap < String , crate ::mir ::BindingId > > {
2025-12-13 07:05:30 +09:00
None
}
}
2025-12-13 05:34:56 +09:00
#[ cfg(test) ]
mod binding_id_tests {
use super ::* ;
#[ test ]
fn test_binding_map_initialization ( ) {
let builder = MirBuilder ::new ( ) ;
2025-12-15 23:05:36 +09:00
assert_eq! ( builder . core_ctx . next_binding_id , 0 ) ;
2025-12-16 03:48:44 +09:00
// Phase 2-6: binding_ctx is now SSOT (legacy field removed)
2025-12-15 20:40:23 +09:00
assert! ( builder . binding_ctx . is_empty ( ) ) ;
2025-12-13 05:34:56 +09:00
}
#[ test ]
fn test_binding_allocation_sequential ( ) {
let mut builder = MirBuilder ::new ( ) ;
let bid0 = builder . allocate_binding_id ( ) ;
let bid1 = builder . allocate_binding_id ( ) ;
let bid2 = builder . allocate_binding_id ( ) ;
assert_eq! ( bid0 . raw ( ) , 0 ) ;
assert_eq! ( bid1 . raw ( ) , 1 ) ;
assert_eq! ( bid2 . raw ( ) , 2 ) ;
2025-12-15 23:05:36 +09:00
assert_eq! ( builder . core_ctx . next_binding_id , 3 ) ;
2025-12-13 05:34:56 +09:00
}
#[ test ]
fn test_shadowing_binding_restore ( ) {
let mut builder = MirBuilder ::new ( ) ;
// Simulate function entry scope
builder . push_lexical_scope ( ) ;
// Declare outer x
2025-12-15 19:37:30 +09:00
// Phase 136 P0: Use SSOT allocator for function scope simulation
let outer_vid = builder . next_value_id ( ) ;
2025-12-13 05:34:56 +09:00
builder
. declare_local_in_current_scope ( " x " , outer_vid )
. unwrap ( ) ;
2025-12-16 03:48:44 +09:00
// Phase 2-6: Check binding_ctx (SSOT)
2025-12-15 20:40:23 +09:00
let outer_bid = builder . binding_ctx . lookup ( " x " ) . unwrap ( ) ;
2025-12-13 05:34:56 +09:00
assert_eq! ( outer_bid . raw ( ) , 0 ) ;
// Enter inner scope and shadow x
builder . push_lexical_scope ( ) ;
2025-12-15 19:37:30 +09:00
// Phase 136 P0: Use SSOT allocator for function scope simulation
let inner_vid = builder . next_value_id ( ) ;
2025-12-13 05:34:56 +09:00
builder
. declare_local_in_current_scope ( " x " , inner_vid )
. unwrap ( ) ;
2025-12-16 03:48:44 +09:00
// Phase 2-6: Check binding_ctx (SSOT)
2025-12-15 20:40:23 +09:00
let inner_bid = builder . binding_ctx . lookup ( " x " ) . unwrap ( ) ;
2025-12-13 05:34:56 +09:00
assert_eq! ( inner_bid . raw ( ) , 1 ) ;
// Exit inner scope - should restore outer binding
builder . pop_lexical_scope ( ) ;
2025-12-16 03:48:44 +09:00
// Phase 2-6: Check binding_ctx (SSOT)
2025-12-15 20:40:23 +09:00
let restored_bid = builder . binding_ctx . lookup ( " x " ) . unwrap ( ) ;
2025-12-13 05:34:56 +09:00
assert_eq! ( restored_bid , outer_bid ) ;
assert_eq! ( restored_bid . raw ( ) , 0 ) ;
// Cleanup
builder . pop_lexical_scope ( ) ;
}
#[ test ]
fn test_valueid_binding_parallel_allocation ( ) {
let mut builder = MirBuilder ::new ( ) ;
2025-12-15 19:37:30 +09:00
// Phase 136 P0: Use SSOT allocator (next_value_id)
// Note: Without current_function, next_value_id() falls back to value_gen.next()
// so this test still validates ValueId/BindingId independence
2025-12-13 05:34:56 +09:00
// Allocate ValueIds and BindingIds in parallel
2025-12-15 19:37:30 +09:00
let vid0 = builder . next_value_id ( ) ;
2025-12-13 05:34:56 +09:00
let bid0 = builder . allocate_binding_id ( ) ;
2025-12-15 19:37:30 +09:00
let vid1 = builder . next_value_id ( ) ;
2025-12-13 05:34:56 +09:00
let bid1 = builder . allocate_binding_id ( ) ;
// ValueId and BindingId should be independent
assert_eq! ( vid0 . 0 , 0 ) ;
assert_eq! ( bid0 . raw ( ) , 0 ) ;
assert_eq! ( vid1 . 0 , 1 ) ;
assert_eq! ( bid1 . raw ( ) , 1 ) ;
// Allocating more ValueIds should not affect BindingId counter
2025-12-15 19:37:30 +09:00
let _ = builder . next_value_id ( ) ;
let _ = builder . next_value_id ( ) ;
2025-12-13 05:34:56 +09:00
let bid2 = builder . allocate_binding_id ( ) ;
assert_eq! ( bid2 . raw ( ) , 2 ) ; // Still sequential
// Allocating more BindingIds should not affect ValueId counter
let _ = builder . allocate_binding_id ( ) ;
let _ = builder . allocate_binding_id ( ) ;
2025-12-15 19:37:30 +09:00
let vid2 = builder . next_value_id ( ) ;
2025-12-13 05:34:56 +09:00
assert_eq! ( vid2 . 0 , 4 ) ; // Continues from where we left off
}
}