keep closure signatures apart when mangled

The argument list was flattened with one separator throughout, so
`((long long))' and `((long) (long))' named one struct. A capture
borrowing a name looked only at the local scope chain.
This commit is contained in:
2026-09-30 14:33:57 +03:00
parent 578feb6b73
commit 024e97553b
3 changed files with 72 additions and 5 deletions

View File

@@ -765,10 +765,24 @@
*pending-closure-structs*)))))
(delete-duplicates (aggregates-in type))))
;;; Where one argument ends and the next begins has to survive the
;;; flattening, or `((long long))' and `((long) (long))' mangle alike and
;;; the second signature silently reuses the first one's struct. Words
;;; within an argument keep the single separator; the arguments take a
;;; doubled one.
;;;
;;; Not proof against a type name that mangles to a trailing `_' of its
;;; own -- for that the arguments would have to carry their lengths, and
;;; the name in the C is worth more than the last of the ambiguity.
(define (mangle-arglist args)
(if (null? args)
"void"
(string-intersperse (map mangle-type args) "__")))
(define (closure-struct-name type)
;; the glyph says `closure' already, so the tag is just the signature
(string->symbol (string-append "ƛ"
(mangle-type (second type))
(mangle-arglist (second type))
"_"
(mangle-type (third type)))))
@@ -937,9 +951,9 @@
(let ((name (capture-name capture)))
(unless (symbol? name)
(sex-error form "a closure capture needs a name" capture))
(let ((type (if (pair? capture)
(expression-type (capture-argument capture) env)
(lookup-name env name))))
;; the same lookup either way: a capture that borrows a name can
;; borrow a global's or a function's, not only a local's
(let ((type (expression-type (capture-argument capture) env)))
(unless type
(sex-error form "cannot infer what is captured as" name))
(list name type))))