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>
347 lines
10 KiB
Rust
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)
|
|
}
|
|
}
|