diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs b/src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs index f72a1ab3..bf9f4dbf 100644 --- a/src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs +++ b/src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs @@ -250,6 +250,8 @@ fn promote_and_prepare_carriers( 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) { diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs b/src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs index 5aaf6210..010193ce 100644 --- a/src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs +++ b/src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs @@ -239,6 +239,8 @@ fn prepare_pattern4_context( break_cond: None, // Pattern 4 has no break continue_cond, loop_body: &normalized_body, + #[cfg(feature = "normalized_dev")] + binding_map: Some(&builder.binding_map), }; match LoopBodyCondPromoter::try_promote_for_condition(promotion_req) { diff --git a/src/mir/builder/control_flow/joinir/patterns/trim_loop_lowering.rs b/src/mir/builder/control_flow/joinir/patterns/trim_loop_lowering.rs index ec573365..a3a5e3f8 100644 --- a/src/mir/builder/control_flow/joinir/patterns/trim_loop_lowering.rs +++ b/src/mir/builder/control_flow/joinir/patterns/trim_loop_lowering.rs @@ -226,6 +226,8 @@ impl TrimLoopLowerer { cond_scope: &cond_scope, break_cond: Some(break_cond), loop_body: body, + #[cfg(feature = "normalized_dev")] + binding_map: Some(&builder.binding_map), }; match LoopBodyCarrierPromoter::try_promote(&request) { @@ -236,6 +238,9 @@ impl TrimLoopLowerer { ); // Step 3: Convert to CarrierInfo and merge + #[cfg(feature = "normalized_dev")] + let promoted_carrier = trim_info.to_carrier_info(Some(&builder.binding_map)); + #[cfg(not(feature = "normalized_dev"))] let promoted_carrier = trim_info.to_carrier_info(); carrier_info.merge_from(&promoted_carrier); diff --git a/src/mir/join_ir/lowering/carrier_info.rs b/src/mir/join_ir/lowering/carrier_info.rs index 8f77902d..3e231498 100644 --- a/src/mir/join_ir/lowering/carrier_info.rs +++ b/src/mir/join_ir/lowering/carrier_info.rs @@ -491,7 +491,22 @@ impl CarrierInfo { /// /// * `Some(ValueId)` - 対応する carrier の join_id が見つかった場合 /// * `None` - promoted_loopbodylocals に含まれない、または join_id 未設定の場合 + /// + /// # Phase 77: DEPRECATED + /// + /// This method uses fragile naming conventions ("is_*", "is_*_match") and will + /// be removed in Phase 78+ when all call sites migrate to BindingId-based lookup. + /// Use `resolve_promoted_with_binding()` for type-safe BindingId lookup. + #[deprecated( + since = "phase77", + note = "Use resolve_promoted_with_binding() for type-safe BindingId lookup" + )] pub fn resolve_promoted_join_id(&self, original_name: &str) -> Option { + #[cfg(feature = "normalized_dev")] + eprintln!( + "[phase77/legacy/carrier_info] WARNING: Using deprecated name-based promoted lookup for '{}'", + original_name + ); if !self .promoted_loopbodylocals .contains(&original_name.to_string()) diff --git a/src/mir/join_ir/lowering/scope_manager.rs b/src/mir/join_ir/lowering/scope_manager.rs index 56716bd7..a2d289da 100644 --- a/src/mir/join_ir/lowering/scope_manager.rs +++ b/src/mir/join_ir/lowering/scope_manager.rs @@ -290,6 +290,13 @@ impl<'a> ScopeManager for Pattern2ScopeManager<'a> { } // Step 3: Fallback to legacy name-based lookup (Phase 75 fallback path) + // Phase 77: DEPRECATED - Will be removed in Phase 78+ + #[cfg(feature = "normalized_dev")] + eprintln!( + "[phase77/fallback] WARNING: BindingId({}) for '{}' not resolved, falling back to name-based lookup (DEPRECATED)", + bid.0, name + ); + #[cfg(not(feature = "normalized_dev"))] if std::env::var("NYASH_JOINIR_DEBUG").is_ok() { eprintln!( "[phase76/fallback] BindingId({}) miss, falling back to name '{}' lookup", @@ -298,7 +305,8 @@ impl<'a> ScopeManager for Pattern2ScopeManager<'a> { } } - // Step 4: Legacy name-based lookup (Phase 75 behavior, will be removed in Phase 77) + // Step 4: Legacy name-based lookup (Phase 75 behavior) + // Phase 77: DEPRECATED - Will be removed in Phase 78+ after all call sites use BindingId self.lookup(name) } } diff --git a/src/mir/loop_pattern_detection/loop_body_carrier_promoter.rs b/src/mir/loop_pattern_detection/loop_body_carrier_promoter.rs index 42930da9..e032f5d6 100644 --- a/src/mir/loop_pattern_detection/loop_body_carrier_promoter.rs +++ b/src/mir/loop_pattern_detection/loop_body_carrier_promoter.rs @@ -35,6 +35,10 @@ pub struct PromotionRequest<'a> { pub break_cond: Option<&'a ASTNode>, /// ループ本体の AST pub loop_body: &'a [ASTNode], + + /// Phase 77: Optional BindingId map for type-safe promotion tracking (dev-only) + #[cfg(feature = "normalized_dev")] + pub binding_map: Option<&'a std::collections::BTreeMap>, } /// Phase 171-C-2: 検出された Trim パターン情報 @@ -54,6 +58,10 @@ impl TrimPatternInfo { /// Creates a CarrierInfo containing a single bool carrier representing /// the Trim pattern match condition (e.g., "is_whitespace"). /// + /// # Arguments + /// + /// * `binding_map` - Optional BindingId map for Phase 77 type-safe promotion tracking + /// /// # Returns /// /// CarrierInfo with: @@ -67,7 +75,11 @@ impl TrimPatternInfo { /// - This is JoinIR-local ID space (not host ValueId space) /// - The actual host ValueId will be assigned during merge_joinir_mir_blocks /// - JoinInlineBoundary will handle the boundary mapping - pub fn to_carrier_info(&self) -> crate::mir::join_ir::lowering::carrier_info::CarrierInfo { + pub fn to_carrier_info( + &self, + #[cfg(feature = "normalized_dev")] + binding_map: Option<&std::collections::BTreeMap>, + ) -> crate::mir::join_ir::lowering::carrier_info::CarrierInfo { use super::trim_loop_helper::TrimLoopHelper; use crate::mir::join_ir::lowering::carrier_info::CarrierInfo; use crate::mir::ValueId; @@ -89,6 +101,39 @@ impl TrimPatternInfo { .promoted_loopbodylocals .push(self.var_name.clone()); + // Phase 77: Type-safe BindingId promotion tracking + #[cfg(feature = "normalized_dev")] + if let Some(binding_map) = binding_map { + // Look up original and promoted BindingIds + let original_binding_opt = binding_map.get(&self.var_name); + let promoted_binding_opt = binding_map.get(&self.carrier_name); + + match (original_binding_opt, promoted_binding_opt) { + (Some(&original_bid), Some(&promoted_bid)) => { + carrier_info.record_promoted_binding(original_bid, promoted_bid); + eprintln!( + "[trim_lowerer/phase77] Recorded promoted binding: {} (BindingId({:?})) → {} (BindingId({:?}))", + self.var_name, original_bid, self.carrier_name, promoted_bid + ); + } + (None, _) => { + eprintln!( + "[trim_lowerer/phase77] WARNING: Original variable '{}' not found in binding_map", + self.var_name + ); + } + (_, None) => { + eprintln!( + "[trim_lowerer/phase77] WARNING: Promoted carrier '{}' not found in binding_map", + self.carrier_name + ); + } + } + } else { + #[cfg(feature = "normalized_dev")] + eprintln!("[trim_lowerer/phase77] INFO: binding_map not provided (legacy mode)"); + } + carrier_info } } diff --git a/src/mir/loop_pattern_detection/loop_body_cond_promoter.rs b/src/mir/loop_pattern_detection/loop_body_cond_promoter.rs index 595a86ad..288b4b91 100644 --- a/src/mir/loop_pattern_detection/loop_body_cond_promoter.rs +++ b/src/mir/loop_pattern_detection/loop_body_cond_promoter.rs @@ -53,6 +53,10 @@ pub struct ConditionPromotionRequest<'a> { /// Loop body statements pub loop_body: &'a [ASTNode], + + /// Phase 77: Optional BindingId map for type-safe promotion tracking (dev-only) + #[cfg(feature = "normalized_dev")] + pub binding_map: Option<&'a std::collections::BTreeMap>, } /// Promotion result @@ -175,6 +179,8 @@ impl LoopBodyCondPromoter { cond_scope: req.cond_scope, break_cond: condition_for_promotion, loop_body: req.loop_body, + #[cfg(feature = "normalized_dev")] + binding_map: req.binding_map, }; match LoopBodyCarrierPromoter::try_promote(&promotion_request) { @@ -185,6 +191,9 @@ impl LoopBodyCondPromoter { ); // Convert TrimPatternInfo to CarrierInfo + #[cfg(feature = "normalized_dev")] + let carrier_info = trim_info.to_carrier_info(req.binding_map); + #[cfg(not(feature = "normalized_dev"))] let carrier_info = trim_info.to_carrier_info(); return ConditionPromotionResult::Promoted { @@ -207,6 +216,8 @@ impl LoopBodyCondPromoter { break_cond: req.break_cond, continue_cond: req.continue_cond, loop_body: req.loop_body, + #[cfg(feature = "normalized_dev")] + binding_map: req.binding_map, }; match DigitPosPromoter::try_promote(digitpos_request) { @@ -373,6 +384,8 @@ mod tests { break_cond: None, continue_cond: None, loop_body: &[], + #[cfg(feature = "normalized_dev")] + binding_map: None, }; match LoopBodyCondPromoter::try_promote_for_condition(req) { @@ -395,6 +408,8 @@ mod tests { break_cond: None, continue_cond: None, loop_body: &[], + #[cfg(feature = "normalized_dev")] + binding_map: None, }; match LoopBodyCondPromoter::try_promote_for_condition(req) { @@ -426,6 +441,8 @@ mod tests { break_cond: None, continue_cond: Some(&continue_cond), loop_body: &loop_body, + #[cfg(feature = "normalized_dev")] + binding_map: None, }; match LoopBodyCondPromoter::try_promote_for_condition(req) { @@ -463,6 +480,8 @@ mod tests { break_cond: Some(&break_cond), continue_cond: None, loop_body: &loop_body, + #[cfg(feature = "normalized_dev")] + binding_map: None, }; match LoopBodyCondPromoter::try_promote_for_condition(req) { @@ -493,6 +512,8 @@ mod tests { break_cond: None, continue_cond: Some(&continue_cond), loop_body: &loop_body, + #[cfg(feature = "normalized_dev")] + binding_map: None, }; match LoopBodyCondPromoter::try_promote_for_condition(req) { diff --git a/src/mir/loop_pattern_detection/loop_body_digitpos_promoter.rs b/src/mir/loop_pattern_detection/loop_body_digitpos_promoter.rs index 474896c1..de830e51 100644 --- a/src/mir/loop_pattern_detection/loop_body_digitpos_promoter.rs +++ b/src/mir/loop_pattern_detection/loop_body_digitpos_promoter.rs @@ -60,6 +60,14 @@ pub struct DigitPosPromotionRequest<'a> { /// Loop body statements pub loop_body: &'a [ASTNode], + + /// Phase 77: Optional BindingId map for type-safe promotion tracking (dev-only) + /// + /// When provided, the promoter will record promoted bindings + /// (e.g., BindingId(5) for "digit_pos" → BindingId(10) for "is_digit_pos") + /// in CarrierInfo.promoted_bindings. + #[cfg(feature = "normalized_dev")] + pub binding_map: Option<&'a std::collections::BTreeMap>, } /// Promotion result @@ -228,6 +236,39 @@ impl DigitPosPromoter { .promoted_loopbodylocals .push(var_in_cond.clone()); + // Phase 77: Type-safe BindingId promotion tracking + #[cfg(feature = "normalized_dev")] + if let Some(binding_map) = req.binding_map { + // Look up original and promoted BindingIds + let original_binding_opt = binding_map.get(&var_in_cond); + let promoted_bool_binding_opt = binding_map.get(&bool_carrier_name); + + match (original_binding_opt, promoted_bool_binding_opt) { + (Some(&original_bid), Some(&promoted_bid)) => { + carrier_info.record_promoted_binding(original_bid, promoted_bid); + eprintln!( + "[digitpos_promoter/phase77] Recorded promoted binding: {} (BindingId({:?})) → {} (BindingId({:?}))", + var_in_cond, original_bid, bool_carrier_name, promoted_bid + ); + } + (None, _) => { + eprintln!( + "[digitpos_promoter/phase77] WARNING: Original variable '{}' not found in binding_map", + var_in_cond + ); + } + (_, None) => { + eprintln!( + "[digitpos_promoter/phase77] WARNING: Promoted carrier '{}' not found in binding_map", + bool_carrier_name + ); + } + } + } else { + #[cfg(feature = "normalized_dev")] + eprintln!("[digitpos_promoter/phase77] INFO: binding_map not provided (legacy mode)"); + } + eprintln!( "[digitpos_promoter] Phase 247-EX: A-4 DigitPos pattern promoted: {} → {} (bool) + {} (i64)", var_in_cond, bool_carrier_name, int_carrier_name @@ -526,6 +567,8 @@ mod tests { break_cond: None, continue_cond: None, loop_body: &[], + #[cfg(feature = "normalized_dev")] + binding_map: None, }; match DigitPosPromoter::try_promote(req) { @@ -563,6 +606,8 @@ mod tests { break_cond: Some(&break_cond), continue_cond: None, loop_body: &loop_body, + #[cfg(feature = "normalized_dev")] + binding_map: None, }; match DigitPosPromoter::try_promote(req) { @@ -601,6 +646,8 @@ mod tests { break_cond: Some(&break_cond), continue_cond: None, loop_body: &loop_body, + #[cfg(feature = "normalized_dev")] + binding_map: None, }; match DigitPosPromoter::try_promote(req) { @@ -639,6 +686,8 @@ mod tests { break_cond: Some(&break_cond), continue_cond: None, loop_body: &loop_body, + #[cfg(feature = "normalized_dev")] + binding_map: None, }; match DigitPosPromoter::try_promote(req) { @@ -680,6 +729,8 @@ mod tests { break_cond: Some(&break_cond), continue_cond: None, loop_body: &loop_body, + #[cfg(feature = "normalized_dev")] + binding_map: None, }; match DigitPosPromoter::try_promote(req) { @@ -722,6 +773,8 @@ mod tests { break_cond: Some(&break_cond), continue_cond: None, loop_body: &loop_body, + #[cfg(feature = "normalized_dev")] + binding_map: None, }; match DigitPosPromoter::try_promote(req) {