feat(joinir): Phase 92完了 - ConditionalStep + body-local変数サポート
## Phase 92全体の成果 **Phase 92 P0-P2**: ConditionalStep JoinIR生成とbody-local変数サポート - ConditionalStep(条件付きキャリア更新)のJoinIR生成実装 - Body-local変数(ch等)の条件式での参照サポート - 変数解決優先度: ConditionEnv → LoopBodyLocalEnv **Phase 92 P3**: BodyLocalPolicyBox + 安全ガード - BodyLocalPolicyDecision実装(Accept/Reject判定) - BodyLocalSlot + DualValueRewriter(JoinIR/MIR二重書き込み) - Fail-Fast契約(Cannot promote LoopBodyLocal検出) **Phase 92 P4**: E2E固定+回帰最小化 (本コミット) - Unit test 3本追加(body-local変数解決検証) - Integration smoke追加(phase92_pattern2_baseline.sh、2ケースPASS) - P4-E2E-PLAN.md、P4-COMPLETION.md作成 ## 主要な実装 ### ConditionalStep(条件付きキャリア更新) - `conditional_step_emitter.rs`: JoinIR Select命令生成 - `loop_with_break_minimal.rs`: ConditionalStep検出と統合 - `loop_with_continue_minimal.rs`: Pattern4対応 ### Body-local変数サポート - `condition_lowerer.rs`: body-local変数解決機能 - `lower_condition_to_joinir`: body_local_env パラメータ追加 - 変数解決優先度実装(ConditionEnv優先) - Unit test 3本追加: 変数解決/優先度/エラー - `header_break_lowering.rs`: break条件でbody-local変数参照 - 7ファイルで後方互換ラッパー(lower_condition_to_joinir_no_body_locals) ### Body-local Policy & Safety - `body_local_policy.rs`: BodyLocalPolicyDecision(Accept/Reject) - `body_local_slot.rs`: JoinIR/MIR二重書き込み - `dual_value_rewriter.rs`: ValueId書き換えヘルパー ## テスト体制 ### Unit Tests (+3) - `test_body_local_variable_resolution`: body-local変数解決 - `test_variable_resolution_priority`: 変数解決優先度(ConditionEnv優先) - `test_undefined_variable_error`: 未定義変数エラー - 全7テストPASS(cargo test --release condition_lowerer::tests) ### Integration Smoke (+1) - `phase92_pattern2_baseline.sh`: - Case A: loop_min_while.hako (Pattern2 baseline) - Case B: phase92_conditional_step_minimal.hako (条件付きインクリメント) - 両ケースPASS、integration profileで発見可能 ### 退行確認 - ✅ 既存Pattern2Breakテスト正常(退行なし) - ✅ Phase 135 smoke正常(MIR検証PASS) ## アーキテクチャ設計 ### 変数解決メカニズム ```rust // Priority 1: ConditionEnv (loop params, captured) if let Some(value_id) = env.get(name) { return Ok(value_id); } // Priority 2: LoopBodyLocalEnv (body-local like `ch`) if let Some(body_env) = body_local_env { if let Some(value_id) = body_env.get(name) { return Ok(value_id); } } ``` ### Fail-Fast契約 - Delta equality check (conditional_step_emitter.rs) - Variable resolution error messages (ConditionEnv) - Body-local promotion rejection (BodyLocalPolicyDecision::Reject) ## ドキュメント - `P4-E2E-PLAN.md`: 3レベルテスト戦略(Level 1-2完了、Level 3延期) - `P4-COMPLETION.md`: Phase 92完了報告 - `README.md`: Phase 92全体のまとめ ## 将来の拡張(Phase 92スコープ外) - Body-local promotionシステム拡張 - P5bパターン認識の汎化(flagベース条件サポート) - 完全なP5b E2Eテスト(body-local promotion実装後) 🎯 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -0,0 +1,92 @@
|
||||
//! Phase 92 P3: BodyLocal policy routing (Box)
|
||||
//!
|
||||
//! Purpose: make the "promotion vs read-only slot vs reject" decision explicit,
|
||||
//! so Pattern2 code does not look like it "falls back" after failure.
|
||||
|
||||
use crate::ast::ASTNode;
|
||||
use crate::mir::builder::MirBuilder;
|
||||
use crate::mir::join_ir::lowering::carrier_info::CarrierInfo;
|
||||
use crate::mir::join_ir::lowering::common::body_local_slot::{
|
||||
ReadOnlyBodyLocalSlot, ReadOnlyBodyLocalSlotBox,
|
||||
};
|
||||
use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape;
|
||||
use crate::mir::loop_pattern_detection::loop_body_cond_promoter::{
|
||||
ConditionPromotionRequest, ConditionPromotionResult, LoopBodyCondPromoter,
|
||||
};
|
||||
use crate::mir::loop_pattern_detection::loop_condition_scope::{CondVarScope, LoopConditionScope};
|
||||
|
||||
/// Explicit routing policy for LoopBodyLocal variables used in Pattern2 conditions.
|
||||
///
|
||||
/// This is a "route" decision (not a fallback): we choose exactly one of the supported
|
||||
/// strategies and reject otherwise.
|
||||
pub enum BodyLocalPolicyDecision {
|
||||
UsePromotion {
|
||||
promoted_carrier: CarrierInfo,
|
||||
promoted_var: String,
|
||||
carrier_name: String,
|
||||
},
|
||||
UseReadOnlySlot(ReadOnlyBodyLocalSlot),
|
||||
Reject { reason: String, vars: Vec<String> },
|
||||
}
|
||||
|
||||
pub fn classify_for_pattern2(
|
||||
_builder: &MirBuilder,
|
||||
loop_var_name: &str,
|
||||
scope: &LoopScopeShape,
|
||||
break_condition_node: &ASTNode,
|
||||
cond_scope: &LoopConditionScope,
|
||||
body: &[ASTNode],
|
||||
) -> BodyLocalPolicyDecision {
|
||||
let vars: Vec<String> = cond_scope
|
||||
.vars
|
||||
.iter()
|
||||
.filter(|v| v.scope == CondVarScope::LoopBodyLocal)
|
||||
.map(|v| v.name.clone())
|
||||
.collect();
|
||||
|
||||
let promotion_req = ConditionPromotionRequest {
|
||||
loop_param_name: loop_var_name,
|
||||
cond_scope,
|
||||
scope_shape: Some(scope),
|
||||
break_cond: Some(break_condition_node),
|
||||
continue_cond: None,
|
||||
loop_body: body,
|
||||
#[cfg(feature = "normalized_dev")]
|
||||
binding_map: Some(&_builder.binding_map),
|
||||
};
|
||||
|
||||
match LoopBodyCondPromoter::try_promote_for_condition(promotion_req) {
|
||||
ConditionPromotionResult::Promoted {
|
||||
carrier_info: promoted_carrier,
|
||||
promoted_var,
|
||||
carrier_name,
|
||||
} => BodyLocalPolicyDecision::UsePromotion {
|
||||
promoted_carrier,
|
||||
promoted_var,
|
||||
carrier_name,
|
||||
},
|
||||
ConditionPromotionResult::CannotPromote { reason, .. } => {
|
||||
match extract_body_local_inits_for_conditions(&vars, body) {
|
||||
Ok(Some(slot)) => BodyLocalPolicyDecision::UseReadOnlySlot(slot),
|
||||
Ok(None) => BodyLocalPolicyDecision::Reject { reason, vars },
|
||||
Err(slot_err) => BodyLocalPolicyDecision::Reject {
|
||||
reason: format!("{reason}; read-only-slot rejected: {slot_err}"),
|
||||
vars,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_body_local_inits_for_conditions(
|
||||
body_local_names_in_conditions: &[String],
|
||||
body: &[ASTNode],
|
||||
) -> Result<Option<ReadOnlyBodyLocalSlot>, String> {
|
||||
if body_local_names_in_conditions.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
Ok(Some(ReadOnlyBodyLocalSlotBox::extract_single(
|
||||
body_local_names_in_conditions,
|
||||
body,
|
||||
)?))
|
||||
}
|
||||
@ -200,7 +200,10 @@ impl CommonPatternInitializer {
|
||||
}
|
||||
UpdateRhs::Other => {
|
||||
// Phase 188: Complex update (method call, nested BinOp) - reject
|
||||
eprintln!("[common_init/check_carriers] Phase 188: Complex update detected (UpdateRhs::Other), rejecting pattern");
|
||||
crate::mir::builder::control_flow::joinir::trace::trace().dev(
|
||||
"common_init/check_carriers",
|
||||
"Phase 188: Complex update detected (UpdateRhs::Other), rejecting pattern",
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,16 +175,14 @@ impl ConditionEnvBuilder {
|
||||
variable_map: &BTreeMap<String, ValueId>,
|
||||
space: &mut JoinValueSpace,
|
||||
) -> (ConditionEnv, ValueId) {
|
||||
use std::env;
|
||||
|
||||
let debug = env::var("NYASH_CAPTURE_DEBUG").is_ok();
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[capture/env_builder] Building ConditionEnv with {} captured vars",
|
||||
let trace = crate::mir::builder::control_flow::joinir::trace::trace();
|
||||
trace.capture(
|
||||
"env_builder",
|
||||
&format!(
|
||||
"Building ConditionEnv with {} captured vars",
|
||||
captured.vars.len()
|
||||
);
|
||||
}
|
||||
),
|
||||
);
|
||||
|
||||
// Step 1: Build base ConditionEnv with loop params using v2 API (Phase 222.5-B)
|
||||
let (mut env, loop_var_join_id) = Self::build_loop_param_only_v2(loop_var_name, space);
|
||||
@ -195,9 +193,13 @@ impl ConditionEnvBuilder {
|
||||
let host_id = match variable_map.get(&var.name) {
|
||||
Some(&id) => id,
|
||||
None => {
|
||||
if debug {
|
||||
eprintln!("[capture/env_builder] WARNING: Captured var '{}' not found in variable_map, skipping", var.name);
|
||||
}
|
||||
trace.capture(
|
||||
"env_builder",
|
||||
&format!(
|
||||
"WARNING: Captured var '{}' not found in variable_map, skipping",
|
||||
var.name
|
||||
),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
@ -217,12 +219,13 @@ impl ConditionEnvBuilder {
|
||||
// 2d: Add to ConditionEnv.captured map
|
||||
env.captured.insert(var.name.clone(), join_id);
|
||||
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[capture/env_builder] Added captured var '{}': host={:?}, join={:?}",
|
||||
trace.capture(
|
||||
"env_builder",
|
||||
&format!(
|
||||
"Added captured var '{}': host={:?}, join={:?}",
|
||||
var.name, host_id, join_id
|
||||
);
|
||||
}
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Step 3: Debug guard - Condition params must NOT be in PHI candidates
|
||||
@ -236,14 +239,15 @@ impl ConditionEnvBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
if debug {
|
||||
let param_count = env.iter().count();
|
||||
eprintln!(
|
||||
"[capture/env_builder] Final ConditionEnv: {} params, {} captured",
|
||||
let param_count = env.iter().count();
|
||||
trace.capture(
|
||||
"env_builder",
|
||||
&format!(
|
||||
"Final ConditionEnv: {} params, {} captured",
|
||||
param_count,
|
||||
env.captured.len()
|
||||
);
|
||||
}
|
||||
),
|
||||
);
|
||||
|
||||
(env, loop_var_join_id)
|
||||
}
|
||||
|
||||
@ -46,6 +46,7 @@
|
||||
//! - Extracted from ast_feature_extractor for improved modularity
|
||||
|
||||
pub(in crate::mir::builder) mod ast_feature_extractor;
|
||||
pub(in crate::mir::builder) mod body_local_policy; // Phase 92 P3: promotion vs slot routing
|
||||
pub(in crate::mir::builder) mod escape_pattern_recognizer; // Phase 91 P5b
|
||||
pub(in crate::mir::builder) mod common_init;
|
||||
pub(in crate::mir::builder) mod condition_env_builder;
|
||||
|
||||
@ -5,18 +5,36 @@ use crate::ast::ASTNode;
|
||||
use crate::mir::builder::MirBuilder;
|
||||
use crate::mir::join_ir::lowering::carrier_info::{CarrierInfo, CarrierInit};
|
||||
use crate::mir::join_ir::lowering::condition_env::{ConditionBinding, ConditionEnv};
|
||||
use super::body_local_policy::{classify_for_pattern2, BodyLocalPolicyDecision};
|
||||
use crate::mir::join_ir::lowering::common::body_local_slot::ReadOnlyBodyLocalSlot;
|
||||
use crate::mir::join_ir::lowering::debug_output_box::DebugOutputBox;
|
||||
use crate::mir::join_ir::lowering::join_value_space::JoinValueSpace;
|
||||
use crate::mir::join_ir::lowering::loop_body_local_env::LoopBodyLocalEnv;
|
||||
use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape;
|
||||
use crate::mir::join_ir::lowering::loop_with_break_minimal::LoopWithBreakLoweringInputs;
|
||||
use crate::mir::join_ir::lowering::loop_update_analyzer::UpdateExpr;
|
||||
use crate::mir::loop_pattern_detection::error_messages;
|
||||
use crate::mir::loop_pattern_detection::function_scope_capture::CapturedEnv;
|
||||
use crate::mir::ValueId;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
fn log_pattern2(verbose: bool, tag: &str, message: impl AsRef<str>) {
|
||||
if verbose {
|
||||
eprintln!("[joinir/pattern2/{tag}] {}", message.as_ref());
|
||||
struct Pattern2DebugLog {
|
||||
verbose: bool,
|
||||
debug: DebugOutputBox,
|
||||
}
|
||||
|
||||
impl Pattern2DebugLog {
|
||||
fn new(verbose: bool) -> Self {
|
||||
Self {
|
||||
verbose,
|
||||
debug: DebugOutputBox::new_with_enabled("joinir/pattern2", verbose),
|
||||
}
|
||||
}
|
||||
|
||||
fn log(&self, tag: &str, message: impl AsRef<str>) {
|
||||
if self.verbose {
|
||||
self.debug.log(tag, message.as_ref());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,6 +48,11 @@ struct Pattern2Inputs {
|
||||
env: ConditionEnv,
|
||||
condition_bindings: Vec<ConditionBinding>,
|
||||
body_local_env: LoopBodyLocalEnv,
|
||||
/// Phase 92 P3: Allow-list of LoopBodyLocal variable names permitted in conditions.
|
||||
/// This must stay minimal (1 variable) and is validated by ReadOnlyBodyLocalSlotBox.
|
||||
allowed_body_locals_for_conditions: Vec<String>,
|
||||
/// Phase 92 P3: Diagnostics / debug metadata for the allow-listed variable.
|
||||
read_only_body_local_slot: Option<ReadOnlyBodyLocalSlot>,
|
||||
break_condition_node: ASTNode,
|
||||
}
|
||||
|
||||
@ -41,6 +64,7 @@ fn prepare_pattern2_inputs(
|
||||
ctx: &super::pattern_pipeline::PatternPipelineContext,
|
||||
verbose: bool,
|
||||
) -> Result<Pattern2Inputs, String> {
|
||||
let log = Pattern2DebugLog::new(verbose);
|
||||
use super::condition_env_builder::ConditionEnvBuilder;
|
||||
use crate::mir::loop_pattern_detection::function_scope_capture::{
|
||||
analyze_captured_vars_v2, CapturedEnv,
|
||||
@ -51,8 +75,7 @@ fn prepare_pattern2_inputs(
|
||||
let carrier_info = ctx.carrier_info.clone();
|
||||
let scope = ctx.loop_scope.clone();
|
||||
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"init",
|
||||
format!(
|
||||
"PatternPipelineContext: loop_var='{}', loop_var_id={:?}, carriers={}",
|
||||
@ -63,8 +86,7 @@ fn prepare_pattern2_inputs(
|
||||
);
|
||||
|
||||
// Capture analysis
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"phase200c",
|
||||
format!(
|
||||
"fn_body is {}",
|
||||
@ -72,23 +94,20 @@ fn prepare_pattern2_inputs(
|
||||
),
|
||||
);
|
||||
let captured_env = if let Some(fn_body_ref) = fn_body {
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"phase200c",
|
||||
format!("fn_body has {} nodes", fn_body_ref.len()),
|
||||
);
|
||||
analyze_captured_vars_v2(fn_body_ref, condition, body, &scope)
|
||||
} else {
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"phase200c",
|
||||
"fn_body is None, using empty CapturedEnv",
|
||||
);
|
||||
CapturedEnv::new()
|
||||
};
|
||||
if verbose {
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"capture",
|
||||
format!(
|
||||
"Phase 200-C: Captured {} variables",
|
||||
@ -96,8 +115,7 @@ fn prepare_pattern2_inputs(
|
||||
),
|
||||
);
|
||||
for var in &captured_env.vars {
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"capture",
|
||||
format!(
|
||||
" '{}': host_id={:?}, immutable={}",
|
||||
@ -123,8 +141,7 @@ fn prepare_pattern2_inputs(
|
||||
// Phase 136 Step 4/7: Use binding_ctx for lookup
|
||||
if let Some(loop_var_bid) = builder.binding_ctx.lookup(&loop_var_name) {
|
||||
env.register_loop_var_binding(loop_var_bid, _loop_var_join_id);
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"phase79",
|
||||
format!(
|
||||
"Registered loop var BindingId: '{}' BindingId({}) → ValueId({})",
|
||||
@ -133,8 +150,7 @@ fn prepare_pattern2_inputs(
|
||||
);
|
||||
}
|
||||
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"phase201",
|
||||
format!(
|
||||
"Using JoinValueSpace: loop_var '{}' → {:?}",
|
||||
@ -153,8 +169,7 @@ fn prepare_pattern2_inputs(
|
||||
host_value: host_id,
|
||||
join_value: join_id,
|
||||
});
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"capture",
|
||||
format!(
|
||||
"Phase 201: Added captured '{}': host={:?}, join={:?}",
|
||||
@ -165,8 +180,7 @@ fn prepare_pattern2_inputs(
|
||||
}
|
||||
|
||||
let body_local_env = LoopBodyLocalEnv::new();
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"body-local",
|
||||
format!(
|
||||
"Phase 201: Created empty body-local environment (param_count={})",
|
||||
@ -174,13 +188,11 @@ fn prepare_pattern2_inputs(
|
||||
),
|
||||
);
|
||||
if verbose {
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"cond-env",
|
||||
format!("Phase 201: ConditionEnv contains {} variables:", env.len()),
|
||||
);
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"cond-env",
|
||||
format!(
|
||||
" Loop param '{}' → JoinIR {:?}",
|
||||
@ -189,14 +201,12 @@ fn prepare_pattern2_inputs(
|
||||
),
|
||||
);
|
||||
if !condition_bindings.is_empty() {
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"cond-env",
|
||||
format!(" {} condition-only bindings:", condition_bindings.len()),
|
||||
);
|
||||
for binding in &condition_bindings {
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"cond-env",
|
||||
format!(
|
||||
" '{}': HOST {:?} → JoinIR {:?}",
|
||||
@ -205,7 +215,7 @@ fn prepare_pattern2_inputs(
|
||||
);
|
||||
}
|
||||
} else {
|
||||
log_pattern2(verbose, "cond-env", " No condition-only variables");
|
||||
log.log("cond-env", " No condition-only variables");
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,6 +248,8 @@ fn prepare_pattern2_inputs(
|
||||
env,
|
||||
condition_bindings,
|
||||
body_local_env,
|
||||
allowed_body_locals_for_conditions: Vec::new(),
|
||||
read_only_body_local_slot: None,
|
||||
break_condition_node,
|
||||
})
|
||||
}
|
||||
@ -251,9 +263,6 @@ fn promote_and_prepare_carriers(
|
||||
verbose: bool,
|
||||
) -> Result<(), String> {
|
||||
use crate::mir::join_ir::lowering::digitpos_condition_normalizer::DigitPosConditionNormalizer;
|
||||
use crate::mir::loop_pattern_detection::loop_body_cond_promoter::{
|
||||
ConditionPromotionRequest, ConditionPromotionResult, LoopBodyCondPromoter,
|
||||
};
|
||||
use crate::mir::loop_pattern_detection::loop_condition_scope::LoopConditionScopeBox;
|
||||
|
||||
let cond_scope = LoopConditionScopeBox::analyze(
|
||||
@ -262,23 +271,20 @@ fn promote_and_prepare_carriers(
|
||||
Some(&inputs.scope),
|
||||
);
|
||||
|
||||
let log = Pattern2DebugLog::new(verbose);
|
||||
let mut promoted_pairs: Vec<(String, String)> = Vec::new();
|
||||
|
||||
if cond_scope.has_loop_body_local() {
|
||||
let promotion_req = ConditionPromotionRequest {
|
||||
loop_param_name: &inputs.loop_var_name,
|
||||
cond_scope: &cond_scope,
|
||||
scope_shape: Some(&inputs.scope),
|
||||
break_cond: Some(&inputs.break_condition_node),
|
||||
continue_cond: None,
|
||||
loop_body: body,
|
||||
#[cfg(feature = "normalized_dev")]
|
||||
binding_map: Some(&builder.binding_map),
|
||||
};
|
||||
|
||||
match LoopBodyCondPromoter::try_promote_for_condition(promotion_req) {
|
||||
ConditionPromotionResult::Promoted {
|
||||
carrier_info: promoted_carrier,
|
||||
match classify_for_pattern2(
|
||||
builder,
|
||||
&inputs.loop_var_name,
|
||||
&inputs.scope,
|
||||
&inputs.break_condition_node,
|
||||
&cond_scope,
|
||||
body,
|
||||
) {
|
||||
BodyLocalPolicyDecision::UsePromotion {
|
||||
promoted_carrier,
|
||||
promoted_var,
|
||||
carrier_name,
|
||||
} => {
|
||||
@ -312,8 +318,7 @@ fn promote_and_prepare_carriers(
|
||||
inputs.carrier_info.merge_from(&promoted_carrier);
|
||||
}
|
||||
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"cond_promoter",
|
||||
format!(
|
||||
"LoopBodyLocal '{}' promoted to carrier '{}'",
|
||||
@ -326,8 +331,7 @@ fn promote_and_prepare_carriers(
|
||||
.promoted_loopbodylocals
|
||||
.push(promoted_var.clone());
|
||||
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"cond_promoter",
|
||||
format!(
|
||||
"Merged carrier '{}' into CarrierInfo (total carriers: {})",
|
||||
@ -335,8 +339,7 @@ fn promote_and_prepare_carriers(
|
||||
inputs.carrier_info.carrier_count()
|
||||
),
|
||||
);
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"cond_promoter",
|
||||
format!(
|
||||
"Phase 224: Recorded promoted variable '{}' in carrier_info.promoted_loopbodylocals",
|
||||
@ -346,17 +349,15 @@ fn promote_and_prepare_carriers(
|
||||
|
||||
if let Some(helper) = inputs.carrier_info.trim_helper() {
|
||||
if helper.is_safe_trim() {
|
||||
log_pattern2(verbose, "cond_promoter", "Safe Trim pattern detected");
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log("cond_promoter", "Safe Trim pattern detected");
|
||||
log.log(
|
||||
"cond_promoter",
|
||||
format!(
|
||||
"Carrier: '{}', original var: '{}', whitespace chars: {:?}",
|
||||
helper.carrier_name, helper.original_var, helper.whitespace_chars
|
||||
),
|
||||
);
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"phase133",
|
||||
format!(
|
||||
"Phase 133 P1: Trim promotion deferred to TrimLoopLowerer (SSOT for env/join_id)"
|
||||
@ -379,8 +380,7 @@ fn promote_and_prepare_carriers(
|
||||
&carrier_name,
|
||||
);
|
||||
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"phase224e",
|
||||
format!(
|
||||
"Normalized break condition for promoted variable '{}' → carrier '{}'",
|
||||
@ -389,7 +389,18 @@ fn promote_and_prepare_carriers(
|
||||
);
|
||||
}
|
||||
}
|
||||
ConditionPromotionResult::CannotPromote { reason, vars } => {
|
||||
BodyLocalPolicyDecision::UseReadOnlySlot(slot) => {
|
||||
log.log(
|
||||
"body_local_slot",
|
||||
format!(
|
||||
"Phase 92 P3: BodyLocalPolicy=UseReadOnlySlot var='{}' (decl@{}, break_if@{}, init={:?})",
|
||||
slot.name, slot.decl_stmt_index, slot.break_guard_stmt_index, &slot.init_expr
|
||||
),
|
||||
);
|
||||
inputs.allowed_body_locals_for_conditions = vec![slot.name.clone()];
|
||||
inputs.read_only_body_local_slot = Some(slot);
|
||||
}
|
||||
BodyLocalPolicyDecision::Reject { reason, vars } => {
|
||||
return Err(error_messages::format_error_pattern2_promotion_failed(
|
||||
&vars, &reason,
|
||||
));
|
||||
@ -397,8 +408,7 @@ fn promote_and_prepare_carriers(
|
||||
}
|
||||
}
|
||||
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"phase224d",
|
||||
format!(
|
||||
"Allocating join_ids for {} carriers",
|
||||
@ -417,8 +427,7 @@ fn promote_and_prepare_carriers(
|
||||
inputs
|
||||
.env
|
||||
.register_condition_binding(binding_id, carrier_join_id);
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"phase79",
|
||||
format!(
|
||||
"Registered condition-only carrier '{}' BindingId({}) → ValueId({})",
|
||||
@ -430,8 +439,7 @@ fn promote_and_prepare_carriers(
|
||||
inputs
|
||||
.env
|
||||
.register_carrier_binding(binding_id, carrier_join_id);
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"phase79",
|
||||
format!(
|
||||
"Registered loop-state carrier '{}' BindingId({}) → ValueId({})",
|
||||
@ -441,8 +449,7 @@ fn promote_and_prepare_carriers(
|
||||
}
|
||||
}
|
||||
}
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"phase224d",
|
||||
format!(
|
||||
"Allocated carrier '{}' param ID: {:?}",
|
||||
@ -463,8 +470,7 @@ fn promote_and_prepare_carriers(
|
||||
)
|
||||
})?;
|
||||
inputs.env.insert(promoted_var.clone(), join_id);
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"phase229",
|
||||
format!(
|
||||
"Resolved promoted '{}' → carrier '{}' (join_id={:?})",
|
||||
@ -492,25 +498,13 @@ fn promote_and_prepare_carriers(
|
||||
.lower(&inputs.break_condition_node)
|
||||
{
|
||||
Ok(_value_id) => {
|
||||
log_pattern2(
|
||||
verbose,
|
||||
"phase231",
|
||||
"ExprLowerer successfully validated break condition",
|
||||
);
|
||||
log.log("phase231", "ExprLowerer successfully validated break condition");
|
||||
}
|
||||
Err(ExprLoweringError::UnsupportedNode(msg)) => {
|
||||
log_pattern2(
|
||||
verbose,
|
||||
"phase231",
|
||||
format!("ExprLowerer fallback (unsupported): {}", msg),
|
||||
);
|
||||
log.log("phase231", format!("ExprLowerer fallback (unsupported): {}", msg));
|
||||
}
|
||||
Err(e) => {
|
||||
log_pattern2(
|
||||
verbose,
|
||||
"phase231",
|
||||
format!("ExprLowerer validation error: {}", e),
|
||||
);
|
||||
log.log("phase231", format!("ExprLowerer validation error: {}", e));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -525,6 +519,7 @@ fn apply_trim_and_normalize(
|
||||
inputs: &mut Pattern2Inputs,
|
||||
verbose: bool,
|
||||
) -> Result<(ASTNode, Option<Vec<ASTNode>>), String> {
|
||||
let log = Pattern2DebugLog::new(verbose);
|
||||
let mut alloc_join_value = || inputs.join_value_space.alloc_param();
|
||||
|
||||
let effective_break_condition = if let Some(trim_result) =
|
||||
@ -538,11 +533,7 @@ fn apply_trim_and_normalize(
|
||||
&mut inputs.carrier_info,
|
||||
&mut alloc_join_value,
|
||||
)? {
|
||||
log_pattern2(
|
||||
verbose,
|
||||
"trim",
|
||||
"TrimLoopLowerer processed Trim pattern successfully",
|
||||
);
|
||||
log.log("trim", "TrimLoopLowerer processed Trim pattern successfully");
|
||||
inputs.carrier_info = trim_result.carrier_info;
|
||||
inputs
|
||||
.condition_bindings
|
||||
@ -550,8 +541,7 @@ fn apply_trim_and_normalize(
|
||||
for binding in &trim_result.condition_bindings {
|
||||
inputs.env.insert(binding.name.clone(), binding.join_value);
|
||||
}
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"trim",
|
||||
format!(
|
||||
"Extended condition_bindings with {} Trim bindings",
|
||||
@ -577,8 +567,7 @@ fn apply_trim_and_normalize(
|
||||
new_assign,
|
||||
temp_name,
|
||||
} => {
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"phase192",
|
||||
format!(
|
||||
"Normalized complex addend: temp='{}' inserted before update",
|
||||
@ -625,17 +614,14 @@ fn collect_body_local_variables(
|
||||
) -> Vec<(String, ValueId)> {
|
||||
let mut locals = Vec::new();
|
||||
let verbose = crate::config::env::joinir_dev_enabled();
|
||||
let log = Pattern2DebugLog::new(verbose);
|
||||
for node in body {
|
||||
if let ASTNode::Local { variables, .. } = node {
|
||||
// Local declaration can have multiple variables (e.g., local a, b, c)
|
||||
for name in variables {
|
||||
let value_id = alloc_join_value();
|
||||
locals.push((name.clone(), value_id));
|
||||
log_pattern2(
|
||||
verbose,
|
||||
"body-local",
|
||||
format!("Collected local '{}' → {:?}", name, value_id),
|
||||
);
|
||||
log.log("body-local", format!("Collected local '{}' → {:?}", name, value_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -791,6 +777,7 @@ impl MirBuilder {
|
||||
use crate::mir::join_ir::lowering::loop_with_break_minimal::lower_loop_with_break_minimal;
|
||||
|
||||
let verbose = debug || crate::config::env::joinir_dev_enabled();
|
||||
let log = Pattern2DebugLog::new(verbose);
|
||||
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().debug("pattern2", "Calling Pattern 2 minimal lowerer");
|
||||
@ -814,8 +801,7 @@ impl MirBuilder {
|
||||
&inputs.carrier_info.carriers,
|
||||
);
|
||||
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"updates",
|
||||
format!(
|
||||
"Phase 176-3: Analyzed {} carrier updates",
|
||||
@ -826,8 +812,7 @@ impl MirBuilder {
|
||||
let original_carrier_count = inputs.carrier_info.carriers.len();
|
||||
filter_carriers_for_updates(&mut inputs.carrier_info, &carrier_updates);
|
||||
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"updates",
|
||||
format!(
|
||||
"Phase 176-4: Filtered carriers: {} → {} (kept only carriers with updates/condition-only/loop-local-zero)",
|
||||
@ -851,8 +836,7 @@ impl MirBuilder {
|
||||
join_value,
|
||||
});
|
||||
} else {
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"updates",
|
||||
format!(
|
||||
"Phase 247-EX: Skipping host binding for loop-local carrier '{}' (init=LoopLocalZero)",
|
||||
@ -861,8 +845,7 @@ impl MirBuilder {
|
||||
);
|
||||
}
|
||||
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"updates",
|
||||
format!(
|
||||
"Phase 176-5: Added body-only carrier '{}' to ConditionEnv: HOST {:?} → JoinIR {:?}",
|
||||
@ -872,8 +855,7 @@ impl MirBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"before_lowerer",
|
||||
format!(
|
||||
"About to call lower_loop_with_break_minimal with carrier_info.loop_var_name='{}'",
|
||||
@ -881,22 +863,31 @@ impl MirBuilder {
|
||||
),
|
||||
);
|
||||
|
||||
let (join_module, fragment_meta) = match lower_loop_with_break_minimal(
|
||||
inputs.scope,
|
||||
condition,
|
||||
&effective_break_condition,
|
||||
&inputs.env,
|
||||
&inputs.carrier_info,
|
||||
&carrier_updates,
|
||||
analysis_body, // Phase 191/192: Pass normalized body AST for init lowering
|
||||
Some(&mut inputs.body_local_env), // Phase 191: Pass mutable body-local environment
|
||||
&mut inputs.join_value_space, // Phase 201: Unified ValueId allocation (Local region)
|
||||
skeleton, // Phase 92 P0-3: Pass skeleton for ConditionalStep support
|
||||
) {
|
||||
Ok((module, meta)) => (module, meta),
|
||||
Err(e) => {
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().debug("pattern2", &format!("Pattern 2 lowerer failed: {}", e));
|
||||
let body_local_env = &mut inputs.body_local_env;
|
||||
let join_value_space = &mut inputs.join_value_space;
|
||||
let lowering_inputs = LoopWithBreakLoweringInputs {
|
||||
scope: inputs.scope,
|
||||
condition,
|
||||
break_condition: &effective_break_condition,
|
||||
env: &inputs.env,
|
||||
carrier_info: &inputs.carrier_info,
|
||||
carrier_updates: &carrier_updates,
|
||||
body_ast: analysis_body,
|
||||
body_local_env: Some(body_local_env),
|
||||
allowed_body_locals_for_conditions: if inputs.allowed_body_locals_for_conditions.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(inputs.allowed_body_locals_for_conditions.as_slice())
|
||||
},
|
||||
join_value_space,
|
||||
skeleton,
|
||||
};
|
||||
|
||||
let (join_module, fragment_meta) = match lower_loop_with_break_minimal(lowering_inputs) {
|
||||
Ok((module, meta)) => (module, meta),
|
||||
Err(e) => {
|
||||
// Phase 195: Use unified trace
|
||||
trace::trace().debug("pattern2", &format!("Pattern 2 lowerer failed: {}", e));
|
||||
return Err(format!("[cf_loop/pattern2] Lowering failed: {}", e));
|
||||
}
|
||||
};
|
||||
@ -921,8 +912,7 @@ impl MirBuilder {
|
||||
host_input_values.push(carrier.host_id);
|
||||
}
|
||||
|
||||
log_pattern2(
|
||||
verbose,
|
||||
log.log(
|
||||
"boundary",
|
||||
format!(
|
||||
"Phase 176-3: Boundary inputs - {} JoinIR slots, {} host values",
|
||||
|
||||
@ -137,9 +137,14 @@ impl MirBuilder {
|
||||
if let Some(bid) = self.binding_ctx.lookup(&loop_var_name) {
|
||||
cond_env.register_loop_var_binding(bid, _loop_var_join_id);
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[phase80/p3] Registered loop var '{}' BindingId({}) -> ValueId({})",
|
||||
loop_var_name, bid.0, _loop_var_join_id.0
|
||||
super::super::trace::trace().emit_if(
|
||||
"phase80",
|
||||
"p3",
|
||||
&format!(
|
||||
"Registered loop var '{}' BindingId({}) -> ValueId({})",
|
||||
loop_var_name, bid.0, _loop_var_join_id.0
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -152,9 +157,14 @@ impl MirBuilder {
|
||||
if let Some(bid) = self.binding_ctx.lookup(&binding.name) {
|
||||
cond_env.register_condition_binding(bid, binding.join_value);
|
||||
if debug {
|
||||
eprintln!(
|
||||
"[phase80/p3] Registered condition binding '{}' BindingId({}) -> ValueId({})",
|
||||
binding.name, bid.0, binding.join_value.0
|
||||
super::super::trace::trace().emit_if(
|
||||
"phase80",
|
||||
"p3",
|
||||
&format!(
|
||||
"Registered condition binding '{}' BindingId({}) -> ValueId({})",
|
||||
binding.name, bid.0, binding.join_value.0
|
||||
),
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -202,7 +212,8 @@ impl MirBuilder {
|
||||
&ctx.carrier_info,
|
||||
&condition_binding_names,
|
||||
) {
|
||||
eprintln!("[phase64/ownership] Consistency check failed: {}", e);
|
||||
super::super::trace::trace()
|
||||
.dev("phase64/ownership", &format!("Consistency check failed: {}", e));
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
@ -217,9 +228,9 @@ impl MirBuilder {
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"[phase64/ownership] Analysis failed (continuing with legacy): {}",
|
||||
e
|
||||
super::super::trace::trace().dev(
|
||||
"phase64/ownership",
|
||||
&format!("Analysis failed (continuing with legacy): {}", e),
|
||||
);
|
||||
// Don't fail - analysis is optional in Phase 64
|
||||
}
|
||||
|
||||
@ -171,6 +171,9 @@ impl TrimLoopLowerer {
|
||||
carrier_info: &mut CarrierInfo,
|
||||
alloc_join_value: &mut dyn FnMut() -> ValueId,
|
||||
) -> Result<Option<TrimLoweringResult>, String> {
|
||||
let trace = crate::mir::builder::control_flow::joinir::trace::trace();
|
||||
let verbose = crate::config::env::joinir_dev_enabled() || trace.is_joinir_enabled();
|
||||
|
||||
// Phase 180-2: Skeleton implementation
|
||||
// TODO: Phase 180-3 will implement full logic from Pattern2
|
||||
|
||||
@ -178,18 +181,33 @@ impl TrimLoopLowerer {
|
||||
let cond_scope =
|
||||
LoopConditionScopeBox::analyze(loop_var_name, &[loop_cond, break_cond], Some(scope));
|
||||
|
||||
eprintln!(
|
||||
"[TrimLoopLowerer] Analyzing condition scope: {} variables",
|
||||
cond_scope.vars.len()
|
||||
trace.emit_if(
|
||||
"trim",
|
||||
"scope",
|
||||
&format!(
|
||||
"Analyzing condition scope: {} variables",
|
||||
cond_scope.vars.len()
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
|
||||
if !cond_scope.has_loop_body_local() {
|
||||
// Not a Trim pattern - normal loop
|
||||
eprintln!("[TrimLoopLowerer] No LoopBodyLocal detected, skipping Trim lowering");
|
||||
trace.emit_if(
|
||||
"trim",
|
||||
"scope",
|
||||
"No LoopBodyLocal detected, skipping Trim lowering",
|
||||
verbose,
|
||||
);
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
eprintln!("[TrimLoopLowerer] LoopBodyLocal detected in condition scope");
|
||||
trace.emit_if(
|
||||
"trim",
|
||||
"scope",
|
||||
"LoopBodyLocal detected in condition scope",
|
||||
verbose,
|
||||
);
|
||||
|
||||
// Phase 183-2: Filter to only condition LoopBodyLocal (skip body-only)
|
||||
use crate::mir::loop_pattern_detection::loop_condition_scope::CondVarScope;
|
||||
@ -205,19 +223,27 @@ impl TrimLoopLowerer {
|
||||
|
||||
if condition_body_locals.is_empty() {
|
||||
// All LoopBodyLocal are body-only (not in conditions) → Not a Trim pattern
|
||||
eprintln!(
|
||||
"[TrimLoopLowerer] Phase 183: All LoopBodyLocal are body-only (not in conditions), skipping Trim lowering"
|
||||
trace.emit_if(
|
||||
"trim",
|
||||
"phase183",
|
||||
"All LoopBodyLocal are body-only (not in conditions), skipping Trim lowering",
|
||||
verbose,
|
||||
);
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
eprintln!(
|
||||
"[TrimLoopLowerer] Phase 183: Found {} condition LoopBodyLocal variables: {:?}",
|
||||
condition_body_locals.len(),
|
||||
condition_body_locals
|
||||
.iter()
|
||||
.map(|v| &v.name)
|
||||
.collect::<Vec<_>>()
|
||||
trace.emit_if(
|
||||
"trim",
|
||||
"phase183",
|
||||
&format!(
|
||||
"Found {} condition LoopBodyLocal variables: {:?}",
|
||||
condition_body_locals.len(),
|
||||
condition_body_locals
|
||||
.iter()
|
||||
.map(|v| &v.name)
|
||||
.collect::<Vec<_>>()
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
|
||||
// Step 2: Try promotion via LoopBodyCarrierPromoter
|
||||
@ -233,9 +259,14 @@ impl TrimLoopLowerer {
|
||||
|
||||
match LoopBodyCarrierPromoter::try_promote(&request) {
|
||||
PromotionResult::Promoted { trim_info } => {
|
||||
eprintln!(
|
||||
"[TrimLoopLowerer] LoopBodyLocal '{}' promoted to carrier '{}'",
|
||||
trim_info.var_name, trim_info.carrier_name
|
||||
trace.emit_if(
|
||||
"trim",
|
||||
"promote",
|
||||
&format!(
|
||||
"LoopBodyLocal '{}' promoted to carrier '{}'",
|
||||
trim_info.var_name, trim_info.carrier_name
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
|
||||
// Step 3: Convert to CarrierInfo and merge
|
||||
@ -247,10 +278,15 @@ impl TrimLoopLowerer {
|
||||
let promoted_carrier = trim_info.to_carrier_info();
|
||||
carrier_info.merge_from(&promoted_carrier);
|
||||
|
||||
eprintln!(
|
||||
"[TrimLoopLowerer] Merged carrier '{}' into CarrierInfo (total carriers: {})",
|
||||
trim_info.carrier_name,
|
||||
carrier_info.carrier_count()
|
||||
trace.emit_if(
|
||||
"trim",
|
||||
"promote",
|
||||
&format!(
|
||||
"Merged carrier '{}' into CarrierInfo (total carriers: {})",
|
||||
trim_info.carrier_name,
|
||||
carrier_info.carrier_count()
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
|
||||
// Step 4: Safety check via TrimLoopHelper
|
||||
@ -269,37 +305,62 @@ impl TrimLoopLowerer {
|
||||
));
|
||||
}
|
||||
|
||||
eprintln!("[TrimLoopLowerer] Safe Trim pattern detected, implementing lowering");
|
||||
eprintln!(
|
||||
"[TrimLoopLowerer] Carrier: '{}', original var: '{}', whitespace chars: {:?}",
|
||||
trim_helper.carrier_name,
|
||||
trim_helper.original_var,
|
||||
trim_helper.whitespace_chars
|
||||
trace.emit_if(
|
||||
"trim",
|
||||
"safe",
|
||||
"Safe Trim pattern detected, implementing lowering",
|
||||
verbose,
|
||||
);
|
||||
trace.emit_if(
|
||||
"trim",
|
||||
"safe",
|
||||
&format!(
|
||||
"Carrier: '{}', original var: '{}', whitespace chars: {:?}",
|
||||
trim_helper.carrier_name,
|
||||
trim_helper.original_var,
|
||||
trim_helper.whitespace_chars
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
|
||||
// Step 5: Generate carrier initialization code
|
||||
Self::generate_carrier_initialization(builder, body, trim_helper)?;
|
||||
|
||||
eprintln!(
|
||||
"[TrimLoopLowerer] Registered carrier '{}' in variable_ctx.variable_map",
|
||||
trim_helper.carrier_name
|
||||
trace.emit_if(
|
||||
"trim",
|
||||
"init",
|
||||
&format!(
|
||||
"Registered carrier '{}' in variable_ctx.variable_map",
|
||||
trim_helper.carrier_name
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
|
||||
// Step 6: Generate Trim break condition
|
||||
let trim_break_condition = Self::generate_trim_break_condition(trim_helper);
|
||||
|
||||
eprintln!(
|
||||
"[TrimLoopLowerer] Replaced break condition with !{}",
|
||||
trim_helper.carrier_name
|
||||
trace.emit_if(
|
||||
"trim",
|
||||
"cond",
|
||||
&format!(
|
||||
"Replaced break condition with !{}",
|
||||
trim_helper.carrier_name
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
|
||||
// Step 7: Setup ConditionEnv bindings
|
||||
let condition_bindings =
|
||||
Self::setup_condition_env_bindings(builder, trim_helper, alloc_join_value)?;
|
||||
|
||||
eprintln!(
|
||||
"[TrimLoopLowerer] Added {} condition bindings",
|
||||
condition_bindings.len()
|
||||
trace.emit_if(
|
||||
"trim",
|
||||
"cond",
|
||||
&format!(
|
||||
"Added {} condition bindings",
|
||||
condition_bindings.len()
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
|
||||
// Step 8: Return result with all updates
|
||||
@ -313,9 +374,14 @@ impl TrimLoopLowerer {
|
||||
// Phase 196: Treat non-trim loops as normal loops.
|
||||
// If promotion fails, simply skip Trim lowering and let the caller
|
||||
// continue with the original break condition.
|
||||
eprintln!(
|
||||
"[TrimLoopLowerer] Cannot promote LoopBodyLocal variables {:?}: {}; skipping Trim lowering",
|
||||
vars, reason
|
||||
trace.emit_if(
|
||||
"trim",
|
||||
"reject",
|
||||
&format!(
|
||||
"Cannot promote LoopBodyLocal variables {:?}: {}; skipping Trim lowering",
|
||||
vars, reason
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
Ok(None)
|
||||
}
|
||||
@ -336,6 +402,8 @@ impl TrimLoopLowerer {
|
||||
trim_helper: &crate::mir::loop_pattern_detection::trim_loop_helper::TrimLoopHelper,
|
||||
) -> Result<(), String> {
|
||||
use crate::mir::builder::control_flow::joinir::patterns::trim_pattern_validator::TrimPatternValidator;
|
||||
let trace = crate::mir::builder::control_flow::joinir::trace::trace();
|
||||
let verbose = crate::config::env::joinir_dev_enabled() || trace.is_joinir_enabled();
|
||||
|
||||
// Extract substring pattern from body
|
||||
let (s_name, start_expr) =
|
||||
@ -347,9 +415,11 @@ impl TrimLoopLowerer {
|
||||
)
|
||||
})?;
|
||||
|
||||
eprintln!(
|
||||
"[TrimLoopLowerer] Extracted substring pattern: s='{}', start={:?}",
|
||||
s_name, start_expr
|
||||
trace.emit_if(
|
||||
"trim",
|
||||
"init",
|
||||
&format!("Extracted substring pattern: s='{}', start={:?}", s_name, start_expr),
|
||||
verbose,
|
||||
);
|
||||
|
||||
// Get ValueIds for string and start
|
||||
@ -387,9 +457,11 @@ impl TrimLoopLowerer {
|
||||
vec![start_id, start_plus_1],
|
||||
)?;
|
||||
|
||||
eprintln!(
|
||||
"[TrimLoopLowerer] Generated initial substring call: ch0 = {:?}",
|
||||
ch0
|
||||
trace.emit_if(
|
||||
"trim",
|
||||
"init",
|
||||
&format!("Generated initial substring call: ch0 = {:?}", ch0),
|
||||
verbose,
|
||||
);
|
||||
|
||||
// Generate: is_ch_match0 = (ch0 == " " || ch0 == "\t" || ...)
|
||||
@ -399,9 +471,14 @@ impl TrimLoopLowerer {
|
||||
&trim_helper.whitespace_chars,
|
||||
)?;
|
||||
|
||||
eprintln!(
|
||||
"[TrimLoopLowerer] Generated initial whitespace check: is_ch_match0 = {:?}",
|
||||
is_ch_match0
|
||||
trace.emit_if(
|
||||
"trim",
|
||||
"init",
|
||||
&format!(
|
||||
"Generated initial whitespace check: is_ch_match0 = {:?}",
|
||||
is_ch_match0
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
|
||||
// Register carrier in variable_ctx.variable_map
|
||||
@ -438,6 +515,8 @@ impl TrimLoopLowerer {
|
||||
alloc_join_value: &mut dyn FnMut() -> ValueId,
|
||||
) -> Result<Vec<ConditionBinding>, String> {
|
||||
use crate::mir::builder::control_flow::joinir::patterns::trim_pattern_lowerer::TrimPatternLowerer;
|
||||
let trace = crate::mir::builder::control_flow::joinir::trace::trace();
|
||||
let verbose = crate::config::env::joinir_dev_enabled() || trace.is_joinir_enabled();
|
||||
|
||||
let mut bindings = Vec::new();
|
||||
|
||||
@ -454,9 +533,14 @@ impl TrimLoopLowerer {
|
||||
alloc_join_value,
|
||||
)?;
|
||||
|
||||
eprintln!(
|
||||
"[TrimLoopLowerer] Added carrier '{}' to ConditionEnv: HOST {:?} → JoinIR {:?}",
|
||||
trim_helper.carrier_name, binding.host_value, binding.join_value
|
||||
trace.emit_if(
|
||||
"trim",
|
||||
"cond-env",
|
||||
&format!(
|
||||
"Added carrier '{}' to ConditionEnv: HOST {:?} → JoinIR {:?}",
|
||||
trim_helper.carrier_name, binding.host_value, binding.join_value
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
|
||||
bindings.push(binding.clone());
|
||||
@ -470,9 +554,14 @@ impl TrimLoopLowerer {
|
||||
join_value: binding.join_value,
|
||||
};
|
||||
|
||||
eprintln!(
|
||||
"[TrimLoopLowerer] Phase 176-6: Also mapped original var '{}' → JoinIR {:?}",
|
||||
trim_helper.original_var, binding.join_value
|
||||
trace.emit_if(
|
||||
"trim",
|
||||
"cond-env",
|
||||
&format!(
|
||||
"Phase 176-6: Also mapped original var '{}' → JoinIR {:?}",
|
||||
trim_helper.original_var, binding.join_value
|
||||
),
|
||||
verbose,
|
||||
);
|
||||
|
||||
bindings.push(original_binding);
|
||||
|
||||
Reference in New Issue
Block a user