~ chicken-core (chicken-5) 32067934f3dbe6da17ae018187dfeb8a81567d7e
commit 32067934f3dbe6da17ae018187dfeb8a81567d7e
Author: Peter Bex <peter@more-magic.net>
AuthorDate: Wed Dec 11 13:24:48 2019 +0100
Commit: felix <felix@call-with-current-continuation.org>
CommitDate: Thu Dec 12 12:50:12 2019 +0100
Fix restoration of rest operations inside closures
When a rest operation would have to be undone due to no longer having
access to the original procedure's argvector and converted to a
closure, the call would now need to access the variable from the
closure.
Bug found by Kon Lovett
Signed-off-by: felix <felix@call-with-current-continuation.org>
diff --git a/core.scm b/core.scm
index 4623122b..39d0a8d1 100644
--- a/core.scm
+++ b/core.scm
@@ -2636,9 +2636,10 @@
val) ) )
((##core#rest-cdr ##core#rest-car ##core#rest-null? ##core#rest-length)
- (let* ((rest-var (first params))
- (val (ref-var n here closure)))
- (unless (eq? val n)
+ (let* ((val (ref-var n here closure))
+ (rest-var (if (eq? val n) (varnode (first params)) val)))
+ (unless (or (eq? val n)
+ (match-node val `(##core#ref (i) (##core#variable (,here))) '(i)))
;; If it's captured, replacement in optimizer was incorrect
(bomb "Saw rest op for captured variable. This should not happen!" class) )
;; If rest-cdrs have not all been eliminated, restore
@@ -2647,30 +2648,37 @@
;; many more cdr calls than necessary.
(cond ((eq? class '##core#rest-cdr)
(let lp ((cdr-calls (add1 (second params)))
- (var (varnode rest-var)))
+ (var rest-var))
(if (zero? cdr-calls)
(transform var here closure)
(lp (sub1 cdr-calls)
(make-node '##core#inline (list "C_i_cdr") (list var))))))
+
;; If customizable, the list is consed up at the
;; call site and there is no argvector. So convert
;; back to list-ref/list-tail calls.
- ((and (eq? class '##core#rest-car)
- (test here 'customizable))
- (transform (make-node '##core#inline
- (list "C_i_list_ref")
- (list (varnode rest-var) (second params))) here closure))
- ((and (eq? class '##core#rest-null)
- (test here 'customizable))
- (transform (make-node '##core#inline
- (list "C_i_greater_or_equal_p")
- (list (qnode (second params))
- (make-node '##core#inline (list "C_i_length") (list (varnode rest-var))))) here closure))
- ((and (eq? class '##core#rest-length)
- (test here 'customizable))
- (transform (make-node '##core#inline
- (list "C_i_length")
- (list (varnode rest-var) (second params))) here closure))
+ ;;
+ ;; Alternatively, if n isn't val, this node was
+ ;; processed and the variable got replaced by a
+ ;; closure access.
+ ((or (test here 'customizable)
+ (not (eq? val n)))
+ (case class
+ ((##core#rest-car)
+ (transform (make-node '##core#inline
+ (list "C_i_list_ref")
+ (list rest-var (qnode (second params)))) here closure))
+ ((##core#rest-null)
+ (transform (make-node '##core#inline
+ (list "C_i_greater_or_equal_p")
+ (list (qnode (second params))
+ (make-node '##core#inline (list "C_i_length") (list rest-var)))) here closure))
+ ((##core#rest-length)
+ (transform (make-node '##core#inline
+ (list "C_i_length")
+ (list rest-var (qnode (second params)))) here closure))
+ (else (bomb "Unknown rest op node class in while converting to closure. This shouldn't happen!" class))))
+
(else val)) ) )
((if ##core#call ##core#inline ##core#inline_allocate ##core#callunit
@@ -2799,6 +2807,8 @@
(list (qnode (##sys#make-lambda-info (car params))))
'() ) ) ) )
+ ((##core#ref) n)
+
(else (bomb "bad node (closure2)")) ) ) )
(define (maptransform xs here closure)
Trap