destructors: supportsCopyMem finally works for recursive types
This commit is contained in:
parent
4f2b79a380
commit
3aa7c2232e
6 changed files with 53 additions and 18 deletions
|
|
@ -319,6 +319,8 @@ proc liftTypeBoundOps*(c: PContext; typ: PType; info: TLineInfo) =
|
||||||
## to ensure we lift assignment, destructors and moves properly.
|
## to ensure we lift assignment, destructors and moves properly.
|
||||||
## 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
|
||||||
|
# do not produce wrong liftings while we're still instantiating generics:
|
||||||
|
if c.typesWithOps.len > 0: return
|
||||||
let typ = typ.skipTypes({tyGenericInst, tyAlias})
|
let typ = typ.skipTypes({tyGenericInst, tyAlias})
|
||||||
# we generate the destructor first so that other operators can depend on it:
|
# we generate the destructor first so that other operators can depend on it:
|
||||||
if typ.destructor == nil:
|
if typ.destructor == nil:
|
||||||
|
|
|
||||||
|
|
@ -132,6 +132,11 @@ type
|
||||||
recursiveDep*: string
|
recursiveDep*: string
|
||||||
suggestionsMade*: bool
|
suggestionsMade*: bool
|
||||||
inTypeContext*: int
|
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 =
|
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
|
||||||
result.genericSym = s
|
result.genericSym = s
|
||||||
|
|
@ -219,6 +224,7 @@ proc newContext*(graph: ModuleGraph; module: PSym; cache: IdentCache): PContext
|
||||||
result.cache = cache
|
result.cache = cache
|
||||||
result.graph = graph
|
result.graph = graph
|
||||||
initStrTable(result.signatures)
|
initStrTable(result.signatures)
|
||||||
|
result.typesWithOps = @[]
|
||||||
|
|
||||||
|
|
||||||
proc inclSym(sq: var TSymSeq, s: PSym) =
|
proc inclSym(sq: var TSymSeq, s: PSym) =
|
||||||
|
|
|
||||||
|
|
@ -1295,8 +1295,7 @@ proc symFromExpectedTypeNode(c: PContext, n: PNode): PSym =
|
||||||
|
|
||||||
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
result = nil
|
result = nil
|
||||||
when defined(nimsuggest):
|
inc c.inTypeContext
|
||||||
inc c.inTypeContext
|
|
||||||
|
|
||||||
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
if gCmd == cmdIdeTools: suggestExpr(c, n)
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
@ -1511,8 +1510,13 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
localError(n.info, errTypeExpected)
|
localError(n.info, errTypeExpected)
|
||||||
result = newOrPrevType(tyError, prev, c)
|
result = newOrPrevType(tyError, prev, c)
|
||||||
n.typ = result
|
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) =
|
proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
|
||||||
# source : https://en.wikipedia.org/wiki/Data_structure_alignment#x86
|
# source : https://en.wikipedia.org/wiki/Data_structure_alignment#x86
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ type
|
||||||
topLayer*: TIdTable
|
topLayer*: TIdTable
|
||||||
nextLayer*: ptr LayeredIdTable
|
nextLayer*: ptr LayeredIdTable
|
||||||
|
|
||||||
TReplTypeVars* {.final.} = object
|
TReplTypeVars* = object
|
||||||
c*: PContext
|
c*: PContext
|
||||||
typeMap*: ptr LayeredIdTable # map PType to PType
|
typeMap*: ptr LayeredIdTable # map PType to PType
|
||||||
symMap*: TIdTable # map PSym to PSym
|
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
|
if not (t.kind in tyMetaTypes or
|
||||||
(t.kind == tyStatic and t.n == nil)):
|
(t.kind == tyStatic and t.n == nil)):
|
||||||
result.flags.excl tfInstClearedFlags
|
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 =
|
proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
# tyGenericInvocation[A, tyGenericInvocation[A, B]]
|
# 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.kind in {tyRef, tyPtr}
|
||||||
assert newbody.lastSon.typeInst == nil
|
assert newbody.lastSon.typeInst == nil
|
||||||
newbody.lastSon.typeInst = result
|
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:
|
if newDestructors:
|
||||||
typeBound(destructor)
|
cl.c.typesWithOps.add((newbody, result))
|
||||||
typeBound(sink)
|
else:
|
||||||
typeBound(assignment)
|
typeBound(cl.c, newbody, result, assignment, cl.info)
|
||||||
let methods = skipTypes(bbody, abstractPtrs).methods
|
let methods = skipTypes(bbody, abstractPtrs).methods
|
||||||
for col, meth in items(methods):
|
for col, meth in items(methods):
|
||||||
# we instantiate the known methods belonging to that type, this causes
|
# 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
|
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;
|
proc initTypeVars*(p: PContext, typeMap: ptr LayeredIdTable, info: TLineInfo;
|
||||||
owner: PSym): TReplTypeVars =
|
owner: PSym): TReplTypeVars =
|
||||||
initIdTable(result.symMap)
|
initIdTable(result.symMap)
|
||||||
|
|
|
||||||
|
|
@ -2299,7 +2299,8 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
|
||||||
localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
|
localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
|
||||||
else:
|
else:
|
||||||
result = c.semGenerateInstance(c, dc, m.bindings, info)
|
result = c.semGenerateInstance(c, dc, m.bindings, info)
|
||||||
assert sfFromGeneric in result.flags
|
if op == attachedDeepCopy:
|
||||||
|
assert sfFromGeneric in result.flags
|
||||||
|
|
||||||
include suggest
|
include suggest
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,11 @@ discard """
|
||||||
60.0
|
60.0
|
||||||
90.0
|
90.0
|
||||||
120.0
|
120.0
|
||||||
4 4'''
|
10.0
|
||||||
|
60.0
|
||||||
|
90.0
|
||||||
|
120.0
|
||||||
|
8 8'''
|
||||||
cmd: '''nim c --newruntime $file'''
|
cmd: '''nim c --newruntime $file'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
@ -18,8 +22,8 @@ var
|
||||||
|
|
||||||
proc `=destroy`*[T](x: var opt[T]) =
|
proc `=destroy`*[T](x: var opt[T]) =
|
||||||
if x.data != nil:
|
if x.data != nil:
|
||||||
#when not supportsCopyMem(T):
|
when not supportsCopyMem(T):
|
||||||
`=destroy`(x.data[])
|
`=destroy`(x.data[])
|
||||||
dealloc(x.data)
|
dealloc(x.data)
|
||||||
inc deallocCount
|
inc deallocCount
|
||||||
x.data = nil
|
x.data = nil
|
||||||
|
|
@ -93,6 +97,8 @@ proc main =
|
||||||
insert t, 10.0
|
insert t, 10.0
|
||||||
insert t, 120.0
|
insert t, 120.0
|
||||||
write t
|
write t
|
||||||
|
let copy = t
|
||||||
|
write copy
|
||||||
|
|
||||||
main()
|
main()
|
||||||
echo allocCount, " ", deallocCount
|
echo allocCount, " ", deallocCount
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue