Skip to main content

logicaffeine_compile/codegen/
stmt.rs

1use std::collections::{HashMap, HashSet};
2use std::fmt::Write;
3
4use crate::analysis::registry::{FieldType, TypeDef, TypeRegistry};
5use crate::analysis::types::RustNames;
6use crate::ast::stmt::{BinaryOpKind, Expr, Literal, ReadSource, Stmt, TypeExpr};
7use crate::intern::{Interner, Symbol};
8
9use super::context::{RefinementContext, VariableCapabilities, emit_refinement_check, analyze_variable_capabilities};
10use super::detection::{
11    requires_async_stmt, calls_async_function, collect_mutable_vars, collect_mutable_vars_stmt,
12    collect_crdt_register_fields, collect_boxed_fields, collect_expr_identifiers,
13    collect_stmt_identifiers, expr_debug_prefix, expr_reads_any_collection,
14    get_root_identifier_for_mutability, is_copy_type_expr, is_hashable_type,
15    parse_aos_tag,
16};
17use super::expr::{
18    codegen_expr, codegen_expr_with_async, codegen_expr_boxed,
19    codegen_expr_boxed_with_strings, codegen_expr_boxed_with_types,
20    codegen_expr_with_async_oracle, codegen_expr_boxed_with_types_oracle,
21    codegen_expr_boxed_with_types_oracle_tolerant,
22    codegen_interpolated_string, codegen_literal, codegen_assertion,
23    codegen_expr_with_async_and_strings, is_definitely_string_expr_with_vars,
24    is_definitely_string_expr, is_definitely_numeric_expr,
25    collect_string_concat_operands, is_rational_expr,
26};
27use super::peephole::{
28    try_emit_for_range_pattern, try_emit_vec_fill_pattern, try_emit_swap_pattern,
29    try_emit_prefix_reverse,
30    try_emit_seq_copy_pattern, try_emit_seq_from_slice_pattern,
31    try_emit_vec_with_capacity_pattern, try_emit_merge_capacity_pattern,
32    try_emit_rotate_left_pattern, try_emit_buffer_reuse_while,
33    try_emit_drain_tail_in_while, try_emit_byte_compare_window,
34    body_mutates_collection, body_modifies_var, exprs_equal, simplify_1based_index,
35    plan_bounds_hints, emit_bounds_hint_preheader, emit_bounds_hint_header,
36    is_counter_increment, collect_expr_symbols, BoundsHintPlan,
37    body_has_early_exit, body_resizes_collection,
38};
39use super::types::{
40    codegen_type_expr, infer_rust_type_from_expr, infer_numeric_type,
41    infer_variant_type_annotation,
42};
43use super::i64_map::{dense_type_name, is_logos_map_type, map_rust_type};
44use super::escape_rust_ident;
45
46/// The `(Vec<T>, init-expr)` pair for a de-Rc'd Seq declaration, or `None`
47/// when the initializer is not a fresh scalar-Seq allocation (in which case
48/// the normal `LogosSeq` path runs). Mirrors `fresh_scalar_seq_elem` in the
49/// de-Rc eligibility analysis — only those forms are ever marked de-Rc.
50fn derc_vec_decl<'a>(
51    value: &Expr<'a>,
52    interner: &Interner,
53    synced_vars: &HashSet<Symbol>,
54    boxed_fields: &HashSet<(String, String, String)>,
55    registry: &TypeRegistry,
56    async_functions: &HashSet<Symbol>,
57    ctx: &RefinementContext<'a>,
58) -> Option<(String, String)> {
59    match value {
60        Expr::New { type_name, type_args, init_fields } if init_fields.is_empty() => {
61            match interner.resolve(*type_name) {
62                "Seq" | "List" | "Vec" => {
63                    let elem = codegen_type_expr(type_args.first()?, interner);
64                    Some((format!("Vec<{}>", elem), "Vec::new()".to_string()))
65                }
66                _ => None,
67            }
68        }
69        Expr::WithCapacity { value: inner, capacity } => {
70            if let Expr::New { type_name, type_args, .. } = inner {
71                if matches!(interner.resolve(*type_name), "Seq" | "List" | "Vec") {
72                    let elem = codegen_type_expr(type_args.first()?, interner);
73                    let cap = codegen_expr_boxed_with_types(
74                        capacity, interner, synced_vars, boxed_fields, registry,
75                        async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(),
76                    );
77                    return Some((
78                        format!("Vec<{}>", elem),
79                        format!("Vec::with_capacity(({}) as usize)", cap),
80                    ));
81                }
82            }
83            None
84        }
85        // Phase 4: `Let r be f(...)` where `f` returns an OWNED `Vec<T>` (its
86        // return type already de-Rc'd in `fn_returns_map`). The result is a
87        // uniquely-owned fresh value — bind it as `Vec<T>` so every later access
88        // on `r` indexes directly instead of borrowing a RefCell.
89        Expr::Call { function, .. } => {
90            let ret = ctx.get_fn_return(function)?;
91            if !ret.starts_with("Vec<") {
92                return None;
93            }
94            let vec_ty = ret.clone();
95            let init = codegen_expr_boxed_with_types(
96                value, interner, synced_vars, boxed_fields, registry,
97                async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(),
98            );
99            Some((vec_ty, init))
100        }
101        // A homogeneous scalar-literal list de-Rc's to a plain `Vec<T>` literal — the NTT power
102        // table + coefficient array, and any `[…]` of one scalar literal kind, indexed without a
103        // RefCell borrow. Eligibility mirrors `fresh_scalar_seq_elem` via the shared helper.
104        Expr::List(items) => {
105            let elem = crate::codegen::detection::homogeneous_scalar_literal_elem(items)?;
106            let item_strs: Vec<String> = items
107                .iter()
108                .map(|i| {
109                    codegen_expr_boxed_with_types(
110                        i, interner, synced_vars, boxed_fields, registry, async_functions,
111                        ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(),
112                    )
113                })
114                .collect();
115            Some((format!("Vec<{}>", elem), format!("vec![{}]", item_strs.join(", "))))
116        }
117        _ => None,
118    }
119}
120
121/// The `LogosI64Map` constructor for a `Map of Int to Int` declared via `value`
122/// (`a new Map of Int to Int` or `… with capacity n`); `None` for any other
123/// initializer (the normal `LogosMap` codegen runs). Only called when the alias
124/// analysis already selected the variable for `LogosI64Map`.
125fn i64_map_ctor<'a>(
126    value: &Expr<'a>,
127    ty: &str,
128    dense_lo: Option<i64>,
129    interner: &Interner,
130    synced_vars: &HashSet<Symbol>,
131    boxed_fields: &HashSet<(String, String, String)>,
132    registry: &TypeRegistry,
133    async_functions: &HashSet<Symbol>,
134    ctx: &RefinementContext<'a>,
135) -> Option<String> {
136    match value {
137        Expr::New { type_name, init_fields, .. }
138            if init_fields.is_empty()
139                && matches!(interner.resolve(*type_name), "Map" | "HashMap") =>
140        {
141            Some(format!("{}::new()", ty))
142        }
143        Expr::WithCapacity { value: inner, capacity } => {
144            if let Expr::New { type_name, .. } = inner {
145                if matches!(interner.resolve(*type_name), "Map" | "HashMap") {
146                    let cap = codegen_expr_boxed_with_types(
147                        capacity, interner, synced_vars, boxed_fields, registry,
148                        async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(),
149                    );
150                    // A dense map is a direct-addressed array offset by the proven
151                    // window `lo` (currently 0) and sized `capacity + 1` slots: the
152                    // bound proof gives `lo <= key <= lo + capacity`, so the highest
153                    // index `key - lo` is `capacity`, which needs `capacity + 1`
154                    // slots. A non-dense `LogosI64Map`/`Set` takes the plain capacity.
155                    return Some(match dense_lo {
156                        Some(lo) => {
157                            format!("{}::with_bounds({}, (({}) + 1) as usize)", ty, lo, cap)
158                        }
159                        None => format!("{}::with_capacity(({}) as usize)", ty, cap),
160                    });
161                }
162            }
163            None
164        }
165        _ => None,
166    }
167}
168
169/// O5: emit `assert_unchecked` bounds hints for every indexed access in `stmt`
170/// the bounds-elision oracle proves in range (a relational induction bound
171/// `i <= length(arr)` or a concrete interval). Paired with a `debug_assert!`
172/// so an unsound proof panics loudly in debug. No-op when the oracle is absent.
173/// Only Identifier collections (a name is needed for `.len()`).
174fn emit_oracle_index_hints<'a>(
175    stmt: &Stmt<'a>,
176    ctx: &RefinementContext<'a>,
177    interner: &Interner,
178    indent_str: &str,
179) -> String {
180    // Kill switch (A/B): `LOGOS_ORACLE_HINTS=0` suppresses the oracle bounds
181    // hints entirely (the access keeps its runtime bounds check).
182    if !crate::optimize::active_config().is_on(crate::optimization::Opt::OracleHints) {
183        return String::new();
184    }
185    let oracle = match ctx.oracle() {
186        Some(o) => o,
187        None => return String::new(),
188    };
189    let mut accesses: Vec<(&Expr, &Expr)> = Vec::new();
190    collect_index_accesses_in_stmt(stmt, &mut accesses);
191    if accesses.is_empty() {
192        return String::new();
193    }
194    let names = RustNames::new(interner);
195    let mut out = String::new();
196    let mut seen: HashSet<usize> = HashSet::new();
197    for (coll, idx) in accesses {
198        let arr = match coll {
199            Expr::Identifier(s) => *s,
200            _ => continue,
201        };
202        // An affine read-only array is deleted — its reads are pure arithmetic,
203        // so there is no `.len()` to bound-check and no hint to emit.
204        if ctx.affine_array(arr).is_some() {
205            continue;
206        }
207        // An AoS-interleaved member folds into a `[[T; W]; N]` backing. The hint
208        // must name the BACKING (the member's own name no longer exists) and
209        // bound its ROW dimension (`backing.len()` == N) — that elides the
210        // rolled-regime row bounds-check just like C's, since the column is a
211        // constant < W.
212        let aos_backing = parse_aos_tag(ctx.get_variable_types().get(&arr)).map(|t| t.backing);
213        if !seen.insert(idx as *const Expr as usize) {
214            continue;
215        }
216        if !oracle.index_provably_in_bounds(coll, idx) {
217            continue;
218        }
219        // Discharge any `% m` element-bound precondition this elision leaned on
220        // with a hard `assert!(m > 0)` (LLVM hoists the loop-invariant check out
221        // of the loop, so it costs one comparison per region entry). For
222        // `m <= 0` the `% m`-filled array is empty and this access would be out
223        // of bounds: the assert panics there — exactly where the program would
224        // have — instead of the elision becoming UB.
225        for &m in oracle.index_positivity_guards(idx) {
226            let mn = names.ident(m);
227            writeln!(
228                out,
229                "{}assert!(({mn}) > 0, \"LOGOS positivity guard: element bound on `% {mn}` requires {mn} > 0\");",
230                indent_str, mn = mn
231            )
232            .unwrap();
233        }
234        // Match the ACCESS's 0-based index form: a `__zero_based_i64` counter
235        // indexes directly (`arr[i]`), everything else is 1-based (`arr[i-1]`).
236        // The oracle reasons about the 1-based source; codegen may rebase.
237        let i0 = match idx {
238            Expr::Identifier(c)
239                if ctx
240                    .get_variable_types()
241                    .get(c)
242                    .map_or(false, |t| t == "__zero_based_i64") =>
243            {
244                names.ident(*c)
245            }
246            _ => simplify_1based_index(idx, interner, false, ctx.get_variable_types()),
247        };
248        let arr_name = aos_backing.unwrap_or_else(|| names.ident(arr));
249        let cond = format!("({}) >= 0 && ({}) < ({}.len() as i64)", i0, i0, arr_name);
250        writeln!(out, "{}debug_assert!({}, \"LOGOS oracle bounds hint violated: indexing `{}` out of range\");", indent_str, cond, arr_name).unwrap();
251        writeln!(out, "{}unsafe {{ std::hint::assert_unchecked({}); }}", indent_str, cond).unwrap();
252    }
253    if !out.is_empty() {
254        crate::optimize::mark_fired(crate::optimization::Opt::OracleHints);
255    }
256    out
257}
258
259fn collect_index_accesses_in_stmt<'a>(stmt: &'a Stmt<'a>, out: &mut Vec<(&'a Expr<'a>, &'a Expr<'a>)>) {
260    match stmt {
261        Stmt::Let { value, .. } | Stmt::Set { value, .. } => collect_index_in_expr(value, out),
262        Stmt::SetIndex { collection, index, value } => {
263            out.push((collection, index));
264            collect_index_in_expr(index, out);
265            collect_index_in_expr(value, out);
266        }
267        Stmt::If { cond, .. } | Stmt::While { cond, .. } => collect_index_in_expr(cond, out),
268        Stmt::Show { object, .. } | Stmt::Give { object, .. } => collect_index_in_expr(object, out),
269        Stmt::Return { value: Some(e) } => collect_index_in_expr(e, out),
270        Stmt::Push { value, .. } | Stmt::Add { value, .. } | Stmt::Remove { value, .. } => {
271            collect_index_in_expr(value, out)
272        }
273        _ => {}
274    }
275}
276
277fn collect_index_in_expr<'a>(e: &'a Expr<'a>, out: &mut Vec<(&'a Expr<'a>, &'a Expr<'a>)>) {
278    match e {
279        Expr::Index { collection, index } => {
280            out.push((collection, index));
281            collect_index_in_expr(collection, out);
282            collect_index_in_expr(index, out);
283        }
284        Expr::BinaryOp { left, right, .. } => {
285            collect_index_in_expr(left, out);
286            collect_index_in_expr(right, out);
287        }
288        Expr::Not { operand } => collect_index_in_expr(operand, out),
289        Expr::Call { args, .. } => {
290            for a in args.iter() {
291                collect_index_in_expr(a, out);
292            }
293        }
294        Expr::Length { collection } => collect_index_in_expr(collection, out),
295        _ => {}
296    }
297}
298
299/// AOT BCE-hoist: a row-major affine-offset bounds guard for one array in one
300/// loop. The index `item (offset + counter + 1) of arr` is BILINEAR (e.g.
301/// `c[i*n+j]`) — the `i*n` product defeats the linear bounds prover — but from
302/// the inner loop's view `offset` (`i*n`) is loop-INVARIANT, so the emitted
303/// index `offset + counter` is monotone in the counter. A single preheader
304/// `assert!` that `offset >= 0` and the MAX index `offset + (limit - 1) < len`
305/// lets the per-iteration access be elided soundly with no static nonlinear
306/// proof and no UB (it PANICS, never UB, on an out-of-range program).
307pub(crate) struct AffineOffsetGuard<'a> {
308    arr_sym: Symbol,
309    /// The loop-invariant offset (`i * n`).
310    offset: &'a Expr<'a>,
311    /// The emitted index `offset + counter` (`i*n + j`), for the body hint.
312    emitted_index: &'a Expr<'a>,
313}
314
315/// Match the 1-based row-major index `(offset + counter) + 1` whose emitted
316/// index is `offset + counter`. Returns `(offset, offset_plus_counter)` where
317/// `offset` is the operand that is NOT the bare counter.
318fn match_affine_offset_index<'a>(
319    index: &'a Expr<'a>,
320    counter: Symbol,
321) -> Option<(&'a Expr<'a>, &'a Expr<'a>)> {
322    if let Expr::BinaryOp { op: BinaryOpKind::Add, left, right } = index {
323        if matches!(right, Expr::Literal(Literal::Number(1))) {
324            if let Expr::BinaryOp { op: BinaryOpKind::Add, left: a, right: b } = left {
325                if matches!(b, Expr::Identifier(s) if *s == counter) {
326                    return Some((a, left));
327                }
328                if matches!(a, Expr::Identifier(s) if *s == counter) {
329                    return Some((b, left));
330                }
331            }
332        }
333    }
334    None
335}
336
337/// Plan row-major affine-offset bounds guards for an exclusive `while counter <
338/// limit` loop body. Soundness mirrors the O5a counter hints: the access must
339/// be UNCONDITIONAL (top-level in the body), the array a `Vec`/slice that is
340/// not resized or rebound, and the offset loop-invariant (not mentioning the
341/// counter, none of its symbols mutated). v1 handles exclusive loops only (max
342/// counter = limit - 1) and one guard per array.
343pub(crate) fn plan_affine_offset_guards<'a>(
344    body: &'a [Stmt<'a>],
345    counter_sym: Symbol,
346    is_exclusive: bool,
347    var_types: &HashMap<Symbol, String>,
348) -> Vec<AffineOffsetGuard<'a>> {
349    if !is_exclusive || body_has_early_exit(body) {
350        return Vec::new();
351    }
352    let mut guards: Vec<AffineOffsetGuard> = Vec::new();
353    let mut seen: HashSet<Symbol> = HashSet::new();
354    for stmt in body {
355        let mut accesses: Vec<(&Expr, &Expr)> = Vec::new();
356        collect_index_accesses_in_stmt(stmt, &mut accesses);
357        for (coll, index) in accesses {
358            let arr_sym = match coll {
359                Expr::Identifier(s) => *s,
360                _ => continue,
361            };
362            let Some((offset, emitted)) = match_affine_offset_index(index, counter_sym) else {
363                continue;
364            };
365            let base_ty = var_types
366                .get(&arr_sym)
367                .map(|t| t.split("|__hl:").next().unwrap_or(t.as_str()));
368            let qualifies = matches!(
369                base_ty,
370                Some(t) if t.starts_with("Vec<") || t.starts_with("LogosSeq")
371                    || t.starts_with("&[") || t.starts_with("&mut [")
372            );
373            if !qualifies
374                || body_resizes_collection(body, arr_sym)
375                || body_modifies_var(body, arr_sym)
376            {
377                continue;
378            }
379            let mut osyms = Vec::new();
380            collect_expr_symbols(offset, &mut osyms);
381            if osyms.contains(&counter_sym)
382                || osyms
383                    .iter()
384                    .any(|s| body_modifies_var(body, *s) || body_mutates_collection(body, *s))
385            {
386                continue;
387            }
388            if seen.insert(arr_sym) {
389                guards.push(AffineOffsetGuard { arr_sym, offset, emitted_index: emitted });
390            }
391        }
392    }
393    guards
394}
395
396/// Emit the preheader anchor for each affine-offset guard: a length snapshot
397/// plus a hard `assert!` that the MAX index (`offset + limit - 1`) is in range
398/// and the offset is non-negative. Runs once per loop entry; PANICS (never UB)
399/// if the array is too short, which is what licenses the body-side elision.
400pub(crate) fn emit_affine_offset_preheader(
401    guards: &[AffineOffsetGuard],
402    limit_str: &str,
403    interner: &Interner,
404    synced_vars: &HashSet<Symbol>,
405    async_functions: &HashSet<Symbol>,
406    var_types: &HashMap<Symbol, String>,
407    indent_str: &str,
408    output: &mut String,
409) {
410    let names = RustNames::new(interner);
411    for g in guards {
412        let arr = names.ident(g.arr_sym);
413        let off = codegen_expr_with_async(g.offset, interner, synced_vars, async_functions, var_types);
414        writeln!(
415            output,
416            "{}assert!(({off}) >= 0 && (({off}) + ({lim}) - 1) < ({arr}.len() as i64), \"LOGOS bounds guard: indexing `{arr}` (row-major) out of range\");",
417            indent_str, off = off, lim = limit_str, arr = arr
418        ).unwrap();
419    }
420}
421
422/// Emit the per-iteration `assert_unchecked` for each affine-offset guard, at
423/// the top of the loop body. Sound because the preheader `assert!` proved the
424/// max index in range and the index is monotone in the (non-negative) counter.
425pub(crate) fn emit_affine_offset_header(
426    guards: &[AffineOffsetGuard],
427    interner: &Interner,
428    synced_vars: &HashSet<Symbol>,
429    async_functions: &HashSet<Symbol>,
430    var_types: &HashMap<Symbol, String>,
431    body_indent: &str,
432    output: &mut String,
433) {
434    let names = RustNames::new(interner);
435    for g in guards {
436        let arr = names.ident(g.arr_sym);
437        let e = codegen_expr_with_async(g.emitted_index, interner, synced_vars, async_functions, var_types);
438        writeln!(
439            output,
440            "{}unsafe {{ std::hint::assert_unchecked(({e}) >= 0 && ({e}) < ({arr}.len() as i64)); }}",
441            body_indent, e = e, arr = arr
442        ).unwrap();
443    }
444}
445
446/// Emit a `Select` as a raw `tokio::select!` — Mode A (free-running) and the
447/// no-arm-ready fallback of Mode B. Verbatim today's lowering.
448#[allow(clippy::too_many_arguments)]
449fn write_tokio_select<'a>(
450    output: &mut String,
451    branches: &[crate::ast::stmt::SelectBranch<'a>],
452    interner: &Interner,
453    indent: usize,
454    mutable_vars: &HashSet<Symbol>,
455    ctx: &mut RefinementContext<'a>,
456    lww_fields: &HashSet<(String, String)>,
457    mv_fields: &HashSet<(String, String)>,
458    synced_vars: &mut HashSet<Symbol>,
459    var_caps: &HashMap<Symbol, VariableCapabilities>,
460    async_functions: &HashSet<Symbol>,
461    pipe_vars: &HashSet<Symbol>,
462    boxed_fields: &HashSet<(String, String, String)>,
463    registry: &TypeRegistry,
464    type_env: &crate::analysis::types::TypeEnv,
465) {
466    use crate::ast::stmt::SelectBranch;
467    let indent_str = "    ".repeat(indent);
468    writeln!(output, "{}tokio::select! {{", indent_str).unwrap();
469    for branch in branches {
470        match branch {
471            SelectBranch::Receive { var, pipe, body } => {
472                let var_name = interner.resolve(*var);
473                let pipe_str = codegen_expr_with_async(pipe, interner, synced_vars, async_functions, ctx.get_variable_types());
474                let is_local_pipe = if let Expr::Identifier(sym) = pipe {
475                    pipe_vars.contains(sym)
476                } else {
477                    false
478                };
479                let suffix = if is_local_pipe { "_rx" } else { "" };
480                writeln!(output, "{}    {} = {}{}.recv() => {{", indent_str, var_name, pipe_str, suffix).unwrap();
481                writeln!(output, "{}        if let Some({}) = {} {{", indent_str, var_name, var_name).unwrap();
482                for stmt in *body {
483                    let stmt_code = codegen_stmt(stmt, interner, indent + 3, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env);
484                    write!(output, "{}", stmt_code).unwrap();
485                }
486                writeln!(output, "{}        }}", indent_str).unwrap();
487                writeln!(output, "{}    }}", indent_str).unwrap();
488            }
489            SelectBranch::Timeout { milliseconds, body } => {
490                let dur = match milliseconds {
491                    Expr::Literal(Literal::Duration(_)) => codegen_expr_with_async(
492                        milliseconds, interner, synced_vars, async_functions,
493                        ctx.get_variable_types(),
494                    ),
495                    Expr::Literal(Literal::Span { months, days }) => {
496                        let secs = ((*months as i64) * 30 + (*days as i64)) * 86_400;
497                        format!("std::time::Duration::from_secs({}u64)", secs.max(0))
498                    }
499                    _ => {
500                        let n = codegen_expr_with_async(
501                            milliseconds, interner, synced_vars, async_functions,
502                            ctx.get_variable_types(),
503                        );
504                        format!("std::time::Duration::from_secs({} as u64)", n)
505                    }
506                };
507                writeln!(output, "{}    _ = tokio::time::sleep({}) => {{", indent_str, dur).unwrap();
508                for stmt in *body {
509                    let stmt_code = codegen_stmt(stmt, interner, indent + 2, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env);
510                    write!(output, "{}", stmt_code).unwrap();
511                }
512                writeln!(output, "{}    }}", indent_str).unwrap();
513            }
514        }
515    }
516    writeln!(output, "{}}}", indent_str).unwrap();
517}
518
519/// Emit a `Select` as the **Mode-B seeded winner-pick**. Reads every receive
520/// arm's readiness (buffered `len()`, non-consuming); if any are ready, picks the
521/// winner among them with the shared seeded chooser (matching the interpreter's
522/// `below(n_ready)` over the same ready set in declaration order) and runs that
523/// arm; otherwise falls back to `tokio::select!` (so timeouts and not-yet-ready
524/// receives still block correctly).
525#[allow(clippy::too_many_arguments)]
526fn write_seeded_select<'a>(
527    output: &mut String,
528    branches: &[crate::ast::stmt::SelectBranch<'a>],
529    interner: &Interner,
530    indent: usize,
531    mutable_vars: &HashSet<Symbol>,
532    ctx: &mut RefinementContext<'a>,
533    lww_fields: &HashSet<(String, String)>,
534    mv_fields: &HashSet<(String, String)>,
535    synced_vars: &mut HashSet<Symbol>,
536    var_caps: &HashMap<Symbol, VariableCapabilities>,
537    async_functions: &HashSet<Symbol>,
538    pipe_vars: &HashSet<Symbol>,
539    boxed_fields: &HashSet<(String, String, String)>,
540    registry: &TypeRegistry,
541    type_env: &crate::analysis::types::TypeEnv,
542) {
543    use crate::ast::stmt::SelectBranch;
544    let indent_str = "    ".repeat(indent);
545    writeln!(output, "{}{{", indent_str).unwrap();
546    writeln!(output, "{}    let mut __logos_ready: Vec<usize> = Vec::new();", indent_str).unwrap();
547    let mut recv_idx = 0usize;
548    for branch in branches {
549        if let SelectBranch::Receive { pipe, .. } = branch {
550            let pipe_str = codegen_expr_with_async(pipe, interner, synced_vars, async_functions, ctx.get_variable_types());
551            let is_local_pipe = if let Expr::Identifier(sym) = pipe {
552                pipe_vars.contains(sym)
553            } else {
554                false
555            };
556            let suffix = if is_local_pipe { "_rx" } else { "" };
557            writeln!(
558                output,
559                "{}    if {}{}.len() > 0 {{ __logos_ready.push({}); }}",
560                indent_str, pipe_str, suffix, recv_idx
561            ).unwrap();
562            recv_idx += 1;
563        }
564    }
565    writeln!(output, "{}    if __logos_ready.is_empty() {{", indent_str).unwrap();
566    write_tokio_select(
567        output, branches, interner, indent + 2, mutable_vars, ctx, lww_fields, mv_fields,
568        synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env,
569    );
570    writeln!(output, "{}    }} else {{", indent_str).unwrap();
571    writeln!(
572        output,
573        "{}        let __logos_pick = __logos_ready[logicaffeine_system::concurrency::seeded_pick(__logos_ready.len())];",
574        indent_str
575    ).unwrap();
576    writeln!(output, "{}        match __logos_pick {{", indent_str).unwrap();
577    let mut recv_idx = 0usize;
578    for branch in branches {
579        if let SelectBranch::Receive { var, pipe, body } = branch {
580            let var_name = interner.resolve(*var);
581            let pipe_str = codegen_expr_with_async(pipe, interner, synced_vars, async_functions, ctx.get_variable_types());
582            let is_local_pipe = if let Expr::Identifier(sym) = pipe {
583                pipe_vars.contains(sym)
584            } else {
585                false
586            };
587            let suffix = if is_local_pipe { "_rx" } else { "" };
588            writeln!(output, "{}            {} => {{", indent_str, recv_idx).unwrap();
589            writeln!(
590                output,
591                "{}                if let Some({}) = {}{}.recv().await {{",
592                indent_str, var_name, pipe_str, suffix
593            ).unwrap();
594            for stmt in *body {
595                let stmt_code = codegen_stmt(stmt, interner, indent + 5, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env);
596                write!(output, "{}", stmt_code).unwrap();
597            }
598            writeln!(output, "{}                }}", indent_str).unwrap();
599            writeln!(output, "{}            }}", indent_str).unwrap();
600            recv_idx += 1;
601        }
602    }
603    writeln!(output, "{}            _ => unreachable!(),", indent_str).unwrap();
604    writeln!(output, "{}        }}", indent_str).unwrap();
605    writeln!(output, "{}    }}", indent_str).unwrap();
606    writeln!(output, "{}}}", indent_str).unwrap();
607}
608
609/// If `collection` names an OWNED real `LogosSeq`/`LogosMap` value binding, return
610/// its Rust identifier so the caller can emit `<ident>.cow();` before an in-place
611/// mutation (copy-on-write for mutable value semantics: the shared `Rc` is deep-
612/// copied only if another handle observes it).
613///
614/// Returns `None` — no `cow()` — for every representation that is NOT a shared
615/// `Rc<RefCell<…>>`:
616/// - de-Rc'd plain `Vec`/`HashMap` locals (registered type starts `Vec`/`HashMap`),
617/// - the specialized `LogosI64Map`/`LogosI32Map`/`LogosDense…`/set variants (no `Rc`),
618/// - `FxHashSet` / `Set<T>` (Rust `Clone` already deep-copies a `HashSet`),
619/// - a `mutable` collection parameter (a `&LogosSeq`/`&LogosMap` whose in-place
620///   mutation is REQUIRED to reach the caller — and which cannot call `cow()`),
621/// - a non-identifier collection expression (a field/temporary, not a value binding).
622fn cow_target(
623    collection: &Expr,
624    ctx: &RefinementContext,
625    names: &RustNames,
626) -> Option<String> {
627    let Expr::Identifier(sym) = collection else { return None };
628    if ctx.is_mutable_collection_param(*sym) {
629        return None;
630    }
631    let ty = ctx.get_variable_types().get(sym)?;
632    // A hoisted-length suffix (`Vec<i64>|__hl:…`) only tags de-Rc'd Vecs; strip it
633    // before the head match so those never reach the `LogosSeq`/`LogosMap` arm.
634    let ty = ty.split("|__hl:").next().unwrap_or(ty.as_str());
635    if ty.starts_with("LogosSeq") || ty.starts_with("LogosMap") {
636        Some(names.ident(*sym))
637    } else {
638        None
639    }
640}
641
642/// Emit a copy-on-write guard before an in-place mutation of `collection`, when it
643/// is an owned real `LogosSeq`/`LogosMap` value binding (see [`cow_target`]).
644///
645/// Gated on [`value_semantics_enabled`]: under the historical reference semantics
646/// (`LOGOS_VALUE_SEMANTICS=0`, or the compile-time PE reference scope) collections
647/// share their allocation permanently and mutations ARE meant to alias, so no
648/// `cow()` is emitted — the shared `Rc` is left untouched.
649fn emit_cow(
650    collection: &Expr,
651    ctx: &RefinementContext,
652    names: &RustNames,
653    indent_str: &str,
654    output: &mut String,
655) {
656    if !crate::semantics::collections::value_semantics_enabled() {
657        return;
658    }
659    if let Some(name) = cow_target(collection, ctx, names) {
660        writeln!(output, "{}{}.cow();", indent_str, name).unwrap();
661    }
662}
663
664/// If a loop body's sole write to a registered scratch buffer identifies it, return that buffer and its
665/// scalarization info. Only the buffer's own fill loop pushes it (post-fill reads are proven read-only by
666/// `detect_scratch_buffers`), so any loop that pushes a registered scratch buffer IS its fill loop.
667fn scratch_fill_target<'a>(
668    body: &[Stmt<'a>],
669    ctx: &RefinementContext<'a>,
670) -> Option<(Symbol, super::affine_array::ScratchInfo)> {
671    for s in body {
672        if let Stmt::Push { collection: Expr::Identifier(c), .. } = s {
673            if let Some(info) = ctx.scratch_buffer(*c) {
674                return Some((*c, info.clone()));
675            }
676        }
677    }
678    None
679}
680
681pub fn codegen_stmt<'a>(
682    stmt: &Stmt<'a>,
683    interner: &Interner,
684    indent: usize,
685    mutable_vars: &HashSet<Symbol>,
686    ctx: &mut RefinementContext<'a>,
687    lww_fields: &HashSet<(String, String)>,
688    mv_fields: &HashSet<(String, String)>,  // Phase 49b: MVRegister fields (no timestamp)
689    synced_vars: &mut HashSet<Symbol>,  // Phase 52: Track synced variables
690    var_caps: &HashMap<Symbol, VariableCapabilities>,  // Phase 56: Mount+Sync detection
691    async_functions: &HashSet<Symbol>,  // Phase 54: Functions that are async
692    pipe_vars: &HashSet<Symbol>,  // Phase 54: Pipe declarations (have _tx/_rx suffixes)
693    boxed_fields: &HashSet<(String, String, String)>,  // Phase 102: Recursive enum fields
694    registry: &TypeRegistry,  // Phase 103: For type annotations on polymorphic enums
695    type_env: &crate::analysis::types::TypeEnv,
696) -> String {
697    let indent_str = "    ".repeat(indent);
698    let mut output = String::new();
699    let names = RustNames::new(interner);
700
701    // OPT-1C: Take liveness snapshot before any recursion.
702    // None = no liveness info → conservative clone.
703    // Recursive calls (If/While/etc. bodies) see None → conservative clone.
704    let live_vars_after: Option<HashSet<Symbol>> = ctx.take_live_vars_after();
705
706    // Drop a scratch buffer's `new Seq` declaration at any nesting: its fill loop is rewritten in place
707    // to `let w: [T; N] = from_fn(…)` (the `Stmt::Repeat` handler), which becomes the binding, so this
708    // `Seq::default()` declaration would be a dead duplicate.
709    if let Stmt::Let { var, .. } = stmt {
710        if ctx.scratch_buffer(*var).is_some() {
711            return output;
712        }
713    }
714
715    // O5: prepend oracle-proven bounds-elision hints for this statement's
716    // indexed accesses (the relational `i <= length(arr)` proofs O5a's for-range
717    // counter hints cannot reach — e.g. a growing FIFO read by a cursor).
718    output.push_str(&emit_oracle_index_hints(stmt, ctx, interner, &indent_str));
719
720    match stmt {
721        Stmt::Splice { body } => {
722            // Scope-transparent desugar output: emit the statements FLAT —
723            // no braces, same indent — so a multi-push lowers byte-identically
724            // to the consecutive pushes it desugars from.
725            for inner in body.iter() {
726                output.push_str(&codegen_stmt(inner, interner, indent, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env));
727            }
728        }
729        Stmt::Let { var, ty, value, mutable } => {
730            let var_name = names.ident(*var);
731
732            // AoS interleaving: a co-indexed group member. Column 0 emits the
733            // single fused `[[T; W]; N]` backing (reusing the first member's
734            // name); the other columns' declarations are dropped — their storage
735            // lives in the backing. Runs before the scalarization branch below.
736            if matches!(value, Expr::New { .. }) {
737                if let Some(tag) = parse_aos_tag(ctx.get_variable_types().get(var)) {
738                    if tag.col == 0 {
739                        let default = match tag.elem.as_str() {
740                            "f64" => "0f64",
741                            "bool" => "false",
742                            _ => "0i64",
743                        };
744                        writeln!(
745                            output,
746                            "{}let mut {}: [[{}; {}]; {}] = [[{}; {}]; {}];",
747                            indent_str, tag.backing, tag.elem, tag.width, tag.len, default, tag.width, tag.len
748                        )
749                        .unwrap();
750                    }
751                    return output;
752                }
753            }
754
755            // O3: a fixed-size Seq pre-registered as `[T; N]` (scalarization)
756            // — emit a stack array and let the init pushes fill it via indexed
757            // writes. Must run before the `new Seq` type registration below,
758            // which would otherwise overwrite the array type with LogosSeq.
759            if ctx.is_scalarized_array(*var) && matches!(value, Expr::New { .. }) {
760                if let Some(arr_ty) = ctx.get_variable_types().get(var).cloned() {
761                    let inner = arr_ty.trim_start_matches('[').trim_end_matches(']');
762                    let mut parts = inner.split("; ");
763                    let elem = parts.next().unwrap_or("i64");
764                    let n = parts.next().unwrap_or("0");
765                    let default = match elem {
766                        "f64" => "0f64",
767                        "bool" => "false",
768                        "Word8" => "word8(0)",
769                        "Word16" => "word16(0)",
770                        "Word32" => "word32(0)",
771                        "Word64" => "word64(0)",
772                        _ => "0i64",
773                    };
774                    writeln!(output, "{}let mut {}: {} = [{}; {}];",
775                        indent_str, var_name, arr_ty, default, n).unwrap();
776                    // A loop-built return buffer (the digest) fills through a RUNTIME cursor (the pushes
777                    // live in a loop): declare it here; the `Push` handler emits `out[cursor]=v; cursor+=1`.
778                    if let Some(cursor) = ctx.loop_fill_cursor(*var).map(|s| s.to_string()) {
779                        writeln!(output, "{}let mut {}: usize = 0;", indent_str, cursor).unwrap();
780                    }
781                    ctx.init_array_fill(*var);
782                    return output;
783                }
784            }
785
786            // Affine read-only array (CSR offset array): deleted entirely. The
787            // build push is suppressed and every `item _ of`/`length of` read
788            // substitutes the closed form, so the declaration emits nothing. The
789            // `__affine_array:...` type was registered in `codegen_program`.
790            if matches!(value, Expr::New { .. }) && ctx.affine_array(*var).is_some() {
791                return output;
792            }
793
794            // Append-only worklist: a de-Rc'd Seq frontier proven bounded by a
795            // monotone visited-set guard. Emit a PRE-SIZED buffer + a register
796            // tail counter; the pushes lower to `q[tail]=x; tail+=1` and
797            // `length of q` to `tail`. This is C's frontier representation.
798            if matches!(value, Expr::New { .. }) {
799                if let Some((cap, default, tail)) =
800                    ctx.worklist(*var).map(|w| (w.capacity.clone(), w.elem_default.clone(), w.tail_var.clone()))
801                {
802                    writeln!(output, "{}let mut {}: Vec<i64> = vec![{}; {}];", indent_str, var_name, default, cap).unwrap();
803                    writeln!(output, "{}let mut {}: usize = 0;", indent_str, tail).unwrap();
804                    // Encode the LOGICAL length (the tail) as a hoisted length so
805                    // `length of q` reads `tail`, not the buffer size, while every
806                    // other site strips the suffix and sees a plain `Vec<i64>`.
807                    ctx.register_variable_type(*var, format!("Vec<i64>|__hl:({} as i64)", tail));
808                    return output;
809                }
810            }
811
812            // O2 de-Rc: a Seq proven to never need reference semantics is a
813            // plain `Vec<T>` (no Rc/RefCell). Emit the owned-Vec declaration;
814            // access sites dispatch on the `Vec<T>` type exactly as they do for
815            // borrow-hoisted slices and materialized vecs.
816            if ctx.is_de_rc(*var) {
817                if let Some((vec_ty, init)) = derc_vec_decl(
818                    value, interner, synced_vars, boxed_fields, registry, async_functions, ctx,
819                ) {
820                    let is_mut = *mutable || mutable_vars.contains(var);
821                    let kw = if is_mut { "let mut" } else { "let" };
822                    // Pre-size a push-built Vec the program later index-reads up to
823                    // a bound: reserve once instead of reallocating as it grows
824                    // (C sizes the buffer exactly). Capacity is a hint — sound.
825                    let init = match (init.as_str(), ctx.get_vec_presize(*var)) {
826                        ("Vec::new()", Some(cap)) => {
827                            format!("Vec::with_capacity(({}) as usize)", cap)
828                        }
829                        _ => init,
830                    };
831                    // i64→i32 narrowing: a Seq of Int proven to hold only
832                    // i32-range values is `Vec<i32>` (access sites convert).
833                    let vec_ty = if ctx.is_narrowed(*var) && vec_ty == "Vec<i64>" {
834                        "Vec<i32>".to_string()
835                    } else {
836                        vec_ty
837                    };
838                    writeln!(output, "{}{} {}: {} = {};", indent_str, kw, var_name, vec_ty, init).unwrap();
839                    for g in ctx.narrow_guards(*var).to_vec() {
840                        writeln!(output, "{}assert!({}, \"LOGOS i32-narrowing guard: element value must fit i32\");", indent_str, g).unwrap();
841                    }
842                    ctx.register_variable_type(*var, vec_ty);
843                    return output;
844                }
845            }
846
847            // Register collection type for direct indexing optimization.
848            // Check explicit type annotation first, then infer from Expr::New.
849            if let Some(TypeExpr::Generic { base, params }) = ty {
850                let base_name = interner.resolve(*base);
851                match base_name {
852                    "Seq" | "List" | "Vec" => {
853                        let rust_type = if !params.is_empty() {
854                            format!("LogosSeq<{}>", codegen_type_expr(&params[0], interner))
855                        } else {
856                            "LogosSeq<()>".to_string()
857                        };
858                        ctx.register_variable_type(*var, rust_type);
859                    }
860                    "Map" | "HashMap" => {
861                        let rust_type = if params.len() >= 2 {
862                            map_rust_type(
863                                &codegen_type_expr(&params[0], interner),
864                                &codegen_type_expr(&params[1], interner),
865                                *var,
866                                ctx,
867                            )
868                        } else {
869                            "LogosMap<String, String>".to_string()
870                        };
871                        ctx.register_variable_type(*var, rust_type);
872                    }
873                    _ => {}
874                }
875            } else if let Expr::New { type_name, type_args, .. } = value {
876                let type_str = interner.resolve(*type_name);
877                match type_str {
878                    "Seq" | "List" | "Vec" => {
879                        let rust_type = if !type_args.is_empty() {
880                            format!("LogosSeq<{}>", codegen_type_expr(&type_args[0], interner))
881                        } else {
882                            "LogosSeq<()>".to_string()
883                        };
884                        ctx.register_variable_type(*var, rust_type);
885                    }
886                    "Map" | "HashMap" => {
887                        let rust_type = if type_args.len() >= 2 {
888                            map_rust_type(
889                                &codegen_type_expr(&type_args[0], interner),
890                                &codegen_type_expr(&type_args[1], interner),
891                                *var,
892                                ctx,
893                            )
894                        } else {
895                            "LogosMap<String, String>".to_string()
896                        };
897                        ctx.register_variable_type(*var, rust_type);
898                    }
899                    _ => {}
900                }
901            } else if let Expr::List(items) = value {
902                // Infer element type from first literal in the list for Copy elimination
903                let elem_type = items.first()
904                    .map(|e| infer_rust_type_from_expr(e, interner))
905                    .unwrap_or_else(|| "_".to_string());
906                ctx.register_variable_type(*var, format!("LogosSeq<{}>", elem_type));
907            } else if let Expr::Identifier(src_sym) = value {
908                // Propagate type from source variable: `Let result be arr` inherits arr's type.
909                // For borrow params (&[T]), the copy becomes Vec<T> (owned).
910                if let Some(src_type) = ctx.get_variable_types().get(src_sym).cloned() {
911                    if src_type.starts_with("&[") {
912                        // Propagate borrow type — rebinding the slice, not copying
913                        ctx.register_variable_type(*var, src_type);
914                    } else if src_type.starts_with("&mut [") {
915                        // Mutable borrow param consumed into alias → propagate &mut [T]
916                        // so the alias continues to be treated as the in-place mutable borrow.
917                        ctx.register_variable_type(*var, src_type);
918                    } else if !super::is_fn_role_slot(&src_type) {
919                        ctx.register_variable_type(*var, src_type);
920                    }
921                }
922            } else if let Expr::Copy { expr: inner } = value {
923                // `Copy of items ... of arr` or `Copy of arr` produces same collection type
924                let src_sym = match inner {
925                    Expr::Slice { collection, .. } => {
926                        if let Expr::Identifier(s) = collection { Some(*s) } else { None }
927                    }
928                    Expr::Identifier(s) => Some(*s),
929                    _ => None,
930                };
931                if let Some(s) = src_sym {
932                    if let Some(src_type) = ctx.get_variable_types().get(&s).cloned() {
933                        if src_type.starts_with("LogosSeq") || src_type.starts_with("Vec") || src_type.starts_with("&[") {
934                            let elem = if src_type.starts_with("LogosSeq<") {
935                                src_type.strip_prefix("LogosSeq<").and_then(|t| t.strip_suffix('>')).unwrap_or("_")
936                            } else if src_type.starts_with("Vec<") {
937                                src_type.strip_prefix("Vec<").and_then(|t| t.strip_suffix('>')).unwrap_or("_")
938                            } else {
939                                src_type.strip_prefix("&[").and_then(|t| t.strip_suffix(']')).unwrap_or("_")
940                            };
941                            ctx.register_variable_type(*var, format!("LogosSeq<{}>", elem));
942                        } else if src_type.starts_with("LogosMap") {
943                            ctx.register_variable_type(*var, src_type);
944                        }
945                    }
946                }
947            }
948
949            // Infer result type from function call return types
950            if !ctx.get_variable_types().contains_key(var) {
951                if let Expr::Call { function, .. } = value {
952                    // The `decimal(..)` builtin yields an exact `LogosDecimal` — record it so
953                    // later `+ − ×` over this binding take the exact decimal codegen path.
954                    if interner.resolve(*function) == "decimal" {
955                        ctx.register_variable_type(*var, "LogosDecimal".to_string());
956                    } else if interner.resolve(*function) == "complex" {
957                        ctx.register_variable_type(*var, "LogosComplex".to_string());
958                    } else if interner.resolve(*function) == "modular" {
959                        ctx.register_variable_type(*var, "LogosModular".to_string());
960                    } else if matches!(interner.resolve(*function), "quantity" | "convert") {
961                        // Both quantity builtins yield a `LogosQuantity`; record it so later
962                        // `+ − × ÷` / comparison over this binding take the quantity codegen path.
963                        ctx.register_variable_type(*var, "LogosQuantity".to_string());
964                    } else if interner.resolve(*function) == "money" {
965                        // `money(..)` yields a `LogosMoney`; record it so later `+ − × ÷` /
966                        // comparison over this binding take the money codegen path.
967                        ctx.register_variable_type(*var, "LogosMoney".to_string());
968                    } else if matches!(
969                        interner.resolve(*function),
970                        "uuid" | "uuid_nil" | "uuid_max" | "uuid_v3" | "uuid_v5" | "uuid_dns"
971                            | "uuid_url" | "uuid_oid" | "uuid_x500"
972                    ) {
973                        // Every UUID constructor yields a `LogosUuid`; record it so a later
974                        // comparison over this binding takes the (Ord) UUID codegen path.
975                        ctx.register_variable_type(*var, "LogosUuid".to_string());
976                    } else if let Some(rt) = ctx.get_fn_return(function).cloned() {
977                        ctx.register_variable_type(*var, rt);
978                    }
979                }
980            }
981
982            // Register scalar types for mixed Float*Int arithmetic coercion
983            if !ctx.get_variable_types().contains_key(var) {
984                let inferred = infer_rust_type_from_expr(value, interner);
985                if inferred != "_" {
986                    ctx.register_variable_type(*var, inferred);
987                } else {
988                    // Try deeper numeric type inference for expressions like `4.0 * pi * pi`
989                    let numeric = infer_numeric_type(value, interner, ctx.get_variable_types());
990                    if numeric != "unknown" {
991                        ctx.register_variable_type(*var, numeric.to_string());
992                    } else if let crate::analysis::types::LogosType::Map(k, v) =
993                        super::types::infer_logos_type(value, interner, ctx.get_variable_types())
994                    {
995                        // A `{k: v, …}` map-literal binding: record its `Map<K, V>` type so a
996                        // numeric-unified key lookup (`m contains 1.0` on an Int-keyed map) can
997                        // coerce. Only Map is registered here — the narrowest change that closes
998                        // the compiled key-coercion gap.
999                        ctx.register_variable_type(
1000                            *var,
1001                            crate::analysis::types::LogosType::Map(k, v).to_rust_type(),
1002                        );
1003                    }
1004                }
1005            }
1006
1007            // A nested list literal (`[[…], …]`) whose whole-program type only resolved to the
1008            // imprecise `LogosSeq<_>`: re-register the precise `LogosSeq<LogosSeq<…>>` so the
1009            // nested-write through-write fast path can specialise on the inner Seq. Narrowly gated
1010            // on the imprecise inner, so a de-Rc'd `Vec` or a specialised representation is untouched.
1011            if matches!(value, Expr::List(_))
1012                && ctx.get_variable_types().get(var).map_or(false, |t| t == "LogosSeq<_>")
1013            {
1014                if let crate::analysis::types::LogosType::Seq(inner) =
1015                    super::types::infer_logos_type(value, interner, ctx.get_variable_types())
1016                {
1017                    if matches!(*inner, crate::analysis::types::LogosType::Seq(_)) {
1018                        ctx.register_variable_type(
1019                            *var,
1020                            crate::analysis::types::LogosType::Seq(inner).to_rust_type(),
1021                        );
1022                    }
1023                }
1024            }
1025
1026            // OPT: Single-char text variable → u8 byte.
1027            // If this variable is pre-registered as __single_char_u8, emit u8 instead of String.
1028            let is_single_char_u8 = ctx.get_variable_types().get(var)
1029                .map_or(false, |t| t == "__single_char_u8");
1030
1031            if is_single_char_u8 {
1032                if let Expr::Literal(Literal::Text(sym)) = value {
1033                    let text = interner.resolve(*sym);
1034                    if text.len() == 1 {
1035                        let ch = text.as_bytes()[0];
1036                        let is_mutable = *mutable || mutable_vars.contains(var);
1037                        if is_mutable {
1038                            writeln!(output, "{}let mut {}: u8 = b'{}';", indent_str, var_name, ch as char).unwrap();
1039                        } else {
1040                            writeln!(output, "{}let {}: u8 = b'{}';", indent_str, var_name, ch as char).unwrap();
1041                        }
1042                        // Don't register as string var — it's a u8 now
1043                        return output;
1044                    }
1045                }
1046            }
1047
1048            // Materialize Expr::Slice on LogosSeq as Vec<T> to avoid dangling
1049            // &[T] borrows from temporary Ref guards. Stored as Vec (not LogosSeq)
1050            // so that downstream `copy of` can wrap with LogosSeq::from_vec()
1051            // for zero-copy ownership transfer instead of deep_clone.
1052            if let Expr::Slice { collection, start, end } = value {
1053                if let Expr::Identifier(coll_sym) = collection {
1054                    if let Some(coll_type) = ctx.get_variable_types().get(coll_sym).cloned() {
1055                        if coll_type.starts_with("LogosSeq<") {
1056                            let elem_type = coll_type.strip_prefix("LogosSeq<")
1057                                .and_then(|t| t.strip_suffix('>'))
1058                                .unwrap_or("_");
1059                            let coll_name = names.ident(*coll_sym);
1060                            let start_str = codegen_expr_boxed_with_types(
1061                                start, interner, synced_vars, boxed_fields, registry, async_functions,
1062                                ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div()
1063                            );
1064                            let end_str = codegen_expr_boxed_with_types(
1065                                end, interner, synced_vars, boxed_fields, registry, async_functions,
1066                                ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div()
1067                            );
1068                            let is_mutable = *mutable || mutable_vars.contains(var);
1069                            let mutk = if is_mutable { "mut " } else { "" };
1070                            writeln!(output, "{}let {}{}: Vec<{}> = {}.borrow()[({} - 1) as usize..{} as usize].to_vec();",
1071                                indent_str, mutk, var_name, elem_type, coll_name, start_str, end_str).unwrap();
1072                            // Register as Vec<T> — indexing works directly, and `copy of`
1073                            // wraps with LogosSeq::from_vec(x.clone()) for one-copy semantics.
1074                            ctx.register_variable_type(*var, format!("Vec<{}>", elem_type));
1075                            if is_definitely_string_expr_with_vars(value, ctx.get_string_vars()) {
1076                                ctx.register_string_var(*var);
1077                            }
1078                            return output;
1079                        } else if coll_type.starts_with("&[") {
1080                            let elem_type = coll_type.strip_prefix("&[")
1081                                .and_then(|t| t.strip_suffix(']'))
1082                                .unwrap_or("_");
1083                            let coll_name = names.ident(*coll_sym);
1084                            let start_str = codegen_expr_boxed_with_types(
1085                                start, interner, synced_vars, boxed_fields, registry, async_functions,
1086                                ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div()
1087                            );
1088                            let end_str = codegen_expr_boxed_with_types(
1089                                end, interner, synced_vars, boxed_fields, registry, async_functions,
1090                                ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div()
1091                            );
1092                            let is_mutable = *mutable || mutable_vars.contains(var);
1093                            let mutk = if is_mutable { "mut " } else { "" };
1094                            // Direct slice of borrow param — no .borrow() needed
1095                            writeln!(output, "{}let {}{}: Vec<{}> = {}[({} - 1) as usize..{} as usize].to_vec();",
1096                                indent_str, mutk, var_name, elem_type, coll_name, start_str, end_str).unwrap();
1097                            ctx.register_variable_type(*var, format!("Vec<{}>", elem_type));
1098                            if is_definitely_string_expr_with_vars(value, ctx.get_string_vars()) {
1099                                ctx.register_string_var(*var);
1100                            }
1101                            return output;
1102                        }
1103                    }
1104                }
1105            }
1106
1107            // Overflow-promoting Int binding: a promotion candidate whose initializer is an
1108            // integer expression is stored as `LogosInt` (not a bare `i64`), so a value that
1109            // exceeds i64 promotes instead of panicking. Register the `|__bigint` sentinel BEFORE
1110            // codegen so any self-reference in the RHS already reads as a LogosInt.
1111            let is_bigint_binding = ty.is_none()
1112                && ctx.is_promotable_candidate(*var)
1113                && crate::codegen::types::infer_numeric_type(value, interner, ctx.get_variable_types()) == "i64";
1114            if is_bigint_binding {
1115                ctx.register_variable_type(*var, "i64|__bigint".to_string());
1116            }
1117
1118            // Phase 54+: Use codegen_expr_boxed with string+type tracking for proper codegen
1119            let mut value_str = if is_bigint_binding {
1120                // Tolerant (un-narrowed) RHS, coerced to LogosInt (`.into()` is identity when the
1121                // RHS is already a LogosInt, and promotes a plain `i64` otherwise).
1122                let raw = codegen_expr_boxed_with_types_oracle_tolerant(
1123                    value, interner, synced_vars, boxed_fields, registry, async_functions,
1124                    ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle(),
1125                );
1126                format!("logicaffeine_data::LogosInt::from({})", raw)
1127            } else {
1128                codegen_expr_boxed_with_types_oracle(
1129                    value, interner, synced_vars, boxed_fields, registry, async_functions,
1130                    ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle(),
1131                )
1132            };
1133
1134            // Phase D: lower a non-aliased `Map of Int to Int` to the specialized
1135            // open-addressing `LogosI64Map`, or the keys-only `LogosI64Set` when
1136            // the value is never read (contains + insert only). Override the
1137            // constructor AND re-register the type so the two never disagree,
1138            // regardless of which `Let` initializer shape registered it above.
1139            if ctx.is_i64_map(*var) {
1140                // Densest tier first: a proven bounded key domain → a
1141                // direct-addressed array sized to the capacity hint, offset by the
1142                // proven window `lo`. Otherwise the open-addressing map/set.
1143                let dense = ctx.dense_info(*var);
1144                let i64_ty = if let Some(info) = dense {
1145                    dense_type_name(info.kind)
1146                } else if ctx.is_i32_set(*var) {
1147                    "LogosI32Set"
1148                } else if ctx.is_i32_map(*var) {
1149                    "LogosI32Map"
1150                } else if ctx.is_i64_set(*var) {
1151                    "LogosI64Set"
1152                } else {
1153                    "LogosI64Map"
1154                };
1155                if let Some(ctor) = i64_map_ctor(
1156                    value, i64_ty, dense.map(|i| i.lo), interner, synced_vars, boxed_fields,
1157                    registry, async_functions, ctx,
1158                ) {
1159                    value_str = ctor;
1160                    ctx.register_variable_type(*var, i64_ty.to_string());
1161                }
1162            }
1163
1164            // Grand Challenge: Variable is mutable if explicitly marked OR if it's a Set target.
1165            // A `LogosI64Map` is mutated in place via `&mut self` (the analysis
1166            // requires ≥1 insert), so it must bind as `let mut`.
1167            let is_mutable = *mutable || mutable_vars.contains(var) || ctx.is_i64_map(*var);
1168
1169            // Reference semantics: clone LogosSeq/LogosMap on assignment to share the Rc.
1170            // Borrow param (&[T]) assigned to mutable local → convert to owned.
1171            if let Expr::Identifier(src_sym) = value {
1172                if let Some(src_type) = ctx.get_variable_types().get(src_sym) {
1173                    if src_type.starts_with("LogosSeq") || src_type.starts_with("LogosMap") {
1174                        value_str = format!("{}.clone()", value_str);
1175                    } else if is_mutable && src_type.starts_with("&[") {
1176                        value_str = format!("{}.to_vec()", value_str);
1177                    }
1178                }
1179            }
1180
1181            // Phase 103: Get explicit type annotation or infer for multi-param generic enums
1182            let type_annotation = if is_bigint_binding {
1183                Some("logicaffeine_data::LogosInt".to_string())
1184            } else {
1185                ty.map(|t| codegen_type_expr(t, interner))
1186                    .or_else(|| infer_variant_type_annotation(value, registry, interner))
1187            };
1188
1189            // A `Rational`-typed binding whose RHS is a plain integer expression — a bare
1190            // `Let x: Rational be 5`, or the whole-valued constant fold `6 / 2 → 3` — must
1191            // coerce the i64 value to an exact `LogosRational` so the declared type matches.
1192            // An RHS that already produces a Rational (an `ExactDivide` chain) is left as-is.
1193            if type_annotation.as_deref() == Some("LogosRational") {
1194                if !is_rational_expr(value, ctx.get_variable_types()) {
1195                    value_str = format!("LogosRational::from_i64(({}) as i64)", value_str);
1196                }
1197                ctx.register_variable_type(*var, "LogosRational".to_string());
1198            }
1199
1200            match (is_mutable, type_annotation) {
1201                (true, Some(t)) => writeln!(output, "{}let mut {}: {} = {};", indent_str, var_name, t, value_str).unwrap(),
1202                (true, None) => writeln!(output, "{}let mut {} = {};", indent_str, var_name, value_str).unwrap(),
1203                (false, Some(t)) => writeln!(output, "{}let {}: {} = {};", indent_str, var_name, t, value_str).unwrap(),
1204                (false, None) => writeln!(output, "{}let {} = {};", indent_str, var_name, value_str).unwrap(),
1205            }
1206
1207            // O9 libdivide: if this binding is a loop-invariant positive divisor,
1208            // precompute its magic multiply ONCE here so every later `% n` / `/ n`
1209            // lowers to `helper.rem(..)` / `helper.div(..)`. Harmless if `n <= 0`
1210            // (the helper is only ever read inside loops that don't run there).
1211            if let Some(helper) = ctx.get_fast_div().get(var) {
1212                writeln!(
1213                    output,
1214                    "{}let {} = logicaffeine_data::LogosDivU64::new(({}) as u64);",
1215                    indent_str, helper, var_name
1216                )
1217                .unwrap();
1218            }
1219
1220            // Track string variables for proper concatenation in subsequent expressions
1221            if is_definitely_string_expr_with_vars(value, ctx.get_string_vars()) {
1222                ctx.register_string_var(*var);
1223            }
1224
1225            // Phase 43C: Handle refinement type
1226            if let Some(TypeExpr::Refinement { base: _, var: bound_var, predicate }) = ty {
1227                emit_refinement_check(&var_name, *bound_var, predicate, interner, &indent_str, &mut output);
1228                ctx.register(*var, *bound_var, predicate);
1229            }
1230        }
1231
1232        Stmt::Set { target, value } => {
1233            let target_name = names.ident(*target);
1234
1235            // Overflow-promoting Int target: assign an un-narrowed `LogosInt` (`.into()` is
1236            // identity when the RHS already is one, and promotes a plain `i64` otherwise), so a
1237            // running product/sum that exceeds i64 promotes to BigInt instead of panicking. A
1238            // bigint target is always a scalar integer, so none of the string/char/collection
1239            // special cases below apply.
1240            if ctx.is_bigint_var(*target) {
1241                let raw = codegen_expr_boxed_with_types_oracle_tolerant(
1242                    value, interner, synced_vars, boxed_fields, registry, async_functions,
1243                    ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle(),
1244                );
1245                writeln!(output, "{}{} = logicaffeine_data::LogosInt::from({});", indent_str, target_name, raw).unwrap();
1246                if let Some((bound_var, predicate)) = ctx.get_constraint(*target) {
1247                    emit_refinement_check(&target_name, bound_var, predicate, interner, &indent_str, &mut output);
1248                }
1249                return output;
1250            }
1251
1252            // Cursor-indexed string build: `Set text to text + X` writes X at the
1253            // cursor in the pre-sized buffer (no push). The paired `Set c to c +
1254            // len(X)` that follows advances the cursor as usual. See
1255            // peephole::try_emit_indexed_string_build.
1256            if let Some(cursor) = ctx.indexed_string_build(*target).map(|c| c.to_string()) {
1257                if let Expr::BinaryOp { op: BinaryOpKind::Add, right, .. } = value {
1258                    match right {
1259                        Expr::Literal(Literal::Text(sym)) => {
1260                            let lit = interner.resolve(*sym);
1261                            let bytes: Vec<String> =
1262                                lit.bytes().map(|b| format!("{}u8", b)).collect();
1263                            writeln!(
1264                                output,
1265                                "{ind}unsafe {{ std::ptr::copy_nonoverlapping([{b}].as_ptr(), {t}.as_mut_vec().as_mut_ptr().add(({c}) as usize), {k}); }}",
1266                                ind = indent_str, t = target_name, c = cursor, k = lit.len(), b = bytes.join(", ")
1267                            )
1268                            .unwrap();
1269                            return output;
1270                        }
1271                        Expr::Identifier(v)
1272                            if ctx.get_variable_types().get(v).map(String::as_str)
1273                                == Some("__single_char_u8") =>
1274                        {
1275                            let vn = names.ident(*v);
1276                            writeln!(
1277                                output,
1278                                "{ind}unsafe {{ *{t}.as_mut_vec().as_mut_ptr().add(({c}) as usize) = {vn}; }}",
1279                                ind = indent_str, t = target_name, c = cursor
1280                            )
1281                            .unwrap();
1282                            return output;
1283                        }
1284                        _ => {}
1285                    }
1286                }
1287            }
1288
1289            // O2 de-Rc: reassigning a de-Rc'd Seq to a FRESH allocation keeps
1290            // it a plain `Vec<T>` (`xs = Vec::new()`), not `Seq::default()`.
1291            if ctx.is_de_rc(*target) {
1292                if let Some((_, init)) = derc_vec_decl(
1293                    value, interner, synced_vars, boxed_fields, registry, async_functions, ctx,
1294                ) {
1295                    writeln!(output, "{}{} = {};", indent_str, target_name, init).unwrap();
1296                    return output;
1297                }
1298            }
1299
1300            // OPT: Single-char u8 variable → emit byte literal assignment.
1301            let is_target_single_char_u8 = ctx.get_variable_types().get(target)
1302                .map_or(false, |t| t == "__single_char_u8");
1303            if is_target_single_char_u8 {
1304                if let Expr::Literal(Literal::Text(sym)) = value {
1305                    let text = interner.resolve(*sym);
1306                    if text.len() == 1 {
1307                        let ch = text.as_bytes()[0];
1308                        writeln!(output, "{}{} = b'{}';", indent_str, target_name, ch as char).unwrap();
1309                        return output;
1310                    }
1311                }
1312            }
1313
1314            let string_vars = ctx.get_string_vars();
1315            let var_types = ctx.get_variable_types();
1316
1317            // Optimization: detect self-append pattern (result = result + x + y)
1318            // and emit write!(result, "{}{}", x, y) instead of result = format!(...).
1319            // This is O(n) amortized (in-place append) vs O(n²) (full copy each iteration).
1320            let used_write = if ctx.is_string_var(*target)
1321                && is_definitely_string_expr_with_vars(value, string_vars)
1322            {
1323                let mut operands = Vec::new();
1324                collect_string_concat_operands(value, string_vars, &mut operands);
1325
1326                // Need at least 2 operands, leftmost must be the target variable
1327                if operands.len() >= 2 && matches!(operands[0], Expr::Identifier(sym) if *sym == *target) {
1328                    // Check no other operand references target (would cause borrow conflict)
1329                    let tail = &operands[1..];
1330                    let mut tail_ids = HashSet::new();
1331                    for op in tail {
1332                        collect_expr_identifiers(op, &mut tail_ids);
1333                    }
1334
1335                    if !tail_ids.contains(target) {
1336                        if tail.len() == 1 {
1337                            // Single operand: use push/push_str for zero-format-overhead append
1338                            let operand = tail[0];
1339                            if let Expr::Literal(Literal::Text(sym)) = operand {
1340                                let text = interner.resolve(*sym);
1341                                if text.len() == 1 {
1342                                    let ch = text.chars().next().unwrap();
1343                                    writeln!(output, "{}{}.push('{}');",
1344                                        indent_str, target_name, ch).unwrap();
1345                                } else {
1346                                    writeln!(output, "{}{}.push_str(\"{}\");",
1347                                        indent_str, target_name, text).unwrap();
1348                                }
1349                            } else if let Expr::Identifier(sym) = operand {
1350                                if var_types.get(sym).map_or(false, |t| t == "__single_char_u8") {
1351                                    // OPT: u8 single-char var → push(ch as char)
1352                                    let val_str = codegen_expr_boxed_with_types(
1353                                        operand, interner, synced_vars, boxed_fields, registry, async_functions,
1354                                        string_vars, var_types, ctx.get_fast_div()
1355                                    );
1356                                    writeln!(output, "{}{}.push({} as char);",
1357                                        indent_str, target_name, val_str).unwrap();
1358                                } else if string_vars.contains(sym) {
1359                                    let val_str = codegen_expr_boxed_with_types(
1360                                        operand, interner, synced_vars, boxed_fields, registry, async_functions,
1361                                        string_vars, var_types, ctx.get_fast_div()
1362                                    );
1363                                    writeln!(output, "{}{}.push_str(&{});",
1364                                        indent_str, target_name, val_str).unwrap();
1365                                } else {
1366                                    // Non-string single operand: use write!
1367                                    let val_str = codegen_expr_boxed_with_types(
1368                                        operand, interner, synced_vars, boxed_fields, registry, async_functions,
1369                                        string_vars, var_types, ctx.get_fast_div()
1370                                    );
1371                                    writeln!(output, "{}write!({}, \"{{}}\", {}).unwrap();",
1372                                        indent_str, target_name, val_str).unwrap();
1373                                }
1374                            } else {
1375                                // Non-string single operand: use write!
1376                                let val_str = codegen_expr_boxed_with_types(
1377                                    operand, interner, synced_vars, boxed_fields, registry, async_functions,
1378                                    string_vars, var_types, ctx.get_fast_div()
1379                                );
1380                                writeln!(output, "{}write!({}, \"{{}}\", {}).unwrap();",
1381                                    indent_str, target_name, val_str).unwrap();
1382                            }
1383                        } else {
1384                            // Multiple operands: use write!() with format string
1385                            let placeholders: String = tail.iter().map(|_| "{}").collect::<Vec<_>>().join("");
1386                            let values: Vec<String> = tail.iter().map(|e| {
1387                                if let Expr::Literal(Literal::Text(sym)) = e {
1388                                    format!("\"{}\"", interner.resolve(*sym))
1389                                } else {
1390                                    codegen_expr_boxed_with_types(
1391                                        e, interner, synced_vars, boxed_fields, registry, async_functions,
1392                                        string_vars, var_types, ctx.get_fast_div()
1393                                    )
1394                                }
1395                            }).collect();
1396                            writeln!(output, "{}write!({}, \"{}\", {}).unwrap();",
1397                                indent_str, target_name, placeholders, values.join(", ")).unwrap();
1398                        }
1399                        true
1400                    } else {
1401                        false
1402                    }
1403                } else {
1404                    false
1405                }
1406            } else {
1407                false
1408            };
1409
1410            if !used_write {
1411                // &mut borrow call-site transformation:
1412                // `Set x to f(x, ...)` where f has fn_mut_borrow at the target position
1413                // → `f(&mut x, ...)` (no assignment, mutation is in-place)
1414                let mut used_mut_borrow = false;
1415                if let Expr::Call { function, args } = value {
1416                    let callee_mut_borrow_indices: HashSet<usize> =
1417                        super::fn_role_indices(var_types.get(function), super::FnRole::MutBorrow);
1418                    if !callee_mut_borrow_indices.is_empty() {
1419                        // Check if target is at a mut_borrow position
1420                        let target_at_mut_borrow = args.iter().enumerate()
1421                            .any(|(i, a)| {
1422                                callee_mut_borrow_indices.contains(&i)
1423                                    && matches!(a, Expr::Identifier(sym) if *sym == *target)
1424                            });
1425                        if target_at_mut_borrow {
1426                            let callee_borrow_indices: HashSet<usize> =
1427                                super::fn_role_indices(var_types.get(function), super::FnRole::Borrow);
1428                            let func_name = names.ident(*function);
1429                            let args_str: Vec<String> = args.iter().enumerate()
1430                                .map(|(i, a)| {
1431                                    let s = codegen_expr_boxed_with_types(
1432                                        a, interner, synced_vars, boxed_fields, registry,
1433                                        async_functions, string_vars, var_types, ctx.get_fast_div()
1434                                    );
1435                                    if callee_mut_borrow_indices.contains(&i) {
1436                                        // Mut borrow param: pass &mut [T] reference
1437                                        if let Expr::Identifier(sym) = a {
1438                                            if let Some(ty) = var_types.get(sym) {
1439                                                let ty = ty.split("|__hl:").next().unwrap_or(ty.as_str());
1440                                                if ty.starts_with("&mut [") {
1441                                                    return s; // Already &mut slice
1442                                                }
1443                                                // Phase 3b: a de-Rc'd `Vec` lends `&mut x`
1444                                                // directly — no RefCell to borrow_mut.
1445                                                if ty.starts_with("Vec<") {
1446                                                    return format!("&mut {}", s);
1447                                                }
1448                                                if ty.starts_with("LogosSeq") {
1449                                                    return format!("&mut *{}.borrow_mut()", s);
1450                                                }
1451                                            }
1452                                            // Unknown type — default to LogosSeq
1453                                            return format!("&mut *{}.borrow_mut()", s);
1454                                        }
1455                                        format!("&mut {}", s)
1456                                    } else if callee_borrow_indices.contains(&i) {
1457                                        if let Expr::Identifier(sym) = a {
1458                                            if let Some(ty) = var_types.get(sym) {
1459                                                let ty = ty.split("|__hl:").next().unwrap_or(ty.as_str());
1460                                                if ty.starts_with("&[") || ty.starts_with("&mut [") {
1461                                                    return s;
1462                                                }
1463                                                if ty.starts_with("Vec<") {
1464                                                    return format!("&{}", s);
1465                                                }
1466                                                if ty.starts_with('[') {
1467                                                    // Const-table stack array [T; N] coerces to &[T].
1468                                                    return format!("&{}", s);
1469                                                }
1470                                                if ty.starts_with("LogosSeq") {
1471                                                    return format!("&*{}.borrow()", s);
1472                                                }
1473                                            }
1474                                            // Unknown type — default to LogosSeq
1475                                            return format!("&*{}.borrow()", s);
1476                                        }
1477                                        format!("&*{}.borrow()", s)
1478                                    } else {
1479                                        s
1480                                    }
1481                                })
1482                                .collect();
1483                            // Value semantics: make each lent handle's buffer
1484                            // UNIQUE before the in-place call — an alias keeps
1485                            // the pre-call value, the callee's writes land on
1486                            // ours alone. Amortized free: a refcount-1 cow is
1487                            // a branch, only a genuinely shared buffer copies.
1488                            if crate::semantics::collections::value_semantics_enabled() {
1489                                for (i, a) in args.iter().enumerate() {
1490                                    if !callee_mut_borrow_indices.contains(&i) {
1491                                        continue;
1492                                    }
1493                                    if let Expr::Identifier(sym) = a {
1494                                        let lends_refcell = match var_types.get(sym) {
1495                                            Some(t) => t
1496                                                .split("|__hl:")
1497                                                .next()
1498                                                .unwrap_or(t.as_str())
1499                                                .starts_with("LogosSeq"),
1500                                            None => true, // unknown type lowers via borrow_mut above
1501                                        };
1502                                        if lends_refcell {
1503                                            writeln!(output, "{}{}.cow();", indent_str, names.ident(*sym)).unwrap();
1504                                        }
1505                                    }
1506                                }
1507                            }
1508                            let await_suffix = if async_functions.contains(function) { ".await" } else { "" };
1509                            writeln!(output, "{}{}({}){};", indent_str, func_name, args_str.join(", "), await_suffix).unwrap();
1510                            used_mut_borrow = true;
1511                        }
1512                    }
1513                }
1514
1515                // OPT-1B: Last-use clone elimination for `Set x to f(x, ...)`.
1516                // When the target variable appears as a direct non-borrow argument
1517                // and doesn't appear in other arg sub-expressions, skip cloning it
1518                // since the old value is immediately overwritten by the result.
1519                let value_str = if used_mut_borrow {
1520                    String::new() // Already emitted above
1521                } else if let Expr::Call { function, args } = value {
1522                    let target_positions: Vec<usize> = args.iter().enumerate()
1523                        .filter(|(_, a)| matches!(a, Expr::Identifier(sym) if *sym == *target))
1524                        .map(|(i, _)| i)
1525                        .collect();
1526
1527                    let mut other_ids = HashSet::new();
1528                    for (i, a) in args.iter().enumerate() {
1529                        if target_positions.contains(&i) { continue; }
1530                        collect_expr_identifiers(a, &mut other_ids);
1531                    }
1532                    let target_in_others = other_ids.contains(target);
1533
1534                    let callee_borrow_indices: HashSet<usize> =
1535                        super::fn_role_indices(var_types.get(function), super::FnRole::Borrow);
1536
1537                    let can_move = target_positions.len() == 1
1538                        && !callee_borrow_indices.contains(&target_positions[0])
1539                        && !target_in_others
1540                        && var_types.get(target).map_or(false, |t| !is_copy_type(t));
1541
1542                    if can_move {
1543                        let func_name = names.ident(*function);
1544                        let move_pos = target_positions[0];
1545                        let args_str: Vec<String> = args.iter().enumerate()
1546                            .map(|(i, a)| {
1547                                let s = codegen_expr_boxed_with_types(
1548                                    a, interner, synced_vars, boxed_fields, registry,
1549                                    async_functions, string_vars, var_types, ctx.get_fast_div()
1550                                );
1551                                if callee_borrow_indices.contains(&i) {
1552                                    if let Expr::Identifier(sym) = a {
1553                                        if let Some(ty) = var_types.get(sym) {
1554                                            let ty = ty.split("|__hl:").next().unwrap_or(ty.as_str());
1555                                            if ty.starts_with("&[") || ty.starts_with("&mut [") {
1556                                                return s;
1557                                            }
1558                                            if ty.starts_with("Vec<") {
1559                                                return format!("&{}", s);
1560                                            }
1561                                            if ty.starts_with('[') {
1562                                                // Const-table stack array [T; N] coerces to &[T].
1563                                                // A const table is read-only, never the assign target.
1564                                                return format!("&{}", s);
1565                                            }
1566                                            if ty.starts_with("LogosSeq") {
1567                                                if *sym == *target {
1568                                                    return format!("&*{}.clone().borrow()", s);
1569                                                }
1570                                                return format!("&*{}.borrow()", s);
1571                                            }
1572                                        }
1573                                        if *sym == *target {
1574                                            return format!("&*{}.clone().borrow()", s);
1575                                        }
1576                                        return format!("&*{}.borrow()", s);
1577                                    }
1578                                    format!("&*{}.borrow()", s)
1579                                } else if i == move_pos {
1580                                    s // Move: no .clone()
1581                                } else {
1582                                    if let Expr::Identifier(sym) = a {
1583                                        if let Some(ty) = var_types.get(sym) {
1584                                            if !is_copy_type(ty) {
1585                                                return format!("{}.clone()", s);
1586                                            }
1587                                        }
1588                                    }
1589                                    s
1590                                }
1591                            })
1592                            .collect();
1593                        if async_functions.contains(function) {
1594                            format!("{}({}).await", func_name, args_str.join(", "))
1595                        } else {
1596                            format!("{}({})", func_name, args_str.join(", "))
1597                        }
1598                    } else {
1599                        // OPT-1C: Cross-variable last-use move.
1600                        // Build the call manually so we can move args that are not live
1601                        // after this statement instead of cloning them.
1602                        //
1603                        // Safety conditions for moving arg at position i:
1604                        //   1. Liveness info is available (live_vars_after is Some)
1605                        //   2. The variable is NOT live after this statement
1606                        //   3. The variable does NOT appear in any other arg expression
1607                        //      (moving it first would invalidate a borrow in a later arg)
1608                        let func_name = names.ident(*function);
1609                        let args_str: Vec<String> = args.iter().enumerate()
1610                            .map(|(i, a)| {
1611                                let s = codegen_expr_boxed_with_types(
1612                                    a, interner, synced_vars, boxed_fields, registry,
1613                                    async_functions, string_vars, var_types, ctx.get_fast_div()
1614                                );
1615                                if callee_borrow_indices.contains(&i) {
1616                                    if let Expr::Identifier(sym) = a {
1617                                        if let Some(ty) = var_types.get(sym) {
1618                                            let ty = ty.split("|__hl:").next().unwrap_or(ty.as_str());
1619                                            if ty.starts_with("&[") || ty.starts_with("&mut [") {
1620                                                return s;
1621                                            }
1622                                            if ty.starts_with("Vec<") {
1623                                                return format!("&{}", s);
1624                                            }
1625                                            if ty.starts_with('[') {
1626                                                // Const-table stack array [T; N] coerces to &[T].
1627                                                // A const table is read-only, never the assign target.
1628                                                return format!("&{}", s);
1629                                            }
1630                                            if ty.starts_with("LogosSeq") {
1631                                                if *sym == *target {
1632                                                    return format!("&*{}.clone().borrow()", s);
1633                                                }
1634                                                return format!("&*{}.borrow()", s);
1635                                            }
1636                                        }
1637                                        if *sym == *target {
1638                                            return format!("&*{}.clone().borrow()", s);
1639                                        }
1640                                        return format!("&*{}.borrow()", s);
1641                                    }
1642                                    format!("&*{}.borrow()", s)
1643                                } else if let Expr::Identifier(sym) = a {
1644                                    if let Some(ty) = var_types.get(sym) {
1645                                        if !is_copy_type(ty) {
1646                                            // Can move only when liveness says it's dead AND
1647                                            // the variable isn't referenced in any other arg.
1648                                            let can_move_opt1c = live_vars_after
1649                                                .as_ref()
1650                                                .map(|live| {
1651                                                    if live.contains(sym) {
1652                                                        return false;
1653                                                    }
1654                                                    // Check it doesn't appear in other args
1655                                                    let mut other_ids = HashSet::new();
1656                                                    for (j, other_a) in args.iter().enumerate() {
1657                                                        if j == i { continue; }
1658                                                        collect_expr_identifiers(other_a, &mut other_ids);
1659                                                    }
1660                                                    !other_ids.contains(sym)
1661                                                })
1662                                                .unwrap_or(false);
1663                                            if can_move_opt1c {
1664                                                return s; // Move: dead after this stmt, safe
1665                                            }
1666                                            return format!("{}.clone()", s);
1667                                        }
1668                                    }
1669                                    s
1670                                } else {
1671                                    s
1672                                }
1673                            })
1674                            .collect();
1675                        if async_functions.contains(function) {
1676                            format!("{}({}).await", func_name, args_str.join(", "))
1677                        } else {
1678                            format!("{}({})", func_name, args_str.join(", "))
1679                        }
1680                    }
1681                } else {
1682                    let mut vs = codegen_expr_boxed_with_types(
1683                        value, interner, synced_vars, boxed_fields, registry,
1684                        async_functions, string_vars, var_types, ctx.get_fast_div()
1685                    );
1686                    // Reference semantics: clone LogosSeq/LogosMap on assignment to share the Rc.
1687                    if let Expr::Identifier(src_sym) = value {
1688                        if let Some(src_type) = var_types.get(src_sym) {
1689                            if src_type.starts_with("LogosSeq") || src_type.starts_with("LogosMap") {
1690                                vs = format!("{}.clone()", vs);
1691                            }
1692                        }
1693                    }
1694                    vs
1695                };
1696                if !used_mut_borrow {
1697                    writeln!(output, "{}{} = {};", indent_str, target_name, value_str).unwrap();
1698                }
1699            }
1700
1701            // Phase 43C: Check if this variable has a refinement constraint
1702            if let Some((bound_var, predicate)) = ctx.get_constraint(*target) {
1703                emit_refinement_check(&target_name, bound_var, predicate, interner, &indent_str, &mut output);
1704            }
1705        }
1706
1707        Stmt::Call { function, args } => {
1708            let func_name = names.ident(*function);
1709            let variable_types = ctx.get_variable_types();
1710            // Callee param-role indices (packed one slot per function): a readonly
1711            // borrow, an element `&mut` borrow, and a value-semantics `mutable`
1712            // collection param can co-exist, so read each role independently.
1713            let callee_slot = variable_types.get(function);
1714            let callee_borrow_indices: HashSet<usize> =
1715                super::fn_role_indices(callee_slot, super::FnRole::Borrow);
1716            let callee_mut_borrow_indices: HashSet<usize> =
1717                super::fn_role_indices(callee_slot, super::FnRole::MutBorrow);
1718            // `mutable` collection params (value semantics): pass the caller's
1719            // LogosSeq/Map by shared reference (no clone) so the callee mutates it
1720            // in place — the explicit propagation escape hatch.
1721            let callee_value_mutable: HashSet<usize> =
1722                super::fn_role_indices(callee_slot, super::FnRole::ValueMutable);
1723            let args_str: Vec<String> = args.iter().enumerate().map(|(i, a)| {
1724                let s = codegen_expr_with_async(a, interner, synced_vars, async_functions, variable_types);
1725                if callee_value_mutable.contains(&i) {
1726                    // Pass by shared reference (no clone). If already a reference
1727                    // (a `mutable` param threaded through a nested call), pass as-is.
1728                    if let Expr::Identifier(sym) = a {
1729                        if variable_types.get(sym).is_some_and(|t| t.starts_with('&')) {
1730                            return s;
1731                        }
1732                    }
1733                    return format!("&{}", s);
1734                }
1735                if callee_mut_borrow_indices.contains(&i) {
1736                    // Mut borrow param: pass &mut [T] reference
1737                    if let Expr::Identifier(sym) = a {
1738                        if let Some(ty) = variable_types.get(sym) {
1739                            let ty = ty.split("|__hl:").next().unwrap_or(ty.as_str());
1740                            if ty.starts_with("&mut [") {
1741                                return s; // Already &mut slice
1742                            }
1743                            // Phase 3b: a de-Rc'd `Vec` lends `&mut x` directly.
1744                            if ty.starts_with("Vec<") {
1745                                return format!("&mut {}", s);
1746                            }
1747                            if ty.starts_with("LogosSeq") {
1748                                return format!("&mut *{}.borrow_mut()", s);
1749                            }
1750                        }
1751                        // Unknown type — default to LogosSeq
1752                        return format!("&mut *{}.borrow_mut()", s);
1753                    }
1754                    format!("&mut {}", s)
1755                } else if callee_borrow_indices.contains(&i) {
1756                    // Borrow param: pass &[T] reference instead of moving
1757                    if let Expr::Identifier(sym) = a {
1758                        if let Some(ty) = variable_types.get(sym) {
1759                            let ty = ty.split("|__hl:").next().unwrap_or(ty.as_str());
1760                            if ty.starts_with("&[") || ty.starts_with("&mut [") {
1761                                return s; // Already a slice — pass through
1762                            }
1763                            if ty.starts_with("Vec<") {
1764                                return format!("&{}", s);
1765                            }
1766                            if ty.starts_with('[') {
1767                                // Const-table stack array [T; N] coerces to &[T].
1768                                return format!("&{}", s);
1769                            }
1770                            if ty.starts_with("LogosSeq") {
1771                                return format!("&*{}.borrow()", s);
1772                            }
1773                        }
1774                        // Unknown type — default to LogosSeq
1775                        return format!("&*{}.borrow()", s);
1776                    }
1777                    format!("&*{}.borrow()", s)
1778                } else {
1779                    // Regular param: clone non-Copy identifiers to avoid move-after-use.
1780                    // LogosSeq/LogosMap .clone() is O(1) Rc clone — exactly what we want
1781                    // for reference semantics.
1782                    if let Expr::Identifier(sym) = a {
1783                        if let Some(ty) = variable_types.get(sym) {
1784                            if !is_copy_type(ty) {
1785                                return format!("{}.clone()", s);
1786                            }
1787                        }
1788                    }
1789                    s
1790                }
1791            }).collect();
1792            // Add .await if calling an async function
1793            let await_suffix = if async_functions.contains(function) { ".await" } else { "" };
1794            writeln!(output, "{}{}({}){};", indent_str, func_name, args_str.join(", "), await_suffix).unwrap();
1795        }
1796
1797        Stmt::If { cond, then_block, else_block } => {
1798            let cond_str = codegen_expr_with_async_oracle(cond, interner, synced_vars, async_functions, ctx.get_variable_types(), ctx.oracle());
1799            let cond_str = truthy_cond_wrap(cond, cond_str, interner, ctx.get_variable_types());
1800            writeln!(output, "{}if {} {{", indent_str, cond_str).unwrap();
1801            ctx.push_scope();
1802            {
1803                let block_refs: Vec<&Stmt> = then_block.iter().collect();
1804                let mut bi = 0;
1805                while bi < block_refs.len() {
1806                    if let Some((code, skip)) = super::peephole::try_block_peepholes(&block_refs, bi, interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env) {
1807                        output.push_str(&code);
1808                        bi += 1 + skip;
1809                        continue;
1810                    }
1811                    output.push_str(&codegen_stmt(block_refs[bi], interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env));
1812                    bi += 1;
1813                }
1814            }
1815            ctx.pop_scope();
1816            if let Some(else_stmts) = else_block {
1817                writeln!(output, "{}}} else {{", indent_str).unwrap();
1818                ctx.push_scope();
1819                {
1820                    let block_refs: Vec<&Stmt> = else_stmts.iter().collect();
1821                    let mut bi = 0;
1822                    while bi < block_refs.len() {
1823                        if let Some((code, skip)) = super::peephole::try_block_peepholes(&block_refs, bi, interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env) {
1824                            output.push_str(&code);
1825                            bi += 1 + skip;
1826                            continue;
1827                        }
1828                        output.push_str(&codegen_stmt(block_refs[bi], interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env));
1829                        bi += 1;
1830                    }
1831                }
1832                ctx.pop_scope();
1833            }
1834            writeln!(output, "{}}}", indent_str).unwrap();
1835        }
1836
1837        Stmt::While { cond, body, decreasing: _ } => {
1838            // bcmp idiom: a fixed-window byte-compare loop collapses to a slice
1839            // inequality (LLVM `bcmp`) — try it before the scalar while codegen.
1840            if let Some(code) = try_emit_byte_compare_window(stmt, interner, indent, ctx.get_variable_types(), ctx.oracle()) {
1841                return code;
1842            }
1843            // decreasing is compile-time only, ignored at runtime
1844
1845            // OPT: Loop bounds hoisting.
1846            // Collect all `length of X` symbols from condition AND body where X is
1847            // not modified in the loop. Emit hoisted `let x_len = (x.len() as i64);`
1848            // bindings before the loop. Register a sentinel in variable_types so that
1849            // Expr::Length codegen emits the hoisted name directly (no string replacement).
1850            let mut all_length_syms_raw = extract_length_expr_syms(cond);
1851            collect_length_syms_from_stmts(body, &mut all_length_syms_raw);
1852            let mut seen = HashSet::new();
1853            let all_length_syms: Vec<Symbol> = all_length_syms_raw
1854                .into_iter()
1855                .filter(|s| seen.insert(*s))
1856                .collect();
1857
1858            let mut hoisted_syms: Vec<(Symbol, Option<String>)> = Vec::new();
1859            for len_sym in &all_length_syms {
1860                // An affine read-only array is deleted; `length of` it is its trip
1861                // count (no `.len()` to hoist). Leave its `__affine_array:` tag intact.
1862                if ctx.affine_array(*len_sym).is_some() {
1863                    continue;
1864                }
1865                if !body_mutates_collection(body, *len_sym) && !body_modifies_var(body, *len_sym) {
1866                    let name = interner.resolve(*len_sym);
1867                    let hoisted_name = format!("{}_len", name);
1868                    writeln!(output, "{}let {} = ({}.len() as i64);", indent_str, hoisted_name, name).unwrap();
1869                    let old_type = ctx.get_variable_types().get(len_sym).cloned();
1870                    // Append hoisted sentinel to existing type string. Expr::Length checks
1871                    // for |__hl: suffix to emit the hoisted name. All other type checks
1872                    // use starts_with() so the suffix doesn't interfere.
1873                    let new_type = match &old_type {
1874                        Some(existing) => format!("{}|__hl:{}", existing, hoisted_name),
1875                        None => format!("|__hl:{}", hoisted_name),
1876                    };
1877                    ctx.register_variable_type(*len_sym, new_type);
1878                    hoisted_syms.push((*len_sym, old_type));
1879                }
1880            }
1881
1882            // OPT-9: bounds hints for arrays indexed by a unit-stepping while
1883            // counter (`while counter <= bound:` / `< bound:`). Unlike the
1884            // for-range site, this loop shape guarantees nothing by
1885            // construction, so everything plan_bounds_hints assumes must be
1886            // checked here: the counter takes every value up to the bound
1887            // (unit increment last, no other counter writes) and the bound is
1888            // loop-invariant.
1889            let mut while_bounds_hints: Vec<BoundsHintPlan> = Vec::new();
1890            let mut affine_guards: Vec<AffineOffsetGuard> = Vec::new();
1891            if let Expr::BinaryOp { op: op @ (BinaryOpKind::LtEq | BinaryOpKind::Lt), left: Expr::Identifier(counter_sym), right: bound_expr } = cond {
1892                let body_sans_inc = if !body.is_empty()
1893                    && is_counter_increment(&body[body.len() - 1], *counter_sym)
1894                {
1895                    Some(&body[..body.len() - 1])
1896                } else {
1897                    None
1898                };
1899                if let Some(body_sans_inc) = body_sans_inc {
1900                    let counter_clean = !body_modifies_var(body_sans_inc, *counter_sym);
1901                    let mut bound_syms = Vec::new();
1902                    collect_expr_symbols(bound_expr, &mut bound_syms);
1903                    let bound_invariant = bound_syms.iter().all(|s| {
1904                        !body_modifies_var(body, *s) && !body_mutates_collection(body, *s)
1905                    });
1906                    if counter_clean && bound_invariant {
1907                        let bound_str = codegen_expr_with_async(bound_expr, interner, synced_vars, async_functions, ctx.get_variable_types());
1908                        while_bounds_hints = plan_bounds_hints(
1909                            body_sans_inc,
1910                            *counter_sym,
1911                            matches!(op, BinaryOpKind::Lt),
1912                            false,
1913                            bound_expr,
1914                            &bound_str,
1915                            ctx.get_variable_types(),
1916                        );
1917                        emit_bounds_hint_preheader(&while_bounds_hints, interner, &indent_str, &mut output);
1918
1919                        // AOT BCE-hoist: row-major affine-offset guards. One
1920                        // preheader `assert!` per array proves the MAX index
1921                        // (`offset + limit - 1`) in range; the per-iteration
1922                        // access is then elided soundly in the body.
1923                        affine_guards = plan_affine_offset_guards(
1924                            body_sans_inc,
1925                            *counter_sym,
1926                            matches!(op, BinaryOpKind::Lt),
1927                            ctx.get_variable_types(),
1928                        );
1929                        emit_affine_offset_preheader(&affine_guards, &bound_str, interner, synced_vars, async_functions, ctx.get_variable_types(), &indent_str, &mut output);
1930                    }
1931                }
1932            }
1933
1934            // Scratch-buffer allocation hoisting: a loop-local buffer that is
1935            // freshly allocated, fully overwritten by a copy of a source slice,
1936            // used/mutated in place, and never escapes the iteration is hoisted
1937            // to ONE allocation before the loop and reused (`clear()` +
1938            // `extend_from_slice`) each iteration — eliminating one malloc/free
1939            // per iteration (fannkuch's `perm`: ~n! of them). Value-identical to
1940            // the per-iteration `.to_vec()`; gated on the de-Rc non-escape proof.
1941            let scratch_hoisted: Vec<Symbol> =
1942                super::peephole::detect_scratch_hoist_in_body(body, interner, ctx)
1943                    .into_iter()
1944                    .map(|(dst, elem_type)| {
1945                        writeln!(output, "{}let mut {}: Vec<{}> = Vec::new();",
1946                            indent_str, interner.resolve(dst), elem_type).unwrap();
1947                        ctx.register_variable_type(dst, format!("Vec<{}>", elem_type));
1948                        ctx.register_scratch_hoist(dst);
1949                        dst
1950                    })
1951                    .collect();
1952
1953            // O1: scope-extract per-handle borrows around the whole while
1954            // loop when the alias oracle proves it sound. The cond is part of
1955            // the access scan; opened before cond emission so the condition
1956            // also indexes slices.
1957            let hoist_plan = super::hoist::plan_borrow_hoist(stmt, Some(cond), body, ctx, interner);
1958            super::hoist::emit_hoist_open(&hoist_plan, interner, &indent_str, ctx, &mut output);
1959
1960            let cond_str = codegen_expr_with_async_oracle(cond, interner, synced_vars, async_functions, ctx.get_variable_types(), ctx.oracle());
1961            let cond_str = truthy_cond_wrap(cond, cond_str, interner, ctx.get_variable_types());
1962            writeln!(output, "{}while {} {{", indent_str, cond_str).unwrap();
1963            emit_bounds_hint_header(&while_bounds_hints, interner, &"    ".repeat(indent + 1), &mut output);
1964            emit_affine_offset_header(&affine_guards, interner, synced_vars, async_functions, ctx.get_variable_types(), &"    ".repeat(indent + 1), &mut output);
1965            ctx.push_scope();
1966
1967            // OPT-5: Extract sentinel context from while condition.
1968            // For `While counter < limit:`, detect `Set counter to limit` inside If blocks
1969            // as sentinel exits and replace with `break`.
1970            let sentinel_ctx: Option<(Symbol, &Expr)> = match cond {
1971                Expr::BinaryOp { op: BinaryOpKind::Lt, left, right } => {
1972                    if let Expr::Identifier(sym) = left {
1973                        Some((*sym, *right))
1974                    } else {
1975                        None
1976                    }
1977                }
1978                _ => None,
1979            };
1980
1981            // Peephole: process body statements with peephole optimizations.
1982            let body_refs: Vec<&Stmt> = body.iter().collect();
1983            let mut bi = 0;
1984            while bi < body_refs.len() {
1985                if let Some((code, skip)) = super::peephole::try_block_peepholes(&body_refs, bi, interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env) {
1986                    output.push_str(&code);
1987                    bi += 1 + skip;
1988                    continue;
1989                }
1990                // Drain-tail optimization: If a branch in the while body is a
1991                // loop-invariant sequential drain (push-from-array + increment), emit
1992                // extend_from_slice + break instead of element-by-element push.
1993                if let Some(code) = try_emit_drain_tail_in_while(
1994                    body_refs[bi], cond, interner, indent + 1,
1995                    mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps,
1996                    async_functions, pipe_vars, boxed_fields, registry, type_env,
1997                ) {
1998                    output.push_str(&code);
1999                    bi += 1;
2000                    continue;
2001                }
2002                // OPT-5: Sentinel → break transformation.
2003                // If this statement is an If whose then_block ends with `Set counter to limit`,
2004                // emit break instead of the sentinel set.
2005                if let Some((counter_sym, limit_expr)) = &sentinel_ctx {
2006                    if let Some(code) = try_emit_sentinel_break(
2007                        body_refs[bi], *counter_sym, limit_expr, interner, indent + 1,
2008                        mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps,
2009                        async_functions, pipe_vars, boxed_fields, registry, type_env,
2010                    ) {
2011                        // This peephole emits the If inline (bypassing codegen_stmt),
2012                        // so the oracle bounds hints for index accesses in its guard
2013                        // (string_search's `text[i+j]`) must be emitted here too.
2014                        output.push_str(&emit_oracle_index_hints(
2015                            body_refs[bi], ctx, interner, &"    ".repeat(indent + 1),
2016                        ));
2017                        output.push_str(&code);
2018                        bi += 1;
2019                        continue;
2020                    }
2021                }
2022                output.push_str(&codegen_stmt(body_refs[bi], interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env));
2023                bi += 1;
2024            }
2025            ctx.pop_scope();
2026
2027            // Restore original variable_types for hoisted symbols.
2028            // variable_types is a flat HashMap (not scoped), so push/pop_scope doesn't clean it.
2029            for (sym, old_type) in hoisted_syms {
2030                if let Some(old) = old_type {
2031                    ctx.register_variable_type(sym, old);
2032                } else {
2033                    ctx.get_variable_types_mut().remove(&sym);
2034                }
2035            }
2036
2037            // Stop treating the hoisted scratch buffers as reused once their
2038            // loop closes, so a same-named buffer in a sibling loop is not
2039            // mis-rewritten into a refill of a buffer that was never hoisted.
2040            for dst in scratch_hoisted {
2041                ctx.clear_scratch_hoist(dst);
2042            }
2043
2044            writeln!(output, "{}}}", indent_str).unwrap();
2045            // Close the borrow-hoist scope and restore slice-shadowed types.
2046            super::hoist::emit_hoist_close(&hoist_plan, &indent_str, ctx, &mut output);
2047        }
2048
2049        Stmt::Repeat { pattern, iterable, body } => {
2050            use crate::ast::stmt::Pattern;
2051
2052            // Generate pattern string for Rust code
2053            let pattern_str = match pattern {
2054                Pattern::Identifier(sym) => interner.resolve(*sym).to_string(),
2055                Pattern::Tuple(syms) => {
2056                    let names = syms.iter()
2057                        .map(|s| interner.resolve(*s))
2058                        .collect::<Vec<_>>()
2059                        .join(", ");
2060                    format!("({})", names)
2061                }
2062            };
2063
2064            // Indexed-buffer zero-init loop: dropped — the `let mut buf: [T; N] = [0; N]` the O3 `Let`
2065            // handler already emitted zeroes every slot, and the subsequent `Set item i of buf` writes hit
2066            // the array directly. (A push-fill of a `[T; N]` array would be wrong: the fill counter is
2067            // compile-time, so a runtime loop would set slot 0 repeatedly.)
2068            if super::affine_array::is_indexed_init_loop(body, |s| ctx.is_indexed_buffer(s)) {
2069                return output;
2070            }
2071
2072            // Scratch-buffer scalarization: a counted loop whose sole job is to fill a registered
2073            // fixed-size, non-escaping buffer is emitted in place as `let w: [T; N] = from_fn(|__k| { let
2074            // j = LO + __k; <body-lets>; <push-val> })` — a single stack array — instead of a `Vec` that a
2075            // per-entry push loop reallocates on every entry. All non-push body statements (intermediate
2076            // `Let`s) become the closure's leading `let`s; the sole `Push`'s value is the tail expression.
2077            if let Pattern::Identifier(loop_var) = pattern {
2078                if let Some((w, info)) = scratch_fill_target(body, ctx) {
2079                    let wname = names.ident(w);
2080                    writeln!(output, "{}let {}: [{}; {}] = ::std::array::from_fn(|__k: usize| {{",
2081                        indent_str, wname, info.elem_ty, info.len).unwrap();
2082                    writeln!(output, "{}    let {} = ({} as i64) + (__k as i64);",
2083                        indent_str, interner.resolve(*loop_var), info.lo).unwrap();
2084                    ctx.push_scope();
2085                    ctx.register_variable_type(*loop_var, "i64".to_string());
2086                    let mut push_val: Option<&Expr> = None;
2087                    for s in body.iter() {
2088                        match s {
2089                            Stmt::Push { collection: Expr::Identifier(c), value } if *c == w => {
2090                                push_val = Some(value);
2091                            }
2092                            other => output.push_str(&codegen_stmt(
2093                                other, interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields,
2094                                synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env)),
2095                        }
2096                    }
2097                    let val = codegen_expr_boxed_with_types_oracle(
2098                        push_val.expect("scratch fill loop has exactly one push"),
2099                        interner, synced_vars, boxed_fields, registry, async_functions,
2100                        ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2101                    writeln!(output, "{}    {}", indent_str, val).unwrap();
2102                    ctx.pop_scope();
2103                    writeln!(output, "{}}});", indent_str).unwrap();
2104                    return output;
2105                }
2106            }
2107
2108            let iter_str = codegen_expr_with_async(iterable, interner, synced_vars, async_functions, ctx.get_variable_types());
2109
2110            // OPT-PAR: Automatic parallelization for commutative reduction patterns.
2111            // Detect: Repeat for x in coll: Set acc = acc + expr(x)
2112            // Emit: acc += coll.par_iter().copied().map(|x| expr).sum::<i64>()
2113            let par_emitted = if let Pattern::Identifier(var_sym) = pattern {
2114                if let Some(par_code) = try_emit_parallel_reduction(
2115                    *var_sym, &pattern_str, &iter_str, iterable, body,
2116                    interner, indent, ctx,
2117                    synced_vars, async_functions,
2118                ) {
2119                    output.push_str(&par_code);
2120                    true
2121                } else {
2122                    false
2123                }
2124            } else {
2125                false
2126            };
2127
2128            if par_emitted {
2129                // Parallel code already emitted — skip normal loop codegen
2130            } else if body.iter().any(|s| {
2131                requires_async_stmt(s) || calls_async_function(s, async_functions)
2132            }) {
2133                // Use while-let with explicit iterator for async compatibility
2134                writeln!(output, "{}let mut __iter = ({}).into_iter();", indent_str, iter_str).unwrap();
2135                writeln!(output, "{}while let Some({}) = __iter.next() {{", indent_str, pattern_str).unwrap();
2136            } else {
2137                // Determine iteration strategy based on collection type
2138                let is_logos_seq = if let Expr::Identifier(coll_sym) = iterable {
2139                    ctx.get_variable_types().get(coll_sym)
2140                        .map(|s| s.split("|__hl:").next().unwrap_or(s.as_str()))
2141                        .map_or(false, |t| t.starts_with("LogosSeq"))
2142                } else {
2143                    false
2144                };
2145
2146                if is_logos_seq {
2147                    // LogosSeq: snapshot the inner vec for iteration.
2148                    // .to_vec() returns an owned Vec<T> — safe to iterate while
2149                    // allowing mutations to the LogosSeq during/after the loop.
2150                    writeln!(output, "{}for {} in {}.to_vec() {{", indent_str, pattern_str, iter_str).unwrap();
2151                } else {
2152                // Optimization: for known Vec<T>/&[T] with Copy element type,
2153                // use .iter().copied() instead of .clone() to avoid copying the entire collection.
2154                // For slices, must use .iter() since .clone() on &[T] clones the reference, not the data.
2155                let (use_iter_copied, use_iter_cloned) = if let Expr::Identifier(coll_sym) = iterable {
2156                    if let Some(coll_type_raw) = ctx.get_variable_types().get(coll_sym) {
2157                        // Strip |__hl: hoisting suffix so strip_suffix(']') works correctly.
2158                        let coll_type = coll_type_raw.split("|__hl:").next().unwrap_or(coll_type_raw.as_str());
2159                        if coll_type.starts_with('[') {
2160                            // O3 fixed array `[T; N]` — iterate by borrow so the array is not consumed.
2161                            let elem = coll_type.strip_prefix('[').and_then(|s| s.split(';').next()).unwrap_or("_").trim();
2162                            if is_copy_type(elem) {
2163                                (true, false)
2164                            } else {
2165                                (false, true)
2166                            }
2167                        } else if coll_type.starts_with("&[") {
2168                            // Borrowed slice `&[T]` or fixed-array ref `&[T; N]`: must use .iter() (can't
2169                            // move/clone a borrowed slice). Take the element type before any `; N` length so
2170                            // a `&[i64; 3]` param iterates by `.copied()` exactly like the `&[i64]` slice.
2171                            let inner = coll_type.strip_prefix("&[").and_then(|s| s.strip_suffix(']')).unwrap_or("_");
2172                            let elem = inner.split(';').next().unwrap_or(inner).trim();
2173                            if is_copy_type(elem) {
2174                                (true, false)
2175                            } else {
2176                                (false, true)
2177                            }
2178                        } else if coll_type.starts_with("Vec") && has_copy_element_type(coll_type)
2179                            && !body_mutates_collection(body, *coll_sym)
2180                        {
2181                            (true, false)
2182                        } else if coll_type.starts_with("Vec")
2183                            && !body_mutates_collection(body, *coll_sym)
2184                        {
2185                            // Non-Copy element type, but body doesn't mutate the collection:
2186                            // use .iter().cloned() for lazy per-element cloning instead of
2187                            // .clone() which copies the entire collection upfront.
2188                            (false, true)
2189                        } else {
2190                            (false, false)
2191                        }
2192                    } else {
2193                        (false, false)
2194                    }
2195                } else {
2196                    (false, false)
2197                };
2198
2199                if use_iter_copied {
2200                    writeln!(output, "{}for {} in {}.iter().copied() {{", indent_str, pattern_str, iter_str).unwrap();
2201                } else if use_iter_cloned {
2202                    writeln!(output, "{}for {} in {}.iter().cloned() {{", indent_str, pattern_str, iter_str).unwrap();
2203                } else {
2204                    // Clone the collection before iterating to avoid moving it.
2205                    // This allows the collection to be reused after the loop.
2206                    writeln!(output, "{}for {} in {}.clone() {{", indent_str, pattern_str, iter_str).unwrap();
2207                }
2208                }
2209            }
2210            if !par_emitted {
2211                ctx.push_scope();
2212                // Peephole: process body statements with swap, seq-copy, and rotate-left detection
2213                {
2214                    let body_refs: Vec<&Stmt> = body.iter().collect();
2215                    let mut bi = 0;
2216                    while bi < body_refs.len() {
2217                        if let Some((code, skip)) = super::peephole::try_block_peepholes(&body_refs, bi, interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env) {
2218                            output.push_str(&code);
2219                            bi += 1 + skip;
2220                            continue;
2221                        }
2222                        output.push_str(&codegen_stmt(body_refs[bi], interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env));
2223                        bi += 1;
2224                    }
2225                }
2226                ctx.pop_scope();
2227                writeln!(output, "{}}}", indent_str).unwrap();
2228            }
2229        }
2230
2231        Stmt::Return { value } => {
2232            if let Some(v) = value {
2233                // A `-> LogosInt` function returns its value un-narrowed (`.into()` is identity for a
2234                // LogosInt, and promotes a plain `i64`), so an overflowing result stays a BigInt.
2235                if ctx.returns_bigint() {
2236                    let raw = codegen_expr_boxed_with_types_oracle_tolerant(v, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2237                    writeln!(output, "{}return logicaffeine_data::LogosInt::from({});", indent_str, raw).unwrap();
2238                    return output;
2239                }
2240                let value_str = codegen_expr_boxed_with_types_oracle(v, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2241                // If returning a borrowed slice param (or copy of one), wrap in LogosSeq
2242                let slice_sym = match v {
2243                    Expr::Identifier(sym) => Some(*sym),
2244                    Expr::Copy { expr: inner } => {
2245                        if let Expr::Identifier(sym) = inner { Some(*sym) } else { None }
2246                    }
2247                    _ => None,
2248                };
2249                let needs_to_vec = slice_sym
2250                    .and_then(|sym| ctx.get_variable_types().get(&sym))
2251                    .map(|t| t.starts_with("&["))
2252                    .unwrap_or(false);
2253                // If returning a &mut borrow param, the mutation was in-place — just return
2254                let is_mut_borrow_return = if let Expr::Identifier(sym) = v {
2255                    ctx.get_variable_types().get(sym)
2256                        .map(|t| t.starts_with("&mut ["))
2257                        .unwrap_or(false)
2258                } else {
2259                    false
2260                };
2261                if is_mut_borrow_return {
2262                    writeln!(output, "{}return;", indent_str).unwrap();
2263                } else if needs_to_vec && ctx.returns_vec() {
2264                    // Phase 4: the function returns owned `Vec<T>` — return the
2265                    // owned copy directly, no `LogosSeq::from_vec(...)` wrapper.
2266                    writeln!(output, "{}return {}.to_vec();", indent_str, value_str).unwrap();
2267                } else if needs_to_vec {
2268                    writeln!(output, "{}return LogosSeq::from_vec({}.to_vec());", indent_str, value_str).unwrap();
2269                } else {
2270                    writeln!(output, "{}return {};", indent_str, value_str).unwrap();
2271                }
2272            } else {
2273                writeln!(output, "{}return;", indent_str).unwrap();
2274            }
2275        }
2276
2277        Stmt::Break => {
2278            writeln!(output, "{}break;", indent_str).unwrap();
2279        }
2280
2281        Stmt::Assert { proposition } => {
2282            let condition = codegen_assertion(proposition, interner);
2283            writeln!(output, "{}debug_assert!({});", indent_str, condition).unwrap();
2284        }
2285
2286        // Phase 35: Trust with documented justification
2287        Stmt::Trust { proposition, justification } => {
2288            let reason = interner.resolve(*justification);
2289            // Strip quotes if present (string literals include their quotes)
2290            let reason_clean = reason.trim_matches('"');
2291            writeln!(output, "{}// TRUST: {}", indent_str, reason_clean).unwrap();
2292            let condition = codegen_assertion(proposition, interner);
2293            writeln!(output, "{}debug_assert!({});", indent_str, condition).unwrap();
2294        }
2295
2296        Stmt::RuntimeAssert { condition, hard } => {
2297            let cond_str = codegen_expr_with_async_oracle(condition, interner, synced_vars, async_functions, ctx.get_variable_types(), ctx.oracle());
2298            // `Require` → `assert!` (enforced, survives release); `Assert` →
2299            // `debug_assert!` (a development check, stripped in release).
2300            let macro_name = if *hard { "assert!" } else { "debug_assert!" };
2301            writeln!(output, "{}{}({});", indent_str, macro_name, cond_str).unwrap();
2302        }
2303
2304        // Phase 50: Security Check - mandatory runtime guard (NEVER optimized out)
2305        Stmt::Check { subject, predicate, is_capability, object, source_text, span } => {
2306            let subj_name = interner.resolve(*subject);
2307            let pred_name = interner.resolve(*predicate).to_lowercase();
2308
2309            let call = if *is_capability {
2310                let obj_sym = object.expect("capability must have object");
2311                let obj_word = interner.resolve(obj_sym);
2312
2313                // Phase 50: Type-based resolution
2314                // "Check that user can publish the document" -> find variable of type Document
2315                // First try to find a variable whose type matches the object word
2316                let obj_name = ctx.find_variable_by_type(obj_word, interner)
2317                    .unwrap_or_else(|| obj_word.to_string());
2318
2319                format!("{}.can_{}(&{})", subj_name, pred_name, obj_name)
2320            } else {
2321                format!("{}.is_{}()", subj_name, pred_name)
2322            };
2323
2324            writeln!(output, "{}if !({}) {{", indent_str, call).unwrap();
2325            writeln!(output, "{}    logicaffeine_system::panic_with(\"Security Check Failed at line {}: {}\");",
2326                     indent_str, span.start, source_text).unwrap();
2327            writeln!(output, "{}}}", indent_str).unwrap();
2328        }
2329
2330        // Phase 51: P2P Networking - Listen on network address
2331        Stmt::Listen { address, secure } => {
2332            // The PNP one-time pad is wired only into the interpreter's channel seam; the native-AOT
2333            // transpile backend does not carry that seam yet, so fail loud (never silently drop crypto).
2334            if secure.is_some() {
2335                writeln!(output, "{}compile_error!(\"the PNP one-time pad (`with pad`) is only supported by the interpreter tier, not the native-AOT/transpile backend\");", indent_str).unwrap();
2336                return output;
2337            }
2338            let addr_str = codegen_expr_with_async(address, interner, synced_vars, async_functions, ctx.get_variable_types());
2339            // Pass &str instead of String
2340            writeln!(output, "{}logicaffeine_system::network::listen(&{}).await.expect(\"Failed to listen\");",
2341                     indent_str, addr_str).unwrap();
2342        }
2343
2344        // Phase 51: P2P Networking - Connect to remote peer
2345        Stmt::ConnectTo { address, secure } => {
2346            if secure.is_some() {
2347                writeln!(output, "{}compile_error!(\"the PNP one-time pad (`with pad`) is only supported by the interpreter tier, not the native-AOT/transpile backend\");", indent_str).unwrap();
2348                return output;
2349            }
2350            let addr_str = codegen_expr_with_async(address, interner, synced_vars, async_functions, ctx.get_variable_types());
2351            // Pass &str instead of String
2352            writeln!(output, "{}logicaffeine_system::network::connect(&{}).await.expect(\"Failed to connect\");",
2353                     indent_str, addr_str).unwrap();
2354        }
2355
2356        // Phase 51: P2P Networking - Create PeerAgent remote handle
2357        Stmt::LetPeerAgent { var, address } => {
2358            let var_name = interner.resolve(*var);
2359            let addr_str = codegen_expr_with_async(address, interner, synced_vars, async_functions, ctx.get_variable_types());
2360            // Pass &str instead of String
2361            writeln!(output, "{}let {} = logicaffeine_system::network::PeerAgent::new(&{}).expect(\"Invalid address\");",
2362                     indent_str, var_name, addr_str).unwrap();
2363        }
2364
2365        // Phase 51: Sleep - supports Duration literals or milliseconds
2366        Stmt::Sleep { milliseconds } => {
2367            let expr_str = codegen_expr_with_async(milliseconds, interner, synced_vars, async_functions, ctx.get_variable_types());
2368            let inferred_type = infer_rust_type_from_expr(milliseconds, interner);
2369
2370            if inferred_type == "std::time::Duration" {
2371                // Duration type: use directly (already a std::time::Duration)
2372                writeln!(output, "{}tokio::time::sleep({}).await;",
2373                         indent_str, expr_str).unwrap();
2374            } else {
2375                // Assume milliseconds (integer) - legacy behavior
2376                writeln!(output, "{}tokio::time::sleep(std::time::Duration::from_millis({} as u64)).await;",
2377                         indent_str, expr_str).unwrap();
2378            }
2379        }
2380
2381        // Phase 52/56: Sync CRDT variable on topic
2382        Stmt::Sync { var, topic } => {
2383            let var_name = interner.resolve(*var);
2384            let topic_str = codegen_expr_with_async(topic, interner, synced_vars, async_functions, ctx.get_variable_types());
2385
2386            // Phase 56: Check if this variable is also mounted
2387            if let Some(caps) = var_caps.get(var) {
2388                if caps.mounted {
2389                    // Both Mount and Sync: use Distributed<T>
2390                    // Mount statement will handle the Distributed::mount call
2391                    // Here we just track it as synced
2392                    synced_vars.insert(*var);
2393                    return output;  // Skip - Mount will emit Distributed<T>
2394                }
2395            }
2396
2397            // Sync-only: use Synced<T>
2398            writeln!(
2399                output,
2400                "{}let {} = logicaffeine_system::crdt::Synced::new({}, &{}).await;",
2401                indent_str, var_name, var_name, topic_str
2402            ).unwrap();
2403            synced_vars.insert(*var);
2404        }
2405
2406        // Phase 53/56: Mount persistent CRDT from journal
2407        Stmt::Mount { var, path } => {
2408            let var_name = interner.resolve(*var);
2409            let path_str = codegen_expr_with_async(path, interner, synced_vars, async_functions, ctx.get_variable_types());
2410
2411            // Phase 56: Check if this variable is also synced
2412            if let Some(caps) = var_caps.get(var) {
2413                if caps.synced {
2414                    // Both Mount and Sync: use Distributed<T>
2415                    let topic_str = caps.sync_topic.as_ref()
2416                        .map(|s| s.as_str())
2417                        .unwrap_or("\"default\"");
2418                    writeln!(
2419                        output,
2420                        "{}let {} = logicaffeine_system::distributed::Distributed::mount(vfs.clone(), &{}, Some({}.to_string())).await.expect(\"Failed to mount\");",
2421                        indent_str, var_name, path_str, topic_str
2422                    ).unwrap();
2423                    synced_vars.insert(*var);
2424                    return output;
2425                }
2426            }
2427
2428            // Mount-only: use Persistent<T>
2429            writeln!(
2430                output,
2431                "{}let {} = logicaffeine_system::storage::Persistent::mount(vfs.clone(), &{}).await.expect(\"Failed to mount\");",
2432                indent_str, var_name, path_str
2433            ).unwrap();
2434            synced_vars.insert(*var);
2435        }
2436
2437        // =====================================================================
2438        // Phase 54: Go-like Concurrency Codegen
2439        // =====================================================================
2440
2441        Stmt::LaunchTask { function, args } => {
2442            let fn_name = names.ident(*function);
2443            // Phase 54: When passing a pipe variable, pass the sender (_tx)
2444            let args_str: Vec<String> = args.iter()
2445                .map(|a| {
2446                    if let Expr::Identifier(sym) = a {
2447                        if pipe_vars.contains(sym) {
2448                            return format!("{}_tx.clone()", interner.resolve(*sym));
2449                        }
2450                    }
2451                    codegen_expr_with_async(a, interner, synced_vars, async_functions, ctx.get_variable_types())
2452                })
2453                .collect();
2454            // Phase 54: Add .await only if the function is async
2455            let await_suffix = if async_functions.contains(function) { ".await" } else { "" };
2456            writeln!(
2457                output,
2458                "{}tokio::spawn(async move {{ {}({}){await_suffix}; }});",
2459                indent_str, fn_name, args_str.join(", ")
2460            ).unwrap();
2461        }
2462
2463        Stmt::LaunchTaskWithHandle { handle, function, args } => {
2464            let handle_name = interner.resolve(*handle);
2465            let fn_name = names.ident(*function);
2466            // Phase 54: When passing a pipe variable, pass the sender (_tx)
2467            let args_str: Vec<String> = args.iter()
2468                .map(|a| {
2469                    if let Expr::Identifier(sym) = a {
2470                        if pipe_vars.contains(sym) {
2471                            return format!("{}_tx.clone()", interner.resolve(*sym));
2472                        }
2473                    }
2474                    codegen_expr_with_async(a, interner, synced_vars, async_functions, ctx.get_variable_types())
2475                })
2476                .collect();
2477            // Phase 54: Add .await only if the function is async
2478            let await_suffix = if async_functions.contains(function) { ".await" } else { "" };
2479            writeln!(
2480                output,
2481                "{}let {} = tokio::spawn(async move {{ {}({}){await_suffix} }});",
2482                indent_str, handle_name, fn_name, args_str.join(", ")
2483            ).unwrap();
2484        }
2485
2486        Stmt::CreatePipe { var, element_type, capacity } => {
2487            let var_name = interner.resolve(*var);
2488            let type_name = interner.resolve(*element_type);
2489            let cap = capacity.unwrap_or(32);
2490            // Map LOGOS types to Rust types
2491            let rust_type = match type_name {
2492                "Int" => "i64",
2493                "Nat" => "u64",
2494                "Text" => "String",
2495                "Bool" => "bool",
2496                _ => type_name,
2497            };
2498            writeln!(
2499                output,
2500                "{}let ({}_tx, mut {}_rx) = tokio::sync::mpsc::channel::<{}>({});",
2501                indent_str, var_name, var_name, rust_type, cap
2502            ).unwrap();
2503        }
2504
2505        Stmt::SendPipe { value, pipe } => {
2506            let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2507            let pipe_str = codegen_expr_with_async(pipe, interner, synced_vars, async_functions, ctx.get_variable_types());
2508            // Phase 54: Check if pipe is a local declaration (has _tx suffix) or parameter (no suffix)
2509            let is_local_pipe = if let Expr::Identifier(sym) = pipe {
2510                pipe_vars.contains(sym)
2511            } else {
2512                false
2513            };
2514            if is_local_pipe {
2515                writeln!(
2516                    output,
2517                    "{}{}_tx.send({}).await.expect(\"pipe send failed\");",
2518                    indent_str, pipe_str, val_str
2519                ).unwrap();
2520            } else {
2521                writeln!(
2522                    output,
2523                    "{}{}.send({}).await.expect(\"pipe send failed\");",
2524                    indent_str, pipe_str, val_str
2525                ).unwrap();
2526            }
2527        }
2528
2529        Stmt::ReceivePipe { var, pipe } => {
2530            let var_name = interner.resolve(*var);
2531            let pipe_str = codegen_expr_with_async(pipe, interner, synced_vars, async_functions, ctx.get_variable_types());
2532            // Phase 54: Check if pipe is a local declaration (has _rx suffix) or parameter (no suffix)
2533            let is_local_pipe = if let Expr::Identifier(sym) = pipe {
2534                pipe_vars.contains(sym)
2535            } else {
2536                false
2537            };
2538            if is_local_pipe {
2539                writeln!(
2540                    output,
2541                    "{}let {} = {}_rx.recv().await.expect(\"pipe closed\");",
2542                    indent_str, var_name, pipe_str
2543                ).unwrap();
2544            } else {
2545                writeln!(
2546                    output,
2547                    "{}let {} = {}.recv().await.expect(\"pipe closed\");",
2548                    indent_str, var_name, pipe_str
2549                ).unwrap();
2550            }
2551        }
2552
2553        Stmt::TrySendPipe { value, pipe, result } => {
2554            let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2555            let pipe_str = codegen_expr_with_async(pipe, interner, synced_vars, async_functions, ctx.get_variable_types());
2556            // Phase 54: Check if pipe is a local declaration
2557            let is_local_pipe = if let Expr::Identifier(sym) = pipe {
2558                pipe_vars.contains(sym)
2559            } else {
2560                false
2561            };
2562            let suffix = if is_local_pipe { "_tx" } else { "" };
2563            if let Some(res) = result {
2564                let res_name = interner.resolve(*res);
2565                writeln!(
2566                    output,
2567                    "{}let {} = {}{}.try_send({}).is_ok();",
2568                    indent_str, res_name, pipe_str, suffix, val_str
2569                ).unwrap();
2570            } else {
2571                writeln!(
2572                    output,
2573                    "{}let _ = {}{}.try_send({});",
2574                    indent_str, pipe_str, suffix, val_str
2575                ).unwrap();
2576            }
2577        }
2578
2579        Stmt::TryReceivePipe { var, pipe } => {
2580            let var_name = interner.resolve(*var);
2581            let pipe_str = codegen_expr_with_async(pipe, interner, synced_vars, async_functions, ctx.get_variable_types());
2582            // Phase 54: Check if pipe is a local declaration
2583            let is_local_pipe = if let Expr::Identifier(sym) = pipe {
2584                pipe_vars.contains(sym)
2585            } else {
2586                false
2587            };
2588            let suffix = if is_local_pipe { "_rx" } else { "" };
2589            writeln!(
2590                output,
2591                "{}let {} = {}{}.try_recv().ok();",
2592                indent_str, var_name, pipe_str, suffix
2593            ).unwrap();
2594        }
2595
2596        Stmt::StopTask { handle } => {
2597            let handle_str = codegen_expr_with_async(handle, interner, synced_vars, async_functions, ctx.get_variable_types());
2598            writeln!(output, "{}{}.abort();", indent_str, handle_str).unwrap();
2599        }
2600
2601        Stmt::Select { branches } => {
2602            // Mode A (default): raw `tokio::select!`, byte-identical to today.
2603            // Mode B (`--deterministic`): the seeded winner-pick sharing the
2604            // interpreter's choice function. The gate is compile-global, so Mode-A
2605            // emission never carries any seeded machinery.
2606            if crate::codegen::seeded_select_enabled() {
2607                write_seeded_select(
2608                    &mut output, branches, interner, indent, mutable_vars, ctx, lww_fields,
2609                    mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields,
2610                    registry, type_env,
2611                );
2612            } else {
2613                write_tokio_select(
2614                    &mut output, branches, interner, indent, mutable_vars, ctx, lww_fields,
2615                    mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields,
2616                    registry, type_env,
2617                );
2618            }
2619        }
2620
2621        Stmt::Give { object, recipient } => {
2622            // Move semantics: pass ownership without borrowing
2623            let obj_str = codegen_expr_with_async(object, interner, synced_vars, async_functions, ctx.get_variable_types());
2624            let recv_str = codegen_expr_with_async(recipient, interner, synced_vars, async_functions, ctx.get_variable_types());
2625            writeln!(output, "{}{}({});", indent_str, recv_str, obj_str).unwrap();
2626        }
2627
2628        Stmt::Show { object, recipient } => {
2629            // OPT: Show single-char u8 variable → println!("{}", ch as char)
2630            if let Expr::Identifier(sym) = object {
2631                if ctx.get_variable_types().get(sym).map_or(false, |t| t == "__single_char_u8") {
2632                    let var_name = names.ident(*sym);
2633                    writeln!(output, "{}println!(\"{{}}\", {} as char);", indent_str, var_name).unwrap();
2634                    return output;
2635                }
2636            }
2637            // Optimization: Show with InterpolatedString → println! directly
2638            if let Expr::InterpolatedString(parts) = object {
2639                let recv_name = if let Expr::Identifier(sym) = recipient {
2640                    interner.resolve(*sym).to_string()
2641                } else {
2642                    String::new()
2643                };
2644                if recv_name == "show" {
2645                    // Emit println! directly — no intermediate String allocation
2646                    let mut fmt_str = String::new();
2647                    let mut args = Vec::new();
2648                    for part in parts {
2649                        match part {
2650                            crate::ast::stmt::StringPart::Literal(sym) => {
2651                                let text = interner.resolve(*sym);
2652                                for ch in text.chars() {
2653                                    match ch {
2654                                        '{' => fmt_str.push_str("{{"),
2655                                        '}' => fmt_str.push_str("}}"),
2656                                        '\n' => fmt_str.push_str("\\n"),
2657                                        '\t' => fmt_str.push_str("\\t"),
2658                                        '\r' => fmt_str.push_str("\\r"),
2659                                        _ => fmt_str.push(ch),
2660                                    }
2661                                }
2662                            }
2663                            crate::ast::stmt::StringPart::Expr { value, format_spec, debug } => {
2664                                if *debug {
2665                                    let debug_prefix = expr_debug_prefix(value, interner);
2666                                    for ch in debug_prefix.chars() {
2667                                        match ch {
2668                                            '{' => fmt_str.push_str("{{"),
2669                                            '}' => fmt_str.push_str("}}"),
2670                                            _ => fmt_str.push(ch),
2671                                        }
2672                                    }
2673                                    fmt_str.push('=');
2674                                }
2675                                let needs_float_cast = if let Some(spec) = format_spec {
2676                                    let spec_str = interner.resolve(*spec);
2677                                    if spec_str == "$" {
2678                                        fmt_str.push('$');
2679                                        fmt_str.push_str("{:.2}");
2680                                        true
2681                                    } else if spec_str.starts_with('.') {
2682                                        fmt_str.push_str(&format!("{{:{}}}", spec_str));
2683                                        true
2684                                    } else {
2685                                        fmt_str.push_str(&format!("{{:{}}}", spec_str));
2686                                        false
2687                                    }
2688                                } else {
2689                                    fmt_str.push_str("{}");
2690                                    false
2691                                };
2692                                let arg_str = codegen_expr_with_async_and_strings(value, interner, synced_vars, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div());
2693                                if needs_float_cast {
2694                                    args.push(format!("{} as f64", arg_str));
2695                                } else {
2696                                    args.push(arg_str);
2697                                }
2698                            }
2699                        }
2700                    }
2701                    writeln!(output, "{}println!(\"{}\"{});", indent_str, fmt_str,
2702                        args.iter().map(|a| format!(", {}", a)).collect::<String>()).unwrap();
2703                } else {
2704                    let obj_str = codegen_expr_with_async_and_strings(object, interner, synced_vars, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div());
2705                    let recv_str = codegen_expr_with_async(recipient, interner, synced_vars, async_functions, ctx.get_variable_types());
2706                    writeln!(output, "{}{}(&{});", indent_str, recv_str, obj_str).unwrap();
2707                }
2708            } else {
2709                // Borrow semantics: pass immutable reference
2710                // Use string_vars for proper concatenation of string variables
2711                let obj_str = codegen_expr_with_async_and_strings(object, interner, synced_vars, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div());
2712                let recv_str = codegen_expr_with_async(recipient, interner, synced_vars, async_functions, ctx.get_variable_types());
2713                writeln!(output, "{}{}(&{});", indent_str, recv_str, obj_str).unwrap();
2714            }
2715        }
2716
2717        Stmt::SetField { object, field, value } => {
2718            let obj_str = codegen_expr_with_async(object, interner, synced_vars, async_functions, ctx.get_variable_types());
2719            let field_name = interner.resolve(*field);
2720            let value_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2721
2722            // Phase 49: Check if this field is an LWWRegister or MVRegister
2723            // LWW needs .set(value, timestamp), MV needs .set(value)
2724            let is_lww = lww_fields.iter().any(|(_, f)| f == field_name);
2725            let is_mv = mv_fields.iter().any(|(_, f)| f == field_name);
2726            if is_lww {
2727                // LWWRegister needs a timestamp - use current system time in microseconds
2728                writeln!(output, "{}{}.{}.set({}, std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_micros() as u64);", indent_str, obj_str, field_name, value_str).unwrap();
2729            } else if is_mv {
2730                // MVRegister just needs the value
2731                writeln!(output, "{}{}.{}.set({});", indent_str, obj_str, field_name, value_str).unwrap();
2732            } else {
2733                writeln!(output, "{}{}.{} = {};", indent_str, obj_str, field_name, value_str).unwrap();
2734            }
2735        }
2736
2737        Stmt::StructDef { .. } => {
2738            // Struct definitions are handled in codegen_program, not here
2739        }
2740
2741        Stmt::FunctionDef { .. } => {
2742            // Function definitions are handled in codegen_program, not here
2743        }
2744
2745        Stmt::Inspect { target, arms, .. } => {
2746            let target_str = codegen_expr_with_async(target, interner, synced_vars, async_functions, ctx.get_variable_types());
2747
2748            writeln!(output, "{}match {} {{", indent_str, target_str).unwrap();
2749
2750            for arm in arms {
2751                // Phase 102: Track which bindings come from boxed fields for inner Inspects
2752                // Use NAMES (strings) not symbols, because parser may create different symbols
2753                // for the same identifier in different syntactic positions.
2754                // Must be per-arm so bindings from other arms don't leak into this arm's scope.
2755                let mut inner_boxed_binding_names: HashSet<String> = HashSet::new();
2756                if let Some(variant) = arm.variant {
2757                    let variant_name = interner.resolve(variant);
2758                    // Get the enum name from the arm, or fallback to just variant name
2759                    let enum_name_str = arm.enum_name.map(|e| interner.resolve(e));
2760                    let enum_prefix = enum_name_str
2761                        .map(|e| format!("{}::", e))
2762                        .unwrap_or_default();
2763
2764                    if arm.bindings.is_empty() {
2765                        // Unit variant pattern
2766                        writeln!(output, "{}    {}{} => {{", indent_str, enum_prefix, variant_name).unwrap();
2767                    } else {
2768                        // Pattern with bindings
2769                        // Phase 102: Check which bindings are from boxed fields
2770                        let bindings_str: Vec<String> = arm.bindings.iter()
2771                            .map(|(field, binding)| {
2772                                let field_name = interner.resolve(*field);
2773                                let binding_name = interner.resolve(*binding);
2774
2775                                // Check if this field is boxed
2776                                if let Some(enum_name) = enum_name_str {
2777                                    let key = (enum_name.to_string(), variant_name.to_string(), field_name.to_string());
2778                                    if boxed_fields.contains(&key) {
2779                                        inner_boxed_binding_names.insert(binding_name.to_string());
2780                                    }
2781                                }
2782
2783                                if field_name == binding_name {
2784                                    format!("ref {}", field_name)
2785                                } else {
2786                                    format!("{}: ref {}", field_name, binding_name)
2787                                }
2788                            })
2789                            .collect();
2790                        writeln!(output, "{}    {}{} {{ {} }} => {{", indent_str, enum_prefix, variant_name, bindings_str.join(", ")).unwrap();
2791                    }
2792                } else {
2793                    // Otherwise (wildcard) pattern
2794                    writeln!(output, "{}    _ => {{", indent_str).unwrap();
2795                }
2796
2797                ctx.push_scope();
2798
2799                // Register pattern-bound variable types from Inspect arms so that
2800                // type inference (e.g. for mixed Int/Real coercion) works correctly.
2801                if let Some(variant_sym) = arm.variant {
2802                    if let Some((_enum_name, variant_def)) = registry.find_variant(variant_sym) {
2803                        for (field_sym, binding_sym) in &arm.bindings {
2804                            if let Some(field_def) = variant_def.fields.iter().find(|f| f.name == *field_sym) {
2805                                let rust_type = super::types::codegen_field_type(&field_def.ty, interner);
2806                                ctx.register_variable_type(*binding_sym, rust_type);
2807                            }
2808                        }
2809                    }
2810                }
2811
2812                // Generate explicit dereferences for boxed bindings at the start of the arm
2813                // With ref bindings, boxed fields need double deref: ref -> Box -> inner
2814                for binding_name in &inner_boxed_binding_names {
2815                    writeln!(output, "{}        let {} = (**{}).clone();", indent_str, binding_name, binding_name).unwrap();
2816                }
2817
2818                // Clone non-boxed ref bindings to get owned values
2819                if let Some(_) = arm.variant {
2820                    for (_field, binding) in &arm.bindings {
2821                        let binding_name = interner.resolve(*binding);
2822                        if !inner_boxed_binding_names.contains(binding_name) {
2823                            writeln!(output, "{}        let {} = {}.clone();", indent_str, binding_name, binding_name).unwrap();
2824                        }
2825                    }
2826                }
2827
2828                for stmt in arm.body {
2829                    // Phase 102: Handle inner Inspect statements with boxed bindings
2830                    // Note: Since we now dereference boxed bindings at the start of the arm,
2831                    // inner matches don't need the `*` dereference operator.
2832                    let inner_stmt_code = if let Stmt::Inspect { target: inner_target, .. } = stmt {
2833                        // Check if the inner target is a boxed binding (already dereferenced above)
2834                        // Use name comparison since symbols may differ between binding and reference
2835                        if let Expr::Identifier(sym) = inner_target {
2836                            let target_name = interner.resolve(*sym);
2837                            if inner_boxed_binding_names.contains(target_name) {
2838                                // Generate match (binding was already dereferenced at arm start)
2839                                let mut inner_output = String::new();
2840                                writeln!(inner_output, "{}match {} {{", "    ".repeat(indent + 2), target_name).unwrap();
2841
2842                                if let Stmt::Inspect { arms: inner_arms, .. } = stmt {
2843                                    for inner_arm in inner_arms.iter() {
2844                                        if let Some(v) = inner_arm.variant {
2845                                            let v_name = interner.resolve(v);
2846                                            let inner_enum_prefix = inner_arm.enum_name
2847                                                .map(|e| format!("{}::", interner.resolve(e)))
2848                                                .unwrap_or_default();
2849
2850                                            if inner_arm.bindings.is_empty() {
2851                                                writeln!(inner_output, "{}    {}{} => {{", "    ".repeat(indent + 2), inner_enum_prefix, v_name).unwrap();
2852                                            } else {
2853                                                let bindings: Vec<String> = inner_arm.bindings.iter()
2854                                                    .map(|(f, b)| {
2855                                                        let fn_name = interner.resolve(*f);
2856                                                        let bn_name = interner.resolve(*b);
2857                                                        if fn_name == bn_name { format!("ref {}", fn_name) }
2858                                                        else { format!("{}: ref {}", fn_name, bn_name) }
2859                                                    })
2860                                                    .collect();
2861                                                writeln!(inner_output, "{}    {}{} {{ {} }} => {{", "    ".repeat(indent + 2), inner_enum_prefix, v_name, bindings.join(", ")).unwrap();
2862                                            }
2863                                        } else {
2864                                            writeln!(inner_output, "{}    _ => {{", "    ".repeat(indent + 2)).unwrap();
2865                                        }
2866
2867                                        ctx.push_scope();
2868                                        for inner_stmt in inner_arm.body {
2869                                            inner_output.push_str(&codegen_stmt(inner_stmt, interner, indent + 4, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env));
2870                                        }
2871                                        ctx.pop_scope();
2872                                        writeln!(inner_output, "{}    }}", "    ".repeat(indent + 2)).unwrap();
2873                                    }
2874                                }
2875                                writeln!(inner_output, "{}}}", "    ".repeat(indent + 2)).unwrap();
2876                                inner_output
2877                            } else {
2878                                codegen_stmt(stmt, interner, indent + 2, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env)
2879                            }
2880                        } else {
2881                            codegen_stmt(stmt, interner, indent + 2, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env)
2882                        }
2883                    } else {
2884                        codegen_stmt(stmt, interner, indent + 2, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env)
2885                    };
2886                    output.push_str(&inner_stmt_code);
2887                }
2888                ctx.pop_scope();
2889                writeln!(output, "{}    }}", indent_str).unwrap();
2890            }
2891
2892            writeln!(output, "{}}}", indent_str).unwrap();
2893        }
2894
2895        Stmt::Push { value, collection } => {
2896            // O3: an init push into a scalarized `[T; N]` array becomes an
2897            // indexed store at the next fill position (detection proved
2898            // exactly N straight-line pushes precede any other use).
2899            if let Expr::Identifier(coll_sym) = collection {
2900                // Loop-built `[T; N]` return buffer (the digest): a push in the fill loop becomes a store
2901                // through the RUNTIME cursor — `out[cursor] = value; cursor += 1` — not the compile-time O3
2902                // fill (which would write slot 0 every iteration).
2903                if let Some(cursor) = ctx.loop_fill_cursor(*coll_sym).map(|s| s.to_string()) {
2904                    let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2905                    let coll_name = names.ident(*coll_sym);
2906                    writeln!(output, "{}{}[{}] = {}; {} += 1;", indent_str, coll_name, cursor, val_str, cursor).unwrap();
2907                    return output;
2908                }
2909                // Affine read-only array: the array is deleted, so its build push
2910                // emits nothing (reads substitute the closed form instead).
2911                if ctx.affine_array(*coll_sym).is_some() {
2912                    return output;
2913                }
2914                // AoS interleaving: the k-th round-robin push of a member becomes
2915                // an indexed store into the backing's k-th row at this column.
2916                if let Some(tag) = parse_aos_tag(ctx.get_variable_types().get(coll_sym)) {
2917                    let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2918                    let k = ctx.next_array_fill(*coll_sym);
2919                    writeln!(output, "{}{}[{}][{}] = {};", indent_str, tag.backing, k, tag.col, val_str).unwrap();
2920                    return output;
2921                }
2922                if ctx.is_scalarized_array(*coll_sym) {
2923                    let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2924                    let k = ctx.next_array_fill(*coll_sym);
2925                    let coll_name = names.ident(*coll_sym);
2926                    writeln!(output, "{}{}[{}] = {};", indent_str, coll_name, k, val_str).unwrap();
2927                    return output;
2928                }
2929                // A1: inside a fill loop, the counted push of a sized
2930                // buffer-reuse buffer becomes an indexed write `buf[counter] =
2931                // val` (the buffer was `resize`d to the loop's trip count).
2932                if let Some((buf, counter)) = ctx.fill_loop().map(|(b, c)| (b, c.to_string())) {
2933                    if buf == *coll_sym {
2934                        let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2935                        let coll_name = names.ident(*coll_sym);
2936                        // The buffer was `resize`d to this fill loop's trip count and
2937                        // `counter` is its 0-based induction variable, so `counter < len`
2938                        // holds by construction (a split-fill resizes to the full column
2939                        // count, so every sub-loop counter stays under it). Hint it so LLVM
2940                        // elides the bounds check on the DP-scan store — the "indexed
2941                        // unchecked write" this transform is meant to be, matching the
2942                        // append-only worklist path below. The `debug_assert` trips loudly
2943                        // in tests if a future detection change ever breaks the invariant,
2944                        // rather than the `assert_unchecked` going silently unsound.
2945                        writeln!(output, "{}debug_assert!(({} as usize) < {}.len(), \"LOGOS fill-loop store out of range\");", indent_str, counter, coll_name).unwrap();
2946                        writeln!(output, "{}unsafe {{ std::hint::assert_unchecked(({} as usize) < {}.len()); }}", indent_str, counter, coll_name).unwrap();
2947                        writeln!(output, "{}{}[{} as usize] = {};", indent_str, coll_name, counter, val_str).unwrap();
2948                        return output;
2949                    }
2950                }
2951                // Append-only worklist: `q.push(x)` becomes a pre-sized buffer
2952                // write at a register tail — `q[tail] = x; tail += 1` — with NO
2953                // capacity check (the monotone visited-set bound proved
2954                // `tail < q.len()`). This is C's exact frontier code.
2955                if let Some(tail) = ctx.worklist(*coll_sym).map(|w| w.tail_var.clone()) {
2956                    let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2957                    let coll_name = names.ident(*coll_sym);
2958                    writeln!(output, "{}unsafe {{ std::hint::assert_unchecked({tail} < {coll_name}.len()); }}", indent_str).unwrap();
2959                    writeln!(output, "{}{coll_name}[{tail}] = {val_str};", indent_str).unwrap();
2960                    writeln!(output, "{}{tail} += 1;", indent_str).unwrap();
2961                    return output;
2962                }
2963            }
2964            let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2965            let coll_str = codegen_expr_with_async(collection, interner, synced_vars, async_functions, ctx.get_variable_types());
2966            // MVS copy-on-write: a shared `LogosSeq` is deep-copied before this
2967            // in-place push so a value-semantics sibling is not mutated.
2968            emit_cow(collection, ctx, &names, &indent_str, &mut output);
2969            // A narrowed (`Vec<i32>`) sequence truncates on store — lossless,
2970            // since narrowing proved every pushed value fits i32.
2971            let narrowed_push = matches!(collection, Expr::Identifier(c) if ctx.is_narrowed(*c));
2972            if narrowed_push {
2973                writeln!(output, "{}{}.push(({}) as i32);", indent_str, coll_str, val_str).unwrap();
2974            } else {
2975                writeln!(output, "{}{}.push({});", indent_str, coll_str, val_str).unwrap();
2976            }
2977        }
2978
2979        Stmt::Pop { collection, into } => {
2980            let coll_str = codegen_expr_with_async(collection, interner, synced_vars, async_functions, ctx.get_variable_types());
2981            // MVS copy-on-write before the in-place pop (mutates the buffer).
2982            emit_cow(collection, ctx, &names, &indent_str, &mut output);
2983            match into {
2984                Some(var) => {
2985                    let var_name = names.ident(*var);
2986                    // Unwrap the Option returned by pop() - panics if empty
2987                    writeln!(output, "{}let {} = {}.pop().expect(\"Pop from empty collection\");", indent_str, var_name, coll_str).unwrap();
2988                }
2989                None => {
2990                    writeln!(output, "{}{}.pop();", indent_str, coll_str).unwrap();
2991                }
2992            }
2993        }
2994
2995        Stmt::Add { value, collection } => {
2996            let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
2997            let coll_str = codegen_expr_with_async(collection, interner, synced_vars, async_functions, ctx.get_variable_types());
2998            // MVS copy-on-write before the in-place insert (a `LogosMap`; a plain
2999            // `FxHashSet`/`Set` is already value-semantic and yields no `cow`).
3000            emit_cow(collection, ctx, &names, &indent_str, &mut output);
3001            writeln!(output, "{}{}.insert({});", indent_str, coll_str, val_str).unwrap();
3002        }
3003
3004        Stmt::Remove { value, collection } => {
3005            let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
3006            let coll_str = codegen_expr_with_async(collection, interner, synced_vars, async_functions, ctx.get_variable_types());
3007            // MVS copy-on-write before the in-place remove.
3008            emit_cow(collection, ctx, &names, &indent_str, &mut output);
3009            // Order-preserving removal: a `Set` is an IndexSet, whose plain
3010            // `remove` is a swap_remove — `shift_remove` keeps insertion
3011            // order (`LogosMap::remove` already shifts internally).
3012            let is_set = matches!(collection, Expr::Identifier(sym)
3013                if ctx.get_variable_types().get(sym).is_some_and(|t| t.starts_with("Set<") || t.starts_with("FxHashSet<")));
3014            let method = if is_set { "shift_remove" } else { "remove" };
3015            writeln!(output, "{}{}.{}(&{});", indent_str, coll_str, method, val_str).unwrap();
3016        }
3017
3018        Stmt::SetIndex { collection, index, value } => {
3019            // Nested value-semantic THROUGH-WRITE `grid[k][i] = v` (a fused place-write, see
3020            // splice_fuse): cow the outer grid, then `set_nested` cow's the ROW only if it is shared
3021            // — O(1) when uniquely owned, versus the desugar's unconditional full-row clone. Scoped
3022            // to a `LogosSeq<LogosSeq<…>>` base (the nested-array case); any other nested shape falls
3023            // through to the general handling below, and the compiled-vs-interpreted differential
3024            // guards value-semantics soundness for every shape.
3025            if let Expr::Index { collection: base, index: outer_idx } = collection {
3026                if let Expr::Identifier(base_sym) = base {
3027                    let is_nested_seq = ctx.get_variable_types().get(base_sym).map_or(false, |t| {
3028                        t.split("|__hl:").next().unwrap_or(t).starts_with("LogosSeq<LogosSeq")
3029                    });
3030                    if is_nested_seq {
3031                        let value_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
3032                        let usize_index = |ix: &Expr| -> String {
3033                            if let Expr::Identifier(s) = ix {
3034                                if ctx.get_variable_types().get(s).map_or(false, |t| t == "__zero_based_i64") {
3035                                    return format!("{} as usize", codegen_expr_with_async(ix, interner, synced_vars, async_functions, ctx.get_variable_types()));
3036                                }
3037                            }
3038                            simplify_1based_index(ix, interner, true, ctx.get_variable_types())
3039                        };
3040                        let k_idx = usize_index(outer_idx);
3041                        let i_idx = usize_index(index);
3042                        emit_cow(base, ctx, &names, &indent_str, &mut output);
3043                        writeln!(output, "{}{}.set_nested({}, {}, {});", indent_str, names.ident(*base_sym), k_idx, i_idx, value_str).unwrap();
3044                        return output;
3045                    }
3046                }
3047            }
3048            // AoS interleaving: `Set item i of member to v` → `backing[(i-1)][col] = v`.
3049            if let Expr::Identifier(sym) = collection {
3050                if let Some(tag) = parse_aos_tag(ctx.get_variable_types().get(sym)) {
3051                    let value_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
3052                    let is_zb = matches!(index, Expr::Identifier(s) if ctx.get_variable_types().get(s).map_or(false, |t| t == "__zero_based_i64"));
3053                    let idx_part = if is_zb {
3054                        format!("{} as usize", codegen_expr_with_async(index, interner, synced_vars, async_functions, ctx.get_variable_types()))
3055                    } else {
3056                        simplify_1based_index(index, interner, true, ctx.get_variable_types())
3057                    };
3058                    writeln!(output, "{}{}[{}][{}] = {};", indent_str, tag.backing, idx_part, tag.col, value_str).unwrap();
3059                    return output;
3060                }
3061            }
3062            let coll_str = codegen_expr_with_async(collection, interner, synced_vars, async_functions, ctx.get_variable_types());
3063            let value_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
3064
3065            // MVS copy-on-write before the in-place indexed store / map insert.
3066            // A no-op for the `Vec`/slice/array and `FxHashMap` arms below (they
3067            // are not shared `Rc`s); fires only for a real `LogosSeq`/`LogosMap`.
3068            emit_cow(collection, ctx, &names, &indent_str, &mut output);
3069
3070            // Direct indexing for known collection types (avoids trait dispatch)
3071            // Strip |__hl: hoisting suffix so type matching works correctly.
3072            let known_type = if let Expr::Identifier(sym) = collection {
3073                ctx.get_variable_types().get(sym).map(|s| s.split("|__hl:").next().unwrap_or(s.as_str()))
3074            } else {
3075                None
3076            };
3077
3078            match known_type {
3079                Some(t) if t.starts_with("LogosSeq") => {
3080                    // Use borrow_mut() for interior mutability — no &mut needed on the variable.
3081                    let is_zero_based_counter = if let Expr::Identifier(idx_sym) = index {
3082                        ctx.get_variable_types().get(idx_sym).map_or(false, |t| t == "__zero_based_i64")
3083                    } else {
3084                        false
3085                    };
3086                    let index_part = if is_zero_based_counter {
3087                        let idx_name = codegen_expr_with_async(index, interner, synced_vars, async_functions, ctx.get_variable_types());
3088                        format!("{} as usize", idx_name)
3089                    } else {
3090                        simplify_1based_index(index, interner, true, ctx.get_variable_types())
3091                    };
3092                    // BCE: when the oracle proves the store index in range, emit
3093                    // an unchecked store through the borrow (no bounds branch)
3094                    // with a `debug_assert!` net — the value-semantic analog of
3095                    // the `Vec` path below. Soundness: the kernel-LIA proof + the
3096                    // function entry precondition. `LOGOS_ORACLE_UNCHECKED=0` forces
3097                    // checked. The `borrow_mut()` sees the owned buffer (a `cow()`
3098                    // was emitted before this store for value bindings).
3099                    let store_unchecked = crate::optimize::active_config()
3100                        .is_on(crate::optimization::Opt::Unchecked)
3101                        && ctx.oracle().map_or(false, |o| o.index_provably_in_bounds(collection, index));
3102                    // If the RHS borrows ANY collection, evaluate it into a temp
3103                    // first: under reference semantics that collection may alias
3104                    // the target (e.g. `prev` after `Set prev to curr`), and a
3105                    // live borrow() across the target's borrow_mut() panics.
3106                    let needs_tmp = store_unchecked || expr_reads_any_collection(value);
3107                    if store_unchecked {
3108                        crate::optimize::mark_fired(crate::optimization::Opt::Unchecked);
3109                        let i0 = if is_zero_based_counter {
3110                            codegen_expr_with_async(index, interner, synced_vars, async_functions, ctx.get_variable_types())
3111                        } else {
3112                            simplify_1based_index(index, interner, false, ctx.get_variable_types())
3113                        };
3114                        writeln!(output, "{}debug_assert!(({}) >= 0 && ({}) < ({}.len() as i64), \"LOGOS oracle BCE: store out of range\");", indent_str, i0, i0, coll_str).unwrap();
3115                        writeln!(output, "{}let __set_val = {};", indent_str, value_str).unwrap();
3116                        writeln!(output, "{}unsafe {{ *{}.borrow_mut().get_unchecked_mut({}) = __set_val; }}", indent_str, coll_str, index_part).unwrap();
3117                    } else if needs_tmp {
3118                        writeln!(output, "{}let __set_val = {};", indent_str, value_str).unwrap();
3119                        writeln!(output, "{}{}.borrow_mut()[{}] = __set_val;", indent_str, coll_str, index_part).unwrap();
3120                    } else {
3121                        writeln!(output, "{}{}.borrow_mut()[{}] = {};", indent_str, coll_str, index_part, value_str).unwrap();
3122                    }
3123                }
3124                Some(t) if is_logos_map_type(t) => {
3125                    let index_str = codegen_expr_with_async(index, interner, synced_vars, async_functions, ctx.get_variable_types());
3126                    writeln!(output, "{}{}.insert({}, {});", indent_str, coll_str, index_str, value_str).unwrap();
3127                }
3128                Some(t) if t.starts_with("Vec") || t.starts_with("&mut [") || t.starts_with("&[") || t.starts_with('[') => {
3129                    // Vec / slice / fixed array (O3) — direct indexed store.
3130                    // OPT-8: Check if index is a zero-based counter
3131                    let is_zero_based_counter = if let Expr::Identifier(idx_sym) = index {
3132                        ctx.get_variable_types().get(idx_sym).map_or(false, |t| t == "__zero_based_i64")
3133                    } else {
3134                        false
3135                    };
3136                    let index_part = if is_zero_based_counter {
3137                        let idx_name = codegen_expr_with_async(index, interner, synced_vars, async_functions, ctx.get_variable_types());
3138                        format!("{} as usize", idx_name)
3139                    } else {
3140                        simplify_1based_index(index, interner, true, ctx.get_variable_types())
3141                    };
3142                    // A narrowed (`Vec<i32>`) sequence truncates on store — lossless,
3143                    // since narrowing proved every stored value fits i32.
3144                    let narrowed = matches!(collection, Expr::Identifier(c) if ctx.is_narrowed(*c));
3145                    let value_str = if narrowed { format!("(({}) as i32)", value_str) } else { value_str };
3146                    // BCE: when the oracle proves the store index in range, emit an
3147                    // unchecked store (no bounds branch) with a `debug_assert!` net.
3148                    // Soundness: the kernel-LIA proof + the function's entry
3149                    // precondition guard. `LOGOS_ORACLE_UNCHECKED=0` forces checked.
3150                    let store_unchecked = crate::optimize::active_config().is_on(crate::optimization::Opt::Unchecked)
3151                        && ctx.oracle().map_or(false, |o| o.index_provably_in_bounds(collection, index));
3152                    if store_unchecked {
3153                        crate::optimize::mark_fired(crate::optimization::Opt::Unchecked);
3154                        let i0 = if is_zero_based_counter {
3155                            codegen_expr_with_async(index, interner, synced_vars, async_functions, ctx.get_variable_types())
3156                        } else {
3157                            simplify_1based_index(index, interner, false, ctx.get_variable_types())
3158                        };
3159                        writeln!(output, "{}debug_assert!(({}) >= 0 && ({}) < ({}.len() as i64), \"LOGOS oracle BCE: store out of range\");", indent_str, i0, i0, coll_str).unwrap();
3160                        // Bind the value to a temp first: it may itself be a proven
3161                        // `get_unchecked` read of the same slice (the partition swap),
3162                        // so evaluating it before the `&mut` access avoids both a
3163                        // nested `unsafe` block and an aliasing borrow.
3164                        writeln!(output, "{}let __set_val = {};", indent_str, value_str).unwrap();
3165                        writeln!(output, "{}unsafe {{ *{}.get_unchecked_mut({}) = __set_val; }}", indent_str, coll_str, index_part).unwrap();
3166                    } else {
3167                        writeln!(output, "{}{}[{}] = {};", indent_str, coll_str, index_part, value_str).unwrap();
3168                    }
3169                }
3170                Some(t) if t.starts_with("std::collections::HashMap") || t.starts_with("HashMap") || t.starts_with("rustc_hash::FxHashMap") || t.starts_with("FxHashMap") => {
3171                    let index_str = codegen_expr_with_async(index, interner, synced_vars, async_functions, ctx.get_variable_types());
3172                    writeln!(output, "{}{}.insert({}, {});", indent_str, coll_str, index_str, value_str).unwrap();
3173                }
3174                _ => {
3175                    let index_str = codegen_expr_with_async(index, interner, synced_vars, async_functions, ctx.get_variable_types());
3176                    // Fallback: polymorphic indexing via trait.
3177                    // If the value expression reads ANY collection, bind it to a
3178                    // temp first: that collection may alias the one being written
3179                    // (reference semantics), and a live borrow across the mutable
3180                    // access would conflict.
3181                    let needs_tmp = expr_reads_any_collection(value);
3182                    if needs_tmp {
3183                        writeln!(output, "{}let __set_tmp = {};", indent_str, value_str).unwrap();
3184                        writeln!(output, "{}LogosIndexMut::logos_set(&mut {}, {}, __set_tmp);", indent_str, coll_str, index_str).unwrap();
3185                    } else {
3186                        writeln!(output, "{}LogosIndexMut::logos_set(&mut {}, {}, {});", indent_str, coll_str, index_str, value_str).unwrap();
3187                    }
3188                }
3189            }
3190        }
3191
3192        // Phase 8.5: Zone (memory arena) block
3193        Stmt::Zone { name, capacity, source_file, body } => {
3194            let zone_name = interner.resolve(*name);
3195
3196            // Generate zone creation based on type
3197            if let Some(src) = source_file {
3198                // Memory-mapped file zone — literal path is quoted; a variable path
3199                // is passed by reference (`new_mapped` takes `AsRef<Path>`).
3200                use crate::ast::stmt::ZoneSource;
3201                let path_expr = match src {
3202                    ZoneSource::Literal(p) => format!("\"{}\"", interner.resolve(*p)),
3203                    ZoneSource::Variable(v) => format!("&{}", interner.resolve(*v)),
3204                };
3205                writeln!(
3206                    output,
3207                    "{}let {} = logicaffeine_system::memory::Zone::new_mapped({}).expect(\"Failed to map file\");",
3208                    indent_str, zone_name, path_expr
3209                ).unwrap();
3210            } else {
3211                // Heap arena zone
3212                let cap = capacity.unwrap_or(4096); // Default 4KB
3213                writeln!(
3214                    output,
3215                    "{}let {} = logicaffeine_system::memory::Zone::new_heap({});",
3216                    indent_str, zone_name, cap
3217                ).unwrap();
3218            }
3219
3220            // Open block scope
3221            writeln!(output, "{}{{", indent_str).unwrap();
3222            ctx.push_scope();
3223
3224            // Generate body statements
3225            for stmt in *body {
3226                output.push_str(&codegen_stmt(stmt, interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env));
3227            }
3228
3229            ctx.pop_scope();
3230            writeln!(output, "{}}}", indent_str).unwrap();
3231        }
3232
3233        // Phase 9: Concurrent execution block (async, I/O-bound)
3234        // Generates tokio::join! for concurrent task execution
3235        // Phase 51: Variables used across multiple tasks are cloned to avoid move issues
3236        Stmt::Concurrent { tasks } => {
3237            // Collect Let statements to generate tuple destructuring
3238            let let_bindings: Vec<_> = tasks.iter().filter_map(|s| {
3239                if let Stmt::Let { var, .. } = s {
3240                    Some(interner.resolve(*var).to_string())
3241                } else {
3242                    None
3243                }
3244            }).collect();
3245
3246            // Collect variables DEFINED in this block (to exclude from cloning)
3247            let defined_vars: HashSet<Symbol> = tasks.iter().filter_map(|s| {
3248                if let Stmt::Let { var, .. } = s {
3249                    Some(*var)
3250                } else {
3251                    None
3252                }
3253            }).collect();
3254
3255            // Check if there are intra-block dependencies (a later task uses a var from earlier task)
3256            // If so, fall back to sequential execution
3257            let mut has_intra_dependency = false;
3258            let mut seen_defs: HashSet<Symbol> = HashSet::new();
3259            for s in *tasks {
3260                // Check if this task uses any variable defined by previous tasks in this block
3261                let mut used_in_task: HashSet<Symbol> = HashSet::new();
3262                collect_stmt_identifiers(s, &mut used_in_task);
3263                for used_var in &used_in_task {
3264                    if seen_defs.contains(used_var) {
3265                        has_intra_dependency = true;
3266                        break;
3267                    }
3268                }
3269                // Track variables defined by this task
3270                if let Stmt::Let { var, .. } = s {
3271                    seen_defs.insert(*var);
3272                }
3273                if has_intra_dependency {
3274                    break;
3275                }
3276            }
3277
3278            // Collect ALL variables used in task expressions (not just Call args)
3279            // Exclude variables defined within this block
3280            let mut used_syms: HashSet<Symbol> = HashSet::new();
3281            for s in *tasks {
3282                collect_stmt_identifiers(s, &mut used_syms);
3283            }
3284            // Remove variables that are defined in this block
3285            for def_var in &defined_vars {
3286                used_syms.remove(def_var);
3287            }
3288            let used_vars: HashSet<String> = used_syms.iter()
3289                .map(|sym| interner.resolve(*sym).to_string())
3290                .collect();
3291
3292            // If there are intra-block dependencies, execute sequentially
3293            if has_intra_dependency {
3294                // Generate sequential Let bindings
3295                for stmt in *tasks {
3296                    output.push_str(&codegen_stmt(stmt, interner, indent, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env));
3297                }
3298            } else {
3299                // Generate concurrent execution with tokio::join!
3300                if !let_bindings.is_empty() {
3301                    // Generate tuple destructuring for concurrent Let bindings
3302                    writeln!(output, "{}let ({}) = tokio::join!(", indent_str, let_bindings.join(", ")).unwrap();
3303                } else {
3304                    writeln!(output, "{}tokio::join!(", indent_str).unwrap();
3305                }
3306
3307                for (i, stmt) in tasks.iter().enumerate() {
3308                    // For Let statements, generate only the VALUE so the async block returns it
3309                    // For Call statements, generate the call with .await
3310                    let inner_code = match stmt {
3311                        Stmt::Let { value, .. } => {
3312                            // Return the value expression directly (not "let x = value;")
3313                            // Phase 54+: Use codegen_expr_with_async to handle all nested async calls
3314                            codegen_expr_with_async(value, interner, synced_vars, async_functions, ctx.get_variable_types())
3315                        }
3316                        Stmt::Call { function, args } => {
3317                            let func_name = interner.resolve(*function);
3318                            let args_str: Vec<String> = args.iter()
3319                                .map(|a| codegen_expr_with_async(a, interner, synced_vars, async_functions, ctx.get_variable_types()))
3320                                .collect();
3321                            // Only add .await for async functions
3322                            let await_suffix = if async_functions.contains(function) { ".await" } else { "" };
3323                            format!("{}({}){}", func_name, args_str.join(", "), await_suffix)
3324                        }
3325                        _ => {
3326                            // Fallback for other statement types
3327                            let inner = codegen_stmt(stmt, interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env);
3328                            inner.trim().to_string()
3329                        }
3330                    };
3331
3332                    // For tasks that use shared variables, wrap in a block that clones them
3333                    if !used_vars.is_empty() && i < tasks.len() - 1 {
3334                        // Clone variables for all tasks except the last one
3335                        let clones: Vec<String> = used_vars.iter()
3336                            .map(|v| format!("let {} = {}.clone();", v, v))
3337                            .collect();
3338                        write!(output, "{}    {{ {} async move {{ {} }} }}",
3339                               indent_str, clones.join(" "), inner_code).unwrap();
3340                    } else {
3341                        // Last task can use original variables
3342                        write!(output, "{}    async {{ {} }}", indent_str, inner_code).unwrap();
3343                    }
3344
3345                    if i < tasks.len() - 1 {
3346                        writeln!(output, ",").unwrap();
3347                    } else {
3348                        writeln!(output).unwrap();
3349                    }
3350                }
3351
3352                writeln!(output, "{});", indent_str).unwrap();
3353            }
3354        }
3355
3356        // Phase 9: Parallel execution block (CPU-bound)
3357        // Generates rayon::join for two tasks, or thread::spawn for 3+ tasks
3358        Stmt::Parallel { tasks } => {
3359            // Collect Let statements to generate tuple destructuring
3360            let let_bindings: Vec<_> = tasks.iter().filter_map(|s| {
3361                if let Stmt::Let { var, .. } = s {
3362                    Some(interner.resolve(*var).to_string())
3363                } else {
3364                    None
3365                }
3366            }).collect();
3367
3368            if tasks.len() == 2 {
3369                // Use rayon::join for exactly 2 tasks
3370                if !let_bindings.is_empty() {
3371                    writeln!(output, "{}let ({}) = rayon::join(", indent_str, let_bindings.join(", ")).unwrap();
3372                } else {
3373                    writeln!(output, "{}rayon::join(", indent_str).unwrap();
3374                }
3375
3376                for (i, stmt) in tasks.iter().enumerate() {
3377                    // For Let statements, generate only the VALUE so the closure returns it
3378                    let inner_code = match stmt {
3379                        Stmt::Let { value, .. } => {
3380                            // Return the value expression directly (not "let x = value;")
3381                            codegen_expr_with_async(value, interner, synced_vars, async_functions, ctx.get_variable_types())
3382                        }
3383                        Stmt::Call { function, args } => {
3384                            let func_name = interner.resolve(*function);
3385                            let variable_types = ctx.get_variable_types();
3386                            let callee_borrow_indices: HashSet<usize> =
3387                                super::fn_role_indices(variable_types.get(function), super::FnRole::Borrow);
3388                            let args_str: Vec<String> = args.iter().enumerate()
3389                                .map(|(idx, a)| {
3390                                    let s = codegen_expr_with_async(a, interner, synced_vars, async_functions, variable_types);
3391                                    if callee_borrow_indices.contains(&idx) {
3392                                        if let Expr::Identifier(sym) = a {
3393                                            if let Some(ty) = variable_types.get(sym) {
3394                                                if ty.starts_with("&[") {
3395                                                    return s;
3396                                                }
3397                                            }
3398                                        }
3399                                        format!("&{}", s)
3400                                    } else { s }
3401                                })
3402                                .collect();
3403                            format!("{}({})", func_name, args_str.join(", "))
3404                        }
3405                        _ => {
3406                            // Fallback for other statement types
3407                            let inner = codegen_stmt(stmt, interner, indent + 1, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env);
3408                            inner.trim().to_string()
3409                        }
3410                    };
3411                    write!(output, "{}    || {{ {} }}", indent_str, inner_code).unwrap();
3412                    if i == 0 {
3413                        writeln!(output, ",").unwrap();
3414                    } else {
3415                        writeln!(output).unwrap();
3416                    }
3417                }
3418                writeln!(output, "{});", indent_str).unwrap();
3419            } else {
3420                // For 3+ tasks, use thread::spawn pattern
3421                writeln!(output, "{}{{", indent_str).unwrap();
3422                writeln!(output, "{}    let handles: Vec<_> = vec![", indent_str).unwrap();
3423                for stmt in *tasks {
3424                    // For Let statements, generate only the VALUE so the closure returns it
3425                    let inner_code = match stmt {
3426                        Stmt::Let { value, .. } => {
3427                            codegen_expr_with_async(value, interner, synced_vars, async_functions, ctx.get_variable_types())
3428                        }
3429                        Stmt::Call { function, args } => {
3430                            let func_name = interner.resolve(*function);
3431                            let variable_types = ctx.get_variable_types();
3432                            let callee_borrow_indices: HashSet<usize> =
3433                                super::fn_role_indices(variable_types.get(function), super::FnRole::Borrow);
3434                            let args_str: Vec<String> = args.iter().enumerate()
3435                                .map(|(idx, a)| {
3436                                    let s = codegen_expr_with_async(a, interner, synced_vars, async_functions, variable_types);
3437                                    if callee_borrow_indices.contains(&idx) {
3438                                        if let Expr::Identifier(sym) = a {
3439                                            if let Some(ty) = variable_types.get(sym) {
3440                                                if ty.starts_with("&[") {
3441                                                    return s;
3442                                                }
3443                                            }
3444                                        }
3445                                        format!("&{}", s)
3446                                    } else { s }
3447                                })
3448                                .collect();
3449                            format!("{}({})", func_name, args_str.join(", "))
3450                        }
3451                        _ => {
3452                            let inner = codegen_stmt(stmt, interner, indent + 2, mutable_vars, ctx, lww_fields, mv_fields, synced_vars, var_caps, async_functions, pipe_vars, boxed_fields, registry, type_env);
3453                            inner.trim().to_string()
3454                        }
3455                    };
3456                    writeln!(output, "{}        std::thread::spawn(move || {{ {} }}),",
3457                             indent_str, inner_code).unwrap();
3458                }
3459                writeln!(output, "{}    ];", indent_str).unwrap();
3460                writeln!(output, "{}    for h in handles {{ h.join().unwrap(); }}", indent_str).unwrap();
3461                writeln!(output, "{}}}", indent_str).unwrap();
3462            }
3463        }
3464
3465        // Phase 10: Read from console or file
3466        // Phase 53: File reads now use async VFS
3467        Stmt::ReadFrom { var, source } => {
3468            let var_name = interner.resolve(*var);
3469            match source {
3470                ReadSource::Console => {
3471                    writeln!(output, "{}let {} = logicaffeine_system::io::read_line();", indent_str, var_name).unwrap();
3472                }
3473                ReadSource::File(path_expr) => {
3474                    let path_str = codegen_expr_with_async(path_expr, interner, synced_vars, async_functions, ctx.get_variable_types());
3475                    // Phase 53: Use VFS with async
3476                    writeln!(
3477                        output,
3478                        "{}let {} = vfs.read_to_string(&{}).await.expect(\"Failed to read file\");",
3479                        indent_str, var_name, path_str
3480                    ).unwrap();
3481                }
3482            }
3483        }
3484
3485        // Phase 10: Write to file
3486        // Phase 53: File writes now use async VFS
3487        Stmt::WriteFile { content, path } => {
3488            let content_str = codegen_expr_with_async(content, interner, synced_vars, async_functions, ctx.get_variable_types());
3489            let path_str = codegen_expr_with_async(path, interner, synced_vars, async_functions, ctx.get_variable_types());
3490            // Phase 53: Use VFS with async
3491            writeln!(
3492                output,
3493                "{}vfs.write(&{}, {}.as_bytes()).await.expect(\"Failed to write file\");",
3494                indent_str, path_str, content_str
3495            ).unwrap();
3496        }
3497
3498        // Phase 46: Spawn an agent
3499        Stmt::Spawn { agent_type, name } => {
3500            let type_name = interner.resolve(*agent_type);
3501            let agent_name = interner.resolve(*name);
3502            // Generate agent spawn with tokio channel
3503            writeln!(
3504                output,
3505                "{}let {} = tokio::spawn(async move {{ /* {} agent loop */ }});",
3506                indent_str, agent_name, type_name
3507            ).unwrap();
3508        }
3509
3510        // Phase 46: Send message to agent
3511        Stmt::SendMessage { message, destination, .. } => {
3512            let msg_str = codegen_expr_with_async(message, interner, synced_vars, async_functions, ctx.get_variable_types());
3513            let dest_str = codegen_expr_with_async(destination, interner, synced_vars, async_functions, ctx.get_variable_types());
3514            writeln!(
3515                output,
3516                "{}{}.send({}).await.expect(\"Failed to send message\");",
3517                indent_str, dest_str, msg_str
3518            ).unwrap();
3519        }
3520
3521        // Streaming is a tree-walker feature (the relay receive runs in the interpreter); the AOT
3522        // path does not lower it yet — emit a marker rather than silently dropping it.
3523        Stmt::StreamMessage { .. } => {
3524            writeln!(output, "{}// Stream: interpreter-only (not yet lowered to AOT)", indent_str).unwrap();
3525        }
3526
3527        // Phase 46: Await response from agent. (`view` is a tree-walker zero-copy receive hint;
3528        // the compiled path decodes eagerly to the same values.)
3529        Stmt::AwaitMessage { source, into, view: _, stream: _ } => {
3530            let src_str = codegen_expr_with_async(source, interner, synced_vars, async_functions, ctx.get_variable_types());
3531            let var_name = interner.resolve(*into);
3532            writeln!(
3533                output,
3534                "{}let {} = {}.recv().await.expect(\"Failed to receive message\");",
3535                indent_str, var_name, src_str
3536            ).unwrap();
3537        }
3538
3539        // Phase 49: Merge CRDT state
3540        Stmt::MergeCrdt { source, target } => {
3541            let src_str = codegen_expr_with_async(source, interner, synced_vars, async_functions, ctx.get_variable_types());
3542            let tgt_str = codegen_expr_with_async(target, interner, synced_vars, async_functions, ctx.get_variable_types());
3543            writeln!(
3544                output,
3545                "{}{}.merge(&{});",
3546                indent_str, tgt_str, src_str
3547            ).unwrap();
3548        }
3549
3550        // Phase 49: Increment GCounter
3551        // Phase 52: If object is synced, wrap in .mutate() for auto-publish
3552        Stmt::IncreaseCrdt { object, field, amount } => {
3553            let field_name = interner.resolve(*field);
3554            let amount_str = codegen_expr_with_async(amount, interner, synced_vars, async_functions, ctx.get_variable_types());
3555
3556            // Check if the root object is synced
3557            let root_sym = get_root_identifier(object);
3558            if let Some(sym) = root_sym {
3559                if synced_vars.contains(&sym) {
3560                    // Synced: use .mutate() for auto-publish
3561                    let obj_name = interner.resolve(sym);
3562                    writeln!(
3563                        output,
3564                        "{}{}.mutate(|inner| inner.{}.increment({} as u64)).await;",
3565                        indent_str, obj_name, field_name, amount_str
3566                    ).unwrap();
3567                    return output;
3568                }
3569            }
3570
3571            // Not synced: direct access
3572            let obj_str = codegen_expr_with_async(object, interner, synced_vars, async_functions, ctx.get_variable_types());
3573            writeln!(
3574                output,
3575                "{}{}.{}.increment({} as u64);",
3576                indent_str, obj_str, field_name, amount_str
3577            ).unwrap();
3578        }
3579
3580        // Phase 49b: Decrement PNCounter
3581        Stmt::DecreaseCrdt { object, field, amount } => {
3582            let field_name = interner.resolve(*field);
3583            let amount_str = codegen_expr_with_async(amount, interner, synced_vars, async_functions, ctx.get_variable_types());
3584
3585            // Check if the root object is synced
3586            let root_sym = get_root_identifier(object);
3587            if let Some(sym) = root_sym {
3588                if synced_vars.contains(&sym) {
3589                    // Synced: use .mutate() for auto-publish
3590                    let obj_name = interner.resolve(sym);
3591                    writeln!(
3592                        output,
3593                        "{}{}.mutate(|inner| inner.{}.decrement({} as u64)).await;",
3594                        indent_str, obj_name, field_name, amount_str
3595                    ).unwrap();
3596                    return output;
3597                }
3598            }
3599
3600            // Not synced: direct access
3601            let obj_str = codegen_expr_with_async(object, interner, synced_vars, async_functions, ctx.get_variable_types());
3602            writeln!(
3603                output,
3604                "{}{}.{}.decrement({} as u64);",
3605                indent_str, obj_str, field_name, amount_str
3606            ).unwrap();
3607        }
3608
3609        // Phase 49b: Append to SharedSequence (RGA)
3610        Stmt::AppendToSequence { sequence, value } => {
3611            let seq_str = codegen_expr_with_async(sequence, interner, synced_vars, async_functions, ctx.get_variable_types());
3612            let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
3613            writeln!(
3614                output,
3615                "{}{}.append({});",
3616                indent_str, seq_str, val_str
3617            ).unwrap();
3618        }
3619
3620        // Phase 49b: Resolve MVRegister conflicts
3621        Stmt::ResolveConflict { object, field, value } => {
3622            let field_name = interner.resolve(*field);
3623            let val_str = codegen_expr_boxed_with_types_oracle(value, interner, synced_vars, boxed_fields, registry, async_functions, ctx.get_string_vars(), ctx.get_variable_types(), ctx.get_fast_div(), ctx.oracle());
3624            let obj_str = codegen_expr_with_async(object, interner, synced_vars, async_functions, ctx.get_variable_types());
3625            writeln!(
3626                output,
3627                "{}{}.{}.resolve({});",
3628                indent_str, obj_str, field_name, val_str
3629            ).unwrap();
3630        }
3631
3632        // Escape hatch: emit raw foreign code wrapped in braces for scope isolation
3633        Stmt::Escape { code, .. } => {
3634            let raw_code = interner.resolve(*code);
3635            write!(output, "{}{{\n", indent_str).unwrap();
3636            for line in raw_code.lines() {
3637                write!(output, "{}    {}\n", indent_str, line).unwrap();
3638            }
3639            write!(output, "{}}}\n", indent_str).unwrap();
3640        }
3641
3642        // Dependencies are metadata; no Rust code emitted.
3643        Stmt::Require { .. } => {}
3644
3645        // Theorems and definitions are proof-layer declarations verified at
3646        // compile-time; they generate no runtime code (handled separately by the
3647        // theorem pipeline at the meta-level).
3648        Stmt::Theorem(_) | Stmt::Definition(_) | Stmt::Axiom(_) | Stmt::Theory(_) => {}
3649    }
3650
3651    output
3652}
3653
3654/// OPT-5: Sentinel → break transformation.
3655///
3656/// Detects `If cond then: ...; Set counter to limit.` inside a `While counter < limit:` loop
3657/// and replaces the sentinel set with `break;`. This gives LLVM a clean early-exit edge
3658/// instead of an opaque counter assignment that forces one more condition check.
3659///
3660/// Returns the generated code if the pattern matches, or None.
3661fn try_emit_sentinel_break<'a>(
3662    stmt: &Stmt<'a>,
3663    counter_sym: Symbol,
3664    limit_expr: &Expr<'a>,
3665    interner: &Interner,
3666    indent: usize,
3667    mutable_vars: &HashSet<Symbol>,
3668    ctx: &mut RefinementContext<'a>,
3669    lww_fields: &HashSet<(String, String)>,
3670    mv_fields: &HashSet<(String, String)>,
3671    synced_vars: &mut HashSet<Symbol>,
3672    var_caps: &HashMap<Symbol, VariableCapabilities>,
3673    async_functions: &HashSet<Symbol>,
3674    pipe_vars: &HashSet<Symbol>,
3675    boxed_fields: &HashSet<(String, String, String)>,
3676    registry: &TypeRegistry,
3677    type_env: &crate::analysis::types::TypeEnv,
3678) -> Option<String> {
3679    // Match: If cond then: ...; Set counter to limit. (no else block)
3680    let (if_cond, then_block, else_block) = match stmt {
3681        Stmt::If { cond, then_block, else_block } => (cond, then_block, else_block),
3682        _ => return None,
3683    };
3684
3685    if else_block.is_some() {
3686        return None;
3687    }
3688
3689    if then_block.is_empty() {
3690        return None;
3691    }
3692
3693    // Last statement in then_block must be `Set counter to limit`
3694    let last = &then_block[then_block.len() - 1];
3695    match last {
3696        Stmt::Set { target, value, .. } => {
3697            if *target != counter_sym || !exprs_equal(value, limit_expr) {
3698                return None;
3699            }
3700        }
3701        _ => return None,
3702    }
3703
3704    // Pattern matched! Emit if block with break instead of sentinel set.
3705    let indent_str = "    ".repeat(indent);
3706    let var_types = ctx.get_variable_types();
3707    let cond_str = codegen_expr_with_async(if_cond, interner, synced_vars, async_functions, var_types);
3708    let mut output = String::new();
3709    writeln!(output, "{}if {} {{", indent_str, cond_str).unwrap();
3710
3711    // Emit all then_block statements except the last (the sentinel set)
3712    for s in &then_block[..then_block.len() - 1] {
3713        output.push_str(&codegen_stmt(
3714            s, interner, indent + 1, mutable_vars, ctx,
3715            lww_fields, mv_fields, synced_vars, var_caps,
3716            async_functions, pipe_vars, boxed_fields, registry, type_env,
3717        ));
3718    }
3719
3720    // Emit break instead of the sentinel set
3721    writeln!(output, "{}    break;", indent_str).unwrap();
3722    writeln!(output, "{}}}", indent_str).unwrap();
3723
3724    Some(output)
3725}
3726
3727/// Phase 52: Extract the root identifier from an expression.
3728/// For `x.field.subfield`, returns `x`.
3729pub(crate) fn get_root_identifier(expr: &Expr) -> Option<Symbol> {
3730    match expr {
3731        Expr::Identifier(sym) => Some(*sym),
3732        Expr::FieldAccess { object, .. } => get_root_identifier(object),
3733        _ => None,
3734    }
3735}
3736
3737/// Extract all symbols from `Expr::Length { collection: Expr::Identifier(sym) }` nodes
3738/// in an expression tree. Used for loop bounds hoisting.
3739pub(crate) fn extract_length_expr_syms(expr: &Expr) -> Vec<Symbol> {
3740    let mut out = Vec::new();
3741    collect_length_syms_from_expr(expr, &mut out);
3742    out
3743}
3744
3745fn collect_length_syms_from_expr(expr: &Expr, out: &mut Vec<Symbol>) {
3746    match expr {
3747        Expr::Length { collection } => {
3748            if let Expr::Identifier(sym) = collection {
3749                out.push(*sym);
3750            }
3751        }
3752        Expr::BinaryOp { left, right, .. } => {
3753            collect_length_syms_from_expr(left, out);
3754            collect_length_syms_from_expr(right, out);
3755        }
3756        Expr::Not { operand } => collect_length_syms_from_expr(operand, out),
3757        Expr::Index { collection, index } => {
3758            collect_length_syms_from_expr(collection, out);
3759            collect_length_syms_from_expr(index, out);
3760        }
3761        Expr::Call { args, .. } => {
3762            for arg in args.iter() {
3763                collect_length_syms_from_expr(arg, out);
3764            }
3765        }
3766        _ => {}
3767    }
3768}
3769
3770/// Collect all `Expr::Length { Identifier(sym) }` symbols from a statement list (recursively).
3771pub(crate) fn collect_length_syms_from_stmts(stmts: &[Stmt], out: &mut Vec<Symbol>) {
3772    for stmt in stmts {
3773        collect_length_syms_from_stmt(stmt, out);
3774    }
3775}
3776
3777fn collect_length_syms_from_stmt(stmt: &Stmt, out: &mut Vec<Symbol>) {
3778    match stmt {
3779        Stmt::Let { value, .. } => collect_length_syms_from_expr(value, out),
3780        Stmt::Set { value, .. } => collect_length_syms_from_expr(value, out),
3781        Stmt::Show { object, .. } => collect_length_syms_from_expr(object, out),
3782        Stmt::Push { value, collection } => {
3783            collect_length_syms_from_expr(value, out);
3784            collect_length_syms_from_expr(collection, out);
3785        }
3786        Stmt::SetIndex { collection, index, value } => {
3787            collect_length_syms_from_expr(collection, out);
3788            collect_length_syms_from_expr(index, out);
3789            collect_length_syms_from_expr(value, out);
3790        }
3791        Stmt::If { cond, then_block, else_block } => {
3792            collect_length_syms_from_expr(cond, out);
3793            collect_length_syms_from_stmts(then_block, out);
3794            if let Some(else_stmts) = else_block {
3795                collect_length_syms_from_stmts(else_stmts, out);
3796            }
3797        }
3798        Stmt::While { cond, body, .. } => {
3799            collect_length_syms_from_expr(cond, out);
3800            collect_length_syms_from_stmts(body, out);
3801        }
3802        Stmt::Repeat { body, .. } => {
3803            collect_length_syms_from_stmts(body, out);
3804        }
3805        Stmt::Return { value } => {
3806            if let Some(v) = value {
3807                collect_length_syms_from_expr(v, out);
3808            }
3809        }
3810        Stmt::Call { args, .. } => {
3811            for arg in args.iter() {
3812                collect_length_syms_from_expr(arg, out);
3813            }
3814        }
3815        _ => {}
3816    }
3817}
3818
3819/// Check if a type string represents a Copy type (no .clone() needed).
3820/// Delegates to `LogosType::is_copy()` — single source of truth.
3821pub(crate) fn is_copy_type(ty: &str) -> bool {
3822    crate::analysis::types::LogosType::from_rust_type_str(ty).is_copy()
3823}
3824
3825/// Wrap an `If`/`While` condition in `logos_truthy` unless it's statically
3826/// Bool — `If xs:` on a Seq tests emptiness, `If 0.0:` is false, exactly the
3827/// interpreter's truthiness. Bool conditions emit untouched (hot paths pay
3828/// nothing); an imprecisely-inferred Bool still works (`Truthy` covers bool).
3829fn truthy_cond_wrap(
3830    cond: &Expr,
3831    cond_str: String,
3832    interner: &Interner,
3833    variable_types: &HashMap<Symbol, String>,
3834) -> String {
3835    if matches!(
3836        super::types::infer_logos_type(cond, interner, variable_types),
3837        crate::analysis::types::LogosType::Bool
3838    ) {
3839        cond_str
3840    } else {
3841        format!("logos_truthy(&({}))", cond_str)
3842    }
3843}
3844
3845/// Check if a Vec<T> type has a Copy element type.
3846/// Delegates to `LogosType::element_type().is_copy()` — single source of truth.
3847pub(crate) fn has_copy_element_type(vec_type: &str) -> bool {
3848    crate::analysis::types::LogosType::from_rust_type_str(vec_type)
3849        .element_type()
3850        .map_or(false, |e| e.is_copy())
3851}
3852
3853/// Check if a HashMap<K, V> type has a Copy value type.
3854/// Delegates to `LogosType::value_type().is_copy()` — single source of truth.
3855pub(crate) fn has_copy_value_type(map_type: &str) -> bool {
3856    crate::analysis::types::LogosType::from_rust_type_str(map_type)
3857        .value_type()
3858        .map_or(false, |v| v.is_copy())
3859}
3860
3861/// Detect commutative reduction patterns in Repeat loops and emit par_iter() code.
3862///
3863/// Pattern: `Repeat for x in coll: Set acc = acc + expr(x)`
3864/// Emits:
3865/// ```text
3866/// if coll.len() >= 10000 {
3867///     acc += coll.par_iter().copied().map(|x| expr).sum::<i64>();
3868/// } else {
3869///     for x in coll.iter().copied() { acc = acc + expr; }
3870/// }
3871/// ```
3872fn try_emit_parallel_reduction<'a>(
3873    var_sym: Symbol,
3874    pattern_str: &str,
3875    iter_str: &str,
3876    iterable: &'a Expr<'a>,
3877    body: &'a [Stmt<'a>],
3878    interner: &Interner,
3879    indent: usize,
3880    ctx: &RefinementContext<'a>,
3881    synced_vars: &HashSet<Symbol>,
3882    async_functions: &HashSet<Symbol>,
3883) -> Option<String> {
3884    // Body must be exactly 1 statement: Set acc = acc OP expr
3885    if body.len() != 1 { return None; }
3886
3887    let (acc_sym, op, increment_expr) = match &body[0] {
3888        Stmt::Set { target, value } => {
3889            if let Expr::BinaryOp { op, left, right } = value {
3890                match op {
3891                    BinaryOpKind::Add => {
3892                        // acc = acc + expr  OR  acc = expr + acc
3893                        if let Expr::Identifier(lhs) = left {
3894                            if *lhs == *target {
3895                                Some((*target, BinaryOpKind::Add, *right))
3896                            } else {
3897                                None
3898                            }
3899                        } else if let Expr::Identifier(rhs) = right {
3900                            if *rhs == *target {
3901                                Some((*target, BinaryOpKind::Add, *left))
3902                            } else {
3903                                None
3904                            }
3905                        } else {
3906                            None
3907                        }
3908                    }
3909                    _ => None,
3910                }
3911            } else {
3912                None
3913            }
3914        }
3915        _ => None,
3916    }?;
3917
3918    // The increment expression must only involve the loop variable and literals
3919    if !expr_is_pure_of(increment_expr, var_sym) {
3920        return None;
3921    }
3922
3923    // The collection must be a typed Vec (for .par_iter().copied())
3924    let is_vec_i64 = if let Expr::Identifier(coll_sym) = iterable {
3925        ctx.get_variable_types().get(coll_sym)
3926            .map(|t| {
3927                let t = t.split("|__hl:").next().unwrap_or(t.as_str());
3928                (t.starts_with("LogosSeq<") || t.starts_with("Vec<") || t.starts_with("&[")) && has_copy_element_type(t)
3929            })
3930            .unwrap_or(false)
3931    } else {
3932        false
3933    };
3934
3935    if !is_vec_i64 { return None; }
3936
3937    let indent_str = "    ".repeat(indent);
3938    let acc_name = interner.resolve(acc_sym);
3939
3940    // The parallel reduction's `.sum::<T>()` must match the accumulator's type,
3941    // not a hardcoded i64 (a float reduction needs `f64`). Decline the
3942    // optimization for any non-numeric accumulator so we never emit a sum that
3943    // fails to type-check.
3944    let acc_ty = ctx
3945        .get_variable_types()
3946        .get(&acc_sym)
3947        .map(|s| s.split("|__hl:").next().unwrap_or(s.as_str()))
3948        .unwrap_or("i64");
3949    let sum_ty = match acc_ty {
3950        "i64" | "f64" | "u64" | "i32" | "u32" | "usize" | "isize" => acc_ty,
3951        _ => return None,
3952    };
3953
3954    // Generate the increment expression as Rust code
3955    let incr_code = codegen_expr_with_async(
3956        increment_expr, interner, synced_vars, async_functions,
3957        ctx.get_variable_types(),
3958    );
3959
3960    // Determine if we need a .map() or can use .sum() directly
3961    let needs_map = !matches!(increment_expr, Expr::Identifier(s) if *s == var_sym);
3962
3963    let mut out = String::new();
3964
3965    // Emit parallel reduction with runtime threshold
3966    // LogosSeq needs .borrow() to access the inner Vec for .par_iter()/.iter()
3967    // &[T] and Vec<T> can be used directly without .borrow()
3968    let (borrow_expr, len_expr) = if let Expr::Identifier(coll_sym) = iterable {
3969        let ty = ctx.get_variable_types().get(coll_sym).map(|s| s.split("|__hl:").next().unwrap_or(s.as_str()));
3970        if matches!(ty, Some(t) if t.starts_with("LogosSeq")) {
3971            (format!("{}.borrow()", iter_str), format!("{}.len()", iter_str))
3972        } else {
3973            (iter_str.to_string(), format!("{}.len()", iter_str))
3974        }
3975    } else {
3976        (format!("{}.borrow()", iter_str), format!("{}.len()", iter_str))
3977    };
3978    writeln!(out, "{}if {} >= 10000 {{", indent_str, len_expr).unwrap();
3979    writeln!(out, "{}    use rayon::prelude::*;", indent_str).unwrap();
3980    writeln!(out, "{}    let __par_ref = {};", indent_str, borrow_expr).unwrap();
3981    if needs_map {
3982        writeln!(out, "{}    {} += __par_ref.par_iter().copied().map(|{}| {}).sum::<{}>();",
3983            indent_str, acc_name, pattern_str, incr_code, sum_ty).unwrap();
3984    } else {
3985        writeln!(out, "{}    {} += __par_ref.par_iter().copied().sum::<{}>();",
3986            indent_str, acc_name, sum_ty).unwrap();
3987    }
3988    writeln!(out, "{}}} else {{", indent_str).unwrap();
3989    writeln!(out, "{}    for {} in {}.to_vec() {{", indent_str, pattern_str, iter_str).unwrap();
3990
3991    match op {
3992        BinaryOpKind::Add => {
3993            writeln!(out, "{}        {} += {};", indent_str, acc_name, incr_code).unwrap();
3994        }
3995        _ => {
3996            writeln!(out, "{}        {} = {} {:?} {};", indent_str, acc_name, acc_name, op, incr_code).unwrap();
3997        }
3998    }
3999    writeln!(out, "{}    }}", indent_str).unwrap();
4000    writeln!(out, "{}}}", indent_str).unwrap();
4001
4002    Some(out)
4003}
4004
4005/// Check if an expression only involves the given symbol and literals (no side effects).
4006fn expr_is_pure_of(expr: &Expr, allowed_sym: Symbol) -> bool {
4007    match expr {
4008        Expr::Identifier(s) => *s == allowed_sym,
4009        Expr::Literal(_) => true,
4010        Expr::BinaryOp { left, right, .. } => {
4011            expr_is_pure_of(left, allowed_sym) && expr_is_pure_of(right, allowed_sym)
4012        }
4013        Expr::Not { operand } => expr_is_pure_of(operand, allowed_sym),
4014        _ => false,
4015    }
4016}
4017