#272 multiple-value-list / nth-value return NIL — form evaluated in single-value context, extras not captured

closed
Opened by atgreen

Split-independent, high-value (multiple-value-list is used pervasively, incl. ansi-aux signals-error). Found via FRESH-mode probing (2026-07-11).

(floor 7 2) => 3 (primary OK) (multiple-value-bind (q r) (floor 7 2) (list q r)) => (3 1) (WORKS) (multiple-value-list (floor 7 2)) => NIL (should be (3 1)) (nth-value 1 (floor 7 2)) => NIL (should be 1) (nth-value 1 (values 10 20 30)) => NIL (should be 20) (multiple-value-call (function list) (floor 7 2)) => (3 1) (WORKS)

ROOT: stdlib multiple-value-list (src/stdlib.lisp ~6644) is (progn (clear-mv-buf) (let ((p FORM)) (cons p (mv-extras-walk 0 (mv-count) nil)))) and nth-value likewise captures (mv-count) in a let-init. FORM in a let-BINDING position is compiled in a SINGLE-value context, so a producer (floor/values) never writes its extras to mv-buf there — (mv-count) reads 0. multiple-value-bind and multiple-value-call work because they put FORM in a MULTIPLE-value context (their codegen spills all values). So the bug is the value-context of a let-init, not the mv-buf mechanism.

TRIED + REVERTED: redefining multiple-value-list/nth-value as (multiple-value-call (function list) FORM) — fixes the runtime cases but SEGFAULTS the self-host build (make build), because these macros are on the COLD compile path and the multiple-value-call expansion does not work under the cold tree-walker there. So the fix must either (a) give multiple-value-list its own multiple-value-context capture that also compiles cold, or (b) special-case it in the compiler. Non-trivial; the mv machinery is delicate (self-host depends on it). Deferred rather than risk the build.

Comments (1)

atgreen3992785481

FIXED (verified 2026-07-11): (multiple-value-list (values 1 2 3)) => (1 2 3); (nth-value 1 (values 4 5 6)) => 5. Likely landed with the cave#265-era mvb work.