refactor(joinir): make Pattern2 body-local handling policy-driven

This commit is contained in:
nyash-codex
2025-12-17 23:00:26 +09:00
parent 10a2f3b48b
commit 09dd10349f
3 changed files with 18 additions and 4 deletions

View File

@ -53,6 +53,12 @@ pub(in crate::mir::builder) struct Pattern2Facts {
pub body_local_env: LoopBodyLocalEnv, pub body_local_env: LoopBodyLocalEnv,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum BodyLocalHandlingPolicy {
DefaultPromotion,
SkipPromotion,
}
pub(in crate::mir::builder) struct Pattern2Inputs { pub(in crate::mir::builder) struct Pattern2Inputs {
pub loop_var_name: String, pub loop_var_name: String,
pub loop_var_id: ValueId, pub loop_var_id: ValueId,
@ -66,6 +72,8 @@ pub(in crate::mir::builder) struct Pattern2Inputs {
/// Phase 92 P3: Allow-list of LoopBodyLocal variable names permitted in conditions. /// Phase 92 P3: Allow-list of LoopBodyLocal variable names permitted in conditions.
/// This must stay minimal (1 variable) and is validated by ReadOnlyBodyLocalSlotBox. /// This must stay minimal (1 variable) and is validated by ReadOnlyBodyLocalSlotBox.
pub allowed_body_locals_for_conditions: Vec<String>, pub allowed_body_locals_for_conditions: Vec<String>,
/// Phase 107: For some policy-routed families, Pattern2 must not run promotion/slot heuristics.
pub body_local_handling: BodyLocalHandlingPolicy,
/// Phase 92 P3: Diagnostics / debug metadata for the allow-listed variable. /// Phase 92 P3: Diagnostics / debug metadata for the allow-listed variable.
pub read_only_body_local_slot: Option<crate::mir::join_ir::lowering::common::body_local_slot::ReadOnlyBodyLocalSlot>, pub read_only_body_local_slot: Option<crate::mir::join_ir::lowering::common::body_local_slot::ReadOnlyBodyLocalSlot>,
/// Policy-routed "break when true" condition node. /// Policy-routed "break when true" condition node.

View File

@ -13,6 +13,7 @@ impl ApplyPolicyStepBox {
pub(crate) fn apply(condition: &ASTNode, body: &[ASTNode], facts: Pattern2Facts) -> Result<Pattern2Inputs, String> { pub(crate) fn apply(condition: &ASTNode, body: &[ASTNode], facts: Pattern2Facts) -> Result<Pattern2Inputs, String> {
use super::super::policies::balanced_depth_scan_policy_box::BalancedDepthScanPolicyBox; use super::super::policies::balanced_depth_scan_policy_box::BalancedDepthScanPolicyBox;
use super::super::policies::PolicyDecision; use super::super::policies::PolicyDecision;
use crate::mir::builder::control_flow::joinir::patterns::pattern2_inputs_facts_box::BodyLocalHandlingPolicy;
use crate::mir::join_ir::lowering::common::body_local_slot::ReadOnlyBodyLocalSlotBox; use crate::mir::join_ir::lowering::common::body_local_slot::ReadOnlyBodyLocalSlotBox;
// Phase 107: balanced depth-scan (return-in-loop) policy. // Phase 107: balanced depth-scan (return-in-loop) policy.
@ -30,6 +31,7 @@ impl ApplyPolicyStepBox {
condition_bindings: facts.condition_bindings, condition_bindings: facts.condition_bindings,
body_local_env: facts.body_local_env, body_local_env: facts.body_local_env,
allowed_body_locals_for_conditions: result.allowed_body_locals_for_conditions, allowed_body_locals_for_conditions: result.allowed_body_locals_for_conditions,
body_local_handling: BodyLocalHandlingPolicy::SkipPromotion,
read_only_body_local_slot: None, read_only_body_local_slot: None,
break_condition_node: result.break_condition_node, break_condition_node: result.break_condition_node,
is_loop_true_read_digits: false, is_loop_true_read_digits: false,
@ -68,6 +70,7 @@ impl ApplyPolicyStepBox {
condition_bindings: facts.condition_bindings, condition_bindings: facts.condition_bindings,
body_local_env: facts.body_local_env, body_local_env: facts.body_local_env,
allowed_body_locals_for_conditions: break_routing.allowed_body_locals_for_conditions, allowed_body_locals_for_conditions: break_routing.allowed_body_locals_for_conditions,
body_local_handling: BodyLocalHandlingPolicy::DefaultPromotion,
read_only_body_local_slot, read_only_body_local_slot,
break_condition_node: break_routing.break_condition_node, break_condition_node: break_routing.break_condition_node,
is_loop_true_read_digits: break_routing.is_loop_true_read_digits, is_loop_true_read_digits: break_routing.is_loop_true_read_digits,

View File

@ -166,10 +166,13 @@ impl PromoteStepBox {
.collect(); .collect();
if cond_scope.has_loop_body_local() { if cond_scope.has_loop_body_local() {
// Phase 107: balanced depth-scan policy already provides an allow-list + derived recipe. // Policy-controlled: some families must not run promotion/slot heuristics here.
// Do not re-run Pattern2 body-local promotion/slot heuristics here (they assume break-guard shapes). // Example: balanced depth-scan uses derived vars and doesn't have a break-guard node.
if inputs.balanced_depth_scan_recipe.is_some() { if matches!(
// no-op: LoopBodyLocalInitLowerer + BalancedDepthScanEmitter will populate the env. inputs.body_local_handling,
crate::mir::builder::control_flow::joinir::patterns::pattern2_inputs_facts_box::BodyLocalHandlingPolicy::SkipPromotion
) {
// no-op: lowerers will populate LoopBodyLocalEnv via init/derived emission.
} else if !inputs.is_loop_true_read_digits { } else if !inputs.is_loop_true_read_digits {
match classify_for_pattern2( match classify_for_pattern2(
builder, builder,