Allow recursive closure iterators (#19939)

This commit is contained in:
Tanguy 2022-06-30 23:19:04 +02:00 • committed by GitHub
commit ce4078acd4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 16 additions and 5 deletions

View file

@ -886,7 +886,8 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
case callee.kind case callee.kind
of skMacro, skTemplate: discard of skMacro, skTemplate: discard
else: else:
if callee.kind == skIterator and callee.id == c.p.owner.id: if callee.kind == skIterator and callee.id == c.p.owner.id and
not isClosureIterator(c.p.owner.typ):
localError(c.config, n.info, errRecursiveDependencyIteratorX % callee.name.s) localError(c.config, n.info, errRecursiveDependencyIteratorX % callee.name.s)
# error correction, prevents endless for loop elimination in transf. # error correction, prevents endless for loop elimination in transf.
# See bug #2051: # See bug #2051:

View file

@ -4326,13 +4326,10 @@ Closure iterators and inline iterators have some restrictions:
1. For now, a closure iterator cannot be executed at compile time. 1. For now, a closure iterator cannot be executed at compile time.
2. `return` is allowed in a closure iterator but not in an inline iterator 2. `return` is allowed in a closure iterator but not in an inline iterator
(but rarely useful) and ends the iteration. (but rarely useful) and ends the iteration.
3. Neither inline nor closure iterators can be (directly)* recursive. 3. Inline iterators cannot be recursive.
4. Neither inline nor closure iterators have the special `result` variable. 4. Neither inline nor closure iterators have the special `result` variable.
5. Closure iterators are not supported by the JS backend. 5. Closure iterators are not supported by the JS backend.
(*) Closure iterators can be co-recursive with a factory proc which results
in similar syntax to a recursive iterator. More details follow.
Iterators that are neither marked `{.closure.}` nor `{.inline.}` explicitly Iterators that are neither marked `{.closure.}` nor `{.inline.}` explicitly
default to being inline, but this may change in future versions of the default to being inline, but this may change in future versions of the
implementation. implementation.

View file

@ -29,6 +29,7 @@ end
9018 9018
@[1, 2] @[1, 2]
@[1, 2, 3] @[1, 2, 3]
1
''' '''
""" """
@ -274,3 +275,15 @@ iterator cc() {.closure.} =
break break
var a2 = cc var a2 = cc
# bug #16876
block:
iterator a(num: int): int {.closure.} =
if num == 1:
yield num
else:
for i in a(num - 1):
yield i
for i in a(5):
echo i