This commit is contained in:
Araq 2012-09-20 23:44:52 +02:00
commit 043921c7a7
6 changed files with 65 additions and 4 deletions

View file

@ -234,10 +234,12 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
result = SemStmtAndGenerateGenerics(c, n) result = SemStmtAndGenerateGenerics(c, n)
else: else:
let oldContextLen = msgs.getInfoContextLen() let oldContextLen = msgs.getInfoContextLen()
let oldInGenericInst = c.InGenericInst
try: try:
result = SemStmtAndGenerateGenerics(c, n) result = SemStmtAndGenerateGenerics(c, n)
except ERecoverableError: except ERecoverableError:
RecoverContext(c) RecoverContext(c)
c.InGenericInst = oldInGenericInst
result = ast.emptyNode result = ast.emptyNode
msgs.setInfoContextLen(oldContextLen) msgs.setInfoContextLen(oldContextLen)
if gCmd == cmdIdeTools: findSuggest(c, n) if gCmd == cmdIdeTools: findSuggest(c, n)

View file

@ -63,12 +63,15 @@ type
tab*: TSymTab # each module has its own symbol table tab*: TSymTab # each module has its own symbol table
AmbiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot AmbiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot
# store this info in the syms themselves!) # store this info in the syms themselves!)
InGenericContext*: int # > 0 if we are in a generic InGenericContext*: int # > 0 if we are in a generic type
InUnrolledContext*: int # > 0 if we are unrolling a loop InUnrolledContext*: int # > 0 if we are unrolling a loop
InCompilesContext*: int # > 0 if we are in a ``compiles`` magic InCompilesContext*: int # > 0 if we are in a ``compiles`` magic
InGenericInst*: int # > 0 if we are instantiating a generic
converters*: TSymSeq # sequence of converters converters*: TSymSeq # sequence of converters
patterns*: TSymSeq # sequence of pattern matchers patterns*: TSymSeq # sequence of pattern matchers
optionStack*: TLinkedList optionStack*: TLinkedList
symMapping*: TIdTable # every gensym'ed symbol needs to be mapped
# to some new symbol in a generic instantiation
libs*: TLinkedList # all libs used by this module libs*: TLinkedList # all libs used by this module
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
semExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas semExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas

View file

@ -1211,6 +1211,7 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
let oldInGenericContext = c.InGenericContext let oldInGenericContext = c.InGenericContext
let oldInUnrolledContext = c.InUnrolledContext let oldInUnrolledContext = c.InUnrolledContext
let oldInGenericInst = c.InGenericInst
let oldProcCon = c.p let oldProcCon = c.p
c.generics = newGenericsCache() c.generics = newGenericsCache()
try: try:
@ -1222,6 +1223,7 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode =
c.generics = oldGenerics c.generics = oldGenerics
c.InGenericContext = oldInGenericContext c.InGenericContext = oldInGenericContext
c.InUnrolledContext = oldInUnrolledContext c.InUnrolledContext = oldInUnrolledContext
c.InGenericInst = oldInGenericInst
c.p = oldProcCon c.p = oldProcCon
msgs.setInfoContextLen(oldContextLen) msgs.setInfoContextLen(oldContextLen)
setlen(gOwners, oldOwnerLen) setlen(gOwners, oldOwnerLen)

View file

@ -92,6 +92,13 @@ proc semGenericStmt(c: PContext, n: PNode,
if s != nil: result = semGenericStmtSymbol(c, n, s) if s != nil: result = semGenericStmtSymbol(c, n, s)
# XXX for example: ``result.add`` -- ``add`` needs to be looked up here... # XXX for example: ``result.add`` -- ``add`` needs to be looked up here...
of nkEmpty, nkSym..nkNilLit: of nkEmpty, nkSym..nkNilLit:
# see tests/compile/tgensymgeneric.nim:
# We need to open the gensym'ed symbol again so that the instantiation
# creates a fresh copy; but this is wrong the very first reason for gensym
# is that scope rules cannot be used! So simply removing 'sfGenSym' does
# not work. Copying the symbol does not work either because we're already
# the owner of the symbol! What we need to do is to copy the symbol
# in the generic instantiation process...
nil nil
of nkBind: of nkBind:
result = semGenericStmt(c, n.sons[0], flags+{withinBind}, toBind) result = semGenericStmt(c, n.sons[0], flags+{withinBind}, toBind)

View file

@ -69,6 +69,18 @@ proc removeDefaultParamValues(n: PNode) =
# not possible... XXX We don't solve this issue here. # not possible... XXX We don't solve this issue here.
a.sons[L-1] = ast.emptyNode a.sons[L-1] = ast.emptyNode
proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) =
# we need to create a fresh set of gensym'ed symbols:
if n.kind == nkSym and sfGenSym in n.sym.flags:
var x = PSym(IdTableGet(symMap, n.sym))
if x == nil:
x = copySym(n.sym, false)
x.owner = owner
IdTablePut(symMap, n.sym, x)
n.sym = x
else:
for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, symMap)
proc instantiateBody(c: PContext, n: PNode, result: PSym) = proc instantiateBody(c: PContext, n: PNode, result: PSym) =
if n.sons[bodyPos].kind != nkEmpty: if n.sons[bodyPos].kind != nkEmpty:
# add it here, so that recursive generic procs are possible: # add it here, so that recursive generic procs are possible:
@ -77,7 +89,11 @@ proc instantiateBody(c: PContext, n: PNode, result: PSym) =
if result.kind in {skProc, skMethod, skConverter, skMacro}: if result.kind in {skProc, skMethod, skConverter, skMacro}:
addResult(c, result.typ.sons[0], n.info, result.kind) addResult(c, result.typ.sons[0], n.info, result.kind)
addResultNode(c, n) addResultNode(c, n)
var b = semStmtScope(c, n.sons[bodyPos]) var b = n.sons[bodyPos]
var symMap: TIdTable
InitIdTable symMap
freshGenSyms(b, result, symMap)
b = semStmtScope(c, b)
b = hloBody(c, b) b = hloBody(c, b)
n.sons[bodyPos] = transformBody(c.module, b, result) n.sons[bodyPos] = transformBody(c.module, b, result)
#echo "code instantiated ", result.name.s #echo "code instantiated ", result.name.s

View file

@ -0,0 +1,31 @@
# We need to open the gensym'ed symbol again so that the instantiation
# creates a fresh copy; but this is wrong the very first reason for gensym
# is that scope rules cannot be used! So simply removing 'sfGenSym' does
# not work. Copying the symbol does not work either because we're already
# the owner of the symbol! What we need to do is to copy the symbol
# in the generic instantiation process...
type
TA = object
x: int
TB = object
x: string
template genImpl() =
var gensymed: T
when T is TB:
gensymed.x = "abc"
else:
gensymed.x = 123
shallowCopy(result, gensymed)
proc gen[T](x: T): T =
genImpl()
var
a: TA
b: TB
let x = gen(a)
let y = gen(b)
echo x.x, " ", y.x