/*! * 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, // 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, captures: Vec<(String, ValueId)>, me_capture: Option, // 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 { 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, /// Call target specification (includes receiver for methods) pub callee: Callee, /// Arguments to the call (receiver NOT included here if method call) pub args: Vec, /// 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, callee: Callee, args: Vec) -> Self { MirCall { dst, callee, args, flags: CallFlags::new(), effects: EffectMask::PURE, } } /// Create a global function call pub fn global(dst: Option, name: String, args: Vec) -> Self { MirCall::new(dst, Callee::Global(name), args) } /// Create a method call pub fn method( dst: Option, box_name: String, method: String, receiver: ValueId, args: Vec, ) -> 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, name: String, args: Vec) -> 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) -> 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, captures: Vec<(String, ValueId)>, me_capture: Option, ) -> 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, func: ValueId, callee: Option, args: Vec, 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, box_val: ValueId, method: String, args: Vec, 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) -> MirCall { MirCall::constructor(dst, box_type, args) } /// Convert ExternCall to MirCall pub fn from_extern_call( dst: Option, iface_name: String, method_name: String, args: Vec, effects: EffectMask, ) -> MirCall { let full_name = format!("{}.{}", iface_name, method_name); MirCall::external(dst, full_name, args).with_effects(effects) } }