Follow-ups identified while auditing #5462 (squash-merged into `codex/type-lowering-runtime-20260616` as 4d8df5a). Neither blocks the feature branch, but both should be resolved before this work is promoted to `main`.
1. U32 packed-loop store is a hard-error landmine
`lower_packed_numeric_loop_store_value` does `bail!("packed-u32 loop stores are not implemented")` (`crates/perry-codegen/src/expr/index_set.rs:311`).
Currently unreachable — the U32 `PackedNumericLoopKind` only arises from read-only loops (`supported_packed_numeric_loop_store_kind` in `stmt/loops.rs:661` only ever returns `I32` or `F64`), so no `IndexSet` triggers the U32 arm. But a `bail!` here propagates as a whole-compile failure rather than a graceful fallback. If a future change ever routes a U32 store through this path, it will hard-error instead of degrading to the dynamic path.
Fix: return `None` / fall back to the runtime-keyed store instead of `bail!`.
2. Confirm Int32[] / PerryU32 fast/slow-path wrapping consistency
The new `expr_is_i32_shaped` classifies `>>>` (UShr) as `PackedI32` (`collectors/hir_facts.rs`). The i32 store/load fast paths use signed `sitofp`/`fptosi`, so a uint32 like `3_000_000_000` round-trips as `-1294967296`.
This is contained for plain `number[]` (both the store path in `stmt/loops.rs:661` and the load path at `loops.rs:556` are gated on `local_is_int32_array` — declared `Int32` element type — so `number[]` always takes the F64 path and stores the full value). For an explicitly-declared `Int32[]`, signed wrap is the correct Int32Array semantics.
Action: verify Perry's `Int32[]` and `PerryU32` slow paths wrap identically to these new fast paths, so fast/slow stay observably consistent. Add a regression test pinning the round-trip value for a `>>>`-produced > i32::MAX element in a declared `Int32[]`.
Source: audit of #5462. Both are minor/low-severity; the evidence gate and 185 codegen regression tests landed in that PR are solid and should remain the bar for the main-bound PR.
Follow-ups identified while auditing #5462 (squash-merged into `codex/type-lowering-runtime-20260616` as 4d8df5a). Neither blocks the feature branch, but both should be resolved before this work is promoted to `main`.
1. U32 packed-loop store is a hard-error landmine
`lower_packed_numeric_loop_store_value` does `bail!("packed-u32 loop stores are not implemented")` (`crates/perry-codegen/src/expr/index_set.rs:311`).
Currently unreachable — the U32 `PackedNumericLoopKind` only arises from read-only loops (`supported_packed_numeric_loop_store_kind` in `stmt/loops.rs:661` only ever returns `I32` or `F64`), so no `IndexSet` triggers the U32 arm. But a `bail!` here propagates as a whole-compile failure rather than a graceful fallback. If a future change ever routes a U32 store through this path, it will hard-error instead of degrading to the dynamic path.
Fix: return `None` / fall back to the runtime-keyed store instead of `bail!`.
2. Confirm Int32[] / PerryU32 fast/slow-path wrapping consistency
The new `expr_is_i32_shaped` classifies `>>>` (UShr) as `PackedI32` (`collectors/hir_facts.rs`). The i32 store/load fast paths use signed `sitofp`/`fptosi`, so a uint32 like `3_000_000_000` round-trips as `-1294967296`.
This is contained for plain `number[]` (both the store path in `stmt/loops.rs:661` and the load path at `loops.rs:556` are gated on `local_is_int32_array` — declared `Int32` element type — so `number[]` always takes the F64 path and stores the full value). For an explicitly-declared `Int32[]`, signed wrap is the correct Int32Array semantics.
Action: verify Perry's `Int32[]` and `PerryU32` slow paths wrap identically to these new fast paths, so fast/slow stay observably consistent. Add a regression test pinning the round-trip value for a `>>>`-produced > i32::MAX element in a declared `Int32[]`.
Source: audit of #5462. Both are minor/low-severity; the evidence gate and 185 codegen regression tests landed in that PR are solid and should remain the bar for the main-bound PR.