simple programs now work with the new destroyer pass

This commit is contained in:
Andreas Rumpf 2017-10-12 17:42:15 +02:00
commit a2e4ab2e4e
4 changed files with 60 additions and 56 deletions

View file

@ -179,28 +179,34 @@ proc genDestroy(t: PType; dest: PNode): PNode =
assert t.destructor != nil assert t.destructor != nil
result = newTree(nkCall, newSymNode(t.destructor), newTree(nkHiddenAddr, dest)) result = newTree(nkCall, newSymNode(t.destructor), newTree(nkHiddenAddr, dest))
proc addTopVar(c: var Con; v: PNode) =
c.topLevelVars.add newTree(nkIdentDefs, v, emptyNode, emptyNode)
proc p(n: PNode; c: var Con): PNode
template recurse(n, dest) =
for i in 0..<n.len:
dest.add p(n[i], c)
proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
if ri.kind in nkCallKinds: if ri.kind in nkCallKinds:
result = genSink(ri.typ, dest) result = genSink(ri.typ, dest)
# watch out and no not transform 'ri' twice if it's a call:
let ri2 = copyNode(ri)
recurse(ri, ri2)
result.add ri2
elif ri.kind == nkSym and isHarmlessVar(ri.sym, c): elif ri.kind == nkSym and isHarmlessVar(ri.sym, c):
result = genSink(ri.typ, dest) result = genSink(ri.typ, dest)
result.add p(ri, c)
else: else:
result = genCopy(ri.typ, dest) result = genCopy(ri.typ, dest)
result.add p(ri, c)
proc addTopVar(c: var Con; v: PNode) = proc p(n: PNode; c: var Con): PNode =
c.topLevelVars.add newTree(nkIdentDefs, v, emptyNode)
proc p(n, parent: PNode; c: var Con) =
template recurse(n, dest) =
let x = dest
for i in 0..<n.safeLen:
p(n[i], x, c)
parent.add x
case n.kind case n.kind
of nkVarSection, nkLetSection: of nkVarSection, nkLetSection:
discard "transform; var x = y to var x; x op y where op is a move or copy" discard "transform; var x = y to var x; x op y where op is a move or copy"
var stmtList = newNodeI(nkStmtList, n.info) result = newNodeI(nkStmtList, n.info)
for i in 0..<n.len: for i in 0..<n.len:
let it = n[i] let it = n[i]
@ -208,10 +214,9 @@ proc p(n, parent: PNode; c: var Con) =
let ri = it[L] let ri = it[L]
if it.kind == nkVarTuple and hasDestructor(ri.typ): if it.kind == nkVarTuple and hasDestructor(ri.typ):
let x = lowerTupleUnpacking(it, c.owner) let x = lowerTupleUnpacking(it, c.owner)
p(x, stmtList, c) result.add p(x, c)
elif it.kind == nkIdentDefs and hasDestructor(it[0].typ): elif it.kind == nkIdentDefs and hasDestructor(it[0].typ):
it.sons[L] = emptyNode for j in 0..L-2:
for j in 0..L-1:
let v = it[j] let v = it[j]
doAssert v.kind == nkSym doAssert v.kind == nkSym
# move the variable declaration to the top of the frame: # move the variable declaration to the top of the frame:
@ -220,48 +225,45 @@ proc p(n, parent: PNode; c: var Con) =
c.destroys.add genDestroy(v.typ, v) c.destroys.add genDestroy(v.typ, v)
if ri.kind != nkEmpty: if ri.kind != nkEmpty:
let r = moveOrCopy(v, ri, c) let r = moveOrCopy(v, ri, c)
recurse(ri, r) result.add r
stmtList.add r
else: else:
# keep it, but transform 'ri': # keep it, but transform 'ri':
var varSection = copyNode(n) var varSection = copyNode(n)
var itCopy = copyNode(it) var itCopy = copyNode(it)
for j in 0..L-1: for j in 0..L-1:
itCopy.add it[j] itCopy.add it[j]
p(ri, itCopy, c) itCopy.add p(ri, c)
varSection.add itCopy varSection.add itCopy
stmtList.add varSection result.add varSection
parent.add stmtList
of nkCallKinds: of nkCallKinds:
if n.typ != nil and hasDestructor(n.typ): if n.typ != nil and hasDestructor(n.typ):
discard "produce temp creation" discard "produce temp creation"
let stmtList = newNodeIT(nkStmtListExpr, n.info, n.typ) result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let f = newSym(skField, getIdent(":d" & $c.tmpObj.n.len), c.owner, n.info) let f = newSym(skField, getIdent(":d" & $c.tmpObj.n.len), c.owner, n.info)
f.typ = n.typ
rawAddField c.tmpObj, f rawAddField c.tmpObj, f
var m = genSink(n.typ, rawDirectAccess(c.tmp, f)) var m = genSink(n.typ, rawDirectAccess(c.tmp, f))
recurse(n, m) var call = copyNode(n)
stmtList.add m recurse(n, call)
stmtList.add rawDirectAccess(c.tmp, f) m.add call
parent.add stmtList result.add m
result.add rawDirectAccess(c.tmp, f)
c.destroys.add genDestroy(n.typ, rawDirectAccess(c.tmp, f)) c.destroys.add genDestroy(n.typ, rawDirectAccess(c.tmp, f))
else: else:
recurse(n, copyNode(n)) result = copyNode(n)
recurse(n, result)
of nkAsgn, nkFastAsgn: of nkAsgn, nkFastAsgn:
if n[0].kind == nkSym and interestingSym(n[0].sym): if n[0].kind == nkSym and interestingSym(n[0].sym):
discard "use move or assignment" result = moveOrCopy(n[0], n[1], c)
let ri = n[1]
let r = moveOrCopy(n[0], ri, c)
# fortunately this skips the nkCall which we do not want to transform
# to a temp here!
recurse(ri, r)
parent.add r
else: else:
recurse(n, copyNode(n)) result = copyNode(n)
of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, recurse(n, result)
nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef: of nkNone..nkNilLit, nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef,
parent.add n nkIteratorDef, nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef:
result = n
else: else:
recurse(n, copyNode(n)) result = copyNode(n)
recurse(n, result)
proc injectDestructorCalls*(owner: PSym; n: PNode): PNode = proc injectDestructorCalls*(owner: PSym; n: PNode): PNode =
var c: Con var c: Con
@ -277,15 +279,15 @@ proc injectDestructorCalls*(owner: PSym; n: PNode): PNode =
for i in 0..<c.g.len: for i in 0..<c.g.len:
if c.g[i].kind in {goto, fork}: if c.g[i].kind in {goto, fork}:
c.jumpTargets.incl(i+c.g[i].dest) c.jumpTargets.incl(i+c.g[i].dest)
var stmtList = newNodeI(nkStmtList, n.info) let body = p(n, c)
for i in 0..<n.len:
p(n[i], stmtList, c)
if c.tmp.typ.n.len > 0: if c.tmp.typ.n.len > 0:
c.addTopVar(newSymNode c.tmp) c.addTopVar(newSymNode c.tmp)
result = newNodeI(nkStmtList, n.info) result = newNodeI(nkStmtList, n.info)
if c.topLevelVars.len > 0: if c.topLevelVars.len > 0:
result.add c.topLevelVars result.add c.topLevelVars
if c.destroys.len > 0: if c.destroys.len > 0:
result.add newTryFinally(stmtList, c.destroys) result.add newTryFinally(body, c.destroys)
else: else:
result.add stmtList result.add body
echo "transformed into: ", result

View file

@ -1383,6 +1383,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
typeMismatch(n.info, lhs.typ, rhs.typ) typeMismatch(n.info, lhs.typ, rhs.typ)
n.sons[1] = fitNode(c, le, rhs, n.info) n.sons[1] = fitNode(c, le, rhs, n.info)
when not newDestructors:
if tfHasAsgn in lhs.typ.flags and not lhsIsResult and if tfHasAsgn in lhs.typ.flags and not lhsIsResult and
mode != noOverloadedAsgn: mode != noOverloadedAsgn:
return overloadedAsgn(c, lhs, n.sons[1]) return overloadedAsgn(c, lhs, n.sons[1])

View file

@ -100,6 +100,7 @@ proc semProc(c: PContext, n: PNode): PNode
include semdestruct include semdestruct
proc semDestructorCheck(c: PContext, n: PNode, flags: TExprFlags) {.inline.} = proc semDestructorCheck(c: PContext, n: PNode, flags: TExprFlags) {.inline.} =
when not newDestructors:
if efAllowDestructor notin flags and if efAllowDestructor notin flags and
n.kind in nkCallKinds+{nkObjConstr,nkBracket}: n.kind in nkCallKinds+{nkObjConstr,nkBracket}:
if instantiateDestructor(c, n.typ) != nil: if instantiateDestructor(c, n.typ) != nil:
@ -116,7 +117,7 @@ proc semExprBranch(c: PContext, n: PNode): PNode =
# XXX tyGenericInst here? # XXX tyGenericInst here?
semProcvarCheck(c, result) semProcvarCheck(c, result)
if result.typ.kind == tyVar: result = newDeref(result) if result.typ.kind == tyVar: result = newDeref(result)
when not newDestructors: semDestructorCheck(c, result, {}) semDestructorCheck(c, result, {})
proc semExprBranchScope(c: PContext, n: PNode): PNode = proc semExprBranchScope(c: PContext, n: PNode): PNode =
openScope(c) openScope(c)

View file

@ -973,7 +973,7 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
incl(result.flags, nfTransf) incl(result.flags, nfTransf)
when useEffectSystem: trackProc(prc, result) when useEffectSystem: trackProc(prc, result)
if prc.kind == skFunc: if prc.kind == skFunc:
result = injectDestructorCalls(prc, n) result = injectDestructorCalls(prc, result)
#if prc.name.s == "testbody": #if prc.name.s == "testbody":
# echo renderTree(result) # echo renderTree(result)