Files
hakorune/src/mir/definitions/call_unified.rs
nyash-codex f9d100ce01 chore: Phase 25.1 完了 - LoopForm v2/Stage1 CLI/環境変数削減 + Phase 26-D からの変更
Phase 25.1 完了成果:
-  LoopForm v2 テスト・ドキュメント・コメント完備
  - 4ケース(A/B/C/D)完全テストカバレッジ
  - 最小再現ケース作成(SSAバグ調査用)
  - SSOT文書作成(loopform_ssot.md)
  - 全ソースに [LoopForm] コメントタグ追加

-  Stage-1 CLI デバッグ環境構築
  - stage1_cli.hako 実装
  - stage1_bridge.rs ブリッジ実装
  - デバッグツール作成(stage1_debug.sh/stage1_minimal.sh)
  - アーキテクチャ改善提案文書

-  環境変数削減計画策定
  - 25変数の完全調査・分類
  - 6段階削減ロードマップ(25→5、80%削減)
  - 即時削除可能変数特定(NYASH_CONFIG/NYASH_DEBUG)

Phase 26-D からの累積変更:
- PHI実装改善(ExitPhiBuilder/HeaderPhiBuilder等)
- MIRビルダーリファクタリング
- 型伝播・最適化パス改善
- その他約300ファイルの累積変更

🎯 技術的成果:
- SSAバグ根本原因特定(条件分岐内loop変数変更)
- Region+next_iパターン適用完了(UsingCollectorBox等)
- LoopFormパターン文書化・テスト化完了
- セルフホスティング基盤強化

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: ChatGPT <noreply@openai.com>
Co-Authored-By: Task Assistant <task@anthropic.com>
2025-11-21 06:25:17 +09:00

347 lines
10 KiB
Rust

/*!
* Unified MIR Call Definitions - ChatGPT5 Pro A++ Design
*
* This module contains all call-related definitions for the unified MIR Call instruction
* that replaces Call/BoxCall/PluginInvoke/ExternCall/NewBox/NewClosure
*/
use crate::mir::{Effect, EffectMask, ValueId};
/// Certainty of callee type information for method calls
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TypeCertainty {
/// Receiver class is known (from origin propagation or static context)
Known,
/// Receiver may be a union/merged flow; class not uniquely known
Union,
}
/// Classification of Box types to prevent static/runtime mixing
/// Prevents Stage-B/Stage-1 compiler boxes from being confused with runtime data boxes
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CalleeBoxKind {
/// Static compiler boxes (StageBArgsBox, Stage1UsingResolverBox, BundleResolver, ParserBox, etc.)
/// These are only for compile-time static method lowering
StaticCompiler,
/// Runtime data boxes (MapBox, ArrayBox, StringBox, IntegerBox, etc.)
/// These handle actual runtime values and method dispatch
RuntimeData,
/// User-defined boxes (neither compiler nor built-in runtime)
UserDefined,
}
/// Call target specification for type-safe function resolution
/// Replaces runtime string-based resolution with compile-time typed targets
#[derive(Debug, Clone, PartialEq)]
pub enum Callee {
/// Global function call (e.g., nyash.builtin.print)
/// Resolves to built-in or global functions at compile time
Global(String),
/// Box method call with explicit receiver
/// Enables static resolution of box.method() patterns
Method {
box_name: String, // "StringBox", "ConsoleStd", etc.
method: String, // "upper", "print", etc.
receiver: Option<ValueId>, // Some(obj) for instance, None for static/constructor
certainty: TypeCertainty, // Phase 3: known vs union
box_kind: CalleeBoxKind, // Structural guard: prevent static/runtime mixing
},
/// Constructor call (NewBox equivalent)
/// Creates new Box instances with birth() method
Constructor {
box_type: String, // "StringBox", "ArrayBox", etc.
// Constructor doesn't have a receiver
},
/// Closure creation (NewClosure equivalent)
/// Creates function values with captured variables
Closure {
params: Vec<String>,
captures: Vec<(String, ValueId)>,
me_capture: Option<ValueId>, // Optional 'me' weak capture
},
/// Dynamic function value call
/// Preserves first-class function semantics for variables containing functions
Value(ValueId),
/// External C ABI function call
/// Direct mapping to host/runtime functions
Extern(String),
}
impl Callee {
/// Check if this is a constructor call
pub fn is_constructor(&self) -> bool {
matches!(self, Callee::Constructor { .. } | Callee::Closure { .. })
}
/// Check if this is a method call with receiver
pub fn has_receiver(&self) -> bool {
match self {
Callee::Method { receiver, .. } => receiver.is_some(),
_ => false,
}
}
/// Get the receiver if this is a method call
pub fn receiver(&self) -> Option<ValueId> {
match self {
Callee::Method { receiver, .. } => *receiver,
_ => None,
}
}
}
/// Call flags for unified MIR Call instruction
/// Controls call behavior and optimization hints
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CallFlags {
/// Tail call optimization hint
pub tail_call: bool,
/// Function never returns (e.g., panic, exit)
pub no_return: bool,
/// Call can be inlined
pub can_inline: bool,
/// Call is a constructor (NewBox/NewClosure)
pub is_constructor: bool,
}
impl CallFlags {
/// Create default call flags (all false)
pub const fn new() -> Self {
CallFlags {
tail_call: false,
no_return: false,
can_inline: false,
is_constructor: false,
}
}
/// Create flags for constructor calls
pub const fn constructor() -> Self {
CallFlags {
tail_call: false,
no_return: false,
can_inline: false,
is_constructor: true,
}
}
/// Create flags for no-return calls (panic, exit)
pub const fn no_return() -> Self {
CallFlags {
tail_call: false,
no_return: true,
can_inline: false,
is_constructor: false,
}
}
/// Builder method to set tail call flag
pub fn with_tail_call(mut self) -> Self {
self.tail_call = true;
self
}
/// Builder method to set inline flag
pub fn with_inline(mut self) -> Self {
self.can_inline = true;
self
}
}
impl Default for CallFlags {
fn default() -> Self {
CallFlags::new()
}
}
/// Unified MIR Call instruction - replaces Call/BoxCall/PluginInvoke/ExternCall/NewBox/NewClosure
/// ChatGPT5 Pro A++ design for complete call unification
#[derive(Debug, Clone, PartialEq)]
pub struct MirCall {
/// Destination value for result (None for void calls)
pub dst: Option<ValueId>,
/// Call target specification (includes receiver for methods)
pub callee: Callee,
/// Arguments to the call (receiver NOT included here if method call)
pub args: Vec<ValueId>,
/// Call behavior flags
pub flags: CallFlags,
/// Effect mask for optimization and analysis
pub effects: EffectMask,
}
impl MirCall {
/// Create a new MirCall with default flags and pure effects
pub fn new(dst: Option<ValueId>, callee: Callee, args: Vec<ValueId>) -> Self {
MirCall {
dst,
callee,
args,
flags: CallFlags::new(),
effects: EffectMask::PURE,
}
}
/// Create a global function call
pub fn global(dst: Option<ValueId>, name: String, args: Vec<ValueId>) -> Self {
MirCall::new(dst, Callee::Global(name), args)
}
/// Create a method call
pub fn method(
dst: Option<ValueId>,
box_name: String,
method: String,
receiver: ValueId,
args: Vec<ValueId>,
) -> Self {
MirCall::new(
dst,
Callee::Method {
box_name,
method,
receiver: Some(receiver),
certainty: TypeCertainty::Known,
box_kind: CalleeBoxKind::RuntimeData, // Default to runtime for helper
},
args,
)
}
/// Create an external call
pub fn external(dst: Option<ValueId>, name: String, args: Vec<ValueId>) -> Self {
let mut call = MirCall::new(dst, Callee::Extern(name), args);
call.effects = EffectMask::IO; // External calls have I/O effects
call
}
/// Create a constructor call (NewBox equivalent)
pub fn constructor(dst: ValueId, box_type: String, args: Vec<ValueId>) -> Self {
let mut call = MirCall::new(Some(dst), Callee::Constructor { box_type }, args);
call.flags = CallFlags::constructor();
call.effects = EffectMask::PURE.add(Effect::Alloc);
call
}
/// Create a closure call (NewClosure equivalent)
pub fn closure(
dst: ValueId,
params: Vec<String>,
captures: Vec<(String, ValueId)>,
me_capture: Option<ValueId>,
) -> Self {
let mut call = MirCall::new(
Some(dst),
Callee::Closure {
params,
captures,
me_capture,
},
vec![], // Closures don't have regular args at creation
);
call.flags = CallFlags::constructor();
call.effects = EffectMask::PURE.add(Effect::Alloc);
call
}
/// Set tail call flag
pub fn with_tail_call(mut self) -> Self {
self.flags.tail_call = true;
self
}
/// Set effects
pub fn with_effects(mut self, effects: EffectMask) -> Self {
self.effects = effects;
self
}
/// Check if this call produces a value
pub fn has_result(&self) -> bool {
self.dst.is_some()
}
/// Get the effective effects for this call
pub fn effective_effects(&self) -> EffectMask {
// Constructors always allocate
if self.flags.is_constructor {
self.effects.add(Effect::Alloc)
} else {
self.effects
}
}
}
/// Helper functions for MirCall migration
pub mod migration {
use super::*;
/// Convert legacy Call instruction to MirCall
pub fn from_legacy_call(
dst: Option<ValueId>,
func: ValueId,
callee: Option<Callee>,
args: Vec<ValueId>,
effects: EffectMask,
) -> MirCall {
// If new callee is provided, use it
if let Some(callee) = callee {
let mut call = MirCall::new(dst, callee, args);
call.effects = effects;
call
} else {
// Fall back to Value call for legacy
let mut call = MirCall::new(dst, Callee::Value(func), args);
call.effects = effects;
call
}
}
/// Convert BoxCall to MirCall
pub fn from_box_call(
dst: Option<ValueId>,
box_val: ValueId,
method: String,
args: Vec<ValueId>,
effects: EffectMask,
) -> MirCall {
// For BoxCall, we need to infer the box type
// Mark certainty as Union (unknown at this stage)
let mut call = MirCall::new(
dst,
Callee::Method {
box_name: "UnknownBox".to_string(),
method,
receiver: Some(box_val),
certainty: TypeCertainty::Union,
box_kind: CalleeBoxKind::RuntimeData, // BoxCall is always runtime
},
args,
);
call.effects = effects;
call
}
/// Convert NewBox to MirCall
pub fn from_new_box(dst: ValueId, box_type: String, args: Vec<ValueId>) -> MirCall {
MirCall::constructor(dst, box_type, args)
}
/// Convert ExternCall to MirCall
pub fn from_extern_call(
dst: Option<ValueId>,
iface_name: String,
method_name: String,
args: Vec<ValueId>,
effects: EffectMask,
) -> MirCall {
let full_name = format!("{}.{}", iface_name, method_name);
MirCall::external(dst, full_name, args).with_effects(effects)
}
}