• Steve Losh's avatar
    Fix control flow when the loop contains NIL blocks · 4864426a
    Steve Losh authored
    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))
    4864426a
iterate.lisp 128 KB