feat(plan): Phase 273 P2 Step 0 - CoreEffectPlan side effect support
Prepare CoreEffectPlan::MethodCall for Pattern7 (split) support: - dst: ValueId → Option<ValueId> (for void methods like push) - effects: EffectMask field added (PURE+Io vs MUT) Changes: - plan/mod.rs: MethodCall struct updated - plan/lowerer.rs: emit_effect() uses dst/effects from plan - plan/normalizer.rs: MethodCall with explicit effects - plan/verifier.rs: Handle Option<ValueId> dst Test: phase258_p0_index_of_string_vm PASS (exit=6) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -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 } => {
|
||||
|
||||
@ -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<ValueId> 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<ValueId>, // 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<ValueId>,
|
||||
effects: EffectMask, // P2: Side effect mask (PURE+Io or MUT)
|
||||
},
|
||||
|
||||
/// Binary operation
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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<ValueId>
|
||||
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!(
|
||||
|
||||
Reference in New Issue
Block a user