# 0112 — out-of-range int literal silently wraps into a narrower annotated target **Symptom.** An integer literal that does not fit its explicitly-annotated integer target truncates with no diagnostic: `x : s8 = 300;` binds 44, `y : u8 = 256;` binds 0. Expected: a compile-time error (the value is known exactly at compile time; this is the integer analogue of the float→int narrowing rule, which errors on non-exact `y : s64 = 1.5`). Split from issue 0111 (whose fix removed the *implicit* narrowing — an unannotated `x := 0` no longer adopts the fn return type — but the explicit annotation path keeps wrapping). ## Reproduction ```sx #import "modules/std.sx"; main :: () { x : s8 = 300; print("x: {}\n", x); y : u8 = 256; print("y: {}\n", y); } ``` - **Observed** (current master): prints `x: 44` / `y: 0`, exit 0, no diagnostic. - **Expected**: compile error per literal, e.g. `integer literal 300 does not fit in s8 (range -128..127)`, and the analog for `256` / `u8 (range 0..255)`. Repro co-located: `issues/0112-int-literal-out-of-range-silent-wrap.sx` (unpinned until fixed). ## Root cause (suspected area) `src/ir/lower/expr.zig` `.int_literal` arm (~1499): when `target_type` is an integer type, it emits `constInt(lit.value, tt)` with no fits-check — the value truncates at LLVM emission width. The annotated-decl path (`lowerVarDecl` with `type_annotation`, `src/ir/lower/stmt.zig` ~255) sets `target_type` to the annotation before lowering the initializer, so every annotated narrow decl funnels through this arm. Assignments to narrow lvalues (`b = 300` where `b: s8`) reach the same arm via `lowerAssignment`'s LHS-derived target and likely need the same check. ## Investigation prompt (paste into a fresh session) > Fix issue 0112: an int literal that does not fit its integer target type > silently wraps. In the `.int_literal` arm of `lowerExpr` > (`src/ir/lower/expr.zig` ~1499), before adopting an integer `target_type`, > range-check `lit.value` against the target's signedness/width (the type > table knows both; mirror the bounds logic used by > `TypeResolver.integerLimitFor`). On overflow emit a diagnostic via > `self.diagnostics.addFmt(.err, node.span, ...)` naming the literal, the > type, and its range — do NOT silently fall back to s64 (REJECTED PATTERNS: > no silent fallback defaults); still return a `constInt` of the target type > so lowering continues to surface further errors. Audit sibling literal > sinks that bypass this arm (comptime folds, `lowerStructConstant`, global > initializers) for the same check. > > Verify: `issues/0112-int-literal-out-of-range-silent-wrap.sx` errors with > two diagnostics (s8/300, u8/256); boundary values still compile > (`x : s8 = -128` / `127`, `y : u8 = 0` / `255`, `m : u64` large literals). > `zig build && zig build test && bash tests/run_examples.sh` — any example > that relied on silent wrapping must be reviewed individually. Promote the > repro per the resolution flow (likely `examples/11xx-diagnostics-...`).