# 0067 — tuple literal used as a type silently accepts non-type elements > **RESOLVED** (2026-06-02). > **Root cause:** `type_bridge.resolveTupleLiteralAsType` treated a tuple literal > as a tuple TYPE and, for any element that wasn't type-shaped, emitted a > `std.debug.print` and substituted `.i64` for that field — a silent fabricated > type (the forbidden silent-fallback pattern). The stateful caller > (`Lowering.resolveTypeArg`, used by `size_of`) delegated `.tuple_literal` > straight to that path, so `size_of((i32, 1))` compiled and printed `16`. > **Fix:** > - `type_bridge.resolveTupleLiteralAsType` now returns `.unresolved` (no `.i64`, > no debug print) when any element is not type-shaped — it refuses to fabricate > a tuple. (type_bridge is stateless, so this is the binding-free backstop.) > - New stateful `Lowering.resolveTupleLiteralTypeArg` validates each element via > `type_bridge.isTypeShapedAstNode`, emits a user-facing diagnostic at the > offending element's span, and returns `.unresolved`. It is wired into BOTH > `resolveTypeArg` (size_of/align_of/…) and the `resolveTypeWithBindings` > name-fallback; type_bridge builds the tuple only after validation passes. > **Regression test:** `examples/1116-diagnostics-tuple-type-nontype-element-rejected.sx` > (exit 1 + diagnostic). Valid `(i32, i32)` still works > (`examples/0115-types-compound-type-in-expression.sx`). Suite 351/0. ## Symptom `size_of((i32, 1))` treats the tuple literal as a tuple TYPE even though `1` is not a type. The compiler prints an internal `type_bridge` debug line, then silently substitutes `.i64` for that slot and compiles successfully. Observed: ```text type_bridge: tuple literal element is not a type (tag=int_literal) — cannot use as tuple type bad tuple type size = 16 ``` Expected: a user-facing compiler diagnostic rejecting the non-type tuple element, with no fabricated tuple type and no successful run. ## Reproduction ```sx #import "modules/std.sx"; main :: () -> i32 { print("bad tuple type size = {}\n", size_of((i32, 1))); 0 } ``` Run: ```sh ./zig-out/bin/sx run .sx-tmp/probe-tuple-literal-type-fallback.sx ``` The repro is standalone; the inline source above is sufficient to recreate the scratch file under `.sx-tmp/`. ## Investigation prompt Fix issue 0067: tuple literals reinterpreted as tuple types must reject non-type elements instead of silently fabricating `.i64` fields. Suspected area: - `src/ir/type_bridge.zig`, `resolveTupleLiteralAsType` - The current non-type branch does `std.debug.print(...)` and `field_ids.append(alloc, .i64)`, which violates the compiler fallback rules. - Related callers: `type_bridge.resolveAstType` for `.tuple_literal`, and `Lowering.resolveTypeWithBindings` fallback paths that reach `type_bridge`. Likely fix: - Replace the `.i64` substitution with a real diagnostic path and an unmistakable failure result (`.unresolved`, or a nullable/result return that forces callers to handle the failure). - Make the diagnostic user-facing via the lowering diagnostics plumbing, not `std.debug.print`. - Preserve the valid behavior pinned by `examples/0115-types-compound-type-in-expression.sx`, where `(i32, i32)` in a type-demanding site resolves as a tuple type. Verification: - Add a focused diagnostics example in the `11xx` block for `size_of((i32, 1))` expecting exit 1 and a clear diagnostic. - Run: ```sh zig build zig build test bash tests/run_examples.sh ``` Expected result: the new invalid tuple-type repro fails with a diagnostic, the valid `0115` tuple-type example still passes, and the full suite remains green.