summary refs log tree commit diff stats
path: root/compiler/seminst.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/seminst.nim')
-rw-r--r--compiler/seminst.nim85
1 files changed, 53 insertions, 32 deletions
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 2decb5d0b..f72e2dc5b 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -11,35 +11,37 @@
 # included from sem.nim
 
 proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
-                                 entry: var TInstantiation) = 
-  if n.kind != nkGenericParams: 
+                                 entry: var TInstantiation) =
+  if n.kind != nkGenericParams:
     internalError(n.info, "instantiateGenericParamList; no generic params")
   newSeq(entry.concreteTypes, n.len)
   for i, a in n.pairs:
-    if a.kind != nkSym: 
+    if a.kind != nkSym:
       internalError(a.info, "instantiateGenericParamList; no symbol")
     var q = a.sym
     if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic, tyIter}+tyTypeClasses:
       continue
-    var s = newSym(skType, q.name, getCurrOwner(), q.info)
+    let symKind = if q.typ.kind == tyStatic: skConst else: skType
+    var s = newSym(symKind, q.name, getCurrOwner(), q.info)
     s.flags = s.flags + {sfUsed, sfFromGeneric}
     var t = PType(idTableGet(pt, q.typ))
     if t == nil:
       if tfRetType in q.typ.flags:
-        # keep the generic type and allow the return type to be bound 
+        # keep the generic type and allow the return type to be bound
         # later by semAsgn in return type inference scenario
         t = q.typ
       else:
         localError(a.info, errCannotInstantiateX, s.name.s)
         t = errorType(c)
-    elif t.kind == tyGenericParam: 
+    elif t.kind == tyGenericParam:
       localError(a.info, errCannotInstantiateX, q.name.s)
       t = errorType(c)
-    elif t.kind == tyGenericInvokation:
+    elif t.kind == tyGenericInvocation:
       #t = instGenericContainer(c, a, t)
       t = generateTypeInstance(c, pt, a, t)
       #t = ReplaceTypeVarsT(cl, t)
     s.typ = t
+    if t.kind == tyStatic: s.ast = t.n
     addDecl(c, s)
     entry.concreteTypes[i] = t
 
@@ -56,17 +58,17 @@ proc genericCacheGet(genericSym: PSym, entry: TInstantiation): PSym =
       if sameInstantiation(entry, inst[]):
         return inst.sym
 
-proc removeDefaultParamValues(n: PNode) = 
+proc removeDefaultParamValues(n: PNode) =
   # we remove default params, because they cannot be instantiated properly
   # and they are not needed anyway for instantiation (each param is already
   # provided).
   when false:
-    for i in countup(1, sonsLen(n)-1): 
+    for i in countup(1, sonsLen(n)-1):
       var a = n.sons[i]
       if a.kind != nkIdentDefs: IllFormedAst(a)
       var L = a.len
       if a.sons[L-1].kind != nkEmpty and a.sons[L-2].kind != nkEmpty:
-        # ``param: typ = defaultVal``. 
+        # ``param: typ = defaultVal``.
         # We don't need defaultVal for semantic checking and it's wrong for
         # ``cmp: proc (a, b: T): int = cmp``. Hm, for ``cmp = cmp`` that is
         # not possible... XXX We don't solve this issue here.
@@ -75,11 +77,12 @@ proc removeDefaultParamValues(n: PNode) =
 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))
+    let s = n.sym
+    var x = PSym(idTableGet(symMap, s))
     if x == nil:
-      x = copySym(n.sym, false)
+      x = copySym(s, false)
       x.owner = owner
-      idTablePut(symMap, n.sym, x)
+      idTablePut(symMap, s, x)
     n.sym = x
   else:
     for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, symMap)
@@ -94,16 +97,21 @@ proc addProcDecls(c: PContext, fn: PSym) =
     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) =
+proc instantiateBody(c: PContext, n, params: PNode, result: PSym) =
   if n.sons[bodyPos].kind != nkEmpty:
     inc c.inGenericInst
     # add it here, so that recursive generic procs are possible:
     var b = n.sons[bodyPos]
     var symMap: TIdTable
     initIdTable symMap
+    if params != nil:
+      for i in 1 .. <params.len:
+        let param = params[i].sym
+        if sfGenSym in param.flags:
+          idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym)
     freshGenSyms(b, result, symMap)
     b = semProcBody(c, b)
     b = hloBody(c, b)
@@ -120,13 +128,13 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
       openScope(c)
       var n = oldPrc.ast
       n.sons[bodyPos] = copyTree(s.getBody)
-      instantiateBody(c, n, oldPrc)
+      instantiateBody(c, n, nil, oldPrc)
       closeScope(c)
       popInfoContext()
 
-proc sideEffectsCheck(c: PContext, s: PSym) = 
+proc sideEffectsCheck(c: PContext, s: PSym) =
   if {sfNoSideEffect, sfSideEffect} * s.flags ==
-      {sfNoSideEffect, sfSideEffect}: 
+      {sfNoSideEffect, sfSideEffect}:
     localError(s.info, errXhasSideEffects, s.name.s)
 
 proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
@@ -154,36 +162,49 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
   # 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.
   addDecl(c, prc)
-  
+
   pushInfoContext(info)
   var cl = initTypeVars(c, pt, info)
   var result = instCopyType(cl, prc.typ)
   let originalParams = result.n
   result.n = originalParams.shallowCopy
-  
+
   for i in 1 .. <result.len:
+    # twrong_field_caching requires these 'resetIdTable' calls:
+    if i > 1:
+      resetIdTable(cl.symMap)
+      resetIdTable(cl.localCache)
     result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
     propagateToOwner(result, result.sons[i])
-    let param = replaceTypeVarsN(cl, originalParams[i])
-    result.n.sons[i] = param
-    if param.kind == nkSym:
-      # XXX: this won't be true for void params
-      # implement pass-through of void params and
-      # the "sort by distance to point" container
+    internalAssert originalParams[i].kind == nkSym
+    when true:
+      let oldParam = originalParams[i].sym
+      let param = copySym(oldParam)
+      param.owner = prc
+      param.typ = result.sons[i]
+      param.ast = oldParam.ast.copyTree
+      # don't be lazy here and call replaceTypeVarsN(cl, originalParams[i])!
+      result.n.sons[i] = newSymNode(param)
+      addDecl(c, param)
+    else:
+      let param = replaceTypeVarsN(cl, originalParams[i])
+      result.n.sons[i] = param
       param.sym.owner = prc
-      addDecl(c, param.sym)
-    
+      addDecl(c, result.n.sons[i].sym)
+
+  resetIdTable(cl.symMap)
+  resetIdTable(cl.localCache)
   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()
@@ -232,7 +253,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
       pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
     if isNil(n.sons[bodyPos]):
       n.sons[bodyPos] = copyTree(fn.getBody)
-    instantiateBody(c, n, result)
+    instantiateBody(c, n, fn.typ.n, result)
     sideEffectsCheck(c, result)
     paramsTypeCheck(c, result.typ)
   else: