Fix transformation of yield in inline context (#9135)
When the loop variables are part of the envP block it is not safe to use a nkFastAsgn. Fixes #2656
This commit is contained in:
parent
21ecf64d24
commit
f98a3056c6
2 changed files with 63 additions and 15 deletions
|
|
@ -110,8 +110,8 @@ proc transformSons(c: PTransf, n: PNode): PTransNode =
|
||||||
for i in countup(0, sonsLen(n)-1):
|
for i in countup(0, sonsLen(n)-1):
|
||||||
result[i] = transform(c, n.sons[i])
|
result[i] = transform(c, n.sons[i])
|
||||||
|
|
||||||
proc newAsgnStmt(c: PTransf, le: PNode, ri: PTransNode): PTransNode =
|
proc newAsgnStmt(c: PTransf, kind: TNodeKind, le: PNode, ri: PTransNode): PTransNode =
|
||||||
result = newTransNode(nkFastAsgn, PNode(ri).info, 2)
|
result = newTransNode(kind, PNode(ri).info, 2)
|
||||||
result[0] = PTransNode(le)
|
result[0] = PTransNode(le)
|
||||||
result[1] = ri
|
result[1] = ri
|
||||||
|
|
||||||
|
|
@ -299,12 +299,6 @@ proc transformBreak(c: PTransf, n: PNode): PTransNode =
|
||||||
else:
|
else:
|
||||||
result = n.PTransNode
|
result = n.PTransNode
|
||||||
|
|
||||||
proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
|
|
||||||
# XXX: BUG: what if `n` is an expression with side-effects?
|
|
||||||
for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
|
|
||||||
add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
|
|
||||||
transform(c, newTupleAccess(c.graph, n, i))))
|
|
||||||
|
|
||||||
proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
|
proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkSym:
|
of nkSym:
|
||||||
|
|
@ -328,6 +322,18 @@ proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
|
||||||
result[i] = introduceNewLocalVars(c, n.sons[i])
|
result[i] = introduceNewLocalVars(c, n.sons[i])
|
||||||
|
|
||||||
proc transformYield(c: PTransf, n: PNode): PTransNode =
|
proc transformYield(c: PTransf, n: PNode): PTransNode =
|
||||||
|
proc asgnTo(lhs: PNode, rhs: PTransNode): PTransNode =
|
||||||
|
# Choose the right assignment instruction according to the given ``lhs``
|
||||||
|
# node since it may not be a nkSym (a stack-allocated skForVar) but a
|
||||||
|
# nkDotExpr (a heap-allocated slot into the envP block)
|
||||||
|
case lhs.kind:
|
||||||
|
of nkSym:
|
||||||
|
internalAssert c.graph.config, lhs.sym.kind == skForVar
|
||||||
|
result = newAsgnStmt(c, nkFastAsgn, lhs, rhs)
|
||||||
|
of nkDotExpr:
|
||||||
|
result = newAsgnStmt(c, nkAsgn, lhs, rhs)
|
||||||
|
else:
|
||||||
|
internalAssert c.graph.config, false
|
||||||
result = newTransNode(nkStmtList, n.info, 0)
|
result = newTransNode(nkStmtList, n.info, 0)
|
||||||
var e = n.sons[0]
|
var e = n.sons[0]
|
||||||
# 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
|
||||||
|
|
@ -340,13 +346,20 @@ proc transformYield(c: PTransf, n: PNode): PTransNode =
|
||||||
for i in countup(0, sonsLen(e) - 1):
|
for i in countup(0, sonsLen(e) - 1):
|
||||||
var v = e.sons[i]
|
var v = e.sons[i]
|
||||||
if v.kind == nkExprColonExpr: v = v.sons[1]
|
if v.kind == nkExprColonExpr: v = v.sons[1]
|
||||||
add(result, newAsgnStmt(c, c.transCon.forStmt.sons[i],
|
let lhs = c.transCon.forStmt.sons[i]
|
||||||
transform(c, v)))
|
let rhs = transform(c, v)
|
||||||
|
add(result, asgnTo(lhs, rhs))
|
||||||
else:
|
else:
|
||||||
unpackTuple(c, e, result)
|
# Unpack the tuple into the loop variables
|
||||||
|
# XXX: BUG: what if `n` is an expression with side-effects?
|
||||||
|
for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
|
||||||
|
let lhs = c.transCon.forStmt.sons[i]
|
||||||
|
let rhs = transform(c, newTupleAccess(c.graph, e, i))
|
||||||
|
add(result, asgnTo(lhs, rhs))
|
||||||
else:
|
else:
|
||||||
var x = transform(c, e)
|
let lhs = c.transCon.forStmt.sons[0]
|
||||||
add(result, newAsgnStmt(c, c.transCon.forStmt.sons[0], x))
|
let rhs = transform(c, e)
|
||||||
|
add(result, asgnTo(lhs, rhs))
|
||||||
|
|
||||||
inc(c.transCon.yieldStmts)
|
inc(c.transCon.yieldStmts)
|
||||||
if c.transCon.yieldStmts <= 1:
|
if c.transCon.yieldStmts <= 1:
|
||||||
|
|
@ -584,7 +597,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||||
# generate a temporary and produce an assignment statement:
|
# generate a temporary and produce an assignment statement:
|
||||||
var temp = newTemp(c, formal.typ, formal.info)
|
var temp = newTemp(c, formal.typ, formal.info)
|
||||||
addVar(v, temp)
|
addVar(v, temp)
|
||||||
add(stmtList, newAsgnStmt(c, temp, arg.PTransNode))
|
add(stmtList, newAsgnStmt(c, nkFastAsgn, temp, arg.PTransNode))
|
||||||
idNodeTablePut(newC.mapping, formal, temp)
|
idNodeTablePut(newC.mapping, formal, temp)
|
||||||
of paVarAsgn:
|
of paVarAsgn:
|
||||||
assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
|
assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
|
||||||
|
|
@ -595,7 +608,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||||
addSonSkipIntLit(typ, formal.typ.sons[0])
|
addSonSkipIntLit(typ, formal.typ.sons[0])
|
||||||
var temp = newTemp(c, typ, formal.info)
|
var temp = newTemp(c, typ, formal.info)
|
||||||
addVar(v, temp)
|
addVar(v, temp)
|
||||||
add(stmtList, newAsgnStmt(c, temp, arg.PTransNode))
|
add(stmtList, newAsgnStmt(c, nkFastAsgn, temp, arg.PTransNode))
|
||||||
idNodeTablePut(newC.mapping, formal, temp)
|
idNodeTablePut(newC.mapping, formal, temp)
|
||||||
|
|
||||||
var body = iter.getBody.copyTree
|
var body = iter.getBody.copyTree
|
||||||
|
|
|
||||||
35
tests/cnstseq/t2656.nim
Normal file
35
tests/cnstseq/t2656.nim
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
discard """
|
||||||
|
output: '''
|
||||||
|
onetwothree
|
||||||
|
onetwothree
|
||||||
|
onetwothree
|
||||||
|
one1two2three3
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
iterator it1(args: seq[string]): string =
|
||||||
|
for s in args: yield s
|
||||||
|
iterator it2(args: seq[string]): string {.closure.} =
|
||||||
|
for s in args: yield s
|
||||||
|
iterator it3(args: openArray[string]): string {.closure.} =
|
||||||
|
for s in args: yield s
|
||||||
|
iterator it4(args: openArray[(string, string)]): string {.closure.} =
|
||||||
|
for s1, s2 in items(args): yield s1 & s2
|
||||||
|
|
||||||
|
block:
|
||||||
|
const myConstSeq = @["one", "two", "three"]
|
||||||
|
for s in it1(myConstSeq):
|
||||||
|
stdout.write s
|
||||||
|
echo ""
|
||||||
|
for s in it2(myConstSeq):
|
||||||
|
stdout.write s
|
||||||
|
echo ""
|
||||||
|
for s in it3(myConstSeq):
|
||||||
|
stdout.write s
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
block:
|
||||||
|
const myConstSeq = @[("one", "1"), ("two", "2"), ("three", "3")]
|
||||||
|
for s in it4(myConstSeq):
|
||||||
|
stdout.write s
|
||||||
|
echo ""
|
||||||
Loading…
Add table
Add a link
Reference in a new issue