diff options
-rw-r--r-- | compiler/destroyer.nim | 26 | ||||
-rw-r--r-- | compiler/sem.nim | 20 | ||||
-rw-r--r-- | compiler/semasgn.nim | 46 | ||||
-rw-r--r-- | compiler/semexprs.nim | 13 | ||||
-rw-r--r-- | compiler/semmagic.nim | 11 | ||||
-rw-r--r-- | compiler/transf.nim | 3 | ||||
-rw-r--r-- | lib/system.nim | 4 | ||||
-rw-r--r-- | tests/destructor/topttree.nim (renamed from tests/destructor/tbintree.nim) | 13 |
8 files changed, 109 insertions, 27 deletions
diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim index fde592f52..a868a64ba 100644 --- a/compiler/destroyer.nim +++ b/compiler/destroyer.nim @@ -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) = diff --git a/compiler/sem.nim b/compiler/sem.nim index ebfdafea7..5e98d7a65 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -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) diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim index 895946281..0454ea379 100644 --- a/compiler/semasgn.nim +++ b/compiler/semasgn.nim @@ -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) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 49dfbe8f4..2c80db52c 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -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) diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 88f1262ae..ba19e0865 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -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: diff --git a/compiler/transf.nim b/compiler/transf.nim index c3d12dafe..b7383c9b8 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -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 diff --git a/lib/system.nim b/lib/system.nim index 10560edaa..585c32556 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -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) diff --git a/tests/destructor/tbintree.nim b/tests/destructor/topttree.nim index 12ba052cf..a6380a2d5 100644 --- a/tests/destructor/tbintree.nim +++ b/tests/destructor/topttree.nim @@ -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: |