summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorTanguy <tanguy@status.im>2022-06-30 23:19:04 +0200
committerGitHub <noreply@github.com>2022-06-30 23:19:04 +0200
commitce4078acd40bb27de5d05832f486dbc95918a3c9 (patch)
treea35d315cc1961d5b22827c722cd527e45f2599ec
parent2c0aaac3045a63b5e4a24468341bf9ccfc8820cc (diff)
downloadNim-ce4078acd40bb27de5d05832f486dbc95918a3c9.tar.gz
Allow recursive closure iterators (#19939)
-rw-r--r--compiler/semexprs.nim3
-rw-r--r--doc/manual.rst5
-rw-r--r--tests/iter/titer_issues.nim13
3 files changed, 16 insertions, 5 deletions
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index ed28d8145..e07a98417 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -886,7 +886,8 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
     case callee.kind
     of skMacro, skTemplate: discard
     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)
         # error correction, prevents endless for loop elimination in transf.
         # See bug #2051:
diff --git a/doc/manual.rst b/doc/manual.rst
index b63a2f68f..571379a87 100644
--- a/doc/manual.rst
+++ b/doc/manual.rst
@@ -4326,13 +4326,10 @@ Closure iterators and inline iterators have some restrictions:
 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
    (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.
 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
 default to being inline, but this may change in future versions of the
 implementation.
diff --git a/tests/iter/titer_issues.nim b/tests/iter/titer_issues.nim
index 15fe867c8..1f7e41e69 100644
--- a/tests/iter/titer_issues.nim
+++ b/tests/iter/titer_issues.nim
@@ -29,6 +29,7 @@ end
 9018
 @[1, 2]
 @[1, 2, 3]
+1
 '''
 """
 
@@ -274,3 +275,15 @@ iterator cc() {.closure.} =
             break
 
 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