mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-04 20:17:42 +00:00
Instantiates generics in the module that uses it (#22513)
Attempts to move the generic instantiation to the module that uses it. This should decrease re-compilation times as the source module where the generic lives doesnt need to be recompiled --------- Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com> Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
This commit is contained in:
@@ -936,6 +936,7 @@ type
|
||||
# it won't cause problems
|
||||
# for skModule the string literal to output for
|
||||
# deprecated modules.
|
||||
instantiatedFrom*: PSym # for instances, the generic symbol where it came from.
|
||||
when defined(nimsuggest):
|
||||
allUsages*: seq[TLineInfo]
|
||||
|
||||
@@ -1936,7 +1937,7 @@ proc skipGenericOwner*(s: PSym): PSym =
|
||||
## Generic instantiations are owned by their originating generic
|
||||
## symbol. This proc skips such owners and goes straight to the owner
|
||||
## of the generic itself (the module or the enclosing proc).
|
||||
result = if s.kind in skProcKinds and sfFromGeneric in s.flags:
|
||||
result = if s.kind in skProcKinds and sfFromGeneric in s.flags and s.owner.kind != skModule:
|
||||
s.owner.owner
|
||||
else:
|
||||
s.owner
|
||||
|
||||
@@ -783,7 +783,10 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||
if conf.backend == backendJs or conf.cmd == cmdNimscript: discard
|
||||
else: processOnOffSwitchG(conf, {optThreads}, arg, pass, info)
|
||||
#if optThreads in conf.globalOptions: conf.setNote(warnGcUnsafe)
|
||||
of "tlsemulation": processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info)
|
||||
of "tlsemulation":
|
||||
processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info)
|
||||
if optTlsEmulation in conf.globalOptions:
|
||||
conf.legacyFeatures.incl emitGenerics
|
||||
of "implicitstatic":
|
||||
processOnOffSwitch(conf, {optImplicitStatic}, arg, pass, info)
|
||||
of "patterns", "trmacros":
|
||||
|
||||
@@ -413,6 +413,7 @@ proc storeSym*(s: PSym; c: var PackedEncoder; m: var PackedModule): PackedItemId
|
||||
p.annex = toPackedLib(s.annex, c, m)
|
||||
when hasFFI:
|
||||
p.cname = toLitId(s.cname, m)
|
||||
p.instantiatedFrom = s.instantiatedFrom.safeItemId(c, m)
|
||||
|
||||
# fill the reserved slot, nothing else:
|
||||
m.syms[s.itemId.item] = p
|
||||
@@ -876,6 +877,7 @@ proc symBodyFromPacked(c: var PackedDecoder; g: var PackedModuleGraph;
|
||||
if externalName != "":
|
||||
result.loc.r = rope externalName
|
||||
result.loc.flags = s.locFlags
|
||||
result.instantiatedFrom = loadSym(c, g, si, s.instantiatedFrom)
|
||||
|
||||
proc loadSym(c: var PackedDecoder; g: var PackedModuleGraph; thisModule: int; s: PackedItemId): PSym =
|
||||
if s == nilItemId:
|
||||
|
||||
@@ -71,6 +71,7 @@ type
|
||||
when hasFFI:
|
||||
cname*: LitId
|
||||
constraint*: NodeId
|
||||
instantiatedFrom*: PackedItemId
|
||||
|
||||
PackedType* = object
|
||||
kind*: TTypeKind
|
||||
|
||||
@@ -235,6 +235,9 @@ type
|
||||
laxEffects
|
||||
## Lax effects system prior to Nim 2.0.
|
||||
verboseTypeMismatch
|
||||
emitGenerics
|
||||
## generics are emitted in the module that contains them.
|
||||
## Useful for libraries that rely on local passC
|
||||
|
||||
SymbolFilesOption* = enum
|
||||
disabledSf, writeOnlySf, readOnlySf, v2Sf, stressTest
|
||||
|
||||
@@ -1129,6 +1129,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
|
||||
of wLocalPassc:
|
||||
assert sym != nil and sym.kind == skModule
|
||||
let s = expectStrLit(c, it)
|
||||
appendToModule(sym, n)
|
||||
extccomp.addLocalCompileOption(c.config, s, toFullPathConsiderDirty(c.config, sym.info.fileIndex))
|
||||
recordPragma(c, it, "localpassl", s)
|
||||
of wPush:
|
||||
|
||||
@@ -19,7 +19,8 @@ import
|
||||
intsets, transf, vmdef, vm, aliases, cgmeth, lambdalifting,
|
||||
evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity,
|
||||
lowerings, plugins/active, lineinfos, strtabs, int128,
|
||||
isolation_check, typeallowed, modulegraphs, enumtostr, concepts, astmsgs
|
||||
isolation_check, typeallowed, modulegraphs, enumtostr, concepts, astmsgs,
|
||||
extccomp
|
||||
|
||||
|
||||
when not defined(leanCompiler):
|
||||
|
||||
@@ -2543,7 +2543,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags; expectedType: P
|
||||
if n[0].kind == nkSym and sfFromGeneric in n[0].sym.flags:
|
||||
# may have been resolved to `@`[empty] at some point,
|
||||
# reset to `@` to deal with this
|
||||
n[0] = newSymNode(n[0].sym.owner, n[0].info)
|
||||
n[0] = newSymNode(n[0].sym.instantiatedFrom, n[0].info)
|
||||
n[1] = semExpr(c, n[1], flags, arrayType)
|
||||
result = semDirectOp(c, n, flags, expectedType)
|
||||
else:
|
||||
|
||||
@@ -313,6 +313,17 @@ proc fillMixinScope(c: PContext) =
|
||||
addSym(c.currentScope, n.sym)
|
||||
p = p.next
|
||||
|
||||
proc getLocalPassC(c: PContext, s: PSym): string =
|
||||
if s.ast == nil or s.ast.len == 0: return ""
|
||||
result = ""
|
||||
template extractPassc(p: PNode) =
|
||||
if p.kind == nkPragma and p[0][0].ident == c.cache.getIdent"localpassc":
|
||||
return p[0][1].strVal
|
||||
extractPassc(s.ast[0]) #it is set via appendToModule in pragmas (fast access)
|
||||
for n in s.ast:
|
||||
for p in n:
|
||||
extractPassc(p)
|
||||
|
||||
proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
info: TLineInfo): PSym =
|
||||
## Generates a new instance of a generic procedure.
|
||||
@@ -328,14 +339,22 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
var n = copyTree(fn.ast)
|
||||
# NOTE: for access of private fields within generics from a different module
|
||||
# we set the friend module:
|
||||
c.friendModules.add(getModule(fn))
|
||||
let producer = getModule(fn)
|
||||
c.friendModules.add(producer)
|
||||
let oldMatchedConcept = c.matchedConcept
|
||||
c.matchedConcept = nil
|
||||
let oldScope = c.currentScope
|
||||
while not isTopLevel(c): c.currentScope = c.currentScope.parent
|
||||
result = copySym(fn, c.idgen)
|
||||
incl(result.flags, sfFromGeneric)
|
||||
result.owner = fn
|
||||
result.instantiatedFrom = fn
|
||||
if sfGlobal in result.flags and c.config.symbolFiles != disabledSf:
|
||||
let passc = getLocalPassC(c, producer)
|
||||
if passc != "": #pass the local compiler options to the consumer module too
|
||||
extccomp.addLocalCompileOption(c.config, passc, toFullPathConsiderDirty(c.config, c.module.info.fileIndex))
|
||||
result.owner = c.module
|
||||
else:
|
||||
result.owner = fn
|
||||
result.ast = n
|
||||
pushOwner(c, result)
|
||||
|
||||
|
||||
@@ -502,6 +502,8 @@ proc semNewFinalize(c: PContext; n: PNode): PNode =
|
||||
getAttachedOp(c.graph, t, attachedDestructor).owner == fin:
|
||||
discard "already turned this one into a finalizer"
|
||||
else:
|
||||
if fin.instantiatedFrom != nil and fin.instantiatedFrom != fin.owner: #undo move
|
||||
fin.owner = fin.instantiatedFrom
|
||||
let wrapperSym = newSym(skProc, getIdent(c.graph.cache, fin.name.s & "FinalizerWrapper"), c.idgen, fin.owner, fin.info)
|
||||
let selfSymNode = newSymNode(copySym(fin.ast[paramsPos][1][0].sym, c.idgen))
|
||||
selfSymNode.typ = fin.typ[1]
|
||||
|
||||
@@ -1313,7 +1313,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
if a.kind == nkSym and a.sym.kind in skProcKinds and
|
||||
b.kind == nkSym and b.sym.kind in skProcKinds:
|
||||
regs[ra].intVal =
|
||||
if sfFromGeneric in a.sym.flags and a.sym.owner == b.sym: 1
|
||||
if sfFromGeneric in a.sym.flags and a.sym.instantiatedFrom == b.sym: 1
|
||||
else: 0
|
||||
else:
|
||||
stackTrace(c, tos, pc, "node is not a proc symbol")
|
||||
|
||||
@@ -2098,7 +2098,7 @@ proc toKey(s: PSym): string =
|
||||
result.add s.name.s
|
||||
if s.owner != nil:
|
||||
if sfFromGeneric in s.flags:
|
||||
s = s.owner.owner
|
||||
s = s.instantiatedFrom.owner
|
||||
else:
|
||||
s = s.owner
|
||||
result.add "."
|
||||
|
||||
11
tests/ic/tgenericinst.nim
Normal file
11
tests/ic/tgenericinst.nim
Normal file
@@ -0,0 +1,11 @@
|
||||
discard """
|
||||
cmd: "nim cpp --incremental:on $file"
|
||||
"""
|
||||
|
||||
{.emit:"""/*TYPESECTION*/
|
||||
#include <iostream>
|
||||
struct Foo { };
|
||||
""".}
|
||||
|
||||
type Foo {.importcpp.} = object
|
||||
echo $Foo() #Notice the generic is instantiate in the this module if not, it wouldnt find Foo
|
||||
Reference in New Issue
Block a user