diff --git a/compiler/seminst.nim b/compiler/seminst.nim index b5dca4c1bc..486065563d 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -88,7 +88,8 @@ proc sameInstantiation(a, b: TInstantiation): bool = if a.concreteTypes.len == b.concreteTypes.len: for i in 0..a.concreteTypes.high: if not compareTypes(a.concreteTypes[i], b.concreteTypes[i], - flags = {ExactTypeDescValues}): return + flags = {ExactTypeDescValues, + ExactGcSafety}): return result = true proc genericCacheGet(genericSym: PSym, entry: TInstantiation; diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 80fb9168b5..037b075107 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -243,6 +243,7 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType = proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = # tyGenericInvocation[A, tyGenericInvocation[A, B]] # is difficult to handle: + const eqFlags = eqTypeFlags + {tfGcSafe} var body = t.sons[0] if body.kind != tyGenericBody: internalError(cl.info, "no generic body") var header: PType = t @@ -252,7 +253,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = else: result = searchInstTypes(t) - if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return + if result != nil and eqFlags*result.flags == eqFlags*t.flags: return for i in countup(1, sonsLen(t) - 1): var x = t.sons[i] if x.kind in {tyGenericParam}: @@ -267,7 +268,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = if header != t: # search again after first pass: result = searchInstTypes(header) - if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return + if result != nil and eqFlags*result.flags == eqFlags*t.flags: return else: header = instCopyType(cl, t) diff --git a/compiler/types.nim b/compiler/types.nim index 2886ac619a..13b24ccf80 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -139,6 +139,9 @@ proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string = add(result, ')') if n.sons[0].typ != nil: result.add(": " & typeToString(n.sons[0].typ, prefer)) + result.add "[declared in " + result.add($sym.info) + result.add "]" proc elemType*(t: PType): PType = assert(t != nil) @@ -688,6 +691,7 @@ type ExactTypeDescValues ExactGenericParams ExactConstraints + ExactGcSafety AllowCommonBase TTypeCmpFlags* = set[TTypeCmpFlag] @@ -976,6 +980,8 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = cycleCheck() if a.kind == tyUserTypeClass and a.n != nil: return a.n == b.n result = sameChildrenAux(a, b, c) and sameFlags(a, b) + if result and ExactGcSafety in c.flags: + result = a.flags * {tfThread} == b.flags * {tfThread} if result and a.kind == tyProc: result = ((IgnoreCC in c.flags) or a.callConv == b.callConv) and ((ExactConstraints notin c.flags) or sameConstraints(a.n, b.n)) diff --git a/tests/generics/tproctypecache_falsepositive.nim b/tests/generics/tproctypecache_falsepositive.nim new file mode 100644 index 0000000000..4f24a1fc8f --- /dev/null +++ b/tests/generics/tproctypecache_falsepositive.nim @@ -0,0 +1,17 @@ + +import asyncdispatch + +type + Callback = proc() {.closure, gcsafe.} + GameState = ref object + playerChangeHandlers: seq[Callback] + +#proc dummy() = +# var x = newSeq[proc() {.cdecl, gcsafe.}]() + +proc newGameState(): GameState = + result = GameState( + playerChangeHandlers: newSeq[Callback]() # this fails + ) + +#dummy()