ir: dedicated TypeId.unresolved sentinel; kill inferred_type => .s64
An unannotated param resolving to a plausible .s64 was the classic silent-default trap (root of the 2.5 multi-param-closure bug). Replace it with a dedicated TypeId.unresolved at slot 0, so a zero-initialised or forgotten TypeId trips the sentinel instead of masquerading as a real type. - types.zig: TypeId.unresolved = 0 (void moves to 17); TypeInfo.unresolved; sizeOf/toLLVMType @panic on it (codegen tripwire); hash/eql/printer cover it. - type_bridge: inferred_type => .unresolved (was .s64). - resolveParamType: emit "parameter 'x' has no type annotation" for a genuinely-unannotated value param (comptime/variadic/pack params exempt -- they resolve via per-call substitution). - lowerLambda: resolve unannotated params from the target closure signature; otherwise emit "cannot infer type of lambda parameter". - CLAUDE.md: .void documented as an UNACCEPTABLE failed-type sentinel (it conflates with a real, heavily-checked type); prescribe a distinct .unresolved-style value + codegen tripwire. Snapshot churn: one .ir (ffi-objc-call-06) -- the runtime type-name table and typeof match arms renumber by the new builtin slot; program output unchanged.
This commit is contained in:
26
CLAUDE.md
26
CLAUDE.md
@@ -93,10 +93,28 @@ everything else.
|
||||
|
||||
✅ **Required:** when a lookup that *must* succeed fails, emit a
|
||||
diagnostic via `self.diagnostics.addFmt(.err, span, "...", .{...})`
|
||||
and return the most clearly-broken sentinel the calling code can
|
||||
survive (e.g. `.void`, a `Ref.none`, or via a `?T` return that forces
|
||||
the caller to handle the null). Errors must surface to the user as
|
||||
text, not as a silently-corrupted size or alignment.
|
||||
and return a **dedicated, unmistakable sentinel** — one that can never
|
||||
be confused with a legitimate result — or a `?T` return that forces the
|
||||
caller to handle the null. Errors must surface to the user as text, not
|
||||
as a silently-corrupted size or alignment.
|
||||
|
||||
❌ **`.void` is an UNACCEPTABLE sentinel for a failed *type* lookup.**
|
||||
`void` is a real, heavily-checked type (void returns, void params, "no
|
||||
value" markers), and pervasive `if (ty == .void) { skip / return-nothing }`
|
||||
checks would silently swallow the failure — trading one silent default
|
||||
(`.s64`) for another (`.void`) one layer down. The same objection rules
|
||||
out `noreturn` (diverging expressions) and any other load-bearing builtin.
|
||||
Instead, add a **distinct** `.unresolved`-style `TypeId` whose sole meaning
|
||||
is "resolution failed". A dedicated value (1) can't be mistaken for a real
|
||||
type by any downstream check, (2) makes the exhaustive `switch`es in the
|
||||
type table fail to compile until every site handles it (forcing coverage),
|
||||
and (3) can be a hard tripwire — `if (ty == .unresolved) @panic(...)` in
|
||||
codegen/emit guarantees it never silently ships. The one-time plumbing
|
||||
cost is exactly the trade this file mandates ("the field plumbing is a
|
||||
one-time cost; silent-clobber debugging is forever"). The same principle
|
||||
applies to non-type sentinels: prefer a `Ref.none`-style value that is
|
||||
distinct from every valid result, not a real one that "looks broken
|
||||
enough".
|
||||
|
||||
If you find an existing default-return in the compiler that swallows
|
||||
a lookup failure, treat it as a discovered bug — file an issue per
|
||||
|
||||
Reference in New Issue
Block a user