diff --git a/src/mir/builder/control_flow/plan/lowerer.rs b/src/mir/builder/control_flow/plan/lowerer.rs index c9f36224..5f072352 100644 --- a/src/mir/builder/control_flow/plan/lowerer.rs +++ b/src/mir/builder/control_flow/plan/lowerer.rs @@ -14,7 +14,7 @@ use super::{CoreEffectPlan, CoreLoopPlan, CorePlan}; use crate::mir::builder::control_flow::joinir::patterns::router::LoopPatternContext; use crate::mir::builder::MirBuilder; -use crate::mir::{Effect, EffectMask, MirInstruction, ValueId}; +use crate::mir::{MirInstruction, ValueId}; /// Phase 273 P1: PlanLowerer - CorePlan → MIR 生成 (SSOT) pub(in crate::mir::builder) struct PlanLowerer; @@ -218,14 +218,15 @@ impl PlanLowerer { value: value.clone(), })?; } - CoreEffectPlan::MethodCall { dst, object, method, args } => { + CoreEffectPlan::MethodCall { dst, object, method, args, effects } => { + // P2: dst and effects are now specified by Normalizer builder.emit_instruction(MirInstruction::BoxCall { - dst: Some(*dst), + dst: *dst, box_val: *object, method: method.clone(), method_id: None, args: args.clone(), - effects: EffectMask::PURE.add(Effect::Io), + effects: *effects, })?; } CoreEffectPlan::BinOp { dst, lhs, op, rhs } => { diff --git a/src/mir/builder/control_flow/plan/mod.rs b/src/mir/builder/control_flow/plan/mod.rs index 1b160804..f1024cfe 100644 --- a/src/mir/builder/control_flow/plan/mod.rs +++ b/src/mir/builder/control_flow/plan/mod.rs @@ -24,7 +24,7 @@ //! This prevents "second language processor" from growing inside Lowerer. use crate::ast::ASTNode; -use crate::mir::{BasicBlockId, BinaryOp, CompareOp, ConstValue, ValueId}; +use crate::mir::{BasicBlockId, BinaryOp, CompareOp, ConstValue, EffectMask, ValueId}; pub(in crate::mir::builder) mod lowerer; pub(in crate::mir::builder) mod normalizer; @@ -186,14 +186,21 @@ pub(in crate::mir::builder) struct CoreIfPlan { /// /// Effect vocabulary is minimal (scan-specific variants forbidden): /// - MethodCall, BinOp, Compare, Const only +/// +/// Phase 273 P2: MethodCall now supports: +/// - dst: Option for void methods (e.g., push) +/// - effects: EffectMask for side effects (e.g., MUT for push) #[derive(Debug, Clone)] pub(in crate::mir::builder) enum CoreEffectPlan { /// Method call (args are ValueIds, not Strings!) + /// + /// Phase 273 P2: dst is Option for void methods, effects for side effects MethodCall { - dst: ValueId, + dst: Option, // P2: Option for void methods (push) object: ValueId, - method: String, // Method name only (OK as String) + method: String, // Method name only (OK as String) args: Vec, + effects: EffectMask, // P2: Side effect mask (PURE+Io or MUT) }, /// Binary operation diff --git a/src/mir/builder/control_flow/plan/normalizer.rs b/src/mir/builder/control_flow/plan/normalizer.rs index 3303ce33..6753aea0 100644 --- a/src/mir/builder/control_flow/plan/normalizer.rs +++ b/src/mir/builder/control_flow/plan/normalizer.rs @@ -16,7 +16,7 @@ use super::{ }; use crate::mir::builder::control_flow::joinir::patterns::router::LoopPatternContext; use crate::mir::builder::MirBuilder; -use crate::mir::{BinaryOp, CompareOp, ConstValue, MirType}; +use crate::mir::{BinaryOp, CompareOp, ConstValue, Effect, EffectMask, MirType}; /// Phase 273 P1: PlanNormalizer - DomainPlan → CorePlan 変換 (SSOT) pub(in crate::mir::builder) struct PlanNormalizer; @@ -189,19 +189,21 @@ impl PlanNormalizer { // needle_len = needle.length() if dynamic, else reuse one_val if parts.dynamic_needle { header_effects.push(CoreEffectPlan::MethodCall { - dst: needle_len_val, + dst: Some(needle_len_val), object: needle_host, method: "length".to_string(), args: vec![], + effects: EffectMask::PURE.add(Effect::Io), }); } // len = s.length() header_effects.push(CoreEffectPlan::MethodCall { - dst: len_val, + dst: Some(len_val), object: s_host, method: "length".to_string(), args: vec![], + effects: EffectMask::PURE.add(Effect::Io), }); // bound = len - needle_len @@ -231,10 +233,11 @@ impl PlanNormalizer { }), // window = s.substring(i, i + needle_len) CorePlan::Effect(CoreEffectPlan::MethodCall { - dst: window_val, + dst: Some(window_val), object: s_host, method: "substring".to_string(), args: vec![i_current, i_plus_needle_len], + effects: EffectMask::PURE.add(Effect::Io), }), // cond_match = window == needle CorePlan::Effect(CoreEffectPlan::Compare { diff --git a/src/mir/builder/control_flow/plan/verifier.rs b/src/mir/builder/control_flow/plan/verifier.rs index bca7639b..ee81aa05 100644 --- a/src/mir/builder/control_flow/plan/verifier.rs +++ b/src/mir/builder/control_flow/plan/verifier.rs @@ -142,8 +142,11 @@ impl PlanVerifier { /// V6: Effect ValueId validity fn verify_effect(effect: &CoreEffectPlan, depth: usize) -> Result<(), String> { match effect { - CoreEffectPlan::MethodCall { dst, object, method, args } => { - Self::verify_value_id_basic(*dst, depth, "MethodCall.dst")?; + CoreEffectPlan::MethodCall { dst, object, method, args, effects: _ } => { + // P2: dst is now Option + if let Some(dst_val) = dst { + Self::verify_value_id_basic(*dst_val, depth, "MethodCall.dst")?; + } Self::verify_value_id_basic(*object, depth, "MethodCall.object")?; if method.is_empty() { return Err(format!(