Comment made by: cgrand
The proposal here is to catch recursive seq realization (ie when computing the body of a lazy-seq attempts to access the same seq) and throw an exception.
Currently when such a case happens, the recursive access to the seq returns nil. This results in incorrect code seemingly working but producing incorrect results or even incorrect code producing correct results out of luck (see https://groups.google.com/d/topic/clojure/yD941fIxhyE/discussion for such an example).
So this patch moves around the modification to the LazySeq state (f, sv and s fields) before all potentially recursive method call (.sval in the while of .seq and .invoke in .sval) so that, upon reentrance, the state of the LazySeq is coherent and able to convey the fact the seq is already being computed.
Currently a recursive call may find f and sv cleared and concludes the computation is done and the result is in s despite s being unaffected yet.
Currently:
|State|f|sv|s|
| :-- | :-- | :-- | :-- | :-- |
|Unrealized|not null|null|null|
|Realized|null|null|anything|
|Being realized/recursive call from fn.invoke|not null|null|null|
|Being realized/recursive call from ls.sval|null|null|null|
Note that "Being realized" states overlap with Unrealized or Realized.
(NB: "anything" includes null)
With the patch:
|State|f|sv|s|
| :-- | :-- | :-- | :-- | :-- |
|Unrealized|not null|null|null|
|Realized|null|null|anything but this|
|Being realized|null|null|this|