Files
sx/examples/concurrency/1819-concurrency-fiber-double-wait.sx
agra 6ee4d066b3 fibers: address adversarial review of the B1 changes (6 findings)
UFCS generic overload resolution (issue 0157 follow-ups):
- P1-a: call planning (calls.zig) used the last-wins fn_ast_map winner
  while lowering reselected by receiver, so the planned result type
  could disagree with the dispatched function and misbox the result.
  Both now share selectUfcsGenericByReceiver(.., fd0).
- P1-b: selection scanned module_decls globally, flagging a
  transitively-hidden same-named overload as a false ambiguity. Now
  two-tier: directly-visible authors first (ambiguity only among
  those), global fallback for receiver-reachable namespaced methods
  (e.g. Task.cancel) that defers to fd0 on a hidden tie.
- P2-b: boolean specificity tied *$T with *Box($T). Now peels pointer
  layers so the structurally-narrower receiver wins.

Scheduler (sched.sx):
- P1-c: a second concurrent Task.wait overwrote the single waiter slot
  -> silent deadlock. Now one-awaiter-per-task loud abort.
- P2-c: sleep(negative) rewound the monotonic virtual clock. Rejected
  loudly.

(P2-a, non-generic-winner-hides-generic, did not reproduce -- the
non-generic arm already falls through.)

Regressions: examples/generics/0218 (receiver specificity +
plan/lowering agreement), examples/concurrency/1818 (negative-sleep
abort), 1819 (double-wait abort). Suite green 758/0.
2026-06-21 22:05:22 +03:00

19 lines
914 B
Plaintext

// A `Task` allows ONE awaiter — a second concurrent `wait` on the same pending
// task would overwrite the single `waiter` slot, and completion would wake only
// the second, stranding the first forever. Regression (B1.4a review, P1-c): the
// guard aborts loudly instead of silently deadlocking.
//
// aborts (exit 134) after the diagnostic — aarch64-macOS-pinned.
#import "modules/std.sx";
sched :: #import "modules/std/sched.sx";
S :: struct { t: *sched.Task(i64); }
main :: () -> i64 {
st : S = ---; st.t = null;
s := sched.Scheduler.init(); ps := @s; pst := @st;
mkprod :: (ps: *sched.Scheduler, pst: *S) { pst.t = ps.go(() -> i64 => { ps.yield_now(); 42 }); }
mkw :: (ps: *sched.Scheduler, pst: *S) { ps.spawn(() => { x := pst.t.wait() or { -1 }; print("got {}\n", x); }); }
mkprod(ps, pst); mkw(ps, pst); mkw(ps, pst); // second waiter → loud abort
s.run();
return 0;
}