destructors: lift type bound ops to objects and arrays etc
This commit is contained in:
parent
a0c5260c20
commit
58d5f96790
4 changed files with 71 additions and 32 deletions
|
|
@ -22,7 +22,8 @@ type
|
||||||
recurse: bool
|
recurse: bool
|
||||||
|
|
||||||
proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode)
|
proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode)
|
||||||
proc liftBody(c: PContext; typ: PType; info: TLineInfo): PSym
|
proc liftBody(c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||||
|
info: TLineInfo): PSym {.discardable.}
|
||||||
|
|
||||||
proc at(a, i: PNode, elemType: PType): PNode =
|
proc at(a, i: PNode, elemType: PType): PNode =
|
||||||
result = newNodeI(nkBracketExpr, a.info, 2)
|
result = newNodeI(nkBracketExpr, a.info, 2)
|
||||||
|
|
@ -97,9 +98,37 @@ proc newOpCall(op: PSym; x: PNode): PNode =
|
||||||
result.add(newSymNode(op))
|
result.add(newSymNode(op))
|
||||||
result.add x
|
result.add x
|
||||||
|
|
||||||
|
proc destructorCall(c: PContext; op: PSym; x: PNode): PNode =
|
||||||
|
result = newNodeIT(nkCall, x.info, op.typ.sons[0])
|
||||||
|
result.add(newSymNode(op))
|
||||||
|
if newDestructors:
|
||||||
|
result.add genAddr(c, x)
|
||||||
|
else:
|
||||||
|
result.add x
|
||||||
|
|
||||||
proc newDeepCopyCall(op: PSym; x, y: PNode): PNode =
|
proc newDeepCopyCall(op: PSym; x, y: PNode): PNode =
|
||||||
result = newAsgnStmt(x, newOpCall(op, y))
|
result = newAsgnStmt(x, newOpCall(op, y))
|
||||||
|
|
||||||
|
proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
|
||||||
|
field: PSym): bool =
|
||||||
|
if tfHasAsgn in t.flags:
|
||||||
|
var op: PSym
|
||||||
|
if sameType(t, c.asgnForType):
|
||||||
|
# generate recursive call:
|
||||||
|
if c.recurse:
|
||||||
|
op = c.fn
|
||||||
|
else:
|
||||||
|
c.recurse = true
|
||||||
|
return false
|
||||||
|
else:
|
||||||
|
op = field
|
||||||
|
if op == nil:
|
||||||
|
op = liftBody(c.c, t, c.kind, c.info)
|
||||||
|
markUsed(c.info, op, c.c.graph.usageSym)
|
||||||
|
styleCheckUse(c.info, op)
|
||||||
|
body.add newAsgnCall(c.c, op, x, y)
|
||||||
|
result = true
|
||||||
|
|
||||||
proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||||
case c.kind
|
case c.kind
|
||||||
of attachedDestructor:
|
of attachedDestructor:
|
||||||
|
|
@ -107,26 +136,12 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
|
||||||
if op != nil:
|
if op != nil:
|
||||||
markUsed(c.info, op, c.c.graph.usageSym)
|
markUsed(c.info, op, c.c.graph.usageSym)
|
||||||
styleCheckUse(c.info, op)
|
styleCheckUse(c.info, op)
|
||||||
body.add newOpCall(op, x)
|
body.add destructorCall(c.c, op, x)
|
||||||
result = true
|
|
||||||
of attachedAsgn, attachedSink:
|
|
||||||
if tfHasAsgn in t.flags:
|
|
||||||
var op: PSym
|
|
||||||
if sameType(t, c.asgnForType):
|
|
||||||
# generate recursive call:
|
|
||||||
if c.recurse:
|
|
||||||
op = c.fn
|
|
||||||
else:
|
|
||||||
c.recurse = true
|
|
||||||
return false
|
|
||||||
else:
|
|
||||||
op = t.assignment
|
|
||||||
if op == nil:
|
|
||||||
op = liftBody(c.c, t, c.info)
|
|
||||||
markUsed(c.info, op, c.c.graph.usageSym)
|
|
||||||
styleCheckUse(c.info, op)
|
|
||||||
body.add newAsgnCall(c.c, op, x, y)
|
|
||||||
result = true
|
result = true
|
||||||
|
of attachedAsgn:
|
||||||
|
result = considerAsgnOrSink(c, t, body, x, y, t.assignment)
|
||||||
|
of attachedSink:
|
||||||
|
result = considerAsgnOrSink(c, t, body, x, y, t.sink)
|
||||||
of attachedDeepCopy:
|
of attachedDeepCopy:
|
||||||
let op = t.deepCopy
|
let op = t.deepCopy
|
||||||
if op != nil:
|
if op != nil:
|
||||||
|
|
@ -245,12 +260,20 @@ proc addParam(procType: PType; param: PSym) =
|
||||||
addSon(procType.n, newSymNode(param))
|
addSon(procType.n, newSymNode(param))
|
||||||
rawAddSon(procType, param.typ)
|
rawAddSon(procType, param.typ)
|
||||||
|
|
||||||
proc liftBody(c: PContext; typ: PType; info: TLineInfo): PSym =
|
proc liftBody(c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||||
|
info: TLineInfo): PSym {.discardable.} =
|
||||||
var a: TLiftCtx
|
var a: TLiftCtx
|
||||||
a.info = info
|
a.info = info
|
||||||
a.c = c
|
a.c = c
|
||||||
|
a.kind = kind
|
||||||
let body = newNodeI(nkStmtList, info)
|
let body = newNodeI(nkStmtList, info)
|
||||||
result = newSym(skProc, getIdent":lifted=", typ.owner, info)
|
let procname = case kind
|
||||||
|
of attachedAsgn: getIdent":Asgn"
|
||||||
|
of attachedSink: getIdent":Sink"
|
||||||
|
of attachedDeepCopy: getIdent":DeepCopy"
|
||||||
|
of attachedDestructor: getIdent":Destroy"
|
||||||
|
|
||||||
|
result = newSym(skProc, procname, typ.owner, info)
|
||||||
a.fn = result
|
a.fn = result
|
||||||
a.asgnForType = typ
|
a.asgnForType = typ
|
||||||
|
|
||||||
|
|
@ -261,7 +284,16 @@ proc liftBody(c: PContext; typ: PType; info: TLineInfo): PSym =
|
||||||
|
|
||||||
result.typ = newProcType(info, typ.owner)
|
result.typ = newProcType(info, typ.owner)
|
||||||
result.typ.addParam dest
|
result.typ.addParam dest
|
||||||
result.typ.addParam src
|
if kind != attachedDestructor:
|
||||||
|
result.typ.addParam src
|
||||||
|
|
||||||
|
# recursion is handled explicitly, but register the type based operation
|
||||||
|
# here in order to keep things robust against runaway recursions:
|
||||||
|
case kind
|
||||||
|
of attachedAsgn: typ.assignment = result
|
||||||
|
of attachedSink: typ.sink = result
|
||||||
|
of attachedDeepCopy: typ.deepCopy = result
|
||||||
|
of attachedDestructor: typ.destructor = result
|
||||||
|
|
||||||
liftBodyAux(a, typ, body, newSymNode(dest).newDeref, newSymNode(src))
|
liftBodyAux(a, typ, body, newSymNode(dest).newDeref, newSymNode(src))
|
||||||
|
|
||||||
|
|
@ -272,21 +304,18 @@ proc liftBody(c: PContext; typ: PType; info: TLineInfo): PSym =
|
||||||
n.sons[bodyPos] = body
|
n.sons[bodyPos] = body
|
||||||
result.ast = n
|
result.ast = n
|
||||||
|
|
||||||
# register late as recursion is handled differently
|
|
||||||
typ.assignment = result
|
|
||||||
#echo "Produced this ", n
|
|
||||||
|
|
||||||
proc getAsgnOrLiftBody(c: PContext; typ: PType; info: TLineInfo): PSym =
|
proc getAsgnOrLiftBody(c: PContext; typ: PType; info: TLineInfo): PSym =
|
||||||
let t = typ.skipTypes({tyGenericInst, tyVar, tyAlias})
|
let t = typ.skipTypes({tyGenericInst, tyVar, tyAlias})
|
||||||
result = t.assignment
|
result = t.assignment
|
||||||
if result.isNil:
|
if result.isNil:
|
||||||
result = liftBody(c, t, info)
|
result = liftBody(c, t, attachedAsgn, info)
|
||||||
|
|
||||||
proc overloadedAsgn(c: PContext; dest, src: PNode): PNode =
|
proc overloadedAsgn(c: PContext; dest, src: PNode): PNode =
|
||||||
let a = getAsgnOrLiftBody(c, dest.typ, dest.info)
|
let a = getAsgnOrLiftBody(c, dest.typ, dest.info)
|
||||||
result = newAsgnCall(c, a, dest, src)
|
result = newAsgnCall(c, a, dest, src)
|
||||||
|
|
||||||
proc liftTypeBoundOps*(c: PContext; typ: PType) =
|
proc liftTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) =
|
||||||
## In the semantic pass this is called in strategic places
|
## In the semantic pass this is called in strategic places
|
||||||
## to ensure we lift assignment, destructors and moves properly.
|
## to ensure we lift assignment, destructors and moves properly.
|
||||||
## Since this is done in the sem* routines generics already have
|
## Since this is done in the sem* routines generics already have
|
||||||
|
|
@ -295,3 +324,10 @@ proc liftTypeBoundOps*(c: PContext; typ: PType) =
|
||||||
## in the generic instantiations though.
|
## in the generic instantiations though.
|
||||||
## The later 'destroyer' pass depends on it.
|
## The later 'destroyer' pass depends on it.
|
||||||
if not newDestructors or not hasDestructor(typ): return
|
if not newDestructors or not hasDestructor(typ): return
|
||||||
|
# we generate the destructor first so that other operators can depend on it:
|
||||||
|
if typ.destructor == nil:
|
||||||
|
liftBody(c, typ, attachedDestructor, info)
|
||||||
|
if typ.assignment == nil:
|
||||||
|
liftBody(c, typ, attachedAsgn, info)
|
||||||
|
if typ.sink == nil:
|
||||||
|
liftBody(c, typ, attachedSink, info)
|
||||||
|
|
|
||||||
|
|
@ -670,7 +670,7 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
|
||||||
analyseIfAddressTakenInCall(c, result)
|
analyseIfAddressTakenInCall(c, result)
|
||||||
if callee.magic != mNone:
|
if callee.magic != mNone:
|
||||||
result = magicsAfterOverloadResolution(c, result, flags)
|
result = magicsAfterOverloadResolution(c, result, flags)
|
||||||
if result.typ != nil: liftTypeBoundOps(c, result.typ)
|
if result.typ != nil: liftTypeBoundOps(c, result.typ, n.info)
|
||||||
if c.matchedConcept == nil:
|
if c.matchedConcept == nil:
|
||||||
result = evalAtCompileTime(c, result)
|
result = evalAtCompileTime(c, result)
|
||||||
|
|
||||||
|
|
@ -1392,7 +1392,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
|
||||||
mode != noOverloadedAsgn:
|
mode != noOverloadedAsgn:
|
||||||
return overloadedAsgn(c, lhs, n.sons[1])
|
return overloadedAsgn(c, lhs, n.sons[1])
|
||||||
else:
|
else:
|
||||||
liftTypeBoundOps(c, lhs.typ)
|
liftTypeBoundOps(c, lhs.typ, lhs.info)
|
||||||
|
|
||||||
fixAbstractType(c, n)
|
fixAbstractType(c, n)
|
||||||
asgnToResultVar(c, n, n.sons[0], n.sons[1])
|
asgnToResultVar(c, n, n.sons[0], n.sons[1])
|
||||||
|
|
|
||||||
|
|
@ -553,7 +553,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
# this can only happen for errornous var statements:
|
# this can only happen for errornous var statements:
|
||||||
if typ == nil: continue
|
if typ == nil: continue
|
||||||
typeAllowedCheck(a.info, typ, symkind)
|
typeAllowedCheck(a.info, typ, symkind)
|
||||||
liftTypeBoundOps(c, typ)
|
liftTypeBoundOps(c, typ, a.info)
|
||||||
var tup = skipTypes(typ, {tyGenericInst, tyAlias})
|
var tup = skipTypes(typ, {tyGenericInst, tyAlias})
|
||||||
if a.kind == nkVarTuple:
|
if a.kind == nkVarTuple:
|
||||||
if tup.kind != tyTuple:
|
if tup.kind != tyTuple:
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ foo bar to appendmore here
|
||||||
foo bar to appendmore here
|
foo bar to appendmore here
|
||||||
foo bar to appendmore here
|
foo bar to appendmore here
|
||||||
foo bar to appendmore here
|
foo bar to appendmore here
|
||||||
after 16 16'''
|
after 20 20'''
|
||||||
cmd: '''nim c --newruntime $file'''
|
cmd: '''nim c --newruntime $file'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -92,5 +92,8 @@ proc main(n: int) =
|
||||||
a.add c
|
a.add c
|
||||||
echo cstring(a.data)
|
echo cstring(a.data)
|
||||||
|
|
||||||
|
var x: array[4, mystring]
|
||||||
|
for i in 0..high(x): x[i] = create"added to array"
|
||||||
|
|
||||||
main(1000)
|
main(1000)
|
||||||
echo "after ", allocCount, " ", deallocCount
|
echo "after ", allocCount, " ", deallocCount
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue