#281 Capturing closures are conses: functionp returns NIL, breaks typep 'function & asdf ensure-function

closed
Opened by atgreen

ROOT CAUSE of asdf:load-system "alexandria" failure ('attempt to call an object that is not a function').

The bug

funcl represents a variable-capturing lambda as a 'closure cons' (cons (function GENSYM) (list CAP1 CAP2 ...)) (compiler.lisp:5058-5080, CL.md Phase 3 lambda-lifting/closure-conversion). funcall/apply special-case cons lowtag 001 to unpack captures. BUT:

Reproduced cleanly (no asdf): (defun mk (x) (function (lambda () x))) (defvar c (mk 99)) (list (funcall c) (functionp c) (consp c)) ;; => (99 NIL T) ; runs, but functionp NIL and consp T

Why it breaks asdf

asdf's ensure-function is (etypecase fun (function fun) ... (cons (if (eq 'lambda (car fun)) (eval fun) #'(lambda (&rest a) (apply (car fun) (append (cdr fun) a))))) ...). A capturing closure is a CONS, so it falls into the (cons ...) designator branch and gets treated as a (fn . args) call-spec: (apply (car closure) ...) -> the closure's internal code-word isn't a callable => 'not a function'. asdf passes with-asdf-session thunks (capturing closures) through call-function/ensure-function pervasively, so load-system dies. Traced via find-system -> call-with-asdf-session (thunk functionp=NIL) -> consult-asdf-cache -> call-function.

Conformance impact

ANSI: (functionp ) must be T; FUNCTION and CONS must be disjoint types; (typep closure 'function) must be T. All currently violated for capturing closures.

Fix direction

Give capturing closures a first-class funcallable representation (tagged closure record: [header|fn-ptr|cap0|...]) that satisfies functionp/typep 'function and is disjoint from cons; update funcall/apply/GC/functionp/typep. ADR-sized object-model change. (A 'make functionp T for closure-conses' hack is impossible without a distinguishing tag, since closure-conses are indistinguishable from data conses today.)

Blocks: asdf:load-system (alexandria). Related: ADR-0026 work (distinct issue - this is NOT the symbol layer).

Comments (1)

atgreen3992783298

Fixed by e17d39b (ADR-0028 first-class closure records). functionp/consp/typep correct for capturing closures; funcall/apply unpack the record; self-host fixed point held; alexandria asdf goal reached on top of this.