Commit Graph

10 Commits

Author SHA1 Message Date
agra
493469fd74 fix: lambda inferred return type from a block body's early returns (issue 0187)
A `:=`-bound closure with no explicit `-> T` and a BLOCK body inferred its
return type via inferExprType(lam.body), which yields the last statement's
type. A block whose value comes only from early `return`s ends in a return
statement (void/noreturn), so the closure was built with a void return while
the body returned i64 — the call site then fed `i64 undef` and LLVM
verification failed. (A block whose tail referenced a block-local hit the
sibling failure: inferExprType returned .unresolved → an LLVM panic.)

Infer the return type exactly as a named fn does (resolveReturnType in
lower.zig): an arrow body `(params) => expr` uses the expression type; a block
body `(params) { stmts }` takes the first explicit `return <val>` type via
findReturnValueType, else void (the block tail is a discarded statement unless
an explicit `-> R` makes it the value). Regression test:
examples/closures/0313-closure-inferred-return-early.sx.
2026-06-26 09:28:29 +03:00
agra
468461becc fix: gate implicit optional unwrap on flow narrowing (issue 0179)
Optional (?T) operands were implicitly unwrapped without proof of
presence, silently miscompiling a NULL ?T to garbage. Unwraps in
binary ops and other expression positions are now gated on flow
narrowing: a ?T value is only auto-unwrapped where control flow has
established it is non-null (the narrowed_refs set). Outside a narrowed
region, an implicit unwrap is rejected rather than producing garbage.

Touches the lowering pipeline (lower.zig + lower/{call,closure,coerce,
comptime,control_flow,expr,ffi,generic,pack,stmt}.zig). Adds optionals
examples 0919-0923 and closures example 0312 covering flow narrowing,
binop narrowing, no-implicit-unwrap rejection, and no closure leak of
narrowed state. Updates specs.md and readme.md.
2026-06-25 13:57:48 +03:00
agra
cd5b958d19 comptime compiler-API: Phase 1 foundation + Phase 2.1 weld plan
Introduce the welded comptime `compiler` library (`#library "compiler"` +
`abi(.zig) extern compiler`), per design/comptime-compiler-api.md, and unify
`callconv(...)` into the new `abi(...)` annotation.

abi(...) replaces callconv(...):
- New ABI enum { default, c, zig, pure }; `abi(.c|.zig|.pure)` parses in the
  postfix slot before extern/export (and standalone). `kw_callconv` -> `kw_abi`.
- Migrated 52 sx files, the call-convention-mismatch diagnostic, and docs
  (readme/specs) from `callconv(.c)` to `abi(.c)`.

Phase 1 — welded compiler library (parse -> registry -> validation -> bridge):
- `abi(.zig) extern compiler` parses on fn decls (carries abi/extern_lib) and
  struct decls (StructDecl.abi/extern_lib).
- `#library "compiler"` is the comptime-only internal surface — never dlopen'd.
- src/ir/compiler_lib.zig: the binding registry (the safety boundary). `Field`
  welded to StructInfo.Field with layout baked from the real Zig type
  (@offsetOf/@sizeOf); `findType`/`findFn`. Welded structs are layout-validated
  at registration (field set + total size) as a header checked against the impl.
- Host-call bridge: a `fn abi(.zig) extern compiler` dispatches under the
  comptime interp to its registered Zig handler (intern/text_of round-trip),
  never dlsym. IR Function.compiler_welded; validated in declareFunction.
- Comptime-only enforcement: a runtime call to a welded fn is a clean
  build-gating error (emitCall), not an undefined-symbol link failure.

Phase 2.1 — byte-layout weld foundation:
- Decision: full byte-layout weld (sx struct laid out byte-identically to the
  bound Zig type). Registered StructInfo (first non-natural / Zig-reordered
  layout). `computeWeldPlan` — pure offset-ordered element plan + padding +
  sx-field->LLVM-element remap; unit-tested. Emit/interp wiring is the next
  sub-step (2.2+, see current/CHECKPOINT-COMPILER-API.md).

Examples: 0625/0626 (welded struct + fn round-trip), 1183/1184/1185
(layout-mismatch, unexported-fn, runtime-call diagnostics).
2026-06-17 13:31:11 +03:00
agra
dc51c4b5bf refactor(ffi-linkage): Phase 9.3-src — purge 'foreign' from src/ comments + a user-facing diagnostic
Reword every 'foreign' comment to the extern/runtime-class vocabulary matching the
renamed identifiers (foreign call→extern call, foreign class→runtime class, foreign
path→runtime path, the #foreign-literal comment mentions → extern, etc.). Also fixes
two USER-FACING issues: the 'expected … #foreign … after type annotation' parse error
no longer advertises the removed keyword, and the Android 'no #jni_main' help
diagnostic now shows '#jni_class(…) extern' instead of the rejected '#foreign
#jni_class'. Removed the now-dead prefix-#foreign-vs-postfix conflict branch in
parseRuntimeClassDecl (the caller rejects #foreign before it runs).

src/ now contains 'foreign' ONLY in the hash_foreign token machinery + its 4
rejection messages — the deprecation mechanism (kept per the 9.0 recommendation; the
message MUST name #foreign to guide migration). Snapshot-neutral; suite green
(646 corpus / 444 unit, 0 failed).
2026-06-15 09:35:00 +03:00
agra
b838f6383f refactor(ffi-linkage): Phase 9.1a — rename collision-free linkage identifiers
Mechanical src/ rename of the linkage-family identifiers whose extern_* target is
collision-free: callForeign→callExtern, marshalForeignArg→marshalExternArg,
dedupeForeignSymbol→dedupeExternSymbol, foreign_name_map→extern_name_map,
is_foreign_c_api→is_extern_c_api. Snapshot-neutral (internal only); suite green
(646 corpus / 444 unit, 0 failed).

Deferred (need per-site analysis — target name already exists): is_foreign↔is_extern
(38 existing), foreign_lib/foreign_name↔extern_lib/extern_name (15/16 existing),
foreign_expr (still built by c_import.zig auto-synthesis). Runtime-class family
(ForeignClassDecl etc. → Runtime*, Decision 5) is Phase 9.2.
2026-06-15 08:39:59 +03:00
agra
d8076b9333 lang: rename signed integer types sN -> iN
Surface rename of the signed integer family: s1..s64 become i1..i64
(u1..u64, usize, isize unchanged). 'string' keeps the s-prefix arm in
name classification; width parsing moves to the i-prefix arm next to
isize.

Internal TypeId tags follow the surface (.s8/.s16/.s32/.s64 ->
.i8/.i16/.i32/.i64), as do mono-key mangle fragments (ptr_i64,
tu_i64_bool) and all display/diagnostic formatting (i{d}).

Migrated in the same sweep: stdlib + examples + issue repros + FFI C
companions (shared symbol names like ffi_id_i64), expected
stdout/stderr/ir snapshots, specs.md, readme.md, CLAUDE.md/AGENTS.md,
implementation_plan.md, docs/, issue writeups. Vendored stb_image and
historical flow state left untouched.

zig build test: 426/426; examples suite: 595/595.
2026-06-12 09:31:53 +03:00
agra
116af2359e lang: multi-iterable for loops — drop ':', add '..=', open ranges, arrow bodies
The for header is now a comma-separated list of iterables with a
positional capture group and no ':' separator:

    for xs (x) { }                    // collection
    for 0..n (i) { }                  // range (end exclusive)
    for 1..=5 (a) { }                 // ..= inclusive end
    for xs, 0.. (x, i) { }            // index idiom (replaces (x, i))
    for xs, ys (x, y) { }             // parallel (zip) iteration
    for xs (x) => sum += x;           // arrow body (full statement)

First-iterable-wins: the first iterable's length drives the loop and
must be bounded; the other positions follow by their own cursors (a
non-first range's end is not consulted or evaluated; a shorter
non-first collection is read past its length on mismatch). The old
single-iterable index capture is replaced by the trailing open range.

Capture/call disambiguation is positional: the paren group immediately
before '{' or '=>' is the capture, every earlier top-level group is a
call. 'for zip(a, b) (x, y)' calls zip; 'for f(n) { }' reads (n) as
the capture and errors with a parenthesize/add-capture hint. The old
':' form errors with a migration hint.

Lowering is unified across forms: one cursor slot per position (ranges
start at their start, collections at 0), all advanced together, the
first position's bound terminating. inline for keeps the single
bounded comptime range.

Migrated the full corpus (examples, library modules, issue repros,
in-source test strings). New coverage: examples/0050 (the full feature
surface) and examples/1149-1155 (seven diagnostic faces). specs.md For
Loop section + grammar rewritten; readme teaser updated.
2026-06-10 20:30:55 +03:00
agra
2b8041a828 cleanup: drop resolved-issue citations from src comments
Sweep all src/**.zig comments that cite resolved issues (issue NNNN /
fix-NNNN / KB-N): the invariant or mechanism each comment states is
kept; the historical citation is dropped, per the no-conclusion-comments
rule. Pure-history parentheticals are removed outright. References to
the 16 still-open issues (0030, 0041-0056) are untouched, as are test
NAMES carrying regression provenance (matching the sanctioned
"Regression (issue NNNN)" example-header convention).

Also removes the issues/0019-import-non-transitive-c-scope/ fixture dir
— the issue is superseded and its behavior is covered by
examples/0706-modules-import-non-transitive.sx (the .md writeup stays).
issues/0030's repro .sx stays: that issue is an open feature request.

Gate: zig build OK; zig build test 426/426; run_examples 541/0; zero
expected/ snapshot churn.
2026-06-10 16:34:17 +03:00
agra
82500931ce cleanup(B-review): fix stale section banners, merge alias block, prune imports
Review follow-up to the ARCH-B split (comment/import hygiene only, no
code changes):

- Section banners that travelled to the wrong file with the B1-B8 cuts
  are reworded to describe the section that actually follows (e.g.
  stmt.zig's trailing "Expression lowering", expr.zig's "Control flow"
  before lowerChainedComparison) or deleted where nothing follows
  (4 trailing-at-EOF banners). ffi.zig's facade note no longer claims
  the IMP builders "stay here" (they live in lower/objc_class.zig);
  protocol.zig's namespace-lookup banner now points at
  pack.zig:resolvePackProjection for the orchestrator.
- lower.zig's two lower/expr.zig alias blocks (B8.1 + B8.2 appends)
  merged into one.
- 448 unused header decls pruned from the 15 lower/*.zig files (each
  had inherited lower.zig's full import block; pruned to fixpoint so
  cascading type-extraction consts went too).

Gate: zig build OK; zig build test 426/426; run_examples 541/0; zero
expected/ snapshot churn.
2026-06-10 16:09:24 +03:00
agra
89b3789973 refactor(B8.3): move lambdas + captures to lower/closure.zig
Verbatim relocation of the 5-method closure cluster (lowerLambda,
bare-fn trampoline, closure-to-bare-fn adapter, capture collection, env
sizing) into src/ir/lower/closure.zig. 5 aliases on Lowering keep all
call sites unchanged. Method pub-flip: typeAlignBytes.

Resolves the B7.1 flag: CaptureInfo relocates from lower/call.zig to
lower/closure.zig (its domain home, next to collectCaptures); the
Lowering type alias is repointed so external references are unchanged.

Gate: zig build OK; zig build test 426/426; run_examples 541/0; zero
expected/ snapshot churn.
2026-06-10 14:43:04 +03:00