Fix control flow when the loop contains NIL blocks
(Had to take over !2 (closed) because I could not rebase it on the fork. Now we will get this running in the CI/CD and can get it merged. Please have a look, @sjl)
Control flow clauses that return from an iterate form without executing
the epilogue code (e.g. never
and leave
) currently do so by
expanding into (return-from ,*block-name*)
. For iterate forms without
a user-provided name, the block will be named nil
. This causes
problems when used with other Common Lisp looping constructs such as
dolist
:
(iterate
(for i :from 0 :below 10)
(dolist (x '(5 10 15))
(never (= i x))))
; => T, but should be NIL
This patch adds a separate *loop-name*
variable that will be bound to
a gensym for NIL
-named blocks and makes the various epilogue-skipping
code refer to that instead of *block-name*
. Iterate forms without
an explicit user-provided name will still have a separate (block nil ...)
wrapping so users can still (return ...)
as before.
Before (simplified):
(iterate (leave))
; ==> (block nil (return-from nil))
(iterate foo (leave))
; ==> (block foo (return-from nil))
After:
(iterate (leave))
; ==> (block nil (block #:ITERATE123 (return-from #:ITERATE123)))
(iterate foo (leave))
; ==> (block foo (return-from foo))