Support iterators returning lent T (#11938)
* lent iterators * rebase tests * update changelog * fix comments, more tests
This commit is contained in:
parent
9ae0dd611f
commit
2b565aad89
7 changed files with 116 additions and 27 deletions
|
|
@ -61,6 +61,11 @@ type
|
||||||
|
|
||||||
## Language additions
|
## 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
|
## Language changes
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ proc newDeref*(n: PNode): PNode {.inline.} =
|
||||||
|
|
||||||
proc newTupleAccess*(g: ModuleGraph; tup: PNode, i: int): PNode =
|
proc newTupleAccess*(g: ModuleGraph; tup: PNode, i: int): PNode =
|
||||||
if tup.kind == nkHiddenAddr:
|
if tup.kind == nkHiddenAddr:
|
||||||
result = newNodeIT(nkHiddenAddr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar}))
|
result = newNodeIT(nkHiddenAddr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyLent}))
|
||||||
result.addSon(newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar}).sons[i]))
|
result.addSon(newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(abstractInst+{tyPtr, tyVar, tyLent}).sons[i]))
|
||||||
addSon(result[0], tup[0])
|
addSon(result[0], tup[0])
|
||||||
var lit = newNodeIT(nkIntLit, tup.info, getSysType(g, tup.info, tyInt))
|
var lit = newNodeIT(nkIntLit, tup.info, getSysType(g, tup.info, tyInt))
|
||||||
lit.intVal = i
|
lit.intVal = i
|
||||||
|
|
|
||||||
|
|
@ -1781,21 +1781,21 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) =
|
||||||
var t = skipTypes(restype, {tyGenericInst, tyAlias, tySink})
|
var t = skipTypes(restype, {tyGenericInst, tyAlias, tySink})
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyVar, tyLent:
|
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}:
|
if n.sons[0].kind in {nkHiddenStdConv, nkHiddenSubConv}:
|
||||||
n.sons[0] = n.sons[0].sons[1]
|
n.sons[0] = n.sons[0].sons[1]
|
||||||
n.sons[0] = takeImplicitAddr(c, n.sons[0], t.kind == tyLent)
|
n.sons[0] = takeImplicitAddr(c, n.sons[0], t.kind == tyLent)
|
||||||
of tyTuple:
|
of tyTuple:
|
||||||
for i in 0..<t.sonsLen:
|
for i in 0..<t.sonsLen:
|
||||||
var e = skipTypes(t.sons[i], {tyGenericInst, tyAlias, tySink})
|
let e = skipTypes(t.sons[i], {tyGenericInst, tyAlias, tySink})
|
||||||
if e.kind in {tyVar, tyLent}:
|
if e.kind in {tyVar, tyLent}:
|
||||||
if e.kind == tyVar: e.flags.incl tfVarIsPtr # bugfix for #4048, #4910, #6892
|
e.flags.incl tfVarIsPtr # bugfix for #4048, #4910, #6892
|
||||||
if n.sons[0].kind in {nkPar, nkTupleConstr}:
|
if n.sons[0].kind in {nkPar, nkTupleConstr}:
|
||||||
n.sons[0].sons[i] = takeImplicitAddr(c, n.sons[0].sons[i], e.kind == tyLent)
|
n.sons[0].sons[i] = takeImplicitAddr(c, n.sons[0].sons[i], e.kind == tyLent)
|
||||||
elif n.sons[0].kind in {nkHiddenStdConv, nkHiddenSubConv} and
|
elif n.sons[0].kind in {nkHiddenStdConv, nkHiddenSubConv} and
|
||||||
n.sons[0].sons[1].kind in {nkPar, nkTupleConstr}:
|
n.sons[0].sons[1].kind in {nkPar, nkTupleConstr}:
|
||||||
var a = n.sons[0].sons[1]
|
var a = n.sons[0].sons[1]
|
||||||
a.sons[i] = takeImplicitAddr(c, a.sons[i], false)
|
a.sons[i] = takeImplicitAddr(c, a.sons[i], e.kind == tyLent)
|
||||||
else:
|
else:
|
||||||
localError(c.config, n.sons[0].info, errXExpected, "tuple constructor")
|
localError(c.config, n.sons[0].info, errXExpected, "tuple constructor")
|
||||||
else: discard
|
else: discard
|
||||||
|
|
|
||||||
|
|
@ -678,25 +678,30 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
var length = sonsLen(n)
|
var length = sonsLen(n)
|
||||||
let iterBase = n.sons[length-2].typ
|
let iterBase = n.sons[length-2].typ
|
||||||
var iter = skipTypes(iterBase, {tyGenericInst, tyAlias, tySink})
|
var iter = skipTypes(iterBase, {tyGenericInst, tyAlias, tySink})
|
||||||
|
var iterAfterVarLent = iter.skipTypes({tyLent, tyVar})
|
||||||
# length == 3 means that there is one for loop variable
|
# length == 3 means that there is one for loop variable
|
||||||
# and thus no tuple unpacking:
|
# and thus no tuple unpacking:
|
||||||
if iter.kind != tyTuple or length == 3:
|
if iterAfterVarLent.kind != tyTuple or length == 3:
|
||||||
if length == 3:
|
if length == 3:
|
||||||
if n.sons[0].kind == nkVarTuple:
|
if n.sons[0].kind == nkVarTuple:
|
||||||
var mutable = false
|
if sonsLen(n[0])-1 != sonsLen(iterAfterVarLent):
|
||||||
if iter.kind == tyVar:
|
|
||||||
iter = iter.skipTypes({tyVar})
|
|
||||||
mutable = true
|
|
||||||
if sonsLen(n[0])-1 != sonsLen(iter):
|
|
||||||
localError(c.config, n[0].info, errWrongNumberOfVariables)
|
localError(c.config, n[0].info, errWrongNumberOfVariables)
|
||||||
for i in 0 ..< sonsLen(n[0])-1:
|
for i in 0 ..< sonsLen(n[0])-1:
|
||||||
var v = symForVar(c, n[0][i])
|
var v = symForVar(c, n[0][i])
|
||||||
if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal)
|
if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal)
|
||||||
if mutable:
|
case iter.kind
|
||||||
v.typ = newTypeS(tyVar, c)
|
of tyVar:
|
||||||
v.typ.sons.add iter[i]
|
v.typ = newTypeS(tyVar, c)
|
||||||
else:
|
v.typ.sons.add iterAfterVarLent[i]
|
||||||
v.typ = iter.sons[i]
|
if tfVarIsPtr in iter.flags:
|
||||||
|
v.typ.flags.incl tfVarIsPtr
|
||||||
|
of tyLent:
|
||||||
|
v.typ = newTypeS(tyLent, c)
|
||||||
|
v.typ.sons.add iterAfterVarLent[i]
|
||||||
|
if tfVarIsPtr in iter.flags:
|
||||||
|
v.typ.flags.incl tfVarIsPtr
|
||||||
|
else:
|
||||||
|
v.typ = iter.sons[i]
|
||||||
n.sons[0][i] = newSymNode(v)
|
n.sons[0][i] = newSymNode(v)
|
||||||
if sfGenSym notin v.flags: addDecl(c, v)
|
if sfGenSym notin v.flags: addDecl(c, v)
|
||||||
elif v.owner == nil: v.owner = getCurrOwner(c)
|
elif v.owner == nil: v.owner = getCurrOwner(c)
|
||||||
|
|
@ -712,15 +717,22 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
elif v.owner == nil: v.owner = getCurrOwner(c)
|
elif v.owner == nil: v.owner = getCurrOwner(c)
|
||||||
else:
|
else:
|
||||||
localError(c.config, n.info, errWrongNumberOfVariables)
|
localError(c.config, n.info, errWrongNumberOfVariables)
|
||||||
elif length-2 != sonsLen(iter):
|
elif length-2 != sonsLen(iterAfterVarLent):
|
||||||
localError(c.config, n.info, errWrongNumberOfVariables)
|
localError(c.config, n.info, errWrongNumberOfVariables)
|
||||||
else:
|
else:
|
||||||
for i in 0 .. length - 3:
|
for i in 0 .. length - 3:
|
||||||
if n.sons[i].kind == nkVarTuple:
|
if n.sons[i].kind == nkVarTuple:
|
||||||
var mutable = false
|
var mutable = false
|
||||||
if iter[i].kind == tyVar:
|
var isLent = false
|
||||||
iter[i] = iter[i].skipTypes({tyVar})
|
iter[i] = case iter[i].kind
|
||||||
mutable = true
|
of tyVar:
|
||||||
|
mutable = true
|
||||||
|
iter[i].skipTypes({tyVar})
|
||||||
|
of tyLent:
|
||||||
|
isLent = true
|
||||||
|
iter[i].skipTypes({tyLent})
|
||||||
|
else: iter[i]
|
||||||
|
|
||||||
if sonsLen(n[i])-1 != sonsLen(iter[i]):
|
if sonsLen(n[i])-1 != sonsLen(iter[i]):
|
||||||
localError(c.config, n[i].info, errWrongNumberOfVariables)
|
localError(c.config, n[i].info, errWrongNumberOfVariables)
|
||||||
for j in 0 ..< sonsLen(n[i])-1:
|
for j in 0 ..< sonsLen(n[i])-1:
|
||||||
|
|
@ -729,6 +741,9 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
if mutable:
|
if mutable:
|
||||||
v.typ = newTypeS(tyVar, c)
|
v.typ = newTypeS(tyVar, c)
|
||||||
v.typ.sons.add iter[i][j]
|
v.typ.sons.add iter[i][j]
|
||||||
|
elif isLent:
|
||||||
|
v.typ = newTypeS(tyLent, c)
|
||||||
|
v.typ.sons.add iter[i][j]
|
||||||
else:
|
else:
|
||||||
v.typ = iter[i][j]
|
v.typ = iter[i][j]
|
||||||
n.sons[i][j] = newSymNode(v)
|
n.sons[i][j] = newSymNode(v)
|
||||||
|
|
@ -737,7 +752,19 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
|
||||||
else:
|
else:
|
||||||
var v = symForVar(c, n.sons[i])
|
var v = symForVar(c, n.sons[i])
|
||||||
if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal)
|
if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal)
|
||||||
v.typ = iter.sons[i]
|
case iter.kind
|
||||||
|
of tyVar:
|
||||||
|
v.typ = newTypeS(tyVar, c)
|
||||||
|
v.typ.sons.add iterAfterVarLent[i]
|
||||||
|
if tfVarIsPtr in iter.flags:
|
||||||
|
v.typ.flags.incl tfVarIsPtr
|
||||||
|
of tyLent:
|
||||||
|
v.typ = newTypeS(tyLent, c)
|
||||||
|
v.typ.sons.add iterAfterVarLent[i]
|
||||||
|
if tfVarIsPtr in iter.flags:
|
||||||
|
v.typ.flags.incl tfVarIsPtr
|
||||||
|
else:
|
||||||
|
v.typ = iter.sons[i]
|
||||||
n.sons[i] = newSymNode(v)
|
n.sons[i] = newSymNode(v)
|
||||||
if sfGenSym notin v.flags:
|
if sfGenSym notin v.flags:
|
||||||
if not isDiscardUnderscore(v): addDecl(c, v)
|
if not isDiscardUnderscore(v): addDecl(c, v)
|
||||||
|
|
|
||||||
|
|
@ -371,8 +371,7 @@ proc transformYield(c: PTransf, n: PNode): PTransNode =
|
||||||
# c.transCon.forStmt.len == 3 means that there is one for loop variable
|
# c.transCon.forStmt.len == 3 means that there is one for loop variable
|
||||||
# and thus no tuple unpacking:
|
# and thus no tuple unpacking:
|
||||||
if e.typ.isNil: return result # can happen in nimsuggest for unknown reasons
|
if e.typ.isNil: return result # can happen in nimsuggest for unknown reasons
|
||||||
if skipTypes(e.typ, {tyGenericInst, tyAlias, tySink}).kind == tyTuple and
|
if c.transCon.forStmt.len != 3:
|
||||||
c.transCon.forStmt.len != 3:
|
|
||||||
e = skipConv(e)
|
e = skipConv(e)
|
||||||
if e.kind in {nkPar, nkTupleConstr}:
|
if e.kind in {nkPar, nkTupleConstr}:
|
||||||
for i in 0 ..< sonsLen(e):
|
for i in 0 ..< sonsLen(e):
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ iterator pairs*[T](a: openArray[T]): tuple[key: int, val: T] {.inline.} =
|
||||||
yield (i, a[i])
|
yield (i, a[i])
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
||||||
iterator mpairs*[T](a: var openArray[T]): tuple[key:int, val:var T]{.inline.} =
|
iterator mpairs*[T](a: var openArray[T]): tuple[key: int, val: var T]{.inline.} =
|
||||||
## Iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
|
## Iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
|
||||||
## ``a[index]`` can be modified.
|
## ``a[index]`` can be modified.
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
@ -102,7 +102,7 @@ iterator pairs*[IX, T](a: array[IX, T]): tuple[key: IX, val: T] {.inline.} =
|
||||||
if i >= high(IX): break
|
if i >= high(IX): break
|
||||||
inc(i)
|
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.
|
## Iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
|
||||||
## ``a[index]`` can be modified.
|
## ``a[index]`` can be modified.
|
||||||
var i = low(IX)
|
var i = low(IX)
|
||||||
|
|
@ -179,7 +179,6 @@ iterator mpairs*(a: var cstring): tuple[key: int, val: var char] {.inline.} =
|
||||||
yield (i, a[i])
|
yield (i, a[i])
|
||||||
inc(i)
|
inc(i)
|
||||||
|
|
||||||
|
|
||||||
iterator items*[T](a: seq[T]): T {.inline.} =
|
iterator items*[T](a: seq[T]): T {.inline.} =
|
||||||
## Iterates over each item of `a`.
|
## Iterates over each item of `a`.
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,62 @@ for a in items(arr):
|
||||||
|
|
||||||
echo ""
|
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 ")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue