fix: diagnose ?(?T) tuple-payload mismatch instead of malformed IR (issue 0165)

In type position (T) is a 1-tuple (specs.md:843), so ?(?i64) is
optional(tuple(?i64)); assigning a bare ?i64 had coerceToType classify
.none and pass the value through, then optionalWrap built a corrupt
insertvalue that aborted the LLVM verifier. After coercing toward an
optional's child, verify the coerced type equals the child type
(stmt.zig decl-init + coerce.zig .optional_wrap); on mismatch emit a
located diagnostic (tuple-specific note only when the child is a tuple).
formatTypeName now renders tuples as (x: i64, y: i64).

Regressions: optionals/0911 (nested optional via alias, round-trip),
diagnostics/1195 (the mismatch diagnostic). Updated diagnostics/1101 +
protocols/0414 goldens for the improved tuple type-name rendering.
Verified by 3 adversarial reviews. Filed adjacent bug 0171 (?any child
not canonicalized).
This commit is contained in:
agra
2026-06-22 21:54:12 +03:00
parent 3e8d003e3d
commit 0bc8005b99
16 changed files with 198 additions and 4 deletions

View File

@@ -0,0 +1,29 @@
// Nested optional `?(?i64)` written via a type alias — `Opt :: ?i64; ?Opt`.
// The outer optional's payload is the inner optional, so the layout is the
// well-formed double-wrap `{ {i64,i1}, i1 }`. Assigning an inner `?i64`,
// unwrapping the outer to recover the inner `?i64`, and unwrapping that all
// round-trip cleanly.
//
// Regression (issue 0165): the type-table interning always produced the
// correct `{ {i64,i1}, i1 }` for a genuine nested optional — this locks that in.
#import "modules/std.sx";
Opt :: ?i64;
main :: () {
inner : ?i64 = 5;
outer : ?Opt = inner; // ?(?i64) — payload is the inner optional
print("outer present: {}\n", outer != null);
mid := outer!; // unwrap outer -> ?i64
print("mid present: {}\n", mid != null);
print("value: {}\n", mid!); // unwrap inner -> 5
// null-coalesce through the recovered inner optional
print("coalesced: {}\n", mid ?? 0);
// a none outer
empty : ?Opt = null;
print("empty present: {}\n", empty != null);
}

View File

@@ -0,0 +1 @@
0

View File

@@ -0,0 +1,5 @@
outer present: true
mid present: true
value: 5
coalesced: 5
empty present: false