fibers B1.2: BLOCKED on compiler bugs 0150 + 0151 (Io design proven)
Stream B1 B1.2 (Io capability + context.io + Future + cancel) is blocked on two newly-discovered, independent compiler bugs, both with standalone repros: - 0150: a `void` struct field crashes the compiler with an unsized-type SIGTRAP in LLVM getTypeSizeInBits. Blocks `Future(void)` -> `timeout`. - 0151: a type-var inferred from a fn-pointer parameter's RETURN type is not bound as a usable type in the function body (`unknown type 'R'`). Blocks the central `async(io, worker: ($A)->$R, arg)` free-fn's `Future(R)`. The B1.2 design itself is validated end-to-end (the Io protocol threaded on Context like Allocator, the stateless blocking CBlockingIo default, both __sx_default_context materializers, and `context.io.now_ms()` all work live). Only the async/await/timeout ergonomic layer hits the two bugs. Per the IMPASSABLE STOP rule, all B1.2 working changes were reverted (master green, 726/0) and the work paused pending fixes; WIP is saved at .sx-tmp/b12-wip/. Checkpoint + plan updated to mark B1.2 BLOCKED with full resume notes.
This commit is contained in:
@@ -59,6 +59,58 @@ body); closed + locked. The review's `.naked`-lambda CRITICAL was a false positi
|
||||
(unparseable — `isLambda` breaks on the `abi` keyword).
|
||||
|
||||
## Current state
|
||||
**B1.2 is BLOCKED on two newly-filed compiler bugs (issues 0150 + 0151). Master is GREEN
|
||||
(726/0); all B1.2 working changes were REVERTED so the installed `zig-out/bin/sx` is clean.**
|
||||
See the "B1.2 attempt (BLOCKED)" subsection below + "Known issues" for the full story. The
|
||||
B1.2 *design* is validated end-to-end (the `Io` protocol on `Context`, the blocking
|
||||
`CBlockingIo` default, and `context.io.now_ms()` all WORK — verified live); only the two
|
||||
generic/void compiler gaps stop the `async`/`await`/`timeout` ergonomic layer. WIP saved at
|
||||
`.sx-tmp/b12-wip/` (io.sx + the compiler+lib diff + the 1805 example) for a fast resume.
|
||||
|
||||
### B1.2 attempt (BLOCKED — design proven, two compiler bugs filed)
|
||||
What was built + verified WORKING (then reverted to keep master green):
|
||||
- `Io :: protocol #inline { spawn_raw; suspend_raw -> !; ready; poll; now_ms; arm_timer; }`
|
||||
in `core.sx` next to `Allocator`, with `SpawnOpts{ pin: PinTarget }` + `ParkToken{ handle }`.
|
||||
Six methods, each justified by a downstream consumer (B1.3-B1.5).
|
||||
- `Context :: struct { allocator; data; io: Io; }` — `io` appended LAST so `allocator` stays
|
||||
index 0 (the `call.zig:1229` hardcode) and `data` keeps index 1 (minimal VM-fallback churn).
|
||||
- Both `__sx_default_context` materializers updated in lockstep + verified: `protocol.zig`
|
||||
`emitDefaultContextGlobal` (extended `ctx_fields` 2→3, built the `CBlockingIo→Io` inline
|
||||
7-word vtable `{null-ctx, fn0..fn5}` via `getOrCreateThunks("Io","CBlockingIo")`) and
|
||||
`comptime_vm.zig` `materializeDefaultContext` fallback (wrote the 6 thunk func-refs at
|
||||
`io_base = addr + 4*ps`, offset `+ (i+1)*ps`). The global path auto-followed the 3-field
|
||||
Context type. **`context.io.now_ms()` printed `clock ok` live — the capability threads + the
|
||||
vtable dispatches correctly.**
|
||||
- Stateless `CBlockingIo :: struct {}` + `impl Io for CBlockingIo` (mirror of `CAllocator`):
|
||||
blocking semantics — `spawn_raw`/`ready`/`poll`/`arm_timer` no-op/0, `now_ms` → `time.mono_ms()`.
|
||||
- **push-inherit-omitted fix** (`stmt.zig` `lowerPush`): a `push Context.{...}` now SEEDS the
|
||||
new slot from the ambient context (load+store), then overwrites ONLY the literal's named
|
||||
fields — so omitted fields (now incl. `io`) are INHERITED, never zero-inited to a null
|
||||
vtable. Eliminates the omitted-field footgun globally (zero per-site churn across the 17
|
||||
partial-literal sites). This is the correct capability-bag semantics; it compiled clean.
|
||||
- **`!`-protocol-method warning fix** (`error_analysis.zig` + a new `Lowering.impl_method_names`
|
||||
set populated in `protocols.zig` `registerImplBlock`): a protocol impl method may be declared
|
||||
`!` by contract (e.g. `Io.suspend_raw`) yet never raise; the "declared `!` but never errors —
|
||||
drop the `!`" hint is a false positive for impl methods, now suppressed for them.
|
||||
|
||||
Where it BROKE (the two blockers — both INDEPENDENT of the Io design, both repro standalone):
|
||||
- **issue 0150** — `Future(void)` (for `timeout -> Future(void)`) makes a `result: void` field;
|
||||
a `void` struct field crashes the compiler with an unsized-type SIGTRAP in LLVM
|
||||
`getTypeSizeInBits` (a bare `struct { v: void; }` repros it). `timeout` was DEFERRED (it is a
|
||||
B1.4 stub needing `arm_timer` anyway) rather than routed around with a non-void shape.
|
||||
- **issue 0151** — `async(io, worker: ($A) -> $R, arg: $A) -> Future($R)`: `$R` inferred from a
|
||||
fn-pointer parameter's RETURN type type-checks the call but is NOT bound as a usable type in
|
||||
the body, so `Future(R)` errors `unknown type 'R'`. A direct `arg: $A` binds fine — the gap is
|
||||
specific to type-vars nested in a fn-ptr/closure param signature. This blocks the central
|
||||
`async`/`await` free-fns. (Manifested as the "unresolved type reached LLVM emission" panic —
|
||||
the same one another session filed against my dirty binary as issue 0149, now moot after the
|
||||
revert.)
|
||||
|
||||
Per the IMPASSABLE STOP rule: filed 0150 + 0151, reverted all B1.2 working changes (master
|
||||
green again, photo project unbroken), STOPPED. Resume B1.2 once 0150 + 0151 land — the WIP in
|
||||
`.sx-tmp/b12-wip/` makes it ~mechanical (the design is proven).
|
||||
|
||||
### Earlier — B1.0 + B1.1 complete
|
||||
Stream A (atomics) is feature-complete (✅). Stream B1: **B1.0 + B1.1 complete.** The two
|
||||
compiler-floor preconditions for the fiber runtime are in place: (1) `abi(.naked)` emits a
|
||||
real LLVM `naked` function end-to-end (decl, generic, pack paths) — the context-switch
|
||||
@@ -80,16 +132,31 @@ fibers/Io/scheduler code yet. Grounded floor facts:
|
||||
boundary; a sharper sx diagnostic for it is a candidate polish, not a blocker.
|
||||
|
||||
## Next step
|
||||
**B1.2 (A1 — `Io` interface + `context.io` + `Future` + `cancel()` API).** Per PLAN-FIBERS.md
|
||||
"Phases → B1.2". Library-only: add an `Io` protocol as a `Context` field (mirror `Allocator`
|
||||
at field 0; `Context` is currently `{ allocator, data }` — add `io`), plus the `Future` /
|
||||
`cancel()` surface. Exercise the blocking-`Io` default with an `18xx` example (real suspend
|
||||
lands in B1.3). No compiler change expected; if a protocol-in-context gap appears, file it.
|
||||
NOTE: adding a field to `Context` shifts its layout — check whether any `Context` literal /
|
||||
`push Context.{...}` site or the `__sx_default_context` builder needs the new field (the
|
||||
allocator precedent shows the pattern).
|
||||
**B1.2 is BLOCKED — resume only AFTER issues 0150 + 0151 are fixed.** Then re-land B1.2 from
|
||||
the saved WIP (`.sx-tmp/b12-wip/`): the `Io` protocol + `Context.io` + both materializers +
|
||||
the push-inherit fix + the `!`-impl-warning fix all WORK as-is; restore `timeout ->
|
||||
Future(void)` (needs 0150) and `async`/`await` (needs 0151), add `examples/1805-concurrency-
|
||||
io-blocking-async.sx` (lock→green) + `1806-concurrency-io-cancel.sx` (cancel→`await` raises
|
||||
`.canceled`). Regen `.ir` snapshots ONLY after green (`-Dupdate-goldens`) — adding `Io` to the
|
||||
prelude shifts many `.ir` type tables; confirm the diff is ONLY layout/numbering + the new
|
||||
vtable, NO error text. The `Context` layout decision is settled: `{ allocator; data; io; }`
|
||||
(allocator index 0 fixed by `call.zig:1229`, `io` last).
|
||||
|
||||
NOTE for the resume: do NOT add `io = context.io` to the 17 partial `push Context.{...}` sites
|
||||
— the push-inherit-omitted fix (in the WIP diff) makes omitted fields inherit from the ambient
|
||||
context, which is the correct fix and was verified to compile. Use that, not per-site edits.
|
||||
|
||||
## Known issues / capability gaps
|
||||
- **🔴 B1.2 BLOCKERS (both filed, both standalone-reproducible, both independent of the Io
|
||||
design):**
|
||||
- **issue 0150** — a `void` struct field crashes the compiler (unsized-type SIGTRAP in LLVM
|
||||
`getTypeSizeInBits`). Blocks `Future(void)` → `timeout`. Repro: `issues/0150-...`.
|
||||
- **issue 0151** — a type-var inferred from a fn-pointer parameter's RETURN type is not bound
|
||||
in the function body (`unknown type 'R'`). Blocks `async(io, worker: ($A)->$R, arg)`'s
|
||||
`Future(R)`. Repro: `issues/0151-...`.
|
||||
- (Note: **issue 0149**, filed by another session against the dirty in-progress binary, was a
|
||||
manifestation of 0151 — "unresolved type reached LLVM emission". Moot after the revert; its
|
||||
real root cause is 0151.)
|
||||
- **Orthogonal (not a B1 blocker):** default VALUES for comptime params don't bind on
|
||||
generic-struct methods (free-fn defaults DO work) — inherited from Stream A. Only matters
|
||||
if a B2 lib type wants a defaulted comptime param; atomics/fibers require explicit, so
|
||||
@@ -177,3 +244,12 @@ allocator precedent shows the pattern).
|
||||
reads the snapshot, not the trampoline's ambient ctx, and the `push` scope restores ambient
|
||||
on exit. Locked by `examples/1804-concurrency-context-snapshot.sx` (prints `fiber root: 42`
|
||||
/ `ambient after: 99`). Suite green (726/0). **Next: B1.2 (Io interface + context.io).**
|
||||
- **B1.2 (BLOCKED)** — built the full `Io` capability (protocol on `Context`, stateless
|
||||
`CBlockingIo` blocking default, both `__sx_default_context` materializers, push-inherit-omitted
|
||||
fix, `!`-impl-method warning fix) and VERIFIED the core works live (`context.io.now_ms()` →
|
||||
`clock ok`). Two independent compiler bugs blocked the `async`/`await`/`timeout` layer:
|
||||
**0150** (`void` struct field → unsized SIGTRAP, blocks `Future(void)`) and **0151** (type-var
|
||||
from a fn-ptr param's return type not bound in the body, blocks `async`'s `Future(R)`). Both
|
||||
filed with standalone repros + investigation prompts. Per the STOP rule: reverted ALL B1.2
|
||||
working changes (master green again, 726/0; the dirty binary had broken the photo project —
|
||||
see the now-moot 0149), saved WIP to `.sx-tmp/b12-wip/`, STOPPED. Resume after 0150 + 0151.
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
# PLAN-FIBERS — Stream B1 (fibers + Io + M:1 scheduler)
|
||||
|
||||
> **STATUS: 🚧 in progress.** B1.0 (`abi(.naked)` codegen) ✅ + B1.1 (per-fiber `context`
|
||||
> root — zero compiler change, library convention) ✅ complete. Next step = **B1.2** (`Io`
|
||||
> interface + `context.io` + `Future` + `cancel()`).
|
||||
> root — zero compiler change, library convention) ✅ complete. **B1.2** (`Io` interface +
|
||||
> `context.io` + `Future` + `cancel()`) is **🔴 BLOCKED on compiler issues 0150 (`void`
|
||||
> struct field SIGTRAP) + 0151 (type-var from a fn-ptr-return not bound in body)** — the Io
|
||||
> design is proven (the protocol-on-`Context` + blocking default + `context.io.now_ms()` work
|
||||
> live), but `Future(void)`/`timeout` and the `async`/`await` generics hit those two bugs.
|
||||
> Resume B1.2 after both land (WIP saved at `.sx-tmp/b12-wip/`); see `CHECKPOINT-FIBERS.md`.
|
||||
|
||||
Carved from [PLAN-POST-METATYPE.md](PLAN-POST-METATYPE.md) Stream B (§B1) + the
|
||||
design-of-record [../design/execution-evolution-roadmap.md](../design/execution-evolution-roadmap.md)
|
||||
|
||||
Reference in New Issue
Block a user