mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-20 06:20:38 +00:00
destructors: supportsCopyMem finally works for recursive types
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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) =
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user