summary refs log tree commit diff stats
path: root/compiler/seminst.nim
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2014-03-16 11:39:53 +0200
committerZahary Karadjov <zahary@gmail.com>2014-03-16 20:42:06 +0200
commitac271e76b18110bea8046af64ceccd6b804978dd (patch)
tree3cecf7bed8b9f5759d766e0ec9e8323277b14b7f /compiler/seminst.nim
parent7dcf6ff50b03dfd54968383ad5a4258f040eec1b (diff)
downloadNim-ac271e76b18110bea8046af64ceccd6b804978dd.tar.gz
more robust handling of proc signatures containing inter-param type references
Diffstat (limited to 'compiler/seminst.nim')
-rw-r--r--compiler/seminst.nim69
1 files changed, 58 insertions, 11 deletions
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index dca9e3378..3d3227e4e 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -85,19 +85,21 @@ proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) =
 
 proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind)
 
+proc addProcDecls(c: PContext, fn: PSym) =
+  # get the proc itself in scope (e.g. for recursion)
+  addDecl(c, fn)
+
+  for i in 1 .. <fn.typ.n.len:
+    var param = fn.typ.n.sons[i].sym
+    param.owner = fn
+    addParamOrResult(c, param, fn.kind)
+  
+  maybeAddResult(c, fn, fn.ast)
+
 proc instantiateBody(c: PContext, n: PNode, result: PSym) =
   if n.sons[bodyPos].kind != nkEmpty:
     inc c.inGenericInst
     # add it here, so that recursive generic procs are possible:
-    addDecl(c, result)
-    pushProcCon(c, result)
-    # add params to scope
-    for i in 1 .. <result.typ.n.len:
-      var param = result.typ.n.sons[i].sym
-      param.owner = result
-      addParamOrResult(c, param, result.kind)
-    # debug result.typ.n
-    maybeAddResult(c, result, n)
     var b = n.sons[bodyPos]
     var symMap: TIdTable
     initIdTable symMap
@@ -107,7 +109,6 @@ proc instantiateBody(c: PContext, n: PNode, result: PSym) =
     n.sons[bodyPos] = transformBody(c.module, b, result)
     #echo "code instantiated ", result.name.s
     excl(result.flags, sfForward)
-    popProcCon(c)
     dec c.inGenericInst
 
 proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
@@ -116,9 +117,12 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
       var oldPrc = c.generics[i].inst.sym
       pushInfoContext(oldPrc.info)
       openScope(c)
+      pushProcCon(c, oldPrc)
+      addProcDecls(c, oldPrc)
       var n = oldPrc.ast
       n.sons[bodyPos] = copyTree(s.getBody)
       instantiateBody(c, n, oldPrc)
+      popProcCon(c)
       closeScope(c)
       popInfoContext()
 
@@ -144,6 +148,47 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
 proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
   result = instGenericContainer(c, n.info, header)
 
+proc instantiateProcType(c: PContext, pt: TIdTable,
+                          prc: PSym, info: TLineInfo) =
+  # XXX: Instantiates a generic proc signature, while at the same
+  # time adding the instantiated proc params into the current scope.
+  # This is necessary, because the instantiation process may refer to
+  # these params in situations like this:
+  # proc foo[Container](a: Container, b: a.type.Item): type(b.x)
+  #
+  # Alas, doing this here is probably not enough, because another
+  # proc signature could appear in the params:
+  # proc foo[T](a: proc (x: T, b: type(x.y))
+  #   
+  # The solution would be to move this logic into semtypinst, but
+  # at this point semtypinst have to become part of sem, because it
+  # will need to use openScope, addDecl, etc
+  #
+  pushInfoContext(info)
+  var cl = initTypeVars(c, pt, info)
+  var result = instCopyType(cl, prc.typ)
+  addDecl(c, prc)
+  let originalParams = result.n
+  result.n = originalParams.shallowCopy
+  
+  for i in 1 .. <result.len:
+    result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
+    propagateToOwner(result, result.sons[i])
+    let param = replaceTypeVarsN(cl, originalParams[i])
+    internalAssert param.kind == nkSym
+    result.n.sons[i] = param
+    addDecl(c, param.sym)
+  
+  result.sons[0] = replaceTypeVarsT(cl, result.sons[0])
+  result.n.sons[0] = originalParams[0].copyTree
+  
+  eraseVoidParams(result)
+  skipIntLiteralParams(result)
+ 
+  prc.typ = result
+  maybeAddResult(c, prc, prc.ast)
+  popInfoContext()
+
 proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
                       info: TLineInfo): PSym =
   # no need to instantiate generic templates/macros:
@@ -171,7 +216,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   var entry = TInstantiation.new
   entry.sym = result
   instantiateGenericParamList(c, n.sons[genericParamsPos], pt, entry[])
-  result.typ = generateTypeInstance(c, pt, info, fn.typ)
+  pushProcCon(c, result)
+  instantiateProcType(c, pt, result, info)
   n.sons[genericParamsPos] = ast.emptyNode
   var oldPrc = genericCacheGet(fn, entry[])
   if oldPrc == nil:
@@ -186,6 +232,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
     paramsTypeCheck(c, result.typ)
   else:
     result = oldPrc
+  popProcCon(c)
   popInfoContext()
   closeScope(c)           # close scope for parameters
   popOwner()