feat(joinir): Phase 64 - Ownership P3 production integration (dev-only)
P3(if-sum) 本番ルートに OwnershipPlan 解析を接続(analysis-only)。 Key changes: - ast_analyzer.rs: Added analyze_loop() helper - Loop-specific analysis API for production integration - build_plan_for_scope() helper for single-scope extraction - pattern3_with_if_phi.rs: P3 production integration - OwnershipPlan analysis after ConditionEnv building - check_ownership_plan_consistency() for validation - Feature-gated #[cfg(feature = "normalized_dev")] Consistency checks: - Fail-Fast: Multi-hop relay (relay_path.len() > 1) - Warn-only: Carrier set mismatch (order SSOT deferred) - Warn-only: Condition captures (some patterns have extras) Tests: 49/49 PASS (2 new Phase 64 tests) - test_phase64_p3_ownership_prod_integration - test_phase64_p3_multihop_relay_detection - Zero regressions Design: Analysis-only, no behavior change - Integration point: After ConditionEnv, before JoinIR lowering - Dev-only validation for future SSOT migration Next: Phase 65+ - Carrier order SSOT, owner-based init 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -142,6 +142,54 @@ impl MirBuilder {
|
||||
);
|
||||
}
|
||||
|
||||
// Phase 64: Ownership analysis (dev-only, analysis-only)
|
||||
#[cfg(feature = "normalized_dev")]
|
||||
{
|
||||
use crate::mir::join_ir::ownership::analyze_loop;
|
||||
|
||||
// Collect parent-defined variables from function scope
|
||||
// For now, use all variables in variable_map except loop_var
|
||||
let parent_defined: Vec<String> = self
|
||||
.variable_map
|
||||
.keys()
|
||||
.filter(|name| *name != &loop_var_name)
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
match analyze_loop(condition, body, &parent_defined) {
|
||||
Ok(plan) => {
|
||||
// Convert ConditionBinding Vec to BTreeSet<String> for consistency check
|
||||
let condition_binding_names: std::collections::BTreeSet<String> =
|
||||
condition_bindings.iter().map(|b| b.name.clone()).collect();
|
||||
|
||||
// Run consistency checks
|
||||
if let Err(e) =
|
||||
check_ownership_plan_consistency(&plan, &ctx.carrier_info, &condition_binding_names)
|
||||
{
|
||||
eprintln!("[phase64/ownership] Consistency check failed: {}", e);
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
trace::trace().debug(
|
||||
"pattern3/if-sum",
|
||||
&format!(
|
||||
"OwnershipPlan analysis succeeded: {} owned vars, {} relay writes, {} captures",
|
||||
plan.owned_vars.len(),
|
||||
plan.relay_writes.len(),
|
||||
plan.captures.len()
|
||||
),
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"[phase64/ownership] Analysis failed (continuing with legacy): {}",
|
||||
e
|
||||
);
|
||||
// Don't fail - analysis is optional in Phase 64
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call AST-based if-sum lowerer with ConditionEnv
|
||||
let (join_module, fragment_meta) =
|
||||
lower_if_sum_pattern(condition, if_stmt, body, &cond_env, &mut join_value_space)?;
|
||||
@ -250,3 +298,73 @@ impl MirBuilder {
|
||||
|
||||
// Phase 242-EX-A: lower_pattern3_legacy removed - all patterns now use AST-based lowering
|
||||
}
|
||||
|
||||
/// Phase 64: Ownership plan consistency checks (dev-only)
|
||||
///
|
||||
/// Validates OwnershipPlan against existing CarrierInfo and ConditionBindings.
|
||||
/// This is analysis-only - no behavior change.
|
||||
///
|
||||
/// # Checks
|
||||
///
|
||||
/// 1. **Multi-hop relay rejection**: `relay_path.len() > 1` → Err (out of scope)
|
||||
/// 2. **Carrier set consistency**: plan carriers vs existing carriers (warn-only)
|
||||
/// 3. **Condition captures consistency**: plan captures vs condition bindings (warn-only)
|
||||
#[cfg(feature = "normalized_dev")]
|
||||
fn check_ownership_plan_consistency(
|
||||
plan: &crate::mir::join_ir::ownership::OwnershipPlan,
|
||||
carrier_info: &crate::mir::join_ir::lowering::carrier_info::CarrierInfo,
|
||||
condition_bindings: &std::collections::BTreeSet<String>,
|
||||
) -> Result<(), String> {
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
// Check 1: Multi-hop relay is rejected (Fail-Fast)
|
||||
for relay in &plan.relay_writes {
|
||||
if relay.relay_path.len() > 1 {
|
||||
return Err(format!(
|
||||
"Phase 64 limitation: multi-hop relay not supported. Variable '{}' has relay path length {}",
|
||||
relay.name, relay.relay_path.len()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Check 2: Carrier set consistency (warn-only, order SSOT deferred)
|
||||
let plan_carriers: BTreeSet<String> = plan
|
||||
.owned_vars
|
||||
.iter()
|
||||
.filter(|v| v.is_written)
|
||||
.map(|v| v.name.clone())
|
||||
.collect();
|
||||
|
||||
let existing_carriers: BTreeSet<String> = carrier_info
|
||||
.carriers
|
||||
.iter()
|
||||
.map(|c| c.name.clone())
|
||||
.collect();
|
||||
|
||||
if plan_carriers != existing_carriers {
|
||||
eprintln!("[phase64/ownership] Carrier set mismatch (warn-only, order SSOT deferred):");
|
||||
eprintln!(" OwnershipPlan carriers: {:?}", plan_carriers);
|
||||
eprintln!(" Existing carriers: {:?}", existing_carriers);
|
||||
// Don't fail - just warn (order SSOT not yet implemented)
|
||||
}
|
||||
|
||||
// Check 3: Condition captures consistency (warn-only)
|
||||
let plan_cond_captures: BTreeSet<String> = plan
|
||||
.condition_captures
|
||||
.iter()
|
||||
.map(|c| c.name.clone())
|
||||
.collect();
|
||||
|
||||
if !plan_cond_captures.is_subset(condition_bindings) {
|
||||
let extra: Vec<_> = plan_cond_captures
|
||||
.difference(condition_bindings)
|
||||
.collect();
|
||||
eprintln!(
|
||||
"[phase64/ownership] Extra condition captures in plan (warn-only): {:?}",
|
||||
extra
|
||||
);
|
||||
// Warn only - this might be expected in some cases
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user