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-09-16 03:54:44 +09:00
|
|
|
|
use crate::ast::{ASTNode, LiteralValue};
|
2025-09-26 14:34:42 +09:00
|
|
|
|
use crate::mir::builder::builder_calls::CallTarget;
|
2025-08-12 11:33:48 +00:00
|
|
|
|
use std::collections::HashMap;
|
2025-08-21 01:18:25 +09:00
|
|
|
|
use std::collections::HashSet;
|
2025-09-25 09:01:55 +09:00
|
|
|
|
mod calls; // Call system modules (refactored from builder_calls)
|
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-09-25 02:58:43 +09:00
|
|
|
|
mod method_call_handlers; // Method call handler separation (Phase 3)
|
🎉 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
|
|
|
|
|
|
mod exprs_call; // call(expr)
|
2025-09-25 00:41:56 +09:00
|
|
|
|
// include lowering removed (using is handled in runner)
|
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
|
|
|
|
|
|
pub(crate) mod loops;
|
|
|
|
|
|
mod ops;
|
|
|
|
|
|
mod phi;
|
2025-09-19 02:07:38 +09:00
|
|
|
|
mod if_form;
|
2025-09-19 08:34:29 +09:00
|
|
|
|
mod control_flow; // thin wrappers to centralize control-flow entrypoints
|
2025-09-17 10:58:12 +09:00
|
|
|
|
mod lifecycle; // prepare/lower_root/finalize split
|
|
|
|
|
|
// legacy large-match remains inline for now (planned extraction)
|
2025-09-11 04:20:28 +09:00
|
|
|
|
mod plugin_sigs; // plugin signature loader
|
2025-09-17 07:43:07 +09:00
|
|
|
|
mod stmts;
|
|
|
|
|
|
mod utils;
|
|
|
|
|
|
mod vars; // variables/scope helpers // small loop helpers (header/exit context)
|
2025-09-28 12:19:49 +09:00
|
|
|
|
mod origin; // P0: origin inference(me/Known)と PHI 伝播(軽量)
|
|
|
|
|
|
mod observe; // P0: dev-only observability helpers(ssa/resolve)
|
|
|
|
|
|
mod rewrite; // P1: Known rewrite & special consolidation
|
2025-09-28 20:38:09 +09:00
|
|
|
|
mod ssa; // LocalSSA helpers (in-block materialization)
|
|
|
|
|
|
mod schedule; // BlockScheduleBox(物理順序: PHI→materialize→body)
|
2025-11-17 07:58:44 +09:00
|
|
|
|
mod receiver; // ReceiverMaterializationBox(Method recv の pin+LocalSSA 集約)
|
2025-09-28 20:38:09 +09:00
|
|
|
|
mod metadata; // MetadataPropagationBox(type/originの伝播)
|
|
|
|
|
|
mod emission; // emission::*(Const/Compare/Branch の薄い発行箱)
|
|
|
|
|
|
mod types; // types::annotation / inference(型注釈/推論の箱: 推論は後段)
|
|
|
|
|
|
mod router; // RouterPolicyBox(Unified vs BoxCall)
|
|
|
|
|
|
mod emit_guard; // EmitGuardBox(emit直前の最終関所)
|
|
|
|
|
|
mod name_const; // NameConstBox(関数名Const生成)
|
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-09-01 23:44:34 +09:00
|
|
|
|
|
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-08-12 11:33:48 +00:00
|
|
|
|
/// Variable name to ValueId mapping (for SSA conversion)
|
2025-08-18 23:36:40 +09:00
|
|
|
|
pub(super) variable_map: HashMap<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
|
|
|
|
|
|
pub(super) value_origin_newbox: HashMap<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
|
|
|
|
|
|
pub(super) value_types: HashMap<ValueId, super::MirType>,
|
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-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>,
|
|
|
|
|
|
/// Monotonic counters for region IDs (deterministic across a run).
|
|
|
|
|
|
debug_loop_counter: u32,
|
|
|
|
|
|
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-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(),
|
|
|
|
|
|
variable_map: HashMap::new(),
|
|
|
|
|
|
pending_phis: Vec::new(),
|
2025-08-20 20:56:08 +09:00
|
|
|
|
value_origin_newbox: HashMap::new(),
|
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-08-28 22:31:51 +09:00
|
|
|
|
value_types: HashMap::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-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_loop_counter: 0,
|
|
|
|
|
|
debug_join_counter: 0,
|
2025-09-28 20:38:09 +09:00
|
|
|
|
|
|
|
|
|
|
local_ssa_map: HashMap::new(),
|
|
|
|
|
|
schedule_mat_map: HashMap::new(),
|
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)
|
|
|
|
|
|
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-26 05:28:20 +09:00
|
|
|
|
/// Suppress entry pin copy for the next start_new_block (used for merge blocks).
|
|
|
|
|
|
pub(super) fn suppress_next_entry_pin_copy(&mut self) { self.suppress_pin_entry_copy_next = true; }
|
|
|
|
|
|
|
2025-09-20 03:37:20 +09:00
|
|
|
|
// ---- Hint helpers (no-op by default) ----
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
pub(crate) fn hint_loop_header(&mut self) { self.hint_sink.loop_header(); }
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
pub(crate) fn hint_loop_latch(&mut self) { self.hint_sink.loop_latch(); }
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
pub(crate) fn hint_scope_enter(&mut self, id: u32) { self.hint_sink.scope_enter(id); }
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
pub(crate) fn hint_scope_leave(&mut self, id: u32) { self.hint_sink.scope_leave(id); }
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
pub(crate) fn hint_join_result<S: Into<String>>(&mut self, var: S) { self.hint_sink.join_result(var.into()); }
|
2025-09-20 06:24:33 +09:00
|
|
|
|
#[inline]
|
|
|
|
|
|
pub(crate) fn hint_loop_carrier<S: Into<String>>(&mut self, vars: impl IntoIterator<Item = S>) {
|
|
|
|
|
|
self.hint_sink.loop_carrier(vars.into_iter().map(|s| s.into()).collect::<Vec<_>>());
|
|
|
|
|
|
}
|
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_loop_id(&mut self) -> u32 {
|
|
|
|
|
|
let id = self.debug_loop_counter;
|
|
|
|
|
|
self.debug_loop_counter = self.debug_loop_counter.saturating_add(1);
|
|
|
|
|
|
id
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[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_replace_region<S: Into<String>>(&mut self, region: S) {
|
|
|
|
|
|
if let Some(top) = self.debug_scope_stack.last_mut() {
|
|
|
|
|
|
*top = region.into();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
self.debug_scope_stack.push(region.into());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
|
pub(crate) fn debug_current_region_id(&self) -> Option<String> {
|
|
|
|
|
|
self.debug_scope_stack.last().cloned()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
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-09-17 07:43:07 +09:00
|
|
|
|
|
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-09-17 07:43:07 +09:00
|
|
|
|
|
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
|
|
|
|
|
|
self.build_expression_impl(ast)
|
|
|
|
|
|
}
|
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 {
|
|
|
|
|
|
LiteralValue::Integer(n) => crate::mir::builder::emission::constant::emit_integer(self, n),
|
|
|
|
|
|
LiteralValue::Float(f) => crate::mir::builder::emission::constant::emit_float(self, f),
|
|
|
|
|
|
LiteralValue::String(s) => crate::mir::builder::emission::constant::emit_string(self, s),
|
|
|
|
|
|
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-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)
|
|
|
|
|
|
if name == "local" && !crate::config::env::parser_stage3() {
|
|
|
|
|
|
msg.push_str("\nHint: 'local' is a Stage-3 keyword. Enable NYASH_PARSER_STAGE3=1 (and HAKO_PARSER_STAGE3=1 for Stage-B).");
|
|
|
|
|
|
msg.push_str("\nFor 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() {
|
|
|
|
|
|
msg.push_str(&format!("\nHint: '{}' is a Stage-3 keyword. Enable NYASH_PARSER_STAGE3=1 (and HAKO_PARSER_STAGE3=1 for Stage-B).", name));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
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("\nHint: symbol appears in using module(s): ");
|
|
|
|
|
|
msg.push_str(&suggest.join(", "));
|
|
|
|
|
|
msg.push_str("\nConsider adding 'using <module> [as Alias]' or check nyash.toml [using].");
|
|
|
|
|
|
}
|
|
|
|
|
|
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-09-26 14:34:42 +09:00
|
|
|
|
let raw_value_id = self.build_expression(value)?;
|
|
|
|
|
|
// Correctness-first: assignment results may be used across control-flow joins.
|
|
|
|
|
|
// Pin to a slot so the value has a block-local def and participates in PHI merges.
|
|
|
|
|
|
let value_id = self
|
|
|
|
|
|
.pin_to_slot(raw_value_id, "@assign")
|
|
|
|
|
|
.unwrap_or(raw_value_id);
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
// In SSA form, each assignment creates a new value
|
2025-08-18 22:04:50 +09:00
|
|
|
|
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
|
|
|
|
|
|
let dbg_fn_name = self
|
|
|
|
|
|
.current_function
|
|
|
|
|
|
.as_ref()
|
|
|
|
|
|
.map(|f| f.signature.name.clone());
|
|
|
|
|
|
let dbg_region_id = self.debug_current_region_id();
|
2025-09-28 12:19:49 +09:00
|
|
|
|
// P0: PHI の軽量補強と観測は、関数ブロック取得前に実施して借用競合を避ける
|
|
|
|
|
|
if let MirInstruction::Phi { dst, inputs } = &instruction {
|
|
|
|
|
|
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.
|
|
|
|
|
|
if let MirInstruction::Call { callee: Some(callee), dst, args, effects, .. } = &instruction {
|
|
|
|
|
|
use crate::mir::definitions::call_unified::Callee;
|
|
|
|
|
|
if let Callee::Method { box_name, method, receiver: Some(r), certainty } = callee.clone() {
|
|
|
|
|
|
// 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),
|
|
|
|
|
|
certainty
|
|
|
|
|
|
};
|
|
|
|
|
|
instruction = MirInstruction::Call {
|
|
|
|
|
|
dst: *dst,
|
|
|
|
|
|
func: crate::mir::ValueId::new(0), // Legacy compatibility
|
|
|
|
|
|
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 {
|
|
|
|
|
|
MirInstruction::Branch { then_bb, else_bb, .. } => (Some(*then_bb), Some(*else_bb), None),
|
|
|
|
|
|
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;
|
|
|
|
|
|
if let Some(Callee::Method { box_name, method, receiver: Some(r), .. }) = callee {
|
|
|
|
|
|
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-17 03:19:03 +09:00
|
|
|
|
} else if std::env::var("NYASH_BUILDER_TRACE_RECV").ok().as_deref() == Some("1") {
|
|
|
|
|
|
use crate::mir::definitions::call_unified::Callee;
|
|
|
|
|
|
if let Some(Callee::Method { box_name, method, receiver: Some(r), .. }) = callee {
|
|
|
|
|
|
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-08-12 11:33:48 +00:00
|
|
|
|
block.add_instruction(instruction);
|
2025-11-01 13:41:43 +09:00
|
|
|
|
// Drop the mutable borrow of `block` before updating other blocks
|
|
|
|
|
|
}
|
|
|
|
|
|
// 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 {
|
|
|
|
|
|
if let Some(succ) = function.get_block_mut(t) { succ.add_predecessor(block_id); }
|
|
|
|
|
|
}
|
|
|
|
|
|
if let Some(t) = else_t {
|
|
|
|
|
|
if let Some(succ) = function.get_block_mut(t) { succ.add_predecessor(block_id); }
|
|
|
|
|
|
}
|
|
|
|
|
|
if let Some(t) = jump_t {
|
|
|
|
|
|
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 {
|
|
|
|
|
|
if let MirInstruction::Phi { dst, inputs } = inst {
|
|
|
|
|
|
if *dst == phi_id {
|
|
|
|
|
|
*inputs = new_inputs;
|
|
|
|
|
|
return Ok(());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
Err(format!("PHI instruction {} not found in block {}", phi_id, block))
|
|
|
|
|
|
} 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
|
|
|
|
|
|
let dst = self.value_gen.next();
|
|
|
|
|
|
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-08-30 22:52:16 +09:00
|
|
|
|
let dst = self.value_gen.next();
|
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-08-13 10:20:37 +00:00
|
|
|
|
let dst = self.value_gen.next();
|
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();
|
|
|
|
|
|
let lowered = crate::mir::builder::calls::function_lowering::generate_method_function_name(
|
|
|
|
|
|
&class,
|
|
|
|
|
|
"birth",
|
|
|
|
|
|
arity,
|
|
|
|
|
|
);
|
|
|
|
|
|
let use_lowered = if let Some(ref module) = self.current_module {
|
|
|
|
|
|
module.functions.contains_key(&lowered)
|
|
|
|
|
|
} else { false };
|
|
|
|
|
|
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.
|
|
|
|
|
|
let allow_builtin_birth = std::env::var("NYASH_DEV_BIRTH_INJECT_BUILTINS").ok().as_deref() == Some("1");
|
|
|
|
|
|
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-08-29 21:39:47 +09:00
|
|
|
|
|
|
|
|
|
|
|
2025-09-17 07:43:07 +09:00
|
|
|
|
|
2025-08-12 11:33:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl Default for MirBuilder {
|
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
|
Self::new()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|