Files
hakorune/src/mir/builder/control_flow/joinir/patterns/pattern2

Pattern2 (Loop with Break) - JoinIR

Scope / Criteria

  • loop(...) { ... break ... } (break present, no continue/return)
  • break condition is normalized to "break when is true"
  • loop variable comes from header condition or loop(true) counter extraction
    • loop(true): i = i + 1 + substring(i, i + 1) or i = j + K with j = indexOf(..., i) + substring(i, ...)

LoopBodyLocal promotion

  • SSOT entry: pattern2::api::try_promote
  • Supported: A-3 Trim / A-4 DigitPos (promote LoopBodyLocal to carrier)
  • ConditionOnly carriers are recalculated per iteration (no host binding)

Trim (seg) minimal shape

  • Example shape (A-3): local seg = s.substring(i, i + 1)
  • Break guard: if seg == " " || seg == "\\t" { break }
  • seg is read-only (no reassignment in the loop body)

Derived slot minimal shape (seg)

  • Example shape (Derived): local seg = "" then if cond { seg = expr1 } else { seg = expr2 }
  • Break guard: if seg == "" { break } (seg used in break condition)
  • seg is recomputed per-iteration (Select), no promotion
  • Contract SSOT: pattern2/contracts/derived_slot.rs

Carrier binding rules (Pattern2)

  • CarrierInit::FromHost -> host binding required
  • CarrierInit::BoolConst(_) / CarrierInit::LoopLocalZero -> host binding is skipped
  • ConditionOnly carriers must not use FromHost

Out of scope

  • multiple breaks / continue / return in the loop body
  • reassigned LoopBodyLocal outside the derived-slot shape
  • break conditions with unsupported AST shapes
  • non-substring init for Trim promotion (e.g., seg = other_call())

Fail-Fast policy

  • PromoteDecision::Freeze -> Err (missing implementation or contract violation)
  • JoinIR lowering/merge contract violations -> Err

Ok(None) meaning

  • not Pattern2 (extractor returns None)
  • promotion NotApplicable (continue Pattern2 without promotion)