mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
destructors: work in progress
This commit is contained in:
@@ -93,7 +93,7 @@
|
||||
|
||||
import
|
||||
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
|
||||
strutils, options, dfa, lowerings
|
||||
strutils, options, dfa, lowerings, rodread
|
||||
|
||||
const
|
||||
InterestingSyms = {skVar, skResult, skLet}
|
||||
@@ -164,20 +164,44 @@ proc isHarmlessVar*(s: PSym; c: Con): bool =
|
||||
template interestingSym(s: PSym): bool =
|
||||
s.owner == c.owner and s.kind in InterestingSyms and hasDestructor(s.typ)
|
||||
|
||||
proc patchHead(n: PNode; alreadyPatched: var IntSet) =
|
||||
if n.kind in nkCallKinds and n[0].kind == nkSym and n.len > 1:
|
||||
let s = n[0].sym
|
||||
if sfFromGeneric in s.flags or true:
|
||||
if s.name.s[0] == '=' and not containsOrIncl(alreadyPatched, s.id):
|
||||
patchHead(s.getBody, alreadyPatched)
|
||||
let t = n[1].typ.skipTypes({tyVar, tyGenericInst, tyAlias, tyInferred})
|
||||
template patch(op, field) =
|
||||
if s.name.s == op and field != nil: #and field != s:
|
||||
n.sons[0].sym = field
|
||||
patch "=sink", t.sink
|
||||
patch "=", t.assignment
|
||||
patch "=destroy", t.destructor
|
||||
for x in n:
|
||||
patchHead(x, alreadyPatched)
|
||||
|
||||
template patchHead(n: PNode) =
|
||||
when false:
|
||||
var alreadyPatched = initIntSet()
|
||||
patchHead(n, alreadyPatched)
|
||||
|
||||
proc genSink(t: PType; dest: PNode): PNode =
|
||||
let t = t.skipTypes({tyGenericInst, tyAlias})
|
||||
let op = if t.sink != nil: t.sink else: t.assignment
|
||||
assert op != nil
|
||||
patchHead op.ast[bodyPos]
|
||||
result = newTree(nkCall, newSymNode(op), newTree(nkHiddenAddr, dest))
|
||||
|
||||
proc genCopy(t: PType; dest: PNode): PNode =
|
||||
let t = t.skipTypes({tyGenericInst, tyAlias})
|
||||
assert t.assignment != nil
|
||||
patchHead t.assignment.ast[bodyPos]
|
||||
result = newTree(nkCall, newSymNode(t.assignment), newTree(nkHiddenAddr, dest))
|
||||
|
||||
proc genDestroy(t: PType; dest: PNode): PNode =
|
||||
let t = t.skipTypes({tyGenericInst, tyAlias})
|
||||
assert t.destructor != nil
|
||||
patchHead t.destructor.ast[bodyPos]
|
||||
result = newTree(nkCall, newSymNode(t.destructor), newTree(nkHiddenAddr, dest))
|
||||
|
||||
proc addTopVar(c: var Con; v: PNode) =
|
||||
|
||||
@@ -522,14 +522,18 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
||||
else:
|
||||
result = n
|
||||
result = semStmt(c, result)
|
||||
# BUGFIX: process newly generated generics here, not at the end!
|
||||
if c.lastGenericIdx < c.generics.len:
|
||||
var a = newNodeI(nkStmtList, n.info)
|
||||
addCodeForGenerics(c, a)
|
||||
if sonsLen(a) > 0:
|
||||
# a generic has been added to `a`:
|
||||
if result.kind != nkEmpty: addSon(a, result)
|
||||
result = a
|
||||
when false:
|
||||
# Code generators are lazy now and can deal with undeclared procs, so these
|
||||
# steps are not required anymore and actually harmful for the upcoming
|
||||
# destructor support.
|
||||
# BUGFIX: process newly generated generics here, not at the end!
|
||||
if c.lastGenericIdx < c.generics.len:
|
||||
var a = newNodeI(nkStmtList, n.info)
|
||||
addCodeForGenerics(c, a)
|
||||
if sonsLen(a) > 0:
|
||||
# a generic has been added to `a`:
|
||||
if result.kind != nkEmpty: addSon(a, result)
|
||||
result = a
|
||||
result = hloStmt(c, result)
|
||||
if gCmd == cmdInteractive and not isEmptyType(result.typ):
|
||||
result = buildEchoStmt(c, result)
|
||||
|
||||
@@ -268,10 +268,10 @@ proc liftBody(c: PContext; typ: PType; kind: TTypeAttachedOp;
|
||||
a.kind = kind
|
||||
let body = newNodeI(nkStmtList, info)
|
||||
let procname = case kind
|
||||
of attachedAsgn: getIdent":Asgn"
|
||||
of attachedSink: getIdent":Sink"
|
||||
of attachedDeepCopy: getIdent":DeepCopy"
|
||||
of attachedDestructor: getIdent":Destroy"
|
||||
of attachedAsgn: getIdent"="
|
||||
of attachedSink: getIdent"=sink"
|
||||
of attachedDeepCopy: getIdent"=deepcopy"
|
||||
of attachedDestructor: getIdent"=destroy"
|
||||
|
||||
result = newSym(skProc, procname, typ.owner, info)
|
||||
a.fn = result
|
||||
@@ -314,6 +314,24 @@ proc overloadedAsgn(c: PContext; dest, src: PNode): PNode =
|
||||
let a = getAsgnOrLiftBody(c, dest.typ, dest.info)
|
||||
result = newAsgnCall(c, a, dest, src)
|
||||
|
||||
proc patchHead(n: PNode; alreadyPatched: var IntSet) =
|
||||
when true:
|
||||
if n.kind in nkCallKinds and n[0].kind == nkSym and n.len > 1:
|
||||
let s = n[0].sym
|
||||
if sfFromGeneric in s.flags:
|
||||
if not containsOrIncl(alreadyPatched, s.id):
|
||||
patchHead(s.getBody, alreadyPatched)
|
||||
let t = n[1].typ.skipTypes({tyVar, tyGenericInst, tyAlias, tyInferred})
|
||||
template patch(op, field) =
|
||||
if s.name.s == op and field != nil and field != s:
|
||||
n.sons[0].sym = field
|
||||
|
||||
patch "=sink", t.sink
|
||||
patch "=", t.assignment
|
||||
patch "=destroy", t.destructor
|
||||
for x in n:
|
||||
patchHead(x, alreadyPatched)
|
||||
|
||||
proc liftTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) =
|
||||
## In the semantic pass this is called in strategic places
|
||||
## to ensure we lift assignment, destructors and moves properly.
|
||||
@@ -321,6 +339,20 @@ proc liftTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) =
|
||||
if not newDestructors or not hasDestructor(typ): return
|
||||
let typ = typ.skipTypes({tyGenericInst, tyAlias})
|
||||
# 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)
|
||||
var changed = false
|
||||
if typ.destructor != nil and typ.destructor.magic == mAsgn:
|
||||
typ.destructor = nil
|
||||
if typ.destructor == nil:
|
||||
liftBody(c, typ, attachedDestructor, info)
|
||||
changed = true
|
||||
if typ.assignment == nil:
|
||||
liftBody(c, typ, attachedAsgn, info)
|
||||
changed = true
|
||||
if typ.sink == nil:
|
||||
liftBody(c, typ, attachedSink, info)
|
||||
changed = true
|
||||
if changed:
|
||||
var alreadyPatched = initIntSet()
|
||||
patchHead(typ.destructor.getBody, alreadyPatched)
|
||||
patchHead(typ.assignment.getBody, alreadyPatched)
|
||||
patchHead(typ.sink.getBody, alreadyPatched)
|
||||
|
||||
@@ -664,6 +664,19 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
|
||||
of skMacro: result = semMacroExpr(c, result, orig, callee, flags)
|
||||
of skTemplate: result = semTemplateExpr(c, result, callee, flags)
|
||||
else:
|
||||
when false:
|
||||
if callee.name.s[0] == '=' and result.len > 1:
|
||||
# careful, do not skip tyDistinct here:
|
||||
let t = result[1].typ.skipTypes({tyVar, tyGenericInst, tyAlias, tyInferred})
|
||||
|
||||
proc patchHead(callee: PSym; name: string; field: PSym; result: PNode) =
|
||||
if callee.name.s == name and field != nil:
|
||||
result.sons[0].sym = field
|
||||
|
||||
patchHead(callee, "=destroy", t.destructor, result)
|
||||
patchHead(callee, "=sink", t.sink, result)
|
||||
patchHead(callee, "=", t.assignment, result)
|
||||
|
||||
semFinishOperands(c, result)
|
||||
activate(c, result)
|
||||
fixAbstractType(c, result)
|
||||
|
||||
@@ -147,8 +147,9 @@ proc evalTypeTrait(traitCall: PNode, operand: PType, context: PSym): PNode =
|
||||
of "stripGenericParams":
|
||||
result = uninstantiate(operand).toNode(traitCall.info)
|
||||
of "supportsCopyMem":
|
||||
let complexObj = containsGarbageCollectedRef(operand) or
|
||||
hasDestructor(operand)
|
||||
let t = operand.skipTypes({tyVar, tyGenericInst, tyAlias, tyInferred})
|
||||
let complexObj = containsGarbageCollectedRef(t) or
|
||||
hasDestructor(t)
|
||||
result = newIntNodeT(ord(not complexObj), traitCall)
|
||||
else:
|
||||
localError(traitCall.info, "unknown trait")
|
||||
@@ -251,7 +252,11 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
result = semTypeOf(c, n.sons[1])
|
||||
of mArrGet: result = semArrGet(c, n, flags)
|
||||
of mArrPut: result = semArrPut(c, n, flags)
|
||||
of mAsgn: result = semAsgnOpr(c, n)
|
||||
of mAsgn:
|
||||
if n[0].sym.name.s == "=":
|
||||
result = semAsgnOpr(c, n)
|
||||
else:
|
||||
result = n
|
||||
of mIsPartOf: result = semIsPartOf(c, n, flags)
|
||||
of mTypeTrait: result = semTypeTraits(c, n)
|
||||
of mAstToStr:
|
||||
|
||||
@@ -365,16 +365,19 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
|
||||
# addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
|
||||
n.sons[0].sons[0] = m.sons[0]
|
||||
result = PTransNode(n.sons[0])
|
||||
PNode(result).typ = n.typ
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
var m = n.sons[0].sons[1]
|
||||
if m.kind == a or m.kind == b:
|
||||
# addr ( nkConv ( deref ( x ) ) ) --> nkConv(x)
|
||||
n.sons[0].sons[1] = m.sons[0]
|
||||
result = PTransNode(n.sons[0])
|
||||
PNode(result).typ = n.typ
|
||||
else:
|
||||
if n.sons[0].kind == a or n.sons[0].kind == b:
|
||||
# addr ( deref ( x )) --> x
|
||||
result = PTransNode(n.sons[0].sons[0])
|
||||
PNode(result).typ = n.typ
|
||||
|
||||
proc generateThunk(prc: PNode, dest: PType): PNode =
|
||||
## Converts 'prc' into '(thunk, nil)' so that it's compatible with
|
||||
|
||||
@@ -300,10 +300,10 @@ when defined(nimArrIdx):
|
||||
x: S) {.noSideEffect, magic: "ArrPut".}
|
||||
proc `=`*[T](dest: var T; src: T) {.noSideEffect, magic: "Asgn".}
|
||||
when defined(nimNewRuntime):
|
||||
proc `=destroy`*[T](x: var T) {.inline.} =
|
||||
proc `=destroy`*[T](x: var T) {.inline, magic: "Asgn".} =
|
||||
## generic `destructor`:idx: implementation that can be overriden.
|
||||
discard
|
||||
proc `=sink`*[T](x: var T; y: T) {.inline.} =
|
||||
proc `=sink`*[T](x: var T; y: T) {.inline, magic: "Asgn".} =
|
||||
## generic `sink`:idx: implementation that can be overriden.
|
||||
shallowCopy(x, y)
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ var
|
||||
proc `=destroy`*[T](x: var opt[T]) =
|
||||
if x.data != nil:
|
||||
when not supportsCopyMem(T):
|
||||
`=destroy`(x.data)
|
||||
`=destroy`(x.data[])
|
||||
dealloc(x.data)
|
||||
inc deallocCount
|
||||
x.data = nil
|
||||
@@ -69,11 +69,12 @@ proc createTree(data: float): Tree =
|
||||
result.data = data
|
||||
|
||||
proc insert(t: var opt[Tree]; newVal: float) =
|
||||
if it ?= t:
|
||||
if it.data > newVal:
|
||||
insert(it.le, newVal)
|
||||
elif it.data < newVal:
|
||||
insert(it.ri, newVal)
|
||||
#if it ?= t:
|
||||
if t.data != nil:
|
||||
if newVal < t.data[].data:
|
||||
insert(t.data[].le, newVal)
|
||||
elif t.data[].data < newVal:
|
||||
insert(t.data[].ri, newVal)
|
||||
else:
|
||||
discard "already in the tree"
|
||||
else:
|
||||
Reference in New Issue
Block a user