compilation cache: mostly working; generics not yet
This commit is contained in:
parent
9fb97e24bf
commit
9fb36bd20c
17 changed files with 160 additions and 2949 deletions
|
|
@ -568,7 +568,7 @@ const
|
||||||
ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet,
|
ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet,
|
||||||
tyTuple, tySequence}
|
tyTuple, tySequence}
|
||||||
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator,
|
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator,
|
||||||
skMacro, skTemplate, skConverter, skStub}
|
skMacro, skTemplate, skConverter, skEnumField, skStub}
|
||||||
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfAllConst}
|
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfAllConst}
|
||||||
namePos* = 0
|
namePos* = 0
|
||||||
genericParamsPos* = 1
|
genericParamsPos* = 1
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ type
|
||||||
PRodReader* = ref TRodReader
|
PRodReader* = ref TRodReader
|
||||||
|
|
||||||
const
|
const
|
||||||
FileVersion* = "1024" # modify this if the rod-format changes!
|
FileVersion* = "1026" # modify this if the rod-format changes!
|
||||||
|
|
||||||
var rodCompilerprocs*: TStrTable
|
var rodCompilerprocs*: TStrTable
|
||||||
|
|
||||||
|
|
@ -657,12 +657,21 @@ proc decodeSymSafePos(rd: PRodReader, offset: int, info: TLineInfo): PSym =
|
||||||
result = decodeSym(rd, info)
|
result = decodeSym(rd, info)
|
||||||
rd.pos = oldPos
|
rd.pos = oldPos
|
||||||
|
|
||||||
|
proc findSomeWhere(id: int) =
|
||||||
|
for i in countup(0, high(gMods)):
|
||||||
|
var rd = gMods[i].rd
|
||||||
|
if rd != nil:
|
||||||
|
var d = IITableGet(rd.index.tab, id)
|
||||||
|
if d != invalidKey:
|
||||||
|
echo "found id ", id, " in ", gMods[i].filename
|
||||||
|
|
||||||
proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
|
proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
|
||||||
result = PSym(IdTableGet(r.syms, id))
|
result = PSym(IdTableGet(r.syms, id))
|
||||||
if result == nil:
|
if result == nil:
|
||||||
# load the symbol:
|
# load the symbol:
|
||||||
var d = IITableGet(r.index.tab, id)
|
var d = IITableGet(r.index.tab, id)
|
||||||
if d == invalidKey:
|
if d == invalidKey:
|
||||||
|
# import from other module:
|
||||||
var moduleID = IiTableGet(r.imports.tab, id)
|
var moduleID = IiTableGet(r.imports.tab, id)
|
||||||
if moduleID < 0:
|
if moduleID < 0:
|
||||||
var x = ""
|
var x = ""
|
||||||
|
|
@ -680,6 +689,7 @@ proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
|
||||||
else:
|
else:
|
||||||
var x = ""
|
var x = ""
|
||||||
encodeVInt(id, x)
|
encodeVInt(id, x)
|
||||||
|
when false: findSomeWhere(id)
|
||||||
InternalError(info, "rrGetSym: no reader found: +" & x)
|
InternalError(info, "rrGetSym: no reader found: +" & x)
|
||||||
else:
|
else:
|
||||||
#if IiTableGet(rd.index.tab, id) <> invalidKey then
|
#if IiTableGet(rd.index.tab, id) <> invalidKey then
|
||||||
|
|
|
||||||
|
|
@ -322,7 +322,10 @@ proc addToIndex(w: var TIndex, key, val: int) =
|
||||||
w.lastIdxVal = val
|
w.lastIdxVal = val
|
||||||
IiTablePut(w.tab, key, val)
|
IiTablePut(w.tab, key, val)
|
||||||
|
|
||||||
#var debugWritten = initIntSet()
|
const debugWrittenIds = false
|
||||||
|
|
||||||
|
when debugWrittenIds:
|
||||||
|
var debugWritten = initIntSet()
|
||||||
|
|
||||||
proc symStack(w: PRodWriter) =
|
proc symStack(w: PRodWriter) =
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
@ -335,10 +338,12 @@ proc symStack(w: PRodWriter) =
|
||||||
# put definition in here
|
# put definition in here
|
||||||
var L = w.data.len
|
var L = w.data.len
|
||||||
addToIndex(w.index, s.id, L)
|
addToIndex(w.index, s.id, L)
|
||||||
#intSetIncl(debugWritten, s.id)
|
when debugWrittenIds: incl(debugWritten, s.id)
|
||||||
encodeSym(w, s, w.data)
|
encodeSym(w, s, w.data)
|
||||||
add(w.data, rodNL)
|
add(w.data, rodNL)
|
||||||
if sfExported in s.flags and s.kind in ExportableSymKinds:
|
# put into interface section if appropriate:
|
||||||
|
if {sfExported, sfFromGeneric} * s.flags == {sfExported} and
|
||||||
|
s.kind in ExportableSymKinds:
|
||||||
encodeStr(s.name.s, w.interf)
|
encodeStr(s.name.s, w.interf)
|
||||||
add(w.interf, ' ')
|
add(w.interf, ' ')
|
||||||
encodeVInt(s.id, w.interf)
|
encodeVInt(s.id, w.interf)
|
||||||
|
|
@ -355,12 +360,14 @@ proc symStack(w: PRodWriter) =
|
||||||
if w.methods.len != 0: add(w.methods, ' ')
|
if w.methods.len != 0: add(w.methods, ' ')
|
||||||
encodeVInt(s.id, w.methods)
|
encodeVInt(s.id, w.methods)
|
||||||
elif IiTableGet(w.imports.tab, s.id) == invalidKey:
|
elif IiTableGet(w.imports.tab, s.id) == invalidKey:
|
||||||
addToIndex(w.imports, s.id, m.id) #if not Contains(debugWritten, s.id):
|
addToIndex(w.imports, s.id, m.id)
|
||||||
# MessageOut(w.filename);
|
when debugWrittenIds:
|
||||||
# debug(s.owner);
|
if not Contains(debugWritten, s.id):
|
||||||
# debug(s);
|
echo(w.filename)
|
||||||
# InternalError('BUG!!!!');
|
debug(s)
|
||||||
#end
|
debug(s.owner)
|
||||||
|
debug(m)
|
||||||
|
InternalError("BUG!!!!")
|
||||||
inc(i)
|
inc(i)
|
||||||
setlen(w.sstack, 0)
|
setlen(w.sstack, 0)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -126,13 +126,13 @@ proc semConstBoolExpr(c: PContext, n: PNode): PNode =
|
||||||
include semtypes, semexprs, semgnrc, semstmts
|
include semtypes, semexprs, semgnrc, semstmts
|
||||||
|
|
||||||
proc addCodeForGenerics(c: PContext, n: PNode) =
|
proc addCodeForGenerics(c: PContext, n: PNode) =
|
||||||
for i in countup(lastGenericIdx, Len(generics) - 1):
|
for i in countup(c.generics.lastGenericIdx, Len(c.generics.generics) - 1):
|
||||||
var prc = generics[i].instSym
|
var prc = c.generics.generics[i].instSym
|
||||||
if prc.kind in {skProc, skMethod, skConverter} and prc.magic == mNone:
|
if prc.kind in {skProc, skMethod, skConverter} and prc.magic == mNone:
|
||||||
if prc.ast == nil or prc.ast.sons[codePos] == nil:
|
if prc.ast == nil or prc.ast.sons[codePos] == nil:
|
||||||
InternalError(prc.info, "no code for " & prc.name.s)
|
InternalError(prc.info, "no code for " & prc.name.s)
|
||||||
addSon(n, prc.ast)
|
addSon(n, prc.ast)
|
||||||
lastGenericIdx = Len(generics)
|
c.generics.lastGenericIdx = Len(c.generics.generics)
|
||||||
|
|
||||||
proc semExprNoFlags(c: PContext, n: PNode): PNode {.procvar.} =
|
proc semExprNoFlags(c: PContext, n: PNode): PNode {.procvar.} =
|
||||||
result = semExpr(c, n, {})
|
result = semExpr(c, n, {})
|
||||||
|
|
@ -162,7 +162,7 @@ proc myOpenCached(module: PSym, filename: string,
|
||||||
proc SemStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
proc SemStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
||||||
result = semStmt(c, n)
|
result = semStmt(c, n)
|
||||||
# BUGFIX: process newly generated generics here, not at the end!
|
# BUGFIX: process newly generated generics here, not at the end!
|
||||||
if lastGenericIdx < Len(generics):
|
if c.generics.lastGenericIdx < Len(c.generics.generics):
|
||||||
var a = newNodeI(nkStmtList, n.info)
|
var a = newNodeI(nkStmtList, n.info)
|
||||||
addCodeForGenerics(c, a)
|
addCodeForGenerics(c, a)
|
||||||
if sonsLen(a) > 0:
|
if sonsLen(a) > 0:
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
# This module contains the data structures for the semantic checking phase.
|
## This module contains the data structures for the semantic checking phase.
|
||||||
|
|
||||||
import
|
import
|
||||||
strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab,
|
strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab,
|
||||||
|
|
@ -37,10 +37,24 @@ type
|
||||||
genericSym*, instSym*: PSym
|
genericSym*, instSym*: PSym
|
||||||
concreteTypes*: seq[PType]
|
concreteTypes*: seq[PType]
|
||||||
|
|
||||||
|
# If we generate an instance of a generic, we'd like to re-use that
|
||||||
|
# instance if possible across module boundaries. However, this is not
|
||||||
|
# possible if the compilation cache is enabled. So we give up then and use
|
||||||
|
# the caching of generics only per module, not per project.
|
||||||
|
TGenericsCache* {.final.} = object
|
||||||
|
InstTypes*: TIdTable # map PType to PType
|
||||||
|
generics*: seq[TInstantiatedSymbol] # a list of the things to compile
|
||||||
|
lastGenericIdx*: int # used for the generics stack
|
||||||
|
|
||||||
|
PGenericsCache* = ref TGenericsCache
|
||||||
PContext* = ref TContext
|
PContext* = ref TContext
|
||||||
TContext* = object of TPassContext # a context represents a module
|
TContext* = object of TPassContext # a context represents a module
|
||||||
module*: PSym # the module sym belonging to the context
|
module*: PSym # the module sym belonging to the context
|
||||||
p*: PProcCon # procedure context
|
p*: PProcCon # procedure context
|
||||||
|
generics*: PGenericsCache # may point to a global or module-local structure
|
||||||
|
friendModule*: PSym # current friend module; may access private data;
|
||||||
|
# this is used so that generic instantiations can
|
||||||
|
# access private object fields
|
||||||
InstCounter*: int # to prevent endless instantiations
|
InstCounter*: int # to prevent endless instantiations
|
||||||
|
|
||||||
threadEntries*: TSymSeq # list of thread entries to check
|
threadEntries*: TSymSeq # list of thread entries to check
|
||||||
|
|
@ -56,10 +70,13 @@ type
|
||||||
filename*: string # the module's filename
|
filename*: string # the module's filename
|
||||||
userPragmas*: TStrTable
|
userPragmas*: TStrTable
|
||||||
|
|
||||||
|
var
|
||||||
|
gGenericsCache: PGenericsCache # save for modularity
|
||||||
|
|
||||||
var gInstTypes*: TIdTable # map PType to PType
|
proc newGenericsCache: PGenericsCache =
|
||||||
var generics*: seq[TInstantiatedSymbol] = @[] # a list of the things to compile
|
new(result)
|
||||||
var lastGenericIdx*: int # used for the generics stack
|
initIdTable(result.InstTypes)
|
||||||
|
result.generics = @[]
|
||||||
|
|
||||||
proc newContext*(module: PSym, nimfile: string): PContext
|
proc newContext*(module: PSym, nimfile: string): PContext
|
||||||
|
|
||||||
|
|
@ -126,11 +143,21 @@ proc newContext(module: PSym, nimfile: string): PContext =
|
||||||
initLinkedList(result.libs)
|
initLinkedList(result.libs)
|
||||||
append(result.optionStack, newOptionEntry())
|
append(result.optionStack, newOptionEntry())
|
||||||
result.module = module
|
result.module = module
|
||||||
|
result.friendModule = module
|
||||||
result.threadEntries = @[]
|
result.threadEntries = @[]
|
||||||
result.converters = @[]
|
result.converters = @[]
|
||||||
result.filename = nimfile
|
result.filename = nimfile
|
||||||
result.includedFiles = initIntSet()
|
result.includedFiles = initIntSet()
|
||||||
initStrTable(result.userPragmas)
|
initStrTable(result.userPragmas)
|
||||||
|
if optSymbolFiles notin gGlobalOptions:
|
||||||
|
# re-usage of generic instantiations across module boundaries is
|
||||||
|
# very nice for code size:
|
||||||
|
if gGenericsCache == nil: gGenericsCache = newGenericsCache()
|
||||||
|
result.generics = gGenericsCache
|
||||||
|
else:
|
||||||
|
# we have to give up and use a per-module cache for generic instantiations:
|
||||||
|
result.generics = newGenericsCache()
|
||||||
|
assert gGenericsCache == nil
|
||||||
|
|
||||||
proc addConverter(c: PContext, conv: PSym) =
|
proc addConverter(c: PContext, conv: PSym) =
|
||||||
var L = len(c.converters)
|
var L = len(c.converters)
|
||||||
|
|
@ -190,4 +217,3 @@ proc checkSonsLen*(n: PNode, length: int) =
|
||||||
proc checkMinSonsLen*(n: PNode, length: int) =
|
proc checkMinSonsLen*(n: PNode, length: int) =
|
||||||
if sonsLen(n) < length: illFormedAst(n)
|
if sonsLen(n) < length: illFormedAst(n)
|
||||||
|
|
||||||
initIdTable(gInstTypes)
|
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,9 @@ proc inlineConst(n: PNode, s: PSym): PNode {.inline.} =
|
||||||
proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
case s.kind
|
case s.kind
|
||||||
of skProc, skMethod, skIterator, skConverter:
|
of skProc, skMethod, skIterator, skConverter:
|
||||||
|
var smoduleId = getModule(s).id
|
||||||
if sfProcVar notin s.flags and s.typ.callConv == ccDefault and
|
if sfProcVar notin s.flags and s.typ.callConv == ccDefault and
|
||||||
getModule(s).id != c.module.id:
|
smoduleId != c.module.id and smoduleId != c.friendModule.id:
|
||||||
LocalError(n.info, errXCannotBePassedToProcVar, s.name.s)
|
LocalError(n.info, errXCannotBePassedToProcVar, s.name.s)
|
||||||
result = symChoice(c, n, s)
|
result = symChoice(c, n, s)
|
||||||
of skConst:
|
of skConst:
|
||||||
|
|
@ -673,8 +674,10 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
if ty.sons[0] == nil: break
|
if ty.sons[0] == nil: break
|
||||||
ty = skipTypes(ty.sons[0], {tyGenericInst})
|
ty = skipTypes(ty.sons[0], {tyGenericInst})
|
||||||
if f != nil:
|
if f != nil:
|
||||||
if sfExported in f.flags or getModule(f).id == c.module.id:
|
var fmoduleId = getModule(f).id
|
||||||
# is the access to a public field or in the same module?
|
if sfExported in f.flags or fmoduleId == c.module.id or
|
||||||
|
fmoduleId == c.friendModule.id:
|
||||||
|
# is the access to a public field or in the same module or in a friend?
|
||||||
n.sons[0] = makeDeref(n.sons[0])
|
n.sons[0] = makeDeref(n.sons[0])
|
||||||
n.sons[1] = newSymNode(f) # we now have the correct field
|
n.sons[1] = newSymNode(f) # we now have the correct field
|
||||||
n.typ = f.typ
|
n.typ = f.typ
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||||
if q.typ.kind notin {tyTypeDesc, tyGenericParam}: continue
|
if q.typ.kind notin {tyTypeDesc, tyGenericParam}: continue
|
||||||
var s = newSym(skType, q.name, getCurrOwner())
|
var s = newSym(skType, q.name, getCurrOwner())
|
||||||
s.info = q.info
|
s.info = q.info
|
||||||
incl(s.flags, sfUsed)
|
s.flags = s.flags + {sfUsed, sfFromGeneric}
|
||||||
var t = PType(IdTableGet(pt, q.typ))
|
var t = PType(IdTableGet(pt, q.typ))
|
||||||
if t == nil:
|
if t == nil:
|
||||||
LocalError(a.info, errCannotInstantiateX, s.name.s)
|
LocalError(a.info, errCannotInstantiateX, s.name.s)
|
||||||
|
|
@ -45,9 +45,9 @@ proc sameInstantiation(a, b: TInstantiatedSymbol): bool =
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc GenericCacheGet(c: PContext, entry: var TInstantiatedSymbol): PSym =
|
proc GenericCacheGet(c: PContext, entry: var TInstantiatedSymbol): PSym =
|
||||||
for i in countup(0, Len(generics) - 1):
|
for i in countup(0, Len(c.generics.generics) - 1):
|
||||||
if sameInstantiation(entry, generics[i]):
|
if sameInstantiation(entry, c.generics.generics[i]):
|
||||||
result = generics[i].instSym
|
result = c.generics.generics[i].instSym
|
||||||
# checking for the concrete parameter list is wrong and unnecessary!
|
# checking for the concrete parameter list is wrong and unnecessary!
|
||||||
#if equalParams(b.typ.n, instSym.typ.n) == paramsEqual:
|
#if equalParams(b.typ.n, instSym.typ.n) == paramsEqual:
|
||||||
#echo "found in cache: ", getProcHeader(result)
|
#echo "found in cache: ", getProcHeader(result)
|
||||||
|
|
@ -86,9 +86,9 @@ proc instantiateBody(c: PContext, n: PNode, result: PSym) =
|
||||||
popProcCon(c)
|
popProcCon(c)
|
||||||
|
|
||||||
proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
|
proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
|
||||||
for i in countup(0, Len(generics) - 1):
|
for i in countup(0, Len(c.generics.generics) - 1):
|
||||||
if generics[i].genericSym.id == s.id:
|
if c.generics.generics[i].genericSym.id == s.id:
|
||||||
var oldPrc = generics[i].instSym
|
var oldPrc = c.generics.generics[i].instSym
|
||||||
pushInfoContext(oldPrc.info)
|
pushInfoContext(oldPrc.info)
|
||||||
openScope(c.tab)
|
openScope(c.tab)
|
||||||
var n = oldPrc.ast
|
var n = oldPrc.ast
|
||||||
|
|
@ -112,10 +112,9 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
if c.InstCounter > 1000: InternalError(fn.ast.info, "nesting too deep")
|
if c.InstCounter > 1000: InternalError(fn.ast.info, "nesting too deep")
|
||||||
inc(c.InstCounter)
|
inc(c.InstCounter)
|
||||||
# NOTE: for access of private fields within generics from a different module
|
# NOTE: for access of private fields within generics from a different module
|
||||||
# and other identifiers we fake the current module temporarily!
|
# we set the friend module:
|
||||||
# XXX bad hack!
|
var oldFriend = c.friendModule
|
||||||
var oldMod = c.module
|
c.friendModule = getModule(fn)
|
||||||
c.module = getModule(fn)
|
|
||||||
result = copySym(fn, false)
|
result = copySym(fn, false)
|
||||||
incl(result.flags, sfFromGeneric)
|
incl(result.flags, sfFromGeneric)
|
||||||
result.owner = getCurrOwner().owner
|
result.owner = getCurrOwner().owner
|
||||||
|
|
@ -144,7 +143,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
ParamsTypeCheck(c, result.typ)
|
ParamsTypeCheck(c, result.typ)
|
||||||
var oldPrc = GenericCacheGet(c, entry)
|
var oldPrc = GenericCacheGet(c, entry)
|
||||||
if oldPrc == nil:
|
if oldPrc == nil:
|
||||||
generics.add(entry)
|
c.generics.generics.add(entry)
|
||||||
if n.sons[pragmasPos].kind != nkEmpty:
|
if n.sons[pragmasPos].kind != nkEmpty:
|
||||||
pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
|
pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
|
||||||
instantiateBody(c, n, result)
|
instantiateBody(c, n, result)
|
||||||
|
|
@ -154,7 +153,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
popInfoContext()
|
popInfoContext()
|
||||||
closeScope(c.tab) # close scope for parameters
|
closeScope(c.tab) # close scope for parameters
|
||||||
popOwner()
|
popOwner()
|
||||||
c.module = oldMod
|
c.friendModule = oldFriend
|
||||||
dec(c.InstCounter)
|
dec(c.InstCounter)
|
||||||
|
|
||||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
|
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
|
||||||
|
|
|
||||||
|
|
@ -527,7 +527,6 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
typ = paramType(c, a.sons[length-2], genericParams, cl)
|
typ = paramType(c, a.sons[length-2], genericParams, cl)
|
||||||
#if matchType(typ, [(tyVar, 0)], tyGenericInvokation):
|
#if matchType(typ, [(tyVar, 0)], tyGenericInvokation):
|
||||||
# debug a.sons[length-2][0][1]
|
# debug a.sons[length-2][0][1]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
typ = nil
|
typ = nil
|
||||||
if a.sons[length-1].kind != nkEmpty:
|
if a.sons[length-1].kind != nkEmpty:
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
var header: PType = nil
|
var header: PType = nil
|
||||||
when true:
|
when true:
|
||||||
# search for some instantiation here:
|
# search for some instantiation here:
|
||||||
result = searchInstTypes(gInstTypes, t)
|
result = searchInstTypes(cl.c.generics.InstTypes, t)
|
||||||
if result != nil: return
|
if result != nil: return
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
for i in countup(1, sonsLen(t) - 1):
|
||||||
var x = t.sons[i]
|
var x = t.sons[i]
|
||||||
|
|
@ -116,7 +116,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
#idTablePut(cl.typeMap, body.sons[i-1], x)
|
#idTablePut(cl.typeMap, body.sons[i-1], x)
|
||||||
if header != nil:
|
if header != nil:
|
||||||
# search again after first pass:
|
# search again after first pass:
|
||||||
result = searchInstTypes(gInstTypes, header)
|
result = searchInstTypes(cl.c.generics.InstTypes, header)
|
||||||
if result != nil: return
|
if result != nil: return
|
||||||
else:
|
else:
|
||||||
header = copyType(t, t.owner, false)
|
header = copyType(t, t.owner, false)
|
||||||
|
|
@ -124,7 +124,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
# we need to add the candidate here, before it's fully instantiated for
|
# we need to add the candidate here, before it's fully instantiated for
|
||||||
# recursive instantions:
|
# recursive instantions:
|
||||||
result = newType(tyGenericInst, t.sons[0].owner)
|
result = newType(tyGenericInst, t.sons[0].owner)
|
||||||
idTablePut(gInstTypes, header, result)
|
idTablePut(cl.c.generics.InstTypes, header, result)
|
||||||
|
|
||||||
for i in countup(1, sonsLen(t) - 1):
|
for i in countup(1, sonsLen(t) - 1):
|
||||||
var x = replaceTypeVarsT(cl, t.sons[i])
|
var x = replaceTypeVarsT(cl, t.sons[i])
|
||||||
|
|
@ -154,14 +154,14 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
assert x.kind != tyGenericInvokation
|
assert x.kind != tyGenericInvokation
|
||||||
idTablePut(cl.typeMap, body.sons[i-1], x)
|
idTablePut(cl.typeMap, body.sons[i-1], x)
|
||||||
if header == nil: header = t
|
if header == nil: header = t
|
||||||
result = searchInstTypes(gInstTypes, header)
|
result = searchInstTypes(cl.c.generics.InstTypes, header)
|
||||||
if result != nil: return
|
if result != nil: return
|
||||||
result = newType(tyGenericInst, t.sons[0].owner)
|
result = newType(tyGenericInst, t.sons[0].owner)
|
||||||
for i in countup(0, sonsLen(t) - 1):
|
for i in countup(0, sonsLen(t) - 1):
|
||||||
# if one of the params is not concrete, we cannot do anything
|
# if one of the params is not concrete, we cannot do anything
|
||||||
# but we already raised an error!
|
# but we already raised an error!
|
||||||
addSon(result, header.sons[i])
|
addSon(result, header.sons[i])
|
||||||
idTablePut(gInstTypes, header, result)
|
idTablePut(cl.c.generics.InstTypes, header, result)
|
||||||
var newbody = ReplaceTypeVarsT(cl, lastSon(body))
|
var newbody = ReplaceTypeVarsT(cl, lastSon(body))
|
||||||
newbody.flags = newbody.flags + t.flags + body.flags
|
newbody.flags = newbody.flags + t.flags + body.flags
|
||||||
newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n)
|
newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n)
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
# This module implements the signature matching for resolving
|
## This module implements the signature matching for resolving
|
||||||
# the call to overloaded procs, generic procs and operators.
|
## the call to overloaded procs, generic procs and operators.
|
||||||
|
|
||||||
import
|
import
|
||||||
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
|
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
|
||||||
|
|
|
||||||
|
|
@ -160,6 +160,9 @@ program*.
|
||||||
Frontend issues
|
Frontend issues
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
Methods and type converters
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Nimrod contains language features that are *global*. The best example for that
|
Nimrod contains language features that are *global*. The best example for that
|
||||||
are multi methods: Introducing a new method with the same name and some
|
are multi methods: Introducing a new method with the same name and some
|
||||||
compatible object parameter means that the method's dispatcher needs to take
|
compatible object parameter means that the method's dispatcher needs to take
|
||||||
|
|
@ -189,6 +192,17 @@ Both the multi method and the type converter problems are solved by storing
|
||||||
them in special sections in the ROD file that are loaded *unconditionally*
|
them in special sections in the ROD file that are loaded *unconditionally*
|
||||||
when the ROD file is read.
|
when the ROD file is read.
|
||||||
|
|
||||||
|
Generics
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
If we generate an instance of a generic, we'd like to re-use that
|
||||||
|
instance if possible across module boundaries. However, this is not
|
||||||
|
possible if the compilation cache is enabled. So we give up then and use
|
||||||
|
the caching of generics only per module, not per project. This means that
|
||||||
|
``--symbolFiles:on`` hurts a bit for efficiency. A better solution would
|
||||||
|
be to persist the instantiations in a global cache per project. This might be
|
||||||
|
implemented in later versions.
|
||||||
|
|
||||||
|
|
||||||
Backend issues
|
Backend issues
|
||||||
--------------
|
--------------
|
||||||
|
|
|
||||||
1418
llvm/llvm.h
1418
llvm/llvm.h
File diff suppressed because it is too large
Load diff
1452
llvm/llvm.nim
1452
llvm/llvm.nim
File diff suppressed because it is too large
Load diff
11
tests/accept/run/mfriends.nim
Normal file
11
tests/accept/run/mfriends.nim
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
|
||||||
|
type
|
||||||
|
TMyObj = object
|
||||||
|
x: int
|
||||||
|
|
||||||
|
proc gen*[T](): T =
|
||||||
|
var d: TMyObj
|
||||||
|
# access private field here
|
||||||
|
d.x = 3
|
||||||
|
result = d.x
|
||||||
|
|
||||||
11
tests/accept/run/tfriends.nim
Normal file
11
tests/accept/run/tfriends.nim
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
discard """
|
||||||
|
output: "3"
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Tests that a generic instantiation from a different module may access
|
||||||
|
# private object fields:
|
||||||
|
|
||||||
|
import mfriends
|
||||||
|
|
||||||
|
echo gen[int]()
|
||||||
|
|
||||||
5
todo.txt
5
todo.txt
|
|
@ -16,11 +16,12 @@ Version 0.8.14
|
||||||
incremental compilation
|
incremental compilation
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
|
- object types need to be compared by container ID!
|
||||||
- adapt thread var implementation to care about the new merge operation
|
- adapt thread var implementation to care about the new merge operation
|
||||||
- write test cases: needs test script support
|
- write test cases: needs test script support
|
||||||
- test thread var
|
|
||||||
- test DLL interfacing!
|
|
||||||
- stress test with whole compiler
|
- stress test with whole compiler
|
||||||
|
- test DLL interfacing!
|
||||||
|
- test thread var
|
||||||
|
|
||||||
- automate tests:
|
- automate tests:
|
||||||
- test basic recompilation scheme
|
- test basic recompilation scheme
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue