diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim index 5ae9feec2..b93cb34da 100644 --- a/compiler/semasgn.nim +++ b/compiler/semasgn.nim @@ -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: diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 8b5803a7f..b6b5db101 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -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) = diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index fbb5d0b6b..06c76a853 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -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 diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 3b99ea562..0f49398f2 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -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) diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 25981b826..b4e79e7e9 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -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 diff --git a/tests/destructor/topttree.nim b/tests/destructor/topttree.nim index 45f2f66e6..924644392 100644 --- a/tests/destructor/topttree.nim +++ b/tests/destructor/topttree.nim @@ -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