diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim index 40a4b74213..146309bbe5 100644 --- a/compiler/injectdestructors.nim +++ b/compiler/injectdestructors.nim @@ -636,7 +636,8 @@ proc reverseDestroys(destroys: seq[PNode]): seq[PNode] = result.add destroys[i] proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode = - if sfGeneratedOp in owner.flags or (owner.kind == skIterator and isInlineIterator(owner.typ)): return n + if sfGeneratedOp in owner.flags or (owner.kind == skIterator and isInlineIterator(owner.typ)): + return n var c: Con c.owner = owner c.destroys = newNodeI(nkStmtList, n.info) diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 2ea5f5263a..34b9d7ecc3 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -245,7 +245,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode = var env: PNode if owner.isIterator: let it = getHiddenParam(g, owner) - addUniqueField(it.typ.sons[0], hp, g.cache) + addUniqueField(it.typ.skipTypes({tyOwned}).sons[0], hp, g.cache) env = indirectAccess(newSymNode(it), hp, hp.info) else: let e = newSym(skLet, iter.name, owner, n.info) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 518b5e5e8b..ace2c79667 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -670,7 +670,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode = result = n var length = len(n) let iterBase = n.sons[length-2].typ - var iter = skipTypes(iterBase, {tyGenericInst, tyAlias, tySink}) + var iter = skipTypes(iterBase, {tyGenericInst, tyAlias, tySink, tyOwned}) var iterAfterVarLent = iter.skipTypes({tyLent, tyVar}) # length == 3 means that there is one for loop variable # and thus no tuple unpacking: @@ -683,18 +683,18 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode = var v = symForVar(c, n[0][i]) if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal) 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] + 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[0][i] = newSymNode(v) if sfGenSym notin v.flags: addDecl(c, v) elif v.owner == nil: v.owner = getCurrOwner(c) @@ -717,14 +717,14 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode = if n.sons[i].kind == nkVarTuple: var mutable = false var isLent = false - iter[i] = case iter[i].kind - of tyVar: - mutable = true - iter[i].skipTypes({tyVar}) - of tyLent: - isLent = true - iter[i].skipTypes({tyLent}) - else: iter[i] + case iter[i].kind + of tyVar: + mutable = true + iter[i] = iter[i].skipTypes({tyVar}) + of tyLent: + isLent = true + iter[i] = iter[i].skipTypes({tyLent}) + else: discard if len(n[i])-1 != len(iter[i]): localError(c.config, n[i].info, errWrongNumberOfVariables) @@ -871,8 +871,7 @@ proc semFor(c: PContext, n: PNode; flags: TExprFlags): PNode = result.kind = nkParForStmt else: result = semForFields(c, n, call.sons[0].sym.magic) - elif isCallExpr and call.sons[0].typ.callConv == ccClosure and - tfIterator in call.sons[0].typ.flags: + elif isCallExpr and isClosureIterator(call.sons[0].typ.skipTypes(abstractInst)): # first class iterator: result = semForVars(c, n, flags) elif not isCallExpr or call.sons[0].kind != nkSym or @@ -1984,6 +1983,9 @@ proc semIterator(c: PContext, n: PNode): PNode = s.typ.callConv = ccInline if n.sons[bodyPos].kind == nkEmpty and s.magic == mNone: localError(c.config, n.info, errImplOfXexpected % s.name.s) + if optOwnedRefs in c.config.globalOptions and result.typ != nil: + result.typ = makeVarType(c, result.typ, tyOwned) + result.typ.callConv = ccClosure proc semProc(c: PContext, n: PNode): PNode = result = semProcAux(c, n, skProc, procPragmas) diff --git a/compiler/transf.nim b/compiler/transf.nim index b95733a37e..5660bcd8c9 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -608,7 +608,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode = return result c.breakSyms.add(labl) if call.kind notin nkCallKinds or call.sons[0].kind != nkSym or - call.sons[0].typ.callConv == ccClosure: + call.sons[0].typ.skipTypes(abstractInst).callConv == ccClosure: result[1] = n.PTransNode result[1][^1] = transformLoopBody(c, n[^1]) result[1][^2] = transform(c, n[^2]) diff --git a/tests/destructor/tsimpleclosure.nim b/tests/destructor/tsimpleclosure.nim index 43b5cb2b63..583cc7d880 100644 --- a/tests/destructor/tsimpleclosure.nim +++ b/tests/destructor/tsimpleclosure.nim @@ -44,5 +44,21 @@ ok0() var ok1 = say ok1() +when false: + # bug #12443 + func newStringIterator(s: string): owned(iterator(): char) = + result = iterator(): char = + var pos = 0 + while pos < s.len: + yield s[pos] + inc pos + + proc stringIter() = + let si = newStringIterator("foo") + for i in si(): + echo i + + stringIter() + let (a, d) = allocCounters() discard cprintf("%ld %ld alloc/dealloc pairs: %ld\n", a, d, system.allocs)