Commit Graph

6 Commits

Author SHA1 Message Date
agra
f1d298764f feat: pointee($P: Type) -> Type comptime reflection builtin
Project a pointer type to its target: `pointee(*X)` -> `X`. The one reflection
primitive missing for the `race` result synthesis (`*Task(A)` -> `A` via
`field_type(pointee(*Task(A)), 0)`) — reflection could read aggregate fields but
was blind to a pointer's target type.

Mirrors the `field_type` builtin: declared `#builtin` in std/core.sx, resolved as
a lower-time type-call fold in resolveTypeCallWithBindings (src/ir/lower/generic.zig)
so it composes in any type-arg slot. `.pointer` -> pointee, `.many_pointer` ->
element; a non-pointer arg is a loud diagnostic + `.unresolved` sentinel (no silent
fallback). Adversarially reviewed (SHIP). Locked by
examples/comptime/0647-comptime-pointee-reflection.sx. Suite green (819/0).

PLAN-RACE step 1 of 6.
2026-06-26 12:47:02 +03:00
agra
8ac6c573e8 fix: comptime field reflection on tuples/arrays/vectors (issue 0195)
`field_count` / `field_name` were broken on every non-struct/enum aggregate:
`field_count(Tuple(i64, bool))` silently returned 0 (a missing `.tuple` arm in
the count switches), and `field_name(tuple/array/vector, i)` SEGFAULTED — the
LLVM backend built a zero-length `[0 x string]` name array for those kinds while
sizing the runtime GEP at the (often non-zero) member count, so the indexed load
ran past the array.

Root cause was three+ parallel switches that each had to know how to count an
aggregate's members, and disagreed: `field_count` lowering and `memberCount` had
struct/union/tagged_union/enum/array/vector but no `.tuple`; the backend's
`field_name_get` build + GEP sizing had neither `.tuple` nor `.array`/`.vector`.

Fix:
- add the `.tuple` arm to `field_count` lowering (src/ir/lower/call.zig) and
  `TypeTable.memberCount` (src/ir/types.zig; this also backs the COMPILER-API
  `type_field_count` VM reader).
- unify the LLVM backend onto the single source of truth: both
  `getOrBuildFieldNameArray` (reflection.zig) and `emitFieldNameGet`'s GEP sizing
  (ops.zig) now derive from `memberCount` / `memberName`, so the name-array
  length and the GEP array type can never diverge again — for any kind. A member
  with no name (positional-tuple / array / vector element) reflects as "" (one
  slot per member, always in-bounds); named-tuple elements recover their labels.

The array/vector clone was surfaced by adversarial review of the tuple-only fix.

Regression: examples/comptime/0646-comptime-field-reflect-tuple-array.sx exercises
field_count/field_name/field_type over struct, enum, positional + named tuple,
array, and vector. Full suite green (818/0). Unblocks the `race` synthesis, which
must reflect a named tuple's labels + element types.
2026-06-26 12:28:09 +03:00
agra
6c89a0aa3e fix: body-local #run of an unbridged shape fails loudly instead of silent garbage (issue 0182)
The body-local #run fold in emitCall was effectively dead (gated on
args.len==0, but the __ct comptime wrapper always carries the implicit
*Context arg), so every body-local #run fell through to a RUNTIME call:
bridgeable shapes lucked into the right value; an unbridgeable shape
(e.g. [2][]i64) ran over --- storage -> garbage, exit 0, no diagnostic.

Fold any is_comptime callee (gated !enclosing.is_comptime so nested
metatype calls in a comptime wrapper's dead body aren't folded). On a
tryEval bail, distinguish a BRIDGE bail (result can't regToValue-
materialize -> error: comptime init of 'X' failed: <reason> +
comptime_failed, build fails, symmetric with the global #run path) from
an EXECUTION bail (VM can't run the body, e.g. NaN/extern -> runtime
fallthrough, preserving types/0150), via comptime_vm.last_bail_was_bridge
(reset at tryEval entry, set only at regToValue). The const name is
threaded onto the wrapper (comptime_display_name) so the diagnostic reads
the source name, not __ct_N.

Regressions: diagnostics/1204 (negative), comptime/0645 (positive).
Verified by 3 adversarial reviews, suite 801/0.
2026-06-23 19:29:11 +03:00
agra
fa7c07faf8 fix: comptime reg->value bridge for array-in-aggregate + clean abort on comptime-init failure (issue 0167)
(C) regToValue (comptime_vm.zig) gained no array arm, so a #run returning
an aggregate containing an array bailed 'reg->value: aggregate shape not
bridged yet'. Add an .array arm: read N elements at stride
typeSizeBytes(elem) from the array address, bridge each recursively via
regToValue -> an .aggregate Value (serializeAggregateValue already emits
arrays). Composes with struct fields, nested arrays, array-of-structs,
and the ?Arr optional payload; unbridgeable elements bail loudly.

(E) A global failing #run proceeded into LLVM emission and panicked
'unresolved type reached LLVM emission' when the unresolved const was
used. Add 'if (self.comptime_failed) return;' in emit() after Pass 0 so
it aborts cleanly (exit 1, the comptime diagnostic) across run/ir/build.

Regression: examples/comptime/0644-comptime-run-array-aggregate.sx.
Verified by 3 adversarial reviews, suite 793/0. Filed separate bugs found
during review: 0181 (optional-chain ?. to array field + index panics),
0182 (body-local #run unbridged silently miscompiles).
2026-06-23 11:34:22 +03:00
agra
7c21f84151 fix: comptime VM reg→value bridge for optional results (issue 0162)
Add an .optional arm to regToValue in comptime_vm.zig: read the
has_value flag at offset sizeof(child), bridge the payload recursively
into a { payload, i1=true } aggregate when set, yield .null_val (zero
{T,i1}) when clear or the bare null sentinel. Matching serialize arm in
serializeAggregateValue (emit_llvm.zig). Pointer/?Closure/?Protocol-child
optionals and array-payload aggregates bail loudly, not silently.

Regression: examples/comptime/0643-comptime-run-optional-aggregate.sx
(present ?T, present ?i64, null ?i64). Verified by 3 adversarial reviews.
2026-06-22 19:42:41 +03:00
agra
66bdc70bf1 test: group examples into per-category folders
Move examples/*.sx and their expected/ snapshots into per-category
subfolders (examples/<category>/...). Folder = leading filename token,
with ffi-objc/ffi-jni kept whole; filenames are unchanged. The corpus
runner and LSP sweep now discover each category's expected/ dir, while
issues/ stays flat. Example 1058's repo-root-relative companion import
is made file-relative. Path strings embedded in 164 snapshots were
regenerated (path-only changes). Test-layout docs in CLAUDE.md updated.
2026-06-21 14:41:34 +03:00