From 2b565aad89587114148052eabdd430b923c21394 Mon Sep 17 00:00:00 2001 From: cooldome Date: Sat, 31 Aug 2019 18:23:54 +0100 Subject: [PATCH] Support iterators returning lent T (#11938) * lent iterators * rebase tests * update changelog * fix comments, more tests --- changelog.md | 5 ++++ compiler/lowerings.nim | 4 +-- compiler/semexprs.nim | 8 +++--- compiler/semstmts.nim | 59 +++++++++++++++++++++++++++++----------- compiler/transf.nim | 3 +- lib/system/iterators.nim | 5 ++-- tests/iter/tmoditer.nim | 59 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 116 insertions(+), 27 deletions(-) diff --git a/changelog.md b/changelog.md index b7c2214c9..38bb412d0 100644 --- a/changelog.md +++ b/changelog.md @@ -61,6 +61,11 @@ type ## Language additions +- Inline iterators returning `lent T` types are now supported, similarly to iterators returning `var T`: +```nim +iterator myitems[T](x: openarray[T]): lent T +iterator mypairs[T](x: openarray[T]): tuple[idx: int, val: lent T] +``` ## Language changes diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 9ff3ece33..fff6c75ca 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -21,8 +21,8 @@ proc newDeref*(n: PNode): PNode {.inline.} = proc newTupleAccess*(g: ModuleGraph; tup: PNode, i: int): PNode = if tup.kind == nkHiddenAddr: - result = newNodeIT(nkHiddenAddr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar})) - result.addSon(newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar}).sons[i])) + result = newNodeIT(nkHiddenAddr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyLent})) + result.addSon(newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyLent}).sons[i])) addSon(result[0], tup[0]) var lit = newNodeIT(nkIntLit, tup.info, getSysType(g, tup.info, tyInt)) lit.intVal = i diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 765110d56..a3d92da8c 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1781,21 +1781,21 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) = var t = skipTypes(restype, {tyGenericInst, tyAlias, tySink}) case t.kind of tyVar, tyLent: - if t.kind == tyVar: t.flags.incl tfVarIsPtr # bugfix for #4048, #4910, #6892 + t.flags.incl tfVarIsPtr # bugfix for #4048, #4910, #6892 if n.sons[0].kind in {nkHiddenStdConv, nkHiddenSubConv}: n.sons[0] = n.sons[0].sons[1] n.sons[0] = takeImplicitAddr(c, n.sons[0], t.kind == tyLent) of tyTuple: for i in 0..= high(IX): break inc(i) -iterator mpairs*[IX, T](a:var array[IX, T]):tuple[key:IX,val:var T] {.inline.} = +iterator mpairs*[IX, T](a: var array[IX, T]): tuple[key: IX, val: var T] {.inline.} = ## Iterates over each item of `a`. Yields ``(index, a[index])`` pairs. ## ``a[index]`` can be modified. var i = low(IX) @@ -179,7 +179,6 @@ iterator mpairs*(a: var cstring): tuple[key: int, val: var char] {.inline.} = yield (i, a[i]) inc(i) - iterator items*[T](a: seq[T]): T {.inline.} = ## Iterates over each item of `a`. var i = 0 diff --git a/tests/iter/tmoditer.nim b/tests/iter/tmoditer.nim index 1e6be37e4..34c6321ce 100644 --- a/tests/iter/tmoditer.nim +++ b/tests/iter/tmoditer.nim @@ -27,3 +27,62 @@ for a in items(arr): echo "" +#-------------------------------------------------------------------- +# Lent iterators +#-------------------------------------------------------------------- +type + NonCopyable = object + x: int + + +proc `=destroy`(o: var NonCopyable) = + discard + +proc `=copy`(dst: var NonCopyable, src: NonCopyable) {.error.} + +proc `=sink`(dst: var NonCopyable, src: NonCopyable) = + dst.x = src.x + +iterator lentItems[T](a: openarray[T]): lent T = + for i in 0..a.high: + yield a[i] + +iterator lentPairs[T](a: array[0..1, T]): tuple[key: int, val: lent T] = + for i in 0..a.high: + yield (i, a[i]) + + +let arr1 = [1, 2, 3] +let arr2 = @["a", "b", "c"] +let arr3 = [NonCopyable(x: 1), NonCopyable(x: 2)] +let arr4 = @[(1, "a"), (2, "b"), (3, "c")] + +var accum: string +for x in lentItems(arr1): + accum &= $x +doAssert(accum == "123") + +accum = "" +for x in lentItems(arr2): + accum &= $x +doAssert(accum == "abc") + +accum = "" +for val in lentItems(arr3): + accum &= $val.x +doAssert(accum == "12") + +accum = "" +for i, val in lentPairs(arr3): + accum &= $i & "-" & $val.x & " " +doAssert(accum == "0-1 1-2 ") + +accum = "" +for i, val in lentItems(arr4): + accum &= $i & "-" & $val & " " +doAssert(accum == "1-a 2-b 3-c ") + +accum = "" +for (i, val) in lentItems(arr4): + accum &= $i & "-" & $val & " " +doAssert(accum == "1-a 2-b 3-c ")