diff --git a/compiler/ast.nim b/compiler/ast.nim index be11e80be2..08a991468d 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -738,6 +738,8 @@ type name*: Rope path*: PNode # can be a string literal! + CompilesId* = int ## id that is used for the caching logic within + ## ``system.compiles``. See the seminst module. TInstantiation* = object sym*: PSym concreteTypes*: seq[PType] @@ -745,6 +747,7 @@ type # needed in caas mode for purging the cache # XXX: it's possible to switch to a # simple ref count here + compilesId*: CompilesId PInstantiation* = ref TInstantiation diff --git a/compiler/semdata.nim b/compiler/semdata.nim index e6456293cd..48255c83d6 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -72,6 +72,7 @@ type inGenericContext*: int # > 0 if we are in a generic type inUnrolledContext*: int # > 0 if we are unrolling a loop inCompilesContext*: int # > 0 if we are in a ``compiles`` magic + compilesContextIdGenerator*: int inGenericInst*: int # > 0 if we are instantiating a generic converters*: TSymSeq # sequence of converters patterns*: TSymSeq # sequence of pattern matchers diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 0e1d52fd4c..9b0e029769 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1636,7 +1636,9 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # watch out, hacks ahead: let oldErrorCount = msgs.gErrorCounter let oldErrorMax = msgs.gErrorMax - inc c.inCompilesContext + let oldCompilesId = c.inCompilesContext + inc c.compilesContextIdGenerator + c.inCompilesContext = c.compilesContextIdGenerator # do not halt after first error: msgs.gErrorMax = high(int) @@ -1660,6 +1662,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = except ERecoverableError: discard # undo symbol table changes (as far as it's possible): + c.inCompilesContext = oldCompilesId c.generics = oldGenerics c.inGenericContext = oldInGenericContext c.inUnrolledContext = oldInUnrolledContext @@ -1668,7 +1671,6 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = msgs.setInfoContextLen(oldContextLen) setLen(gOwners, oldOwnerLen) c.currentScope = oldScope - dec c.inCompilesContext errorOutputs = oldErrorOutputs msgs.gErrorCounter = oldErrorCount msgs.gErrorMax = oldErrorMax diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 1c1d71a2f6..ca9c7c2c0f 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -47,10 +47,11 @@ proc sameInstantiation(a, b: TInstantiation): bool = flags = {ExactTypeDescValues}): return result = true -proc genericCacheGet(genericSym: PSym, entry: TInstantiation): PSym = +proc genericCacheGet(genericSym: PSym, entry: TInstantiation; + id: CompilesId): PSym = if genericSym.procInstCache != nil: for inst in genericSym.procInstCache: - if sameInstantiation(entry, inst[]): + if inst.compilesId == id and sameInstantiation(entry, inst[]): return inst.sym proc removeDefaultParamValues(n: PNode) = @@ -249,13 +250,15 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, if tfTriggersCompileTime in result.typ.flags: incl(result.flags, sfCompileTime) n.sons[genericParamsPos] = ast.emptyNode - var oldPrc = genericCacheGet(fn, entry[]) + var oldPrc = genericCacheGet(fn, entry[], c.inCompilesContext) if oldPrc == nil: # we MUST not add potentially wrong instantiations to the caching mechanism. # This means recursive instantiations behave differently when in # a ``compiles`` context but this is the lesser evil. See # bug #1055 (tevilcompiles). - if c.inCompilesContext == 0: fn.procInstCache.safeAdd(entry) + #if c.inCompilesContext == 0: + entry.compilesId = c.inCompilesContext + fn.procInstCache.safeAdd(entry) c.generics.add(makeInstPair(fn, entry)) if n.sons[pragmasPos].kind != nkEmpty: pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)