diff --git a/src/mir/instruction_introspection.rs b/src/mir/instruction_introspection.rs index 9cbaf2df..52b6a345 100644 --- a/src/mir/instruction_introspection.rs +++ b/src/mir/instruction_introspection.rs @@ -1,116 +1,40 @@ -//! Introspection helpers for MIR instruction set -//! -//! Migration note: -//! - Historically we synced to a canonical 26-instruction doc list. -//! - We are migrating to Core-15 for enforcement and tests. During migration, -//! docs may still list 26; tests should use `core15_instruction_names()`. +//! Introspection helpers for the MIR14 instruction set -/// Returns the legacy canonical list of core MIR instruction names (26 items). -/// This list matched docs/reference/mir/INSTRUCTION_SET.md under "Core Instructions". -pub fn core_instruction_names() -> &'static [&'static str] { +/// Return the canonical list of MIR14 instruction names. +pub fn mir14_instruction_names() -> &'static [&'static str] { &[ - "Const", - "Copy", - "Load", - "Store", - "UnaryOp", - "BinOp", - "Compare", - "Jump", - "Branch", - "Phi", - "Return", - "Call", - "ExternCall", - "BoxCall", - "NewBox", - "ArrayGet", - "ArraySet", - "RefNew", - "RefGet", - "RefSet", - "Await", - "Print", - "TypeOp", - "WeakRef", - "Barrier", - ] -} - -/// Returns the Core-15 instruction names used for the minimal kernel enforcement. -/// This list is implementation-driven for migration stage; docs may differ temporarily. -pub fn core15_instruction_names() -> &'static [&'static str] { - &[ - // 値/計算 + // values / arithmetic "Const", "UnaryOp", "BinOp", "Compare", "TypeOp", - // メモリ + // memory "Load", "Store", - // 制御 + // control flow "Jump", "Branch", "Return", "Phi", - // 呼び出し/Box - "Call", + // boxes / external "NewBox", "BoxCall", "ExternCall", ] } -/// Returns the Core-13 instruction names (final minimal kernel). -/// This is the fixed target set used for MIR unification. -pub fn core13_instruction_names() -> &'static [&'static str] { - &[ - // 値/計算 - "Const", - "BinOp", - "Compare", - // 制御 - "Jump", - "Branch", - "Return", - "Phi", - // 呼び出し - "Call", - "BoxCall", - "ExternCall", - // メタ - "TypeOp", - "Safepoint", - "Barrier", - ] -} - #[cfg(test)] mod tests { use super::*; - use std::fs; - use std::path::Path; use std::collections::BTreeSet; - // Core-15 enforcement: only count check; names are implementation-defined during migration. #[test] - fn core15_instruction_count_is_15() { - let impl_names = core15_instruction_names(); - assert_eq!(impl_names.len(), 15, "Core-15 must contain exactly 15 instructions"); - // basic sanity: includes a few key ops - let set: BTreeSet<_> = impl_names.iter().copied().collect(); - for must in ["Const", "BinOp", "Return", "ExternCall"] { assert!(set.contains(must), "missing '{}'", must); } - } - - #[test] - fn core13_instruction_count_is_13() { - let impl_names = core13_instruction_names(); - assert_eq!(impl_names.len(), 13, "Core-13 must contain exactly 13 instructions"); - let set: BTreeSet<_> = impl_names.iter().copied().collect(); - for must in ["Const", "BinOp", "Return", "BoxCall", "ExternCall", "TypeOp"] { - assert!(set.contains(must), "missing '{}'", must); - } + fn mir14_instruction_count_is_14() { + let names = mir14_instruction_names(); + assert_eq!(names.len(), 14, "MIR14 must contain exactly 14 instructions"); + let set: BTreeSet<_> = names.iter().copied().collect(); + for must in ["Const", "UnaryOp", "BoxCall"] { assert!(set.contains(must), "missing '{}'", must); } } } + diff --git a/src/mir/instruction_v2.rs b/src/mir/instruction_v2.rs deleted file mode 100644 index d384c607..00000000 --- a/src/mir/instruction_v2.rs +++ /dev/null @@ -1,543 +0,0 @@ -/*! - * MIR 25-Instruction Specification Implementation - * - * Complete hierarchical MIR instruction set based on ChatGPT5 + AI Council design - */ - -use super::{ValueId, EffectMask, Effect, BasicBlockId}; -use std::fmt; - -/// MIR instruction types - exactly 25 instructions per specification -#[derive(Debug, Clone, PartialEq)] -pub enum MirInstructionV2 { - // === TIER-0: UNIVERSAL CORE (8 instructions) === - - /// Load a constant value (pure) - /// `%dst = const value` - Const { - dst: ValueId, - value: ConstValue, - }, - - /// Binary arithmetic operation (pure) - /// `%dst = %lhs op %rhs` - BinOp { - dst: ValueId, - op: BinaryOp, - lhs: ValueId, - rhs: ValueId, - }, - - /// Compare two values (pure) - /// `%dst = %lhs cmp %rhs` - Compare { - dst: ValueId, - op: CompareOp, - lhs: ValueId, - rhs: ValueId, - }, - - /// Conditional branch (control) - /// `br %condition -> %then_bb, %else_bb` - Branch { - condition: ValueId, - then_bb: BasicBlockId, - else_bb: BasicBlockId, - }, - - /// Unconditional jump (control) - /// `jmp %target_bb` - Jump { - target: BasicBlockId, - }, - - /// SSA phi function for merging values (pure) - /// `%dst = phi [%val1 from %bb1, %val2 from %bb2, ...]` - Phi { - dst: ValueId, - inputs: Vec<(BasicBlockId, ValueId)>, - }, - - /// External function call (context-dependent) - /// `%dst = call %func(%args...)` - Call { - dst: Option, - func: ValueId, - args: Vec, - effects: EffectMask, - }, - - /// Return from function (control) - /// `ret %value` or `ret void` - Return { - value: Option, - }, - - // === TIER-1: NYASH SEMANTICS (12 instructions) === - - /// Create a new Box instance (strong ownership node in ownership forest) - /// `%dst = new_box "BoxType"(%args...)` - NewBox { - dst: ValueId, - box_type: String, - args: Vec, - }, - - /// Load Box field value (pure) - /// `%dst = %box.field` - BoxFieldLoad { - dst: ValueId, - box_val: ValueId, - field: String, - }, - - /// Store value to Box field (mut) - /// `%box.field = %value` - BoxFieldStore { - box_val: ValueId, - field: String, - value: ValueId, - }, - - /// Box method invocation (context-dependent) - /// `%dst = %box.method(%args...)` - BoxCall { - dst: Option, - box_val: ValueId, - method: String, - args: Vec, - effects: EffectMask, - }, - - /// Safepoint for finalization/interrupts (io) - /// `safepoint` - Safepoint, - - /// Get reference as value (pure) - /// `%dst = ref_get %reference` - RefGet { - dst: ValueId, - reference: ValueId, - }, - - /// Set/replace reference target with ownership validation (mut) - /// `ref_set %reference = %new_target` - RefSet { - reference: ValueId, - new_target: ValueId, - }, - - /// Create weak reference handle (non-owning link) (pure) - /// `%dst = weak_new %box` - WeakNew { - dst: ValueId, - box_val: ValueId, - }, - - /// Load from weak reference with liveness check (returns null if dead) (pure) - /// `%dst = weak_load %weak_ref` - WeakLoad { - dst: ValueId, - weak_ref: ValueId, - }, - - /// Check weak reference validity (returns bool) (pure) - /// `%dst = weak_check %weak_ref` - WeakCheck { - dst: ValueId, - weak_ref: ValueId, - }, - - /// Send message via Bus system (io) - /// `send %bus, %message` - Send { - bus: ValueId, - message: ValueId, - }, - - /// Receive message from Bus system (io) - /// `%dst = recv %bus` - Recv { - dst: ValueId, - bus: ValueId, - }, - - // === TIER-2: IMPLEMENTATION ASSISTANCE (5 instructions) === - - /// Tail call optimization (control) - /// `tail_call %func(%args...)` - TailCall { - func: ValueId, - args: Vec, - effects: EffectMask, - }, - - /// Ownership transfer: this takes strong ownership of child (mut) - /// `adopt %parent, %child` - Adopt { - parent: ValueId, - child: ValueId, - }, - - /// Release strong ownership (weakify or nullify) (mut) - /// `release %reference` - Release { - reference: ValueId, - }, - - /// Optimized memory copy for structs/arrays (mut) - /// `memcopy %dest, %src, %size` - MemCopy { - dest: ValueId, - src: ValueId, - size: ValueId, - }, - - /// Atomic fence for concurrency ordering at Actor/Port boundaries (io) - /// `atomic_fence %ordering` - AtomicFence { - ordering: AtomicOrdering, - }, -} - -/// Constant values in MIR -#[derive(Debug, Clone, PartialEq)] -pub enum ConstValue { - Integer(i64), - Float(f64), - Bool(bool), - String(String), - Null, - Void, -} - -/// Binary operations -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum BinaryOp { - // Arithmetic - Add, Sub, Mul, Div, Mod, - - // Bitwise - BitAnd, BitOr, BitXor, Shl, Shr, - - // Logical - And, Or, -} - -/// Comparison operations -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum CompareOp { - Eq, Ne, Lt, Le, Gt, Ge, -} - -/// Atomic ordering for AtomicFence instruction -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum AtomicOrdering { - Relaxed, - Acquire, - Release, - AcqRel, - SeqCst, -} - -impl MirInstructionV2 { - /// Get the effect mask for this instruction according to 4-category system - pub fn effects(&self) -> EffectMask { - match self { - // TIER-0: Universal Core - // Pure operations - MirInstructionV2::Const { .. } | - MirInstructionV2::BinOp { .. } | - MirInstructionV2::Compare { .. } | - MirInstructionV2::Phi { .. } => EffectMask::PURE, - - // Control flow operations - MirInstructionV2::Branch { .. } | - MirInstructionV2::Jump { .. } | - MirInstructionV2::Return { .. } => EffectMask::CONTROL, - - // Context-dependent operations - MirInstructionV2::Call { effects, .. } => *effects, - - // TIER-1: Nyash Semantics - // Pure operations - MirInstructionV2::BoxFieldLoad { .. } | - MirInstructionV2::RefGet { .. } | - MirInstructionV2::WeakNew { .. } | - MirInstructionV2::WeakLoad { .. } | - MirInstructionV2::WeakCheck { .. } => EffectMask::PURE, - - // Mutable operations - MirInstructionV2::NewBox { .. } => EffectMask::MUT.add(Effect::Alloc), - MirInstructionV2::BoxFieldStore { .. } | - MirInstructionV2::RefSet { .. } => EffectMask::MUT, - - // I/O operations - MirInstructionV2::Safepoint | - MirInstructionV2::Send { .. } | - MirInstructionV2::Recv { .. } => EffectMask::IO, - - // Context-dependent operations - MirInstructionV2::BoxCall { effects, .. } => *effects, - - // TIER-2: Implementation Assistance - // Control flow operations - MirInstructionV2::TailCall { .. } => EffectMask::CONTROL, - - // Mutable operations - MirInstructionV2::Adopt { .. } | - MirInstructionV2::Release { .. } | - MirInstructionV2::MemCopy { .. } => EffectMask::MUT, - - // I/O operations - MirInstructionV2::AtomicFence { .. } => EffectMask::IO.add(Effect::Barrier), - } - } - - /// Get the destination ValueId if this instruction produces a value - pub fn dst_value(&self) -> Option { - match self { - MirInstructionV2::Const { dst, .. } | - MirInstructionV2::BinOp { dst, .. } | - MirInstructionV2::Compare { dst, .. } | - MirInstructionV2::Phi { dst, .. } | - MirInstructionV2::NewBox { dst, .. } | - MirInstructionV2::BoxFieldLoad { dst, .. } | - MirInstructionV2::RefGet { dst, .. } | - MirInstructionV2::WeakNew { dst, .. } | - MirInstructionV2::WeakLoad { dst, .. } | - MirInstructionV2::WeakCheck { dst, .. } | - MirInstructionV2::Recv { dst, .. } => Some(*dst), - - MirInstructionV2::Call { dst, .. } | - MirInstructionV2::BoxCall { dst, .. } => *dst, - - _ => None, - } - } - - /// Get all ValueIds used by this instruction - pub fn used_values(&self) -> Vec { - match self { - MirInstructionV2::Const { .. } => vec![], - - MirInstructionV2::BinOp { lhs, rhs, .. } | - MirInstructionV2::Compare { lhs, rhs, .. } => vec![*lhs, *rhs], - - MirInstructionV2::Branch { condition, .. } => vec![*condition], - - MirInstructionV2::Jump { .. } => vec![], - - MirInstructionV2::Phi { inputs, .. } => { - inputs.iter().map(|(_, value_id)| *value_id).collect() - }, - - MirInstructionV2::Call { func, args, .. } => { - let mut values = vec![*func]; - values.extend(args.iter().copied()); - values - }, - - MirInstructionV2::Return { value } => { - value.map(|v| vec![v]).unwrap_or_default() - }, - - MirInstructionV2::NewBox { args, .. } => args.clone(), - - MirInstructionV2::BoxFieldLoad { box_val, .. } => vec![*box_val], - - MirInstructionV2::BoxFieldStore { box_val, value, .. } => vec![*box_val, *value], - - MirInstructionV2::BoxCall { box_val, args, .. } => { - let mut values = vec![*box_val]; - values.extend(args.iter().copied()); - values - }, - - MirInstructionV2::Safepoint => vec![], - - MirInstructionV2::RefGet { reference, .. } => vec![*reference], - - MirInstructionV2::RefSet { reference, new_target, .. } => vec![*reference, *new_target], - - MirInstructionV2::WeakNew { box_val, .. } => vec![*box_val], - - MirInstructionV2::WeakLoad { weak_ref, .. } | - MirInstructionV2::WeakCheck { weak_ref, .. } => vec![*weak_ref], - - MirInstructionV2::Send { bus, message, .. } => vec![*bus, *message], - - MirInstructionV2::Recv { bus, .. } => vec![*bus], - - MirInstructionV2::TailCall { func, args, .. } => { - let mut values = vec![*func]; - values.extend(args.iter().copied()); - values - }, - - MirInstructionV2::Adopt { parent, child, .. } => vec![*parent, *child], - - MirInstructionV2::Release { reference, .. } => vec![*reference], - - MirInstructionV2::MemCopy { dest, src, size, .. } => vec![*dest, *src, *size], - - MirInstructionV2::AtomicFence { .. } => vec![], - } - } - - /// Get the instruction tier (0, 1, or 2) - pub fn tier(&self) -> u8 { - match self { - // Tier-0: Universal Core - MirInstructionV2::Const { .. } | - MirInstructionV2::BinOp { .. } | - MirInstructionV2::Compare { .. } | - MirInstructionV2::Branch { .. } | - MirInstructionV2::Jump { .. } | - MirInstructionV2::Phi { .. } | - MirInstructionV2::Call { .. } | - MirInstructionV2::Return { .. } => 0, - - // Tier-1: Nyash Semantics - MirInstructionV2::NewBox { .. } | - MirInstructionV2::BoxFieldLoad { .. } | - MirInstructionV2::BoxFieldStore { .. } | - MirInstructionV2::BoxCall { .. } | - MirInstructionV2::Safepoint { .. } | - MirInstructionV2::RefGet { .. } | - MirInstructionV2::RefSet { .. } | - MirInstructionV2::WeakNew { .. } | - MirInstructionV2::WeakLoad { .. } | - MirInstructionV2::WeakCheck { .. } | - MirInstructionV2::Send { .. } | - MirInstructionV2::Recv { .. } => 1, - - // Tier-2: Implementation Assistance - MirInstructionV2::TailCall { .. } | - MirInstructionV2::Adopt { .. } | - MirInstructionV2::Release { .. } | - MirInstructionV2::MemCopy { .. } | - MirInstructionV2::AtomicFence { .. } => 2, - } - } - - /// Get a human-readable description of the instruction - pub fn description(&self) -> &'static str { - match self { - // Tier-0 - MirInstructionV2::Const { .. } => "Load constant value", - MirInstructionV2::BinOp { .. } => "Binary arithmetic operation", - MirInstructionV2::Compare { .. } => "Compare two values", - MirInstructionV2::Branch { .. } => "Conditional branch", - MirInstructionV2::Jump { .. } => "Unconditional jump", - MirInstructionV2::Phi { .. } => "SSA phi function", - MirInstructionV2::Call { .. } => "External function call", - MirInstructionV2::Return { .. } => "Return from function", - - // Tier-1 - MirInstructionV2::NewBox { .. } => "Create Box instance", - MirInstructionV2::BoxFieldLoad { .. } => "Load Box field value", - MirInstructionV2::BoxFieldStore { .. } => "Store to Box field", - MirInstructionV2::BoxCall { .. } => "Box method invocation", - MirInstructionV2::Safepoint => "Finalization/interrupt safepoint", - MirInstructionV2::RefGet { .. } => "Get reference as value", - MirInstructionV2::RefSet { .. } => "Set reference target", - MirInstructionV2::WeakNew { .. } => "Create weak reference", - MirInstructionV2::WeakLoad { .. } => "Load from weak reference", - MirInstructionV2::WeakCheck { .. } => "Check weak reference validity", - MirInstructionV2::Send { .. } => "Send Bus message", - MirInstructionV2::Recv { .. } => "Receive Bus message", - - // Tier-2 - MirInstructionV2::TailCall { .. } => "Tail call optimization", - MirInstructionV2::Adopt { .. } => "Transfer ownership", - MirInstructionV2::Release { .. } => "Release ownership", - MirInstructionV2::MemCopy { .. } => "Optimized memory copy", - MirInstructionV2::AtomicFence { .. } => "Atomic memory fence", - } - } -} - -impl fmt::Display for MirInstructionV2 { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.description()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::mir::{ValueIdGenerator, BasicBlockIdGenerator}; - - #[test] - fn test_instruction_count() { - // Verify we have exactly 25 instruction variants - // This is a compile-time verification - let _tier0_count = 8; // Const, BinOp, Compare, Branch, Jump, Phi, Call, Return - let _tier1_count = 12; // NewBox, BoxFieldLoad/Store, BoxCall, Safepoint, RefGet/Set, WeakNew/Load/Check, Send, Recv - let _tier2_count = 5; // TailCall, Adopt, Release, MemCopy, AtomicFence - let _total = _tier0_count + _tier1_count + _tier2_count; - assert_eq!(_total, 25, "MIR instruction set must have exactly 25 instructions"); - } - - #[test] - fn test_effect_categories() { - let mut value_gen = ValueIdGenerator::new(); - let mut bb_gen = BasicBlockIdGenerator::new(); - - // Test pure operations - let const_inst = MirInstructionV2::Const { - dst: value_gen.next(), - value: ConstValue::Integer(42), - }; - assert!(const_inst.effects().is_pure(), "Const should be pure"); - assert_eq!(const_inst.tier(), 0, "Const should be Tier-0"); - - // Test mut operations - let store_inst = MirInstructionV2::BoxFieldStore { - box_val: value_gen.next(), - field: "value".to_string(), - value: value_gen.next(), - }; - assert!(store_inst.effects().is_mut(), "BoxFieldStore should be mut"); - assert_eq!(store_inst.tier(), 1, "BoxFieldStore should be Tier-1"); - - // Test io operations - let send_inst = MirInstructionV2::Send { - bus: value_gen.next(), - message: value_gen.next(), - }; - assert!(send_inst.effects().is_io(), "Send should be io"); - assert_eq!(send_inst.tier(), 1, "Send should be Tier-1"); - - // Test control operations - let branch_inst = MirInstructionV2::Branch { - condition: value_gen.next(), - then_bb: bb_gen.next(), - else_bb: bb_gen.next(), - }; - assert!(branch_inst.effects().is_control(), "Branch should be control"); - assert_eq!(branch_inst.tier(), 0, "Branch should be Tier-0"); - } - - #[test] - fn test_ownership_operations() { - let mut value_gen = ValueIdGenerator::new(); - - // Test ownership transfer - let adopt_inst = MirInstructionV2::Adopt { - parent: value_gen.next(), - child: value_gen.next(), - }; - assert!(adopt_inst.effects().is_mut(), "Adopt should be mut"); - assert_eq!(adopt_inst.tier(), 2, "Adopt should be Tier-2"); - - // Test weak reference operations - let weak_check = MirInstructionV2::WeakCheck { - dst: value_gen.next(), - weak_ref: value_gen.next(), - }; - assert!(weak_check.effects().is_pure(), "WeakCheck should be pure"); - assert_eq!(weak_check.tier(), 1, "WeakCheck should be Tier-1"); - } -} \ No newline at end of file diff --git a/src/mir/mod.rs b/src/mir/mod.rs index efcd94c6..f3587f24 100644 --- a/src/mir/mod.rs +++ b/src/mir/mod.rs @@ -6,15 +6,13 @@ */ pub mod instruction; -pub mod instruction_v2; // New 25-instruction specification -pub mod instruction_introspection; // Introspection helpers for tests (core instruction names) +pub mod instruction_introspection; // Introspection helpers for tests (instruction names) pub mod basic_block; pub mod function; pub mod builder; pub mod loop_builder; // SSA loop construction with phi nodes pub mod loop_api; // Minimal LoopBuilder facade (adapter-ready) pub mod verification; -pub mod ownership_verifier_simple; // Simple ownership forest verification for current MIR pub mod printer; pub mod value_id; pub mod effect; @@ -26,12 +24,10 @@ pub mod passes; // Optimization subpasses (e.g., type_hints) // Re-export main types for easy access pub use instruction::{MirInstruction, BinaryOp, CompareOp, UnaryOp, ConstValue, MirType, TypeOpKind, WeakRefOp, BarrierOp}; -pub use instruction_v2::{MirInstructionV2, AtomicOrdering}; // New 25-instruction set pub use basic_block::{BasicBlock, BasicBlockId, BasicBlockIdGenerator}; pub use function::{MirFunction, MirModule, FunctionSignature}; pub use builder::MirBuilder; pub use verification::{MirVerifier, VerificationError}; -pub use ownership_verifier_simple::{OwnershipVerifier, OwnershipError, OwnershipStats}; // Simple ownership forest verification pub use printer::MirPrinter; pub use value_id::{ValueId, LocalId, ValueIdGenerator}; pub use effect::{EffectMask, Effect}; @@ -85,79 +81,6 @@ impl MirCompiler { } } - // Core-13 strict: forbid legacy ops in final MIR when enabled - if crate::config::env::mir_core13() || crate::config::env::opt_diag_forbid_legacy() { - let mut legacy_count = 0usize; - for (_fname, function) in &module.functions { - for (_bb, block) in &function.blocks { - for inst in &block.instructions { - if matches!(inst, - MirInstruction::TypeCheck { .. } - | MirInstruction::Cast { .. } - | MirInstruction::WeakNew { .. } - | MirInstruction::WeakLoad { .. } - | MirInstruction::BarrierRead { .. } - | MirInstruction::BarrierWrite { .. } - | MirInstruction::ArrayGet { .. } - | MirInstruction::ArraySet { .. } - | MirInstruction::RefGet { .. } - | MirInstruction::RefSet { .. } - | MirInstruction::PluginInvoke { .. } - ) { legacy_count += 1; } - } - if let Some(term) = &block.terminator { - if matches!(term, - MirInstruction::TypeCheck { .. } - | MirInstruction::Cast { .. } - | MirInstruction::WeakNew { .. } - | MirInstruction::WeakLoad { .. } - | MirInstruction::BarrierRead { .. } - | MirInstruction::BarrierWrite { .. } - | MirInstruction::ArrayGet { .. } - | MirInstruction::ArraySet { .. } - | MirInstruction::RefGet { .. } - | MirInstruction::RefSet { .. } - | MirInstruction::PluginInvoke { .. } - ) { legacy_count += 1; } - } - } - } - if legacy_count > 0 { - return Err(format!("Core-13 strict: final MIR contains {} legacy ops", legacy_count)); - } - } - - // Core-13 pure: allow only the 13 canonical ops; reject all others - if crate::config::env::mir_core13_pure() { - let mut bad = 0usize; - let is_allowed = |i: &MirInstruction| -> bool { - matches!(i, - MirInstruction::Const { .. } - | MirInstruction::BinOp { .. } - | MirInstruction::Compare { .. } - | MirInstruction::Jump { .. } - | MirInstruction::Branch { .. } - | MirInstruction::Return { .. } - | MirInstruction::Phi { .. } - | MirInstruction::Call { .. } - | MirInstruction::BoxCall { .. } - | MirInstruction::ExternCall { .. } - | MirInstruction::TypeOp { .. } - | MirInstruction::Safepoint - | MirInstruction::Barrier { .. } - ) - }; - for (_fname, function) in &module.functions { - for (_bb, block) in &function.blocks { - for inst in &block.instructions { if !is_allowed(inst) { bad += 1; } } - if let Some(term) = &block.terminator { if !is_allowed(term) { bad += 1; } } - } - } - if bad > 0 { - return Err(format!("Core-13 pure strict: final MIR contains {} non-Core-13 ops", bad)); - } - } - // Verify the generated MIR let verification_result = self.verifier.verify_module(&module); diff --git a/src/mir/ownership_verifier.rs b/src/mir/ownership_verifier.rs deleted file mode 100644 index e4c4f953..00000000 --- a/src/mir/ownership_verifier.rs +++ /dev/null @@ -1,559 +0,0 @@ -/*! - * Ownership Forest Verification System - * - * Implements ownership forest validation rules per ChatGPT5 specification: - * - Ownership forest: strong in-degree ≤ 1 - * - Strong cycle prohibition: strong edges form DAG (forest) - * - Weak/strong interaction: bidirectional strong → error - * - RefSet safety: strong→strong requires Release of old target - * - WeakLoad/WeakCheck deterministic behavior: null/false on expiration - */ - -use super::{MirInstruction, ValueId, MirFunction, MirModule}; -use std::collections::{HashMap, HashSet, VecDeque}; - -/// Ownership forest verification errors -#[derive(Debug, Clone, PartialEq)] -pub enum OwnershipError { - /// Strong reference has multiple owners (violates forest constraint) - MultipleStrongOwners { - target: ValueId, - owners: Vec, - }, - - /// Strong reference cycle detected (violates DAG constraint) - StrongCycle { - cycle: Vec, - }, - - /// Bidirectional strong references (should be strong + weak) - BidirectionalStrong { - first: ValueId, - second: ValueId, - }, - - /// RefSet without proper Release of old target - UnsafeRefSet { - reference: ValueId, - old_target: ValueId, - new_target: ValueId, - }, - - /// WeakLoad on expired reference (should return null deterministically) - WeakLoadExpired { - weak_ref: ValueId, - dead_target: ValueId, - }, - - /// Use after Release (accessing released ownership) - UseAfterRelease { - value: ValueId, - released_at: String, - }, - - /// Invalid ownership transfer via Adopt - InvalidAdopt { - parent: ValueId, - child: ValueId, - reason: String, - }, -} - -/// Ownership forest verifier -pub struct OwnershipVerifier { - /// Strong ownership edges: child -> parent - strong_edges: HashMap, - - /// Weak reference edges: weak_ref -> target - weak_edges: HashMap, - - /// Released references (no longer valid for ownership) - released: HashSet, - - /// Track live weak references for liveness checking - live_weak_refs: HashSet, - - /// Track dead targets for WeakLoad/WeakCheck determinism - dead_targets: HashSet, -} - -impl OwnershipVerifier { - /// Create a new ownership verifier - pub fn new() -> Self { - Self { - strong_edges: HashMap::new(), - weak_edges: HashMap::new(), - released: HashSet::new(), - live_weak_refs: HashSet::new(), - dead_targets: HashSet::new(), - } - } - - /// Verify ownership forest properties for an entire module - pub fn verify_module(&mut self, module: &MirModule) -> Result<(), Vec> { - let mut errors = Vec::new(); - - for function in module.functions.values() { - if let Err(mut function_errors) = self.verify_function(function) { - errors.append(&mut function_errors); - } - } - - if errors.is_empty() { - Ok(()) - } else { - Err(errors) - } - } - - /// Verify ownership forest properties for a single function - pub fn verify_function(&mut self, function: &MirFunction) -> Result<(), Vec> { - let mut errors = Vec::new(); - - // Reset state for this function - self.strong_edges.clear(); - self.weak_edges.clear(); - self.released.clear(); - self.live_weak_refs.clear(); - self.dead_targets.clear(); - - // Process all instructions to build ownership graph - for block in function.blocks.values() { - for instruction in block.all_instructions() { - if let Err(mut inst_errors) = self.process_instruction(instruction) { - errors.append(&mut inst_errors); - } - } - } - - // Verify global ownership forest properties - if let Err(mut forest_errors) = self.verify_ownership_forest() { - errors.append(&mut forest_errors); - } - - if errors.is_empty() { - Ok(()) - } else { - Err(errors) - } - } - - /// Process a single instruction and update ownership state - fn process_instruction(&mut self, instruction: &MirInstruction) -> Result<(), Vec> { - let mut errors = Vec::new(); - - match instruction { - // NewBox creates a new ownership root - MirInstructionV2::NewBox { dst, .. } => { - // New boxes are ownership roots (no parent) - // Clear any existing ownership for this value - self.strong_edges.remove(dst); - }, - - // RefSet changes ownership relationships - MirInstructionV2::RefSet { reference, new_target } => { - // Check if the reference currently has a strong target - if let Some(old_target) = self.strong_edges.get(reference) { - // Strong→Strong replacement requires explicit Release - if !self.released.contains(old_target) { - errors.push(OwnershipError::UnsafeRefSet { - reference: *reference, - old_target: *old_target, - new_target: *new_target, - }); - } - } - - // Set new strong ownership - self.strong_edges.insert(*reference, *new_target); - - // Verify no multiple strong owners after this change - if let Err(mut multiple_errors) = self.check_multiple_owners(*new_target) { - errors.append(&mut multiple_errors); - } - }, - - // Adopt transfers ownership - MirInstructionV2::Adopt { parent, child } => { - // Verify the adoption is valid - if self.released.contains(child) { - errors.push(OwnershipError::InvalidAdopt { - parent: *parent, - child: *child, - reason: "Cannot adopt released reference".to_string(), - }); - } - - // Check for cycle creation - if self.would_create_cycle(*parent, *child) { - errors.push(OwnershipError::InvalidAdopt { - parent: *parent, - child: *child, - reason: "Would create strong cycle".to_string(), - }); - } - - // Establish strong ownership - self.strong_edges.insert(*child, *parent); - }, - - // Release removes ownership - MirInstructionV2::Release { reference } => { - self.strong_edges.remove(reference); - self.released.insert(*reference); - - // Mark any targets of this reference as potentially dead - if let Some(target) = self.weak_edges.get(reference) { - self.dead_targets.insert(*target); - } - }, - - // WeakNew creates weak reference - MirInstructionV2::WeakNew { dst, box_val } => { - self.weak_edges.insert(*dst, *box_val); - self.live_weak_refs.insert(*dst); - }, - - // WeakLoad checks liveness - MirInstructionV2::WeakLoad { weak_ref, .. } => { - if let Some(target) = self.weak_edges.get(weak_ref) { - if self.dead_targets.contains(target) { - // This is actually expected behavior - WeakLoad should return null - // We track this for deterministic behavior verification - } - } - }, - - // WeakCheck verifies liveness - MirInstructionV2::WeakCheck { weak_ref, .. } => { - if let Some(target) = self.weak_edges.get(weak_ref) { - if self.dead_targets.contains(target) { - // This is expected - WeakCheck should return false - } - } - }, - - // Other instructions don't affect ownership - _ => {}, - } - - if errors.is_empty() { - Ok(()) - } else { - Err(errors) - } - } - - /// Verify global ownership forest properties - fn verify_ownership_forest(&self) -> Result<(), Vec> { - let mut errors = Vec::new(); - - // Check for multiple strong owners (violates forest constraint) - let mut target_owners: HashMap> = HashMap::new(); - for (child, parent) in &self.strong_edges { - target_owners.entry(*parent).or_insert_with(Vec::new).push(*child); - } - - for (target, owners) in target_owners { - if owners.len() > 1 { - errors.push(OwnershipError::MultipleStrongOwners { target, owners }); - } - } - - // Check for strong cycles (violates DAG constraint) - if let Some(cycle) = self.find_strong_cycle() { - errors.push(OwnershipError::StrongCycle { cycle }); - } - - // Check for bidirectional strong edges - for (child, parent) in &self.strong_edges { - if let Some(grandparent) = self.strong_edges.get(parent) { - if grandparent == child { - errors.push(OwnershipError::BidirectionalStrong { - first: *child, - second: *parent, - }); - } - } - } - - if errors.is_empty() { - Ok(()) - } else { - Err(errors) - } - } - - /// Check if a value has multiple strong owners - fn check_multiple_owners(&self, target: ValueId) -> Result<(), Vec> { - let owners: Vec = self.strong_edges - .iter() - .filter(|(_, &parent)| parent == target) - .map(|(&child, _)| child) - .collect(); - - if owners.len() > 1 { - Err(vec![OwnershipError::MultipleStrongOwners { target, owners }]) - } else { - Ok(()) - } - } - - /// Check if adding an edge would create a cycle - fn would_create_cycle(&self, parent: ValueId, child: ValueId) -> bool { - // DFS to see if parent is reachable from child through strong edges - let mut visited = HashSet::new(); - let mut stack = vec![child]; - - while let Some(current) = stack.pop() { - if current == parent { - return true; // Cycle detected - } - - if visited.insert(current) { - // Add all strong children of current to stack - for (&potential_child, &potential_parent) in &self.strong_edges { - if potential_parent == current { - stack.push(potential_child); - } - } - } - } - - false - } - - /// Find any strong cycle in the ownership graph - fn find_strong_cycle(&self) -> Option> { - let mut visited = HashSet::new(); - let mut rec_stack = HashSet::new(); - let mut path = Vec::new(); - - // Get all nodes in the graph - let mut all_nodes = HashSet::new(); - for (&child, &parent) in &self.strong_edges { - all_nodes.insert(child); - all_nodes.insert(parent); - } - - // DFS from each unvisited node - for &node in &all_nodes { - if !visited.contains(&node) { - if let Some(cycle) = self.dfs_cycle(node, &mut visited, &mut rec_stack, &mut path) { - return Some(cycle); - } - } - } - - None - } - - /// DFS cycle detection helper - fn dfs_cycle( - &self, - node: ValueId, - visited: &mut HashSet, - rec_stack: &mut HashSet, - path: &mut Vec, - ) -> Option> { - visited.insert(node); - rec_stack.insert(node); - path.push(node); - - // Visit all strong children - for (&child, &parent) in &self.strong_edges { - if parent == node { - if rec_stack.contains(&child) { - // Found cycle - return path from child to current - let cycle_start = path.iter().position(|&x| x == child).unwrap(); - return Some(path[cycle_start..].to_vec()); - } - - if !visited.contains(&child) { - if let Some(cycle) = self.dfs_cycle(child, visited, rec_stack, path) { - return Some(cycle); - } - } - } - } - - rec_stack.remove(&node); - path.pop(); - None - } - - /// Get ownership statistics for debugging - pub fn ownership_stats(&self) -> OwnershipStats { - OwnershipStats { - strong_edges: self.strong_edges.len(), - weak_edges: self.weak_edges.len(), - released_count: self.released.len(), - live_weak_refs: self.live_weak_refs.len(), - dead_targets: self.dead_targets.len(), - } - } -} - -/// Ownership statistics for debugging and analysis -#[derive(Debug, Clone, PartialEq)] -pub struct OwnershipStats { - pub strong_edges: usize, - pub weak_edges: usize, - pub released_count: usize, - pub live_weak_refs: usize, - pub dead_targets: usize, -} - -impl Default for OwnershipVerifier { - fn default() -> Self { - Self::new() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::mir::{ValueIdGenerator, ConstValue}; - - #[test] - fn test_ownership_forest_basic() { - let mut verifier = OwnershipVerifier::new(); - let mut value_gen = ValueIdGenerator::new(); - - let parent = value_gen.next(); - let child = value_gen.next(); - - // Create ownership relationship - let adopt = MirInstructionV2::Adopt { parent, child }; - assert!(verifier.process_instruction(&adopt).is_ok()); - - // Verify forest properties - assert!(verifier.verify_ownership_forest().is_ok()); - - let stats = verifier.ownership_stats(); - assert_eq!(stats.strong_edges, 1); - } - - #[test] - fn test_multiple_owners_error() { - let mut verifier = OwnershipVerifier::new(); - let mut value_gen = ValueIdGenerator::new(); - - let parent1 = value_gen.next(); - let parent2 = value_gen.next(); - let child = value_gen.next(); - - // Create multiple ownership (invalid) - verifier.strong_edges.insert(child, parent1); - verifier.strong_edges.insert(child, parent2); // This overwrites, but we'll manually create conflict - - // Manually create the conflicting state for testing - verifier.strong_edges.clear(); - verifier.strong_edges.insert(parent1, child); // parent1 -> child - verifier.strong_edges.insert(parent2, child); // parent2 -> child (multiple owners of child) - - let result = verifier.verify_ownership_forest(); - assert!(result.is_err()); - - if let Err(errors) = result { - assert!(errors.iter().any(|e| matches!(e, OwnershipError::MultipleStrongOwners { .. }))); - } - } - - #[test] - fn test_strong_cycle_detection() { - let mut verifier = OwnershipVerifier::new(); - let mut value_gen = ValueIdGenerator::new(); - - let a = value_gen.next(); - let b = value_gen.next(); - let c = value_gen.next(); - - // Create cycle: a -> b -> c -> a - verifier.strong_edges.insert(b, a); - verifier.strong_edges.insert(c, b); - verifier.strong_edges.insert(a, c); - - let result = verifier.verify_ownership_forest(); - assert!(result.is_err()); - - if let Err(errors) = result { - assert!(errors.iter().any(|e| matches!(e, OwnershipError::StrongCycle { .. }))); - } - } - - #[test] - fn test_weak_reference_safety() { - let mut verifier = OwnershipVerifier::new(); - let mut value_gen = ValueIdGenerator::new(); - - let target = value_gen.next(); - let weak_ref = value_gen.next(); - - // Create weak reference - let weak_new = MirInstructionV2::WeakNew { - dst: weak_ref, - box_val: target, - }; - assert!(verifier.process_instruction(&weak_new).is_ok()); - - // Release the target - let release = MirInstructionV2::Release { - reference: target, - }; - assert!(verifier.process_instruction(&release).is_ok()); - - // WeakLoad should handle expired reference gracefully - let weak_load = MirInstructionV2::WeakLoad { - dst: value_gen.next(), - weak_ref, - }; - assert!(verifier.process_instruction(&weak_load).is_ok()); - - let stats = verifier.ownership_stats(); - assert_eq!(stats.weak_edges, 1); - assert_eq!(stats.dead_targets, 1); - } - - #[test] - fn test_unsafe_ref_set() { - let mut verifier = OwnershipVerifier::new(); - let mut value_gen = ValueIdGenerator::new(); - - let reference = value_gen.next(); - let old_target = value_gen.next(); - let new_target = value_gen.next(); - - // Set initial strong ownership - verifier.strong_edges.insert(reference, old_target); - - // Try to change without Release (should error) - let ref_set = MirInstructionV2::RefSet { reference, new_target }; - let result = verifier.process_instruction(&ref_set); - - assert!(result.is_err()); - if let Err(errors) = result { - assert!(errors.iter().any(|e| matches!(e, OwnershipError::UnsafeRefSet { .. }))); - } - } - - #[test] - fn test_safe_ref_set_with_release() { - let mut verifier = OwnershipVerifier::new(); - let mut value_gen = ValueIdGenerator::new(); - - let reference = value_gen.next(); - let old_target = value_gen.next(); - let new_target = value_gen.next(); - - // Set initial strong ownership - verifier.strong_edges.insert(reference, old_target); - - // Release old target first - verifier.released.insert(old_target); - - // Now RefSet should be safe - let ref_set = MirInstructionV2::RefSet { reference, new_target }; - assert!(verifier.process_instruction(&ref_set).is_ok()); - } -} \ No newline at end of file diff --git a/src/mir/ownership_verifier_simple.rs b/src/mir/ownership_verifier_simple.rs deleted file mode 100644 index 1a6c7b91..00000000 --- a/src/mir/ownership_verifier_simple.rs +++ /dev/null @@ -1,370 +0,0 @@ -/*! - * Ownership Forest Verification System (Simplified for Current MIR) - * - * Basic implementation working with current MirInstruction enum - * Will be expanded when MirInstructionV2 is integrated - */ - -use super::{MirInstruction, ValueId, MirFunction, MirModule}; -use std::collections::{HashMap, HashSet}; - -/// Ownership forest verification errors -#[derive(Debug, Clone, PartialEq)] -pub enum OwnershipError { - /// Strong reference has multiple owners (violates forest constraint) - MultipleStrongOwners { - target: ValueId, - owners: Vec, - }, - - /// Strong reference cycle detected (violates DAG constraint) - StrongCycle { - cycle: Vec, - }, - - /// RefSet without proper Release of old target - UnsafeRefSet { - reference: ValueId, - old_target: ValueId, - new_target: ValueId, - }, -} - -/// Ownership forest verifier -pub struct OwnershipVerifier { - /// Strong ownership edges: child -> parent - strong_edges: HashMap, - - /// Weak reference edges: weak_ref -> target - weak_edges: HashMap, - - /// Released references (no longer valid for ownership) - released: HashSet, - - /// Track live weak references for liveness checking - live_weak_refs: HashSet, - - /// Track dead targets for WeakLoad/WeakCheck determinism - dead_targets: HashSet, -} - -impl OwnershipVerifier { - /// Create a new ownership verifier - pub fn new() -> Self { - Self { - strong_edges: HashMap::new(), - weak_edges: HashMap::new(), - released: HashSet::new(), - live_weak_refs: HashSet::new(), - dead_targets: HashSet::new(), - } - } - - /// Verify ownership forest properties for an entire module - pub fn verify_module(&mut self, module: &MirModule) -> Result<(), Vec> { - let mut errors = Vec::new(); - - for function in module.functions.values() { - if let Err(mut function_errors) = self.verify_function(function) { - errors.append(&mut function_errors); - } - } - - if errors.is_empty() { - Ok(()) - } else { - Err(errors) - } - } - - /// Verify ownership forest properties for a single function - pub fn verify_function(&mut self, function: &MirFunction) -> Result<(), Vec> { - let mut errors = Vec::new(); - - // Reset state for this function - self.strong_edges.clear(); - self.weak_edges.clear(); - self.released.clear(); - self.live_weak_refs.clear(); - self.dead_targets.clear(); - - // Process all instructions to build ownership graph - for block in function.blocks.values() { - for instruction in block.all_instructions() { - if let Err(mut inst_errors) = self.process_instruction(instruction) { - errors.append(&mut inst_errors); - } - } - } - - // Verify global ownership forest properties - if let Err(mut forest_errors) = self.verify_ownership_forest() { - errors.append(&mut forest_errors); - } - - if errors.is_empty() { - Ok(()) - } else { - Err(errors) - } - } - - /// Process a single instruction and update ownership state - pub fn process_instruction(&mut self, instruction: &MirInstruction) -> Result<(), Vec> { - let mut errors = Vec::new(); - - match instruction { - // NewBox creates a new ownership root - MirInstruction::NewBox { dst, .. } => { - // New boxes are ownership roots (no parent) - self.strong_edges.remove(dst); - }, - - // RefSet changes ownership relationships - MirInstruction::RefSet { reference, field: _, value } => { - // Check if the reference currently has a strong target - if let Some(old_target) = self.strong_edges.get(reference) { - // Strong→Strong replacement requires explicit Release - if !self.released.contains(old_target) { - errors.push(OwnershipError::UnsafeRefSet { - reference: *reference, - old_target: *old_target, - new_target: *value, - }); - } - } - - // Set new strong ownership - self.strong_edges.insert(*reference, *value); - - // Verify no multiple owners after this change - if let Err(mut multiple_errors) = self.check_multiple_owners(*value) { - errors.append(&mut multiple_errors); - } - }, - - // WeakNew creates weak reference - MirInstruction::WeakNew { dst, box_val } => { - self.weak_edges.insert(*dst, *box_val); - self.live_weak_refs.insert(*dst); - }, - - // WeakLoad checks liveness - MirInstruction::WeakLoad { weak_ref, .. } => { - if let Some(target) = self.weak_edges.get(weak_ref) { - if self.dead_targets.contains(target) { - // This is expected behavior - WeakLoad should return null deterministically - } - } - }, - - // Other instructions don't affect ownership in current implementation - _ => {}, - } - - if errors.is_empty() { - Ok(()) - } else { - Err(errors) - } - } - - /// Verify global ownership forest properties - fn verify_ownership_forest(&self) -> Result<(), Vec> { - let mut errors = Vec::new(); - - // Check for multiple strong owners (violates forest constraint) - let mut target_owners: HashMap> = HashMap::new(); - for (child, parent) in &self.strong_edges { - target_owners.entry(*parent).or_insert_with(Vec::new).push(*child); - } - - for (target, owners) in target_owners { - if owners.len() > 1 { - errors.push(OwnershipError::MultipleStrongOwners { target, owners }); - } - } - - // Check for strong cycles (violates DAG constraint) - if let Some(cycle) = self.find_strong_cycle() { - errors.push(OwnershipError::StrongCycle { cycle }); - } - - if errors.is_empty() { - Ok(()) - } else { - Err(errors) - } - } - - /// Check if a value has multiple strong owners - fn check_multiple_owners(&self, target: ValueId) -> Result<(), Vec> { - let owners: Vec = self.strong_edges - .iter() - .filter(|(_, &parent)| parent == target) - .map(|(&child, _)| child) - .collect(); - - if owners.len() > 1 { - Err(vec![OwnershipError::MultipleStrongOwners { target, owners }]) - } else { - Ok(()) - } - } - - /// Find any strong cycle in the ownership graph - fn find_strong_cycle(&self) -> Option> { - let mut visited = HashSet::new(); - let mut rec_stack = HashSet::new(); - let mut path = Vec::new(); - - // Get all nodes in the graph - let mut all_nodes = HashSet::new(); - for (&child, &parent) in &self.strong_edges { - all_nodes.insert(child); - all_nodes.insert(parent); - } - - // DFS from each unvisited node - for &node in &all_nodes { - if !visited.contains(&node) { - if let Some(cycle) = self.dfs_cycle(node, &mut visited, &mut rec_stack, &mut path) { - return Some(cycle); - } - } - } - - None - } - - /// DFS cycle detection helper - fn dfs_cycle( - &self, - node: ValueId, - visited: &mut HashSet, - rec_stack: &mut HashSet, - path: &mut Vec, - ) -> Option> { - visited.insert(node); - rec_stack.insert(node); - path.push(node); - - // Visit all strong children - for (&child, &parent) in &self.strong_edges { - if parent == node { - if rec_stack.contains(&child) { - // Found cycle - return path from child to current - let cycle_start = path.iter().position(|&x| x == child).unwrap(); - return Some(path[cycle_start..].to_vec()); - } - - if !visited.contains(&child) { - if let Some(cycle) = self.dfs_cycle(child, visited, rec_stack, path) { - return Some(cycle); - } - } - } - } - - rec_stack.remove(&node); - path.pop(); - None - } - - /// Get ownership statistics for debugging - pub fn ownership_stats(&self) -> OwnershipStats { - OwnershipStats { - strong_edges: self.strong_edges.len(), - weak_edges: self.weak_edges.len(), - released_count: self.released.len(), - live_weak_refs: self.live_weak_refs.len(), - dead_targets: self.dead_targets.len(), - } - } -} - -/// Ownership statistics for debugging and analysis -#[derive(Debug, Clone, PartialEq)] -pub struct OwnershipStats { - pub strong_edges: usize, - pub weak_edges: usize, - pub released_count: usize, - pub live_weak_refs: usize, - pub dead_targets: usize, -} - -impl Default for OwnershipVerifier { - fn default() -> Self { - Self::new() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::mir::ValueIdGenerator; - - #[test] - fn test_ownership_forest_basic() { - let mut verifier = OwnershipVerifier::new(); - let mut value_gen = ValueIdGenerator::new(); - - let parent = value_gen.next(); - let child = value_gen.next(); - - // Create NewBox instruction (current MirInstruction) - let new_box = MirInstruction::NewBox { - dst: parent, - box_type: "TestBox".to_string(), - args: vec![] - }; - assert!(verifier.process_instruction(&new_box).is_ok()); - - // Verify forest properties - assert!(verifier.verify_ownership_forest().is_ok()); - - let stats = verifier.ownership_stats(); - assert_eq!(stats.strong_edges, 0); // NewBox doesn't create edges, just roots - } - - #[test] - fn test_weak_reference_tracking() { - let mut verifier = OwnershipVerifier::new(); - let mut value_gen = ValueIdGenerator::new(); - - let target = value_gen.next(); - let weak_ref = value_gen.next(); - - // Create weak reference - let weak_new = MirInstruction::WeakNew { dst: weak_ref, box_val: target }; - assert!(verifier.process_instruction(&weak_new).is_ok(), "Weak reference creation should succeed"); - - let stats = verifier.ownership_stats(); - assert_eq!(stats.weak_edges, 1, "Should have one weak edge"); - assert_eq!(stats.live_weak_refs, 1, "Should have one live weak reference"); - - // WeakLoad should handle gracefully - let weak_load = MirInstruction::WeakLoad { dst: value_gen.next(), weak_ref }; - assert!(verifier.process_instruction(&weak_load).is_ok(), "WeakLoad should succeed"); - } - - #[test] - fn test_basic_ref_set() { - let mut verifier = OwnershipVerifier::new(); - let mut value_gen = ValueIdGenerator::new(); - - let reference = value_gen.next(); - let target = value_gen.next(); - - // Basic RefSet without prior ownership (should succeed) - let ref_set = MirInstruction::RefSet { - reference, - field: "test".to_string(), - value: target - }; - assert!(verifier.process_instruction(&ref_set).is_ok(), "Basic RefSet should succeed"); - - let stats = verifier.ownership_stats(); - assert_eq!(stats.strong_edges, 1, "Should have one strong edge"); - } -} \ No newline at end of file diff --git a/tests/mir_instruction_set_sync.rs b/tests/mir_instruction_set_sync.rs index a2768cc2..9af5ae1e 100644 --- a/tests/mir_instruction_set_sync.rs +++ b/tests/mir_instruction_set_sync.rs @@ -1,8 +1,8 @@ use nyash_rust::mir::instruction_introspection; -// Core-15: enforce fixed instruction count at 15 (migration mode; docs may differ) +// MIR14: ensure instruction count stays fixed at 14 #[test] -fn mir_core15_instruction_count() { - let impl_names = instruction_introspection::core15_instruction_names(); - assert_eq!(impl_names.len(), 15, "Core-15 must contain exactly 15 instructions"); +fn mir14_instruction_count() { + let impl_names = instruction_introspection::mir14_instruction_names(); + assert_eq!(impl_names.len(), 14, "MIR14 must contain exactly 14 instructions"); } diff --git a/tests/mir_phase8_5_hierarchical_25_instructions.rs b/tests/mir_phase8_5_hierarchical_25_instructions.rs deleted file mode 100644 index 86648da8..00000000 --- a/tests/mir_phase8_5_hierarchical_25_instructions.rs +++ /dev/null @@ -1,479 +0,0 @@ -/*! - * Phase 8.5 MIR 25-Instruction Hierarchical Implementation Tests - * - * Comprehensive test suite for the ChatGPT5 + AI Council designed MIR system - */ - -#![cfg(feature = "mir-v2")] -use nyash_rust::mir::{ - MirInstructionV2, ConstValue, BinaryOp, CompareOp, AtomicOrdering, - EffectMask, Effect, ValueIdGenerator, BasicBlockIdGenerator, - OwnershipVerifier, OwnershipError, -}; - -/// Test that we have exactly 25 instructions in the specification -#[test] -fn test_mir_instruction_count() { - // This is verified at compile time by the instruction enum - // Each tier should have the correct count: - // Tier-0: 8 instructions - // Tier-1: 12 instructions - // Tier-2: 5 instructions - // Total: 25 instructions - - let mut value_gen = ValueIdGenerator::new(); - let mut bb_gen = BasicBlockIdGenerator::new(); - - // Tier-0: Universal Core (8 instructions) - let tier0_instructions = vec![ - MirInstructionV2::Const { dst: value_gen.next(), value: ConstValue::Integer(42) }, - MirInstructionV2::BinOp { dst: value_gen.next(), op: BinaryOp::Add, lhs: value_gen.next(), rhs: value_gen.next() }, - MirInstructionV2::Compare { dst: value_gen.next(), op: CompareOp::Eq, lhs: value_gen.next(), rhs: value_gen.next() }, - MirInstructionV2::Branch { condition: value_gen.next(), then_bb: bb_gen.next(), else_bb: bb_gen.next() }, - MirInstructionV2::Jump { target: bb_gen.next() }, - MirInstructionV2::Phi { dst: value_gen.next(), inputs: vec![(bb_gen.next(), value_gen.next())] }, - MirInstructionV2::Call { dst: Some(value_gen.next()), func: value_gen.next(), args: vec![], effects: EffectMask::PURE }, - MirInstructionV2::Return { value: Some(value_gen.next()) }, - ]; - - for inst in &tier0_instructions { - assert_eq!(inst.tier(), 0, "Tier-0 instruction should have tier 0"); - } - assert_eq!(tier0_instructions.len(), 8, "Tier-0 should have exactly 8 instructions"); - - // Tier-1: Nyash Semantics (12 instructions) - let tier1_instructions = vec![ - MirInstructionV2::NewBox { dst: value_gen.next(), box_type: "TestBox".to_string(), args: vec![] }, - MirInstructionV2::BoxFieldLoad { dst: value_gen.next(), box_val: value_gen.next(), field: "value".to_string() }, - MirInstructionV2::BoxFieldStore { box_val: value_gen.next(), field: "value".to_string(), value: value_gen.next() }, - MirInstructionV2::BoxCall { dst: Some(value_gen.next()), box_val: value_gen.next(), method: "test".to_string(), args: vec![], effects: EffectMask::PURE }, - MirInstructionV2::Safepoint, - MirInstructionV2::RefGet { dst: value_gen.next(), reference: value_gen.next() }, - MirInstructionV2::RefSet { reference: value_gen.next(), new_target: value_gen.next() }, - MirInstructionV2::WeakNew { dst: value_gen.next(), box_val: value_gen.next() }, - MirInstructionV2::WeakLoad { dst: value_gen.next(), weak_ref: value_gen.next() }, - MirInstructionV2::WeakCheck { dst: value_gen.next(), weak_ref: value_gen.next() }, - MirInstructionV2::Send { bus: value_gen.next(), message: value_gen.next() }, - MirInstructionV2::Recv { dst: value_gen.next(), bus: value_gen.next() }, - ]; - - for inst in &tier1_instructions { - assert_eq!(inst.tier(), 1, "Tier-1 instruction should have tier 1"); - } - assert_eq!(tier1_instructions.len(), 12, "Tier-1 should have exactly 12 instructions"); - - // Tier-2: Implementation Assistance (5 instructions) - let tier2_instructions = vec![ - MirInstructionV2::TailCall { func: value_gen.next(), args: vec![], effects: EffectMask::PURE }, - MirInstructionV2::Adopt { parent: value_gen.next(), child: value_gen.next() }, - MirInstructionV2::Release { reference: value_gen.next() }, - MirInstructionV2::MemCopy { dest: value_gen.next(), src: value_gen.next(), size: value_gen.next() }, - MirInstructionV2::AtomicFence { ordering: AtomicOrdering::SeqCst }, - ]; - - for inst in &tier2_instructions { - assert_eq!(inst.tier(), 2, "Tier-2 instruction should have tier 2"); - } - assert_eq!(tier2_instructions.len(), 5, "Tier-2 should have exactly 5 instructions"); - - // Total verification - let total_instructions = tier0_instructions.len() + tier1_instructions.len() + tier2_instructions.len(); - assert_eq!(total_instructions, 25, "Total instruction count must be exactly 25"); -} - -/// Test the 4-category effect system -#[test] -fn test_effect_categories() { - let mut value_gen = ValueIdGenerator::new(); - let mut bb_gen = BasicBlockIdGenerator::new(); - - // Test Pure effects - let pure_instructions = vec![ - MirInstructionV2::Const { dst: value_gen.next(), value: ConstValue::Integer(42) }, - MirInstructionV2::BinOp { dst: value_gen.next(), op: BinaryOp::Add, lhs: value_gen.next(), rhs: value_gen.next() }, - MirInstructionV2::Compare { dst: value_gen.next(), op: CompareOp::Eq, lhs: value_gen.next(), rhs: value_gen.next() }, - MirInstructionV2::Phi { dst: value_gen.next(), inputs: vec![(bb_gen.next(), value_gen.next())] }, - MirInstructionV2::BoxFieldLoad { dst: value_gen.next(), box_val: value_gen.next(), field: "value".to_string() }, - MirInstructionV2::RefGet { dst: value_gen.next(), reference: value_gen.next() }, - MirInstructionV2::WeakNew { dst: value_gen.next(), box_val: value_gen.next() }, - MirInstructionV2::WeakLoad { dst: value_gen.next(), weak_ref: value_gen.next() }, - MirInstructionV2::WeakCheck { dst: value_gen.next(), weak_ref: value_gen.next() }, - ]; - - for inst in pure_instructions { - let effects = inst.effects(); - assert!(effects.is_pure() || effects.primary_category() == Effect::Pure, - "Instruction should be pure: {:?}", inst); - } - - // Test Mut effects - let mut_instructions = vec![ - MirInstructionV2::BoxFieldStore { box_val: value_gen.next(), field: "value".to_string(), value: value_gen.next() }, - MirInstructionV2::RefSet { reference: value_gen.next(), new_target: value_gen.next() }, - MirInstructionV2::Adopt { parent: value_gen.next(), child: value_gen.next() }, - MirInstructionV2::Release { reference: value_gen.next() }, - MirInstructionV2::MemCopy { dest: value_gen.next(), src: value_gen.next(), size: value_gen.next() }, - ]; - - for inst in mut_instructions { - let effects = inst.effects(); - assert!(effects.is_mut() || effects.primary_category() == Effect::Mut, - "Instruction should be mut: {:?}", inst); - } - - // Test Io effects - let io_instructions = vec![ - MirInstructionV2::Safepoint, - MirInstructionV2::Send { bus: value_gen.next(), message: value_gen.next() }, - MirInstructionV2::Recv { dst: value_gen.next(), bus: value_gen.next() }, - MirInstructionV2::AtomicFence { ordering: AtomicOrdering::SeqCst }, - ]; - - for inst in io_instructions { - let effects = inst.effects(); - assert!(effects.is_io() || effects.primary_category() == Effect::Io, - "Instruction should be io: {:?}", inst); - } - - // Test Control effects - let control_instructions = vec![ - MirInstructionV2::Branch { condition: value_gen.next(), then_bb: bb_gen.next(), else_bb: bb_gen.next() }, - MirInstructionV2::Jump { target: bb_gen.next() }, - MirInstructionV2::Return { value: Some(value_gen.next()) }, - MirInstructionV2::TailCall { func: value_gen.next(), args: vec![], effects: EffectMask::PURE }, - ]; - - for inst in control_instructions { - let effects = inst.effects(); - assert!(effects.is_control() || effects.primary_category() == Effect::Control, - "Instruction should be control: {:?}", inst); - } -} - -/// Test optimization safety based on effect categories -#[test] -fn test_optimization_safety() { - let mut value_gen = ValueIdGenerator::new(); - - // Pure operations should be reorderable and eligible for CSE/LICM - let const_inst = MirInstructionV2::Const { dst: value_gen.next(), value: ConstValue::Integer(42) }; - let binop_inst = MirInstructionV2::BinOp { - dst: value_gen.next(), - op: BinaryOp::Add, - lhs: value_gen.next(), - rhs: value_gen.next() - }; - - assert!(const_inst.effects().is_pure(), "Const should be pure and reorderable"); - assert!(binop_inst.effects().is_pure(), "BinOp should be pure and reorderable"); - - // Mut operations should preserve same Box/Field dependencies - let store_inst = MirInstructionV2::BoxFieldStore { - box_val: value_gen.next(), - field: "value".to_string(), - value: value_gen.next() - }; - - assert!(store_inst.effects().is_mut(), "BoxFieldStore should be mut"); - assert!(!store_inst.effects().is_pure(), "Mut operations cannot be reordered freely"); - - // Io operations should not be reordered - let send_inst = MirInstructionV2::Send { - bus: value_gen.next(), - message: value_gen.next() - }; - - assert!(send_inst.effects().is_io(), "Send should be io"); - assert!(!send_inst.effects().is_read_only(), "Io operations have external effects"); -} - -/// Test ownership forest verification -#[test] -fn test_ownership_forest_verification() { - let mut verifier = OwnershipVerifier::new(); - let mut value_gen = ValueIdGenerator::new(); - - // Test basic ownership establishment - let parent = value_gen.next(); - let child = value_gen.next(); - - let adopt_inst = MirInstructionV2::Adopt { parent, child }; - assert!(verifier.process_instruction(&adopt_inst).is_ok(), "Basic adoption should succeed"); - - let stats = verifier.ownership_stats(); - assert_eq!(stats.strong_edges, 1, "Should have one strong edge"); - - // Test forest property verification - assert!(verifier.verify_ownership_forest().is_ok(), "Basic forest should be valid"); - - // Test weak reference creation - let weak_ref = value_gen.next(); - let weak_new_inst = MirInstructionV2::WeakNew { dst: weak_ref, box_val: child }; - assert!(verifier.process_instruction(&weak_new_inst).is_ok(), "Weak reference creation should succeed"); - - let stats_after_weak = verifier.ownership_stats(); - assert_eq!(stats_after_weak.weak_edges, 1, "Should have one weak edge"); - assert_eq!(stats_after_weak.live_weak_refs, 1, "Should have one live weak reference"); -} - -/// Test ownership forest violations -#[test] -fn test_ownership_violations() { - let mut verifier = OwnershipVerifier::new(); - let mut value_gen = ValueIdGenerator::new(); - - // Test unsafe RefSet (changing strong reference without Release) - let reference = value_gen.next(); - let old_target = value_gen.next(); - let new_target = value_gen.next(); - - // Manually set up initial state - verifier.strong_edges.insert(reference, old_target); - - // Try to change reference without releasing old target - let unsafe_ref_set = MirInstructionV2::RefSet { reference, new_target }; - let result = verifier.process_instruction(&unsafe_ref_set); - - assert!(result.is_err(), "Unsafe RefSet should be rejected"); - if let Err(errors) = result { - assert!(errors.iter().any(|e| matches!(e, OwnershipError::UnsafeRefSet { .. })), - "Should detect unsafe RefSet"); - } -} - -/// Test weak reference liveness tracking -#[test] -fn test_weak_reference_liveness() { - let mut verifier = OwnershipVerifier::new(); - let mut value_gen = ValueIdGenerator::new(); - - let target = value_gen.next(); - let weak_ref = value_gen.next(); - - // Create weak reference to target - let weak_new = MirInstructionV2::WeakNew { dst: weak_ref, box_val: target }; - assert!(verifier.process_instruction(&weak_new).is_ok()); - - // Release the target - let release = MirInstructionV2::Release { reference: target }; - assert!(verifier.process_instruction(&release).is_ok()); - - // Check that target is now considered dead - let stats = verifier.ownership_stats(); - assert_eq!(stats.dead_targets, 1, "Target should be marked as dead"); - - // WeakLoad should handle expired reference deterministically - let weak_load = MirInstructionV2::WeakLoad { dst: value_gen.next(), weak_ref }; - assert!(verifier.process_instruction(&weak_load).is_ok(), - "WeakLoad should handle expired reference gracefully"); - - // WeakCheck should also handle expired reference deterministically - let weak_check = MirInstructionV2::WeakCheck { dst: value_gen.next(), weak_ref }; - assert!(verifier.process_instruction(&weak_check).is_ok(), - "WeakCheck should handle expired reference gracefully"); -} - -/// Test Bus communication instructions -#[test] -fn test_bus_operations() { - let mut value_gen = ValueIdGenerator::new(); - - let bus = value_gen.next(); - let message = value_gen.next(); - - // Test Send instruction - let send_inst = MirInstructionV2::Send { bus, message }; - assert_eq!(send_inst.tier(), 1, "Send should be Tier-1"); - assert!(send_inst.effects().is_io(), "Send should have io effects"); - - let used_values = send_inst.used_values(); - assert_eq!(used_values.len(), 2, "Send should use bus and message"); - assert!(used_values.contains(&bus) && used_values.contains(&message)); - - // Test Recv instruction - let recv_inst = MirInstructionV2::Recv { dst: value_gen.next(), bus }; - assert_eq!(recv_inst.tier(), 1, "Recv should be Tier-1"); - assert!(recv_inst.effects().is_io(), "Recv should have io effects"); - - let recv_used = recv_inst.used_values(); - assert_eq!(recv_used.len(), 1, "Recv should use only bus"); - assert!(recv_used.contains(&bus)); -} - -/// Test implementation assistance instructions (Tier-2) -#[test] -fn test_implementation_assistance() { - let mut value_gen = ValueIdGenerator::new(); - - // Test TailCall - let tail_call = MirInstructionV2::TailCall { - func: value_gen.next(), - args: vec![value_gen.next()], - effects: EffectMask::PURE - }; - assert_eq!(tail_call.tier(), 2, "TailCall should be Tier-2"); - assert!(tail_call.effects().is_control(), "TailCall should be control flow"); - - // Test MemCopy - let mem_copy = MirInstructionV2::MemCopy { - dest: value_gen.next(), - src: value_gen.next(), - size: value_gen.next() - }; - assert_eq!(mem_copy.tier(), 2, "MemCopy should be Tier-2"); - assert!(mem_copy.effects().is_mut(), "MemCopy should be mut"); - - // Test AtomicFence - let atomic_fence = MirInstructionV2::AtomicFence { ordering: AtomicOrdering::AcqRel }; - assert_eq!(atomic_fence.tier(), 2, "AtomicFence should be Tier-2"); - assert!(atomic_fence.effects().is_io(), "AtomicFence should be io"); - assert!(atomic_fence.effects().contains(Effect::Barrier), "AtomicFence should have barrier effect"); -} - -/// Test instruction descriptions and display -#[test] -fn test_instruction_descriptions() { - let mut value_gen = ValueIdGenerator::new(); - - let const_inst = MirInstructionV2::Const { dst: value_gen.next(), value: ConstValue::Integer(42) }; - assert_eq!(const_inst.description(), "Load constant value"); - - let send_inst = MirInstructionV2::Send { bus: value_gen.next(), message: value_gen.next() }; - assert_eq!(send_inst.description(), "Send Bus message"); - - let adopt_inst = MirInstructionV2::Adopt { parent: value_gen.next(), child: value_gen.next() }; - assert_eq!(adopt_inst.description(), "Transfer ownership"); - - // Test Display trait - assert_eq!(format!("{}", const_inst), "Load constant value"); - assert_eq!(format!("{}", send_inst), "Send Bus message"); - assert_eq!(format!("{}", adopt_inst), "Transfer ownership"); -} - -/// Test value ID tracking for dependencies -#[test] -fn test_value_id_tracking() { - let mut value_gen = ValueIdGenerator::new(); - - let dst = value_gen.next(); - let lhs = value_gen.next(); - let rhs = value_gen.next(); - - let binop = MirInstructionV2::BinOp { dst, op: BinaryOp::Add, lhs, rhs }; - - // Test destination value - assert_eq!(binop.dst_value(), Some(dst), "BinOp should produce destination value"); - - // Test used values - let used = binop.used_values(); - assert_eq!(used.len(), 2, "BinOp should use two values"); - assert!(used.contains(&lhs) && used.contains(&rhs), "Should use lhs and rhs"); - - // Test instruction with no destination - let store = MirInstructionV2::BoxFieldStore { - box_val: value_gen.next(), - field: "value".to_string(), - value: value_gen.next() - }; - assert_eq!(store.dst_value(), None, "BoxFieldStore should not produce destination value"); -} - -/// Test the complete 25-instruction specification compliance -#[test] -fn test_complete_specification_compliance() { - // This test verifies that our implementation matches the exact specification - - // Verify we can create all 25 instruction types without compilation errors - let mut value_gen = ValueIdGenerator::new(); - let mut bb_gen = BasicBlockIdGenerator::new(); - - let all_instructions = vec![ - // Tier-0: Universal Core (8) - MirInstructionV2::Const { dst: value_gen.next(), value: ConstValue::Integer(42) }, - MirInstructionV2::BinOp { dst: value_gen.next(), op: BinaryOp::Add, lhs: value_gen.next(), rhs: value_gen.next() }, - MirInstructionV2::Compare { dst: value_gen.next(), op: CompareOp::Eq, lhs: value_gen.next(), rhs: value_gen.next() }, - MirInstructionV2::Branch { condition: value_gen.next(), then_bb: bb_gen.next(), else_bb: bb_gen.next() }, - MirInstructionV2::Jump { target: bb_gen.next() }, - MirInstructionV2::Phi { dst: value_gen.next(), inputs: vec![] }, - MirInstructionV2::Call { dst: Some(value_gen.next()), func: value_gen.next(), args: vec![], effects: EffectMask::PURE }, - MirInstructionV2::Return { value: Some(value_gen.next()) }, - - // Tier-1: Nyash Semantics (12) - MirInstructionV2::NewBox { dst: value_gen.next(), box_type: "TestBox".to_string(), args: vec![] }, - MirInstructionV2::BoxFieldLoad { dst: value_gen.next(), box_val: value_gen.next(), field: "field".to_string() }, - MirInstructionV2::BoxFieldStore { box_val: value_gen.next(), field: "field".to_string(), value: value_gen.next() }, - MirInstructionV2::BoxCall { dst: Some(value_gen.next()), box_val: value_gen.next(), method: "method".to_string(), args: vec![], effects: EffectMask::PURE }, - MirInstructionV2::Safepoint, - MirInstructionV2::RefGet { dst: value_gen.next(), reference: value_gen.next() }, - MirInstructionV2::RefSet { reference: value_gen.next(), new_target: value_gen.next() }, - MirInstructionV2::WeakNew { dst: value_gen.next(), box_val: value_gen.next() }, - MirInstructionV2::WeakLoad { dst: value_gen.next(), weak_ref: value_gen.next() }, - MirInstructionV2::WeakCheck { dst: value_gen.next(), weak_ref: value_gen.next() }, - MirInstructionV2::Send { bus: value_gen.next(), message: value_gen.next() }, - MirInstructionV2::Recv { dst: value_gen.next(), bus: value_gen.next() }, - - // Tier-2: Implementation Assistance (5) - MirInstructionV2::TailCall { func: value_gen.next(), args: vec![], effects: EffectMask::PURE }, - MirInstructionV2::Adopt { parent: value_gen.next(), child: value_gen.next() }, - MirInstructionV2::Release { reference: value_gen.next() }, - MirInstructionV2::MemCopy { dest: value_gen.next(), src: value_gen.next(), size: value_gen.next() }, - MirInstructionV2::AtomicFence { ordering: AtomicOrdering::SeqCst }, - ]; - - assert_eq!(all_instructions.len(), 25, "Must have exactly 25 instructions"); - - // Verify tier distribution - let tier0_count = all_instructions.iter().filter(|i| i.tier() == 0).count(); - let tier1_count = all_instructions.iter().filter(|i| i.tier() == 1).count(); - let tier2_count = all_instructions.iter().filter(|i| i.tier() == 2).count(); - - assert_eq!(tier0_count, 8, "Tier-0 should have 8 instructions"); - assert_eq!(tier1_count, 12, "Tier-1 should have 12 instructions"); - assert_eq!(tier2_count, 5, "Tier-2 should have 5 instructions"); - - // Verify each instruction has proper effect classification - for instruction in &all_instructions { - let effects = instruction.effects(); - let category = effects.primary_category(); - - // Ensure every instruction has a valid effect category - assert!( - matches!(category, Effect::Pure | Effect::Mut | Effect::Io | Effect::Control), - "Instruction must have valid effect category: {:?}", instruction - ); - } -} - -/// Performance test: Ensure effect calculations are fast -#[test] -fn test_effect_calculation_performance() { - use std::time::Instant; - - let mut value_gen = ValueIdGenerator::new(); - let mut bb_gen = BasicBlockIdGenerator::new(); - - // Create a large number of instructions - let mut instructions = Vec::new(); - for _ in 0..10000 { - instructions.push(MirInstructionV2::BinOp { - dst: value_gen.next(), - op: BinaryOp::Add, - lhs: value_gen.next(), - rhs: value_gen.next() - }); - } - - // Measure effect calculation time - let start = Instant::now(); - for instruction in &instructions { - let _ = instruction.effects(); - let _ = instruction.tier(); - let _ = instruction.dst_value(); - let _ = instruction.used_values(); - } - let elapsed = start.elapsed(); - - // Should be very fast (< 10ms for 10k instructions) - assert!(elapsed.as_millis() < 100, - "Effect calculations should be fast, took {:?}", elapsed); -}