destructors: supportsCopyMem finally works for recursive types

This commit is contained in:
Araq
2017-10-25 08:39:56 +02:00
parent 4f2b79a380
commit 3aa7c2232e
6 changed files with 53 additions and 18 deletions

View File

@@ -319,6 +319,8 @@ proc liftTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) =
## to ensure we lift assignment, destructors and moves properly.
## The later 'destroyer' pass depends on it.
if not newDestructors or not hasDestructor(typ): return
# do not produce wrong liftings while we're still instantiating generics:
if c.typesWithOps.len > 0: return
let typ = typ.skipTypes({tyGenericInst, tyAlias})
# we generate the destructor first so that other operators can depend on it:
if typ.destructor == nil:

View File

@@ -132,6 +132,11 @@ type
recursiveDep*: string
suggestionsMade*: bool
inTypeContext*: int
typesWithOps*: seq[(PType, PType)] #\
# We need to instantiate the type bound ops lazily after
# the generic type has been constructed completely. See
# tests/destructor/topttree.nim for an example that
# would otherwise fail.
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
result.genericSym = s
@@ -219,6 +224,7 @@ proc newContext*(graph: ModuleGraph; module: PSym; cache: IdentCache): PContext
result.cache = cache
result.graph = graph
initStrTable(result.signatures)
result.typesWithOps = @[]
proc inclSym(sq: var TSymSeq, s: PSym) =

View File

@@ -1295,8 +1295,7 @@ proc symFromExpectedTypeNode(c: PContext, n: PNode): PSym =
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = nil
when defined(nimsuggest):
inc c.inTypeContext
inc c.inTypeContext
if gCmd == cmdIdeTools: suggestExpr(c, n)
case n.kind
@@ -1511,8 +1510,13 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
localError(n.info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
n.typ = result
when defined(nimsuggest):
dec c.inTypeContext
dec c.inTypeContext
if c.inTypeContext == 0: instAllTypeBoundOp(c, n.info)
when false:
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = semTypeNodeInner(c, n, prev)
instAllTypeBoundOp(c, n.info)
proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
# source : https://en.wikipedia.org/wiki/Data_structure_alignment#x86

View File

@@ -77,7 +77,7 @@ type
topLayer*: TIdTable
nextLayer*: ptr LayeredIdTable
TReplTypeVars* {.final.} = object
TReplTypeVars* = object
c*: PContext
typeMap*: ptr LayeredIdTable # map PType to PType
symMap*: TIdTable # map PSym to PSym
@@ -261,6 +261,17 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
if not (t.kind in tyMetaTypes or
(t.kind == tyStatic and t.n == nil)):
result.flags.excl tfInstClearedFlags
when false:
if newDestructors:
result.assignment = nil
#result.destructor = nil
result.sink = nil
template typeBound(c, newty, oldty, field, info) =
let opr = newty.field
if opr != nil and sfFromGeneric notin opr.flags:
# '=' needs to be instantiated for generics when the type is constructed:
newty.field = c.instTypeBoundOp(c, opr, oldty, info, attachedAsgn, 1)
proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
# tyGenericInvocation[A, tyGenericInvocation[A, B]]
@@ -357,16 +368,10 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
assert newbody.kind in {tyRef, tyPtr}
assert newbody.lastSon.typeInst == nil
newbody.lastSon.typeInst = result
template typeBound(field) =
let opr = newbody.field
if opr != nil and sfFromGeneric notin opr.flags:
# '=' needs to be instantiated for generics when the type is constructed:
newbody.field = cl.c.instTypeBoundOp(cl.c, opr, result, cl.info,
attachedAsgn, 1)
if newDestructors:
typeBound(destructor)
typeBound(sink)
typeBound(assignment)
cl.c.typesWithOps.add((newbody, result))
else:
typeBound(cl.c, newbody, result, assignment, cl.info)
let methods = skipTypes(bbody, abstractPtrs).methods
for col, meth in items(methods):
# we instantiate the known methods belonging to that type, this causes
@@ -534,6 +539,17 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
else: discard
proc instAllTypeBoundOp*(c: PContext, info: TLineInfo) =
if not newDestructors: return
var i = 0
while i < c.typesWithOps.len:
let (newty, oldty) = c.typesWithOps[i]
typeBound(c, newty, oldty, destructor, info)
typeBound(c, newty, oldty, sink, info)
typeBound(c, newty, oldty, assignment, info)
inc i
setLen(c.typesWithOps, 0)
proc initTypeVars*(p: PContext, typeMap: ptr LayeredIdTable, info: TLineInfo;
owner: PSym): TReplTypeVars =
initIdTable(result.symMap)

View File

@@ -2299,7 +2299,8 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
else:
result = c.semGenerateInstance(c, dc, m.bindings, info)
assert sfFromGeneric in result.flags
if op == attachedDeepCopy:
assert sfFromGeneric in result.flags
include suggest

View File

@@ -3,7 +3,11 @@ discard """
60.0
90.0
120.0
4 4'''
10.0
60.0
90.0
120.0
8 8'''
cmd: '''nim c --newruntime $file'''
"""
@@ -18,8 +22,8 @@ var
proc `=destroy`*[T](x: var opt[T]) =
if x.data != nil:
#when not supportsCopyMem(T):
`=destroy`(x.data[])
when not supportsCopyMem(T):
`=destroy`(x.data[])
dealloc(x.data)
inc deallocCount
x.data = nil
@@ -93,6 +97,8 @@ proc main =
insert t, 10.0
insert t, 120.0
write t
let copy = t
write copy
main()
echo allocCount, " ", deallocCount