feat(joinir): Phase 77 - BindingId expansion implementation (dev-only)
Phase 77 implements promoted_bindings population in DigitPos/Trim promoters and deprecates legacy name-based resolution paths. Changes: - DigitPosPromoter: Added binding_map field and record_promoted_binding() calls - TrimLoopHelper: Added binding_map field for ch → is_ch_match tracking - Pattern2/4: Wired binding_map from builder.binding_map to promoters - Legacy deprecation: Added #[deprecated] to resolve_promoted_join_id() - Dual-path design: BindingId priority + name fallback maintained Files modified (8): - pattern2_with_break.rs, pattern4_with_continue.rs: binding_map wiring - trim_loop_lowering.rs: Trim promoter integration - carrier_info.rs: Deprecation warnings - scope_manager.rs: Deprecated fallback paths - loop_body_carrier_promoter.rs: Trim binding_map support - loop_body_cond_promoter.rs: Orchestrator updates - loop_body_digitpos_promoter.rs: DigitPos binding_map support Tests: 958/958 PASS (zero regressions) Design: Type-safe BindingId mapping replaces string-based promoted variable resolution Phase 78+ will delete deprecated code (~50 lines) and make binding_map required. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -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<String, crate::mir::BindingId>>,
|
||||
}
|
||||
|
||||
/// 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<String, crate::mir::BindingId>>,
|
||||
) -> 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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<String, crate::mir::BindingId>>,
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
|
||||
@ -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<String, crate::mir::BindingId>>,
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
|
||||
Reference in New Issue
Block a user