simple programs now work with the new destroyer pass
This commit is contained in:
parent
d6c401acfb
commit
a2e4ab2e4e
4 changed files with 60 additions and 56 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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])
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue