Fail to optimize tail recursion when tail call occurs in FINALLY clause of LOOP without RETURN
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
SBCL |
Invalid
|
Undecided
|
Unassigned |
Bug Description
The following code produces the CONTROL-
(defun test-tailrec (table begin-idx)
(declare (optimize (speed 3) (safety 0))
(fixnum begin-idx))
(when (< begin-idx (length table))
(loop with base = (aref table begin-idx)
for end-idx from begin-idx below (length table)
while (= base (aref table end-idx))
finally ; here occur some side effects in practice
(defparameter *table* (make-array 1000000 :element-type 'fixnum))
(dotimes (idx (length *table*))
(setf (aref *table* idx) (random most-positive-
(test-tailrec *table* 0)
By disassembling we can confirm the TCO didn't occur. A workaround is enclosing the last form with an (unnecessary) RETURN as follows:
(defun test-tailrec2 (table begin-idx)
(declare (optimize (speed 3) (safety 0))
(fixnum begin-idx))
(when (< begin-idx (length table))
(loop with base = (aref table begin-idx)
for end-idx from begin-idx below (length table)
while (= base (aref table end-idx))
finally (return (test-tailrec2 table end-idx)))))
Environment: SBCL 1.4.14 (Windows, x64)
summary: |
- fail to optimize tail recursion when tail call occurs in FINALLY clause + Fail to optimize tail recursion when tail call occurs in FINALLY clause of LOOP without RETURN |
Without RETURN it will return NIL, and not the values returned by the function. Tail call optimization can only return the values from the called function.