docs(issues): mark 17 already-fixed issues RESOLVED with verified banners
Each banner was re-verified against the current binary (repro now behaves correctly) and cites the actual fix location in current src/** plus the covering regression example. Closes the stale-but-fixed backlog: 0019, 0042-0056, 0131. No compiler change.
This commit is contained in:
@@ -1,5 +1,13 @@
|
||||
# 0019 — `#import` is non-transitive (C-function scope across files)
|
||||
|
||||
> **RESOLVED.** The `.md`'s own repro is non-runnable (relative `../modules/std.sx`
|
||||
> imports) and superseded; the scenario — A importing B does NOT transitively expose
|
||||
> a third module's top-level names — is enforced by the non-transitive `#import`
|
||||
> visibility check in `lowerCall` (src/ir/lower/call.zig:106-118, gated on
|
||||
> `isNameVisible`, defined in src/ir/lower/decl.zig:2502), with the const-reference
|
||||
> path mirrored in src/ir/lower/expr.zig. Covered by the passing regression test
|
||||
> `examples/0706-modules-import-non-transitive.sx`.
|
||||
|
||||
> **Status: superseded — kept for reference.** Relocated from the old
|
||||
> `examples/issue-0019/` fixture during the test-layout migration. The behavior
|
||||
> it probed (A imports B and C; C must NOT see B's `extern` C functions just
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
# issue-0042 — Const-decl type aliases (`MyInt :: i32;`) silently return `.i64` from `size_of` / `align_of`
|
||||
|
||||
> **RESOLVED.** Root cause: the bare-name type-arg resolver consulted only `findByName`, falling back to `.i64` (8 bytes) for const-decl aliases (`MyInt :: i32;`) recorded in the alias map — silently mis-sizing any non-8-byte alias.
|
||||
> Fix: the nominal-leaf resolver now consults the alias maps before falling back — `resolveNominalLeaf` → `selectNominalLeaf` (`src/ir/lower/decl.zig`) returns `.resolved` with the alias's real `TypeId` from `program_index.type_aliases_by_source` (own-author const_decl branch ~L1820 / unwired branch ~L1801); aliases are registered via `putTypeAlias` (`decl.zig:560`).
|
||||
> The old `resolveTypeArg` `.identifier` arm in `lower.zig` is gone — the source-keyed `selectNominalLeaf` superseded it.
|
||||
> Covering regression test: `examples/0116-types-type-alias-size-align.sx` (alias, chain, and struct-name alias through `size_of`/`align_of`).
|
||||
|
||||
**FIXED.** `MyInt :: i32; size_of(MyInt)` now returns `4`
|
||||
correctly. The `resolveTypeArg` `.identifier` branch consults
|
||||
`type_alias_map` before falling through. The fix landed
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# issue-0043: lazy-lowered function bodies don't resolve runtime-class method dispatch
|
||||
|
||||
> **RESOLVED.** Root cause: chained runtime-class dispatch (`Cls.alloc().init...(x)`) collapsed the inner call's return type, so the outer `.method(...)` couldn't find the receiver's `#objc_class` declaration — and on the lazy-lower path (inside an `inline if OS == .ios` branch) the runtime-class map was unavailable.
|
||||
> Fix: the runtime-class instance/static dispatch now resolves each call's declared return type via `resolveRuntimeMethodReturnType` against the runtime_class_map (`src/ir/calls.zig`, runtime-class branches ~L244-269 / L385-398), and that map lives on the shared `ProgramIndex` (`src/ir/program_index.zig:668`) so it is equally visible to eager and lazy lowering (`lazyLowerFunction`, `src/ir/lower/decl.zig:2508`).
|
||||
> Covering regression: `examples/1306-ffi-objc-runtime-class-chained-dispatch.sx` (header cites issue 0043) exercises both `*ClassName` and `*Self` chained shapes and passes.
|
||||
|
||||
**FIXED.** The original repro
|
||||
(`sx build --target ios-sim issue-0043.sx` with a
|
||||
`UIWindow.alloc().initWithWindowScene(scene)` call inside an
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
**FIXED.** Root cause was NOT the parameter name; the original `this`
|
||||
|
||||
> **RESOLVED.** A runtime-class (`#objc_class`) UFCS call site had no entry in
|
||||
> `resolveCallParamTypes`, so per-arg `target_type` leaked the enclosing method's
|
||||
> return type (e.g. BOOL→i8), truncating `xx this` to its low byte at the receiver.
|
||||
> Fixed by adding the `runtime_class_map.get(sname)` + `findRuntimeMethodInChain`
|
||||
> path in `resolveCallParamTypes` (now `src/ir/lower/call.zig`, lines 2533-2556),
|
||||
> which threads each runtime-class method's declared param types. Regression test:
|
||||
> `examples/1321-ffi-objc-defined-class-method-self.sx`.
|
||||
rename surfaced an unrelated `target_type` leak in
|
||||
`resolveCallParamTypes`. See "Root cause + fix" below.
|
||||
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
**FIXED.** `lowerComptimeCall` now allocates a result slot when
|
||||
|
||||
> **RESOLVED.** A comptime/pack-fn with a non-void return type and a block body
|
||||
> containing `return X;` previously emitted a `ret` in the middle of the caller's
|
||||
> basic block (LLVM verifier: "Terminator found in the middle of a basic block").
|
||||
> Fixed in `lowerComptimeCall` (src/ir/lower/comptime.zig:822-869): when the body
|
||||
> has a `return`, it allocates a result slot + shared `ct.ret_done` block and sets
|
||||
> `inline_return_target`, so `lowerReturn` (src/ir/lower/stmt.zig:442) stores into
|
||||
> the slot and branches to `ret_done` instead of emitting an inline `ret`.
|
||||
> Regression test: examples/0525-packs-pack-fn-comptime-return.sx (prints "42").
|
||||
the body contains a `return` statement and reroutes
|
||||
`lowerReturn` to store into it instead of emitting `ret` into the
|
||||
caller's basic block. Regression test:
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
**FIXED.** `createComptimeFunction` now saves/restores the
|
||||
|
||||
> **RESOLVED.** A nested comptime call inside a comptime fn body that also had a `return X;` lowered the wrapper fn built by `createComptimeFunction` while it still inherited the outer caller's `inline_return_target` (and pack / comptime-param bindings), so the interp stored into a slot belonging to a different basic block — null-pointer store at `storeAtRawPtr`.
|
||||
> Fixed in `src/ir/lower/comptime.zig:createComptimeFunctionWithPrelude` (which `createComptimeFunction` delegates to): it now snapshots-and-clears `inline_return_target`, `pack_arg_nodes`, `pack_param_count`, `pack_arg_types`, `comptime_param_nodes`, `block_terminated`, `target_type`, and `func_defer_base`, restoring them via `defer` so the wrapper runs in isolation. The same protection is generalized as `Lowering.FnBodyReentry` (`src/ir/lower.zig`).
|
||||
> Face 2 (pack-fn `..$args`) was fixed incidentally when pack-fn calls moved off the inline-return path onto the mono path.
|
||||
> Covered by regression test `examples/0607-comptime-nested-comptime-return.sx`.
|
||||
outer `lowerComptimeCall`'s state — specifically
|
||||
`inline_return_target`, `pack_arg_nodes`, `pack_param_count`,
|
||||
`pack_arg_types`, `comptime_param_nodes`, `block_terminated`,
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
**FIXED** in commit `0119c9c`. Both `#run` output and the
|
||||
|
||||
> **RESOLVED.** `#run` (compile-time) `print` output landed on stderr while runtime `print` went to stdout, so separated-stream captures split user output across two fds.
|
||||
> Fixed by routing both compile-time `print` output and the phase delimiter to fd 1 via direct libc `write`: the `--- build done ---` marker now goes through `std.c.write(1, ...)` at `src/main.zig:333` (cited to issue-0047), and `#run` `out`/print output writes straight to fd 1 on the comptime VM path (see `src/ir/comptime_vm.zig:1083` and the "now-direct libc write" notes in `src/ir/emit_llvm.zig:2967`).
|
||||
> Covered by the regression test `examples/0600-comptime-run.sx`, whose expected `.stdout` carries the `#run` output, the delimiter, and runtime output together with an empty `.stderr`.
|
||||
`--- build done ---` delimiter now write to fd 1 (stdout) via
|
||||
`std.c.write` from `core.flushInterpOutput` and main.zig's
|
||||
delimiter site. Test runner uses `2>&1` so snapshots are
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# 0048 — bare `$args` slice loses `.len` (reads 0) when passed across a call
|
||||
|
||||
> **RESOLVED.** Root cause: a callee (`walk`/`describe`) lazily lowered *inside* a
|
||||
> pack-fn mono inherited the active pack's `pack_param_count`, so the
|
||||
> `<pack_name>.len` intercept in `lowerFieldAccess` constant-folded `args.len`
|
||||
> to the outer pack's arity — every shape's cross-call read returned that one
|
||||
> baked constant (originally observed as 0). Fix: `FnBodyReentry.enter` in
|
||||
> `src/ir/lower.zig` (used by `lowerFunctionBodyInto` / `lazyLowerFunction` in
|
||||
> `src/ir/lower/decl.zig`) now nulls `pack_param_count` (and the sibling
|
||||
> `pack_arg_nodes` / `pack_arg_types`) for the nested body and restores them on
|
||||
> exit. Covered by regression test `examples/0522-packs-pack-bare-args-cross-call.sx`.
|
||||
|
||||
## Symptom
|
||||
|
||||
Bare `$args` evaluated inside a pack-fn body has the correct `.len`
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# 0049 — new-form variadic `..name: []Type` defined in an imported module crashes LLVM emit
|
||||
|
||||
> **RESOLVED.** Root cause: the new-form variadic `..name: []T` had its already-sliced declared type double-wrapped to `[][]T` (helpers treated it like legacy `name: ..T` and added a slice level), so the callee's stored param shape mismatched the call-site's `[N x T]` marshalling and emitted null/undef Refs that crashed `LLVMBuildExtractValue` in `emitStrCmp`.
|
||||
> Fix: `resolveParamType` (src/ir/lower.zig:642) now returns `declared_ty` as-is when it is already a slice instead of re-wrapping, and the companion `packVariadicCallArgs` (src/ir/lower/pack.zig:298) unwraps the new-form `[]T` back to element `T` for per-element packing so both surface forms converge.
|
||||
> Covered by regression test `examples/0523-packs-new-form-variadic-cross-module.sx` (pinned, exit 0), which calls the new-form stdlib `path_join` across the import boundary.
|
||||
|
||||
## Symptom
|
||||
|
||||
A pack-fn declared with the **new** variadic syntax
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# 0050 — `monomorphizeFunction` leaks outer pack-fn state into the mono body
|
||||
|
||||
> **RESOLVED.** Root cause: `monomorphizeFunction` saved/nulled `type_bindings`/`scope`/builder state but left the outer pack-fn maps live, so a generic callee with an `args`-named param had its `args.len` constant-folded (via `lowerFieldAccess`'s `<pack>.len` intercept) to the first mono's arity and baked into the cached IR.
|
||||
> Fix: `monomorphizeFunction` in `src/ir/lower/generic.zig` now saves+nulls+defer-restores `pack_arg_nodes` / `pack_param_count` / `pack_arg_types` / `inline_return_target` (lines 51-64), mirroring the `lazyLowerFunction` isolation from issue-0048.
|
||||
> Covered by regression test `examples/0524-packs-generic-fn-pack-state-leak.sx` (probes print 0/1/2/4).
|
||||
|
||||
## Symptom
|
||||
|
||||
A generic function (one with `$T: Type` type params) called from
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
**FIXED.** Two parts, both needed for Finder/`open` to work:
|
||||
|
||||
> **RESOLVED.** A bundled macOS `.app` launched via Finder/`open` starts with
|
||||
> CWD=`/`, so CWD-relative asset loads (`read_file_bytes("assets/...")`) missed
|
||||
> and the app crashed loading fonts/textures. Fixed in `library/modules/platform/sdl3.sx`:
|
||||
> `SdlPlatform.init` now calls `sdl_chdir_to_bundle()`, which `chdir`s to
|
||||
> `SDL_GetBasePath()` only when that path lives inside a `.app` (gated on `OS == .macos`),
|
||||
> mirroring uikit.sx's iOS precedent; the `sx run` dev flow and wasm are left untouched.
|
||||
> This is a platform-library fix (no `src/**` compiler change); no standalone regression
|
||||
> test exists since it requires a bundled GUI `.app` launched via Finder.
|
||||
|
||||
1. **cwd-relative assets** — `SdlPlatform.init` now chdir's to
|
||||
`SDL_GetBasePath()` when running from inside a `.app` (sx commit
|
||||
`b31fbae`, `library/modules/platform/sdl3.sx`), mirroring uikit.sx's iOS
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
**FIXED.** `packVariadicCallArgs` ([src/ir/lower.zig](../src/ir/lower.zig))
|
||||
|
||||
> **RESOLVED.** A slice-of-protocol variadic `..xs: []P` stored each raw 8-byte
|
||||
> concrete arg into a 16-byte protocol-sized array slot, yielding garbage
|
||||
> `{ctx, vtable}` values and a Bus error on `xs[i].method()` dispatch.
|
||||
> Fixed in `packVariadicCallArgs` (`src/ir/lower/pack.zig`): it now computes
|
||||
> `elem_is_protocol` and, per arg, `buildProtocolErasure`-erases each concrete
|
||||
> value into a real protocol value before storing.
|
||||
> Regression test: `examples/0535-packs-slice-of-protocol-variadic.sx`.
|
||||
now detects a protocol element type and `xx`-erases each arg into the
|
||||
`[N]P` array via `buildProtocolErasure`, instead of storing the raw concrete
|
||||
value. Regression: [examples/202-slice-of-protocol-variadic.sx](../examples/202-slice-of-protocol-variadic.sx).
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
**FIXED** via the `xx <pack>` bridge (the preferred fix below), not by changing
|
||||
|
||||
> **RESOLVED.** Spreading a comptime pack into a `[]Any`/`[]P` parameter via `xx args` previously
|
||||
> hit the pack-as-value diagnostic ("pack has no runtime value") before `xx` was considered, so no
|
||||
> slice was ever materialized. Fixed by intercepting `xx <pack>` with a slice target in the
|
||||
> `unary_op .xx` arm of `lowerExpr` (`src/ir/lower/expr.zig`) *before* lowering the operand, calling
|
||||
> `lowerPackToSlice` (`src/ir/lower/pack.zig:167`) to box/erase each element into a runtime `[N]elem` → `[]elem`.
|
||||
> Covered by regression test `examples/0537-packs-pack-xx-to-slice.sx`.
|
||||
the `..args` spread. `xx args` with a slice target now materializes the pack
|
||||
into a runtime `[]Any`/`[]P` — see [examples/204-pack-xx-to-slice.sx](../examples/204-pack-xx-to-slice.sx).
|
||||
`lowerXX`/the unary-op arm intercepts `xx <pack>` before the pack-as-value
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
**FIXED** (`1f6e27d`, `examples/212`). Two root causes:
|
||||
|
||||
> **RESOLVED.** A generic-struct instance erased to a parameterized protocol
|
||||
> (`xx c` : `Combined__i64_i64` → `VL(i64)`) trapped at dispatch because the
|
||||
> erasure thunk's vtable slot was never bound to the monomorphized instance
|
||||
> method. Fixed by `instantiateGenericStruct` binding the template name to the
|
||||
> concrete instance + recording `struct_instance_bindings` (src/ir/lower/generic.zig:1746,1753),
|
||||
> and `createProtocolThunk` monomorphizing the generic-struct instance method
|
||||
> for those bindings (src/ir/lower/protocol.zig:createProtocolThunk, ~line 349).
|
||||
> Covered by `examples/0414-protocols-generic-struct-protocol-erase.sx`.
|
||||
1. `instantiateGenericStruct` now binds the template name to the concrete
|
||||
instance (`tb.put(tmpl.name, id)`), so an impl method `self: *Combined`
|
||||
resolves `self.field` to the instance, not the 0-field generic stub. (This
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# 0055 — binary arithmetic accepts mismatched operand types (`i64 + string`)
|
||||
|
||||
> **RESOLVED.** Scalar binary ops derived the result type from the LHS and never
|
||||
> checked the RHS, so `i64 + string` lowered as `add : i64` and reinterpreted the
|
||||
> string's bytes (garbage); ordering/bitwise had the same hole. Fixed in
|
||||
> `lowerBinaryOp` (src/ir/lower/expr.zig:2520), which now gates arithmetic /
|
||||
> ordering / bitwise-shift groups through `isArithOperand` / `isOrderingOperand` /
|
||||
> `isBitwiseOperand` (src/ir/lower.zig:1408-1437) — `.unresolved` passes through,
|
||||
> a concretely incompatible operand emits `cannot apply '<op>' …` and returns a
|
||||
> placeholder sentinel. Covered by `examples/1106-diagnostics-binop-operand-type-check.sx`.
|
||||
|
||||
**FIXED** (`examples/214-binop-operand-type-check.sx`). `lowerBinaryOp` in
|
||||
[src/ir/lower.zig](../src/ir/lower.zig) now checks operand-type
|
||||
compatibility for every scalar binary-op group before emitting, via three
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# 0056 — parameterised-protocol impl not deduped across a diamond import
|
||||
|
||||
> **RESOLVED.** An anonymous `impl_block` has no `declName`, so the flat decl
|
||||
> list's name-keyed dedup let the same cached AST node (shared by both diamond
|
||||
> paths) be appended twice — `registerParamImpl` in `src/ir/lower.zig` then saw
|
||||
> two same-module entries and raised "duplicate impl 'Into' for source 'i64'".
|
||||
> Fixed in `ResolvedModule.mergeFlat` (and the directory-import merge loop) in
|
||||
> `src/imports.zig`, which now also dedup by node identity via a `seen_nodes:
|
||||
> AutoHashMap(*Node, void)`. Regression test: `examples/0709-modules-issue-0056-diamond-param-impl.sx`.
|
||||
|
||||
**FIXED** (`examples/issue-0056-diamond-param-impl.sx`, helpers in
|
||||
`examples/issue-0056/`). The flat decl list in
|
||||
[src/imports.zig](../src/imports.zig) now dedups by **node identity** as well
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# 0131 — protocol method call with extra arguments compiles and silently drops them
|
||||
|
||||
> **RESOLVED.** Protocol-dispatch lowering matched the call args against the
|
||||
> method's parameter list without an arity check, so extra trailing args were
|
||||
> silently truncated (and missing args left the thunk reading garbage). Fixed in
|
||||
> `src/ir/lower/protocol.zig:emitProtocolDispatch` (lines 531-538), which now
|
||||
> exact-arity-checks and emits `'{name}' expects N argument(s), but M were given`
|
||||
> at the call span. Regression pinned by `examples/1634-protocol-call-arity`.
|
||||
|
||||
## Symptom
|
||||
|
||||
Calling a protocol method with MORE arguments than the protocol
|
||||
|
||||
Reference in New Issue
Block a user