defmethod on a referred multifn resolves to its home ns

A (defmethod m …) where m is :refer'd from another ns passed the bare symbol to
defmethod-setup, which resolved it in the current ns and created a shadow multifn
— the method never reached the real one. Resolve an unqualified name through the
refer table (then current ns) so it lands on the referred multifn.

The AOT build strips the ns form, so the refer table is empty in a binary; emit
chez-register-refer!/-refer-all! per app ns alongside the existing alias
registrations. build-app's fixture gains a defmethod on a referred multifn.
This commit is contained in:
Yogthos 2026-06-24 09:13:28 -04:00
parent 2c5b7fc27a
commit 44b7f39562
4 changed files with 37 additions and 9 deletions

View file

@ -46,7 +46,8 @@ HELLO FROM A BUILT BINARY!
args: [alpha bb ccc]
sum: 10
greet-default: greet:default
greet-loud: greet:loud'
greet-loud: greet:loud
greet-soft: greet:soft'
if [ "$got" != "$want" ]; then
echo " FAIL: binary output mismatch"
echo "--- want ---"; echo "$want"

View file

@ -185,10 +185,26 @@
(let loop ((xs (cdr items)))
(when (and (pair? xs) (pair? (cdr xs)))
(let ((k (car xs)) (v (cadr xs)))
(when (and (keyword? k) (string=? (keyword-t-name k) "as") (symbol-t? v))
(emit! (string-append "(chez-register-alias! " (ei-str-lit ns-name)
" " (ei-str-lit (symbol-t-name v))
" " (ei-str-lit target) ")"))))
(when (keyword? k)
(cond
((and (string=? (keyword-t-name k) "as") (symbol-t? v))
(emit! (string-append "(chez-register-alias! " (ei-str-lit ns-name)
" " (ei-str-lit (symbol-t-name v))
" " (ei-str-lit target) ")")))
;; :refer [a b] / :refer :all — a defmethod on a referred multifn
;; resolves the bare name through the refer table at runtime.
((or (string=? (keyword-t-name k) "refer") (string=? (keyword-t-name k) "only"))
(cond
((and (keyword? v) (string=? (keyword-t-name v) "all"))
(emit! (string-append "(chez-register-refer-all! " (ei-str-lit ns-name)
" " (ei-str-lit target) ")")))
((or (pvec? v) (and (cseq? v) (cseq-list? v)))
(for-each (lambda (n)
(when (symbol-t? n)
(emit! (string-append "(chez-register-refer! " (ei-str-lit ns-name)
" " (ei-str-lit (symbol-t-name n))
" " (ei-str-lit target) ")"))))
(seq->list v))))))))
(loop (cddr xs))))))))
(define (bld-ns-prelude ns-name src)

View file

@ -73,8 +73,14 @@
(sns (symbol-t-ns mm-sym))
(qns (and sns (not (jolt-nil? sns)) (not (null? sns)) sns))
;; qualified (cf.mm/ext) resolves in its own ns (cross-ns defmethod);
;; unqualified stays in the current ns (a shadow, as before).
(mns (if qns (or (chez-resolve-alias (chez-current-ns) qns) qns) (chez-current-ns)))
;; unqualified resolves in the current ns, else a :refer's home ns (so a
;; defmethod on a referred multifn lands on the real one), else stays in
;; the current ns (a shadow, as before).
(mns (cond
(qns (or (chez-resolve-alias (chez-current-ns) qns) qns))
((var-cell-lookup (chez-current-ns) nm) (chez-current-ns))
((chez-resolve-refer (chez-current-ns) nm) => values)
(else (chez-current-ns))))
(cur (var-deref mns nm))
(mf (if (jolt-multifn? cur) cur
;; auto-create: copy the dispatch fn + default from a same-named