summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler/ast.nim8
-rwxr-xr-xcompiler/astalgo.nim5
-rwxr-xr-xcompiler/nimrod.nim14
-rwxr-xr-xcompiler/pragmas.nim1
-rwxr-xr-xcompiler/sem.nim2
-rwxr-xr-xcompiler/semexprs.nim5
-rwxr-xr-xcompiler/seminst.nim15
-rwxr-xr-xcompiler/semstmts.nim7
-rwxr-xr-xcompiler/semtypes.nim75
-rwxr-xr-xcompiler/semtypinst.nim100
-rwxr-xr-xcompiler/sigmatch.nim13
-rwxr-xr-xcompiler/types.nim26
-rwxr-xr-xcontributors.txt1
-rwxr-xr-xdoc/manual.txt27
-rwxr-xr-xlib/core/typeinfo.nim16
-rw-r--r--lib/pure/actors.nim45
-rwxr-xr-xlib/pure/parsecfg.nim1
-rwxr-xr-xlib/system/threads.nim8
-rwxr-xr-xtodo.txt13
19 files changed, 258 insertions, 124 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index e9bf532b1..bb9803830 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -279,8 +279,8 @@ type
 
   TTypeFlags* = set[TTypeFlag]
 
-  TSymKind* = enum # the different symbols (start with the prefix sk);
-                   # order is important for the documentation generator!
+  TSymKind* = enum        # the different symbols (start with the prefix sk);
+                          # order is important for the documentation generator!
     skUnknown,            # unknown symbol: used for parsing assembler blocks
                           # and first phase symbol lookup in generics
     skConditional,        # symbol for the preprocessor (may become obsolete)
@@ -848,6 +848,10 @@ proc initNodeTable(x: var TNodeTable) =
 proc sonsLen(n: PType): int = 
   if isNil(n.sons): result = 0
   else: result = len(n.sons)
+
+proc len*(n: PType): int = 
+  if isNil(n.sons): result = 0
+  else: result = len(n.sons)
   
 proc newSons(father: PType, length: int) = 
   if isNil(father.sons): father.sons = @[]
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index 08b502af7..17875d524 100755
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -46,7 +46,6 @@ proc StrTableContains*(t: TStrTable, n: PSym): bool
 proc StrTableAdd*(t: var TStrTable, n: PSym)
 proc StrTableGet*(t: TStrTable, name: PIdent): PSym  
   
-  # the iterator scheme:
 type 
   TTabIter*{.final.} = object # consider all fields here private
     h*: THash                 # current hash
@@ -749,6 +748,10 @@ proc IdTablePut(t: var TIdTable, key: PIdObj, val: PObject) =
     IdTableRawInsert(t.data, key, val)
     inc(t.counter)
 
+iterator IdTablePairs*(t: TIdTable): tuple[key: PIdObj, val: PObject] =
+  for i in 0 .. high(t.data):
+    if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
+
 proc writeIdNodeTable(t: TIdNodeTable) = 
   nil
 
diff --git a/compiler/nimrod.nim b/compiler/nimrod.nim
index 5c91329cd..3a910cfad 100755
--- a/compiler/nimrod.nim
+++ b/compiler/nimrod.nim
@@ -49,6 +49,13 @@ proc ProcessCmdLine(pass: TCmdLinePass, command, filename: var string) =
     if optRun notin gGlobalOptions and arguments != "": 
       rawMessage(errArgsNeedRunOption, [])
   
+proc prependCurDir(f: string): string =
+  when defined(unix):
+    if os.isAbsolute(f): result = f
+    else: result = "./" & f
+  else:
+    result = f
+  
 proc HandleCmdLine() = 
   var start = epochTime()
   if paramCount() == 0: 
@@ -79,11 +86,8 @@ proc HandleCmdLine() =
         rawMessage(hintSuccessX, [$gLinesCompiled, 
                    formatFloat(epochTime() - start, ffDecimal, 3)])
       if optRun in gGlobalOptions: 
-        when defined(unix): 
-          var prog = "./" & quoteIfContainsWhite(changeFileExt(filename, ""))
-        else: 
-          var prog = quoteIfContainsWhite(changeFileExt(filename, ""))
-        execExternalProgram(prog & ' ' & arguments)
+        var ex = quoteIfContainsWhite(changeFileExt(filename, "").prependCurDir)
+        execExternalProgram(ex & ' ' & arguments)
 
 #GC_disableMarkAndSweep()
 cmdLineInfo = newLineInfo("command line", -1, -1)
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index d5cbae4ab..039474266 100755
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -53,6 +53,7 @@ const
     wExtern, wImportcpp, wImportobjc}
   procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideEffect,
                       wThread}
+  allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas
 
 proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
 proc pragmaAsm*(c: PContext, n: PNode): char
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 5d2e1069f..c0ea23d2e 100755
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -146,7 +146,7 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
       addSon(n, prc.ast)
   lastGenericIdx = Len(generics)
 
-proc semExprNoFlags(c: PContext, n: PNode): PNode = 
+proc semExprNoFlags(c: PContext, n: PNode): PNode {.procvar.} = 
   result = semExpr(c, n, {})
 
 proc myOpen(module: PSym, filename: string): PPassContext = 
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index d116ede2e..f86a4f60d 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1178,9 +1178,10 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
       else:
         #liMessage(n.info, warnUser, renderTree(n));
         result = semIndirectOp(c, n, flags)
-    elif n.sons[0].kind == nkSymChoice: 
+    elif n.sons[0].kind == nkSymChoice or n[0].kind == nkBracketExpr and 
+        n[0][0].kind == nkSymChoice:
       result = semDirectOp(c, n, flags)
-    else: 
+    else:
       result = semIndirectOp(c, n, flags)
   of nkMacroStmt: 
     result = semMacroStmt(c, n)
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 87f988ed9..d53d33898 100755
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -29,6 +29,10 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
       break
     if t.kind == tyGenericParam: 
       InternalError(a.info, "instantiateGenericParamList: " & q.name.s)
+    elif t.kind == tyGenericInvokation:
+      #t = instGenericContainer(c, a, t)
+      t = generateTypeInstance(c, pt, a, t)
+      #t = ReplaceTypeVarsT(cl, t)
     s.typ = t
     addDecl(c, s)
     entry.concreteTypes[i] = t
@@ -94,6 +98,14 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
       closeScope(c.tab)
       popInfoContext()
 
+proc sideEffectsCheck(c: PContext, s: PSym) = 
+  if {sfNoSideEffect, sfSideEffect} * s.flags ==
+      {sfNoSideEffect, sfSideEffect}: 
+    LocalError(s.info, errXhasSideEffects, s.name.s)
+  elif sfThread in s.flags and semthreads.needsGlobalAnalysis() and 
+      s.ast.sons[genericParamsPos].kind == nkEmpty:
+    c.threadEntries.add(s)
+
 proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, 
                       info: TLineInfo): PSym = 
   # generates an instantiated proc
@@ -133,7 +145,10 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   var oldPrc = GenericCacheGet(c, entry)
   if oldPrc == nil:
     generics.add(entry)
+    if n.sons[pragmasPos].kind != nkEmpty:
+      pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
     instantiateBody(c, n, result)
+    sideEffectsCheck(c, result)
   else:
     result = oldPrc
   popInfoContext()
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index c37706f3a..ce870a3ad 100755
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -554,13 +554,6 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) =
     n.sons[codePos] = newSymNode(b)
   else:
     LocalError(n.info, errNoSymbolToBorrowFromFound) 
-
-proc sideEffectsCheck(c: PContext, s: PSym) = 
-  if {sfNoSideEffect, sfSideEffect} * s.flags ==
-      {sfNoSideEffect, sfSideEffect}: 
-    LocalError(s.info, errXhasSideEffects, s.name.s)
-  elif sfThread in s.flags and semthreads.needsGlobalAnalysis():
-    c.threadEntries.add(s)
   
 proc addResult(c: PContext, t: PType, info: TLineInfo) = 
   if t != nil: 
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 7cdb32c79..9ff7ea27f 100755
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -216,23 +216,6 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
       addSon(result.n, newSymNode(field))
       addSon(result, typ)
 
-proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = 
-  if s.typ == nil or s.typ.kind != tyGenericBody: 
-    GlobalError(n.info, errCannotInstantiateX, s.name.s)
-  result = newOrPrevType(tyGenericInvokation, prev, c)
-  if s.typ.containerID == 0: InternalError(n.info, "semtypes.semGeneric")
-  if sonsLen(n) != sonsLen(s.typ): 
-    GlobalError(n.info, errWrongNumberOfArguments)
-  addSon(result, s.typ)
-  var isConcrete = true # iterate over arguments:
-  for i in countup(1, sonsLen(n)-1): 
-    var elem = semTypeNode(c, n.sons[i], nil)
-    if elem.kind in {tyGenericParam, tyGenericInvokation}: isConcrete = false
-    addSon(result, elem)
-  if isConcrete:
-    if s.ast == nil: GlobalError(n.info, errCannotInstantiateX, s.name.s)
-    result = instGenericContainer(c, n, result)
-
 proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, 
                  allowed: TSymFlags): PSym = 
   # identifier with visibility
@@ -489,7 +472,6 @@ proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode,
   if ContainsOrIncl(cl, t.id): return 
   case t.kind
   of tyGenericBody: 
-    #debug(t)
     result = newTypeS(tyGenericInvokation, c)
     addSon(result, t)
     for i in countup(0, sonsLen(t) - 2): 
@@ -505,11 +487,9 @@ proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode,
       addSon(genericParams, newSymNode(s))
       addSon(result, t.sons[i])
   of tyGenericInst: 
-    #debug(t)
     var L = sonsLen(t) - 1
     t.sons[L] = addTypeVarsOfGenericBody(c, t.sons[L], genericParams, cl)
   of tyGenericInvokation: 
-    #debug(t)
     for i in countup(1, sonsLen(t) - 1): 
       t.sons[i] = addTypeVarsOfGenericBody(c, t.sons[i], genericParams, cl)
   else: 
@@ -520,7 +500,6 @@ proc paramType(c: PContext, n, genericParams: PNode, cl: var TIntSet): PType =
   result = semTypeNode(c, n, nil)
   if genericParams != nil and sonsLen(genericParams) == 0: 
     result = addTypeVarsOfGenericBody(c, result, genericParams, cl)
-    #if result.kind == tyGenericInvokation: debug(result)
 
 proc semProcTypeNode(c: PContext, n, genericParams: PNode, 
                      prev: PType): PType = 
@@ -546,6 +525,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
     var length = sonsLen(a)
     if a.sons[length-2].kind != nkEmpty: 
       typ = paramType(c, a.sons[length-2], genericParams, cl)
+      #if matchType(typ, [(tyVar, 0)], tyGenericInvokation):
+      #  debug a.sons[length-2][0][1]
+        
     else: 
       typ = nil
     if a.sons[length-1].kind != nkEmpty:
@@ -557,8 +539,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
         # and def.typ != nil and def.typ.kind != tyNone:
         # example code that triggers it:
         # proc sort[T](cmp: proc(a, b: T): int = cmp)
-        def = fitNode(c, typ, def)
-    else: 
+        if not containsGenericType(typ):
+          def = fitNode(c, typ, def)
+    else:
       def = ast.emptyNode
     if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
     for j in countup(0, length-3): 
@@ -578,6 +561,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
     if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
       result.sons[0] = r
       res.typ = result.sons[0]
+  #if matchType(result, [(tyProc, 1), (tyVar, 0)], tyGenericInvokation):
+  #  debug result
 
 proc semStmtListType(c: PContext, n: PNode, prev: PType): PType = 
   checkMinSonsLen(n, 1)
@@ -603,6 +588,50 @@ proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
   closeScope(c.tab)
   Dec(c.p.nestedBlockCounter)
 
+proc semGenericParamInInvokation(c: PContext, n: PNode): PType =
+  # XXX hack 1022 for generics ... would have been nice if the compiler had
+  # been designed with them in mind from start ...
+  when false:
+    if n.kind == nkSym:
+      # for generics we need to lookup the type var again:
+      var s = SymtabGet(c.Tab, n.sym.name)
+      if s != nil:
+        if s.kind == skType and s.typ != nil:
+          var t = n.sym.typ
+          echo "came here"
+          return t
+        else:
+          echo "s is crap:"
+          debug(s)
+      else:
+        echo "s is nil!!!!"
+  result = semTypeNode(c, n, nil)
+
+proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = 
+  if s.typ == nil or s.typ.kind != tyGenericBody: 
+    GlobalError(n.info, errCannotInstantiateX, s.name.s)
+  result = newOrPrevType(tyGenericInvokation, prev, c)
+  if s.typ.containerID == 0: InternalError(n.info, "semtypes.semGeneric")
+  if sonsLen(n) != sonsLen(s.typ): 
+    GlobalError(n.info, errWrongNumberOfArguments)
+  addSon(result, s.typ)
+  var isConcrete = true # iterate over arguments:
+  for i in countup(1, sonsLen(n)-1):
+    var elem = semGenericParamInInvokation(c, n.sons[i])
+    if containsGenericType(elem): isConcrete = false
+    #if elem.kind in {tyGenericParam, tyGenericInvokation}: isConcrete = false
+    addSon(result, elem)
+  if isConcrete:
+    if s.ast == nil: GlobalError(n.info, errCannotInstantiateX, s.name.s)
+    result = instGenericContainer(c, n, result)
+
+proc FixupRemainingGenericInvokations(c: PContext, n: PNode, 
+                                      typ: PType): PType =
+  if typ.kind == tyGenericInvokation:
+    nil
+  else:
+    result = typ
+
 proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = 
   result = nil
   if gCmd == cmdIdeTools: suggestExpr(c, n)
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 41ec8ddac..88697dc85 100755
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -92,51 +92,90 @@ proc ReplaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
 
 proc lookupTypeVar(cl: TReplTypeVars, t: PType): PType = 
   result = PType(idTableGet(cl.typeMap, t))
-  if result == nil: 
+  if result == nil:
     GlobalError(t.sym.info, errCannotInstantiateX, typeToString(t))
   elif result.kind == tyGenericParam: 
     InternalError(cl.info, "substitution with generic parameter")
   
 proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = 
+  # tyGenericInvokation[A, tyGenericInvokation[A, B]]
+  # is difficult to handle: 
   var body = t.sons[0]
   if body.kind != tyGenericBody: InternalError(cl.info, "no generic body")
   var header: PType = nil
-  for i in countup(1, sonsLen(t) - 1):
-    var x = replaceTypeVarsT(cl, t.sons[i])
-    if t.sons[i].kind == tyGenericParam: 
-      if header == nil: header = copyType(t, t.owner, false)
+  when true:
+    # search for some instantiation here:
+    result = searchInstTypes(gInstTypes, t)
+    if result != nil: return
+    for i in countup(1, sonsLen(t) - 1):
+      var x = t.sons[i]
+      if x.kind == tyGenericParam: 
+        x = lookupTypeVar(cl, x)
+        if header == nil: header = copyType(t, t.owner, false)
+        header.sons[i] = x
+        #idTablePut(cl.typeMap, body.sons[i-1], x)
+    if header != nil:
+      # search again after first pass:
+      result = searchInstTypes(gInstTypes, header)
+      if result != nil: return
+    else:
+      header = copyType(t, t.owner, false)
+    # ugh need another pass for deeply recursive generic types (e.g. PActor)
+    # we need to add the candidate here, before it's fully instantiated for
+    # recursive instantions:
+    result = newType(tyGenericInst, t.sons[0].owner)
+    idTablePut(gInstTypes, header, result)
+
+    for i in countup(1, sonsLen(t) - 1):
+      var x = replaceTypeVarsT(cl, t.sons[i])
+      assert x.kind != tyGenericInvokation
       header.sons[i] = x
-    when false:
-      var x: PType
+      idTablePut(cl.typeMap, body.sons[i-1], x)
+    
+    for i in countup(0, sonsLen(t) - 1): 
+      # if one of the params is not concrete, we cannot do anything
+      # but we already raised an error!
+      addSon(result, header.sons[i])
+    
+    var newbody = ReplaceTypeVarsT(cl, lastSon(body))
+    newbody.flags = newbody.flags + t.flags + body.flags
+    result.flags = result.flags + newbody.flags
+    newbody.callConv = body.callConv
+    newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n)
+    addSon(result, newbody)
+    checkPartialConstructedType(cl.info, newbody)
+  else:
+    for i in countup(1, sonsLen(t) - 1):
+      if PType(idTableGet(cl.typeMap, t.sons[i])) == nil: debug(t)
+      var x = replaceTypeVarsT(cl, t.sons[i])
       if t.sons[i].kind == tyGenericParam: 
-        x = lookupTypeVar(cl, t.sons[i])
         if header == nil: header = copyType(t, t.owner, false)
         header.sons[i] = x
-      else: 
-        x = t.sons[i]
-    idTablePut(cl.typeMap, body.sons[i-1], x)
-  if header == nil: header = t
-  result = searchInstTypes(gInstTypes, header)
-  if result != nil: return 
-  result = newType(tyGenericInst, t.sons[0].owner)
-  for i in countup(0, sonsLen(t) - 1): 
-    # if one of the params is not concrete, we cannot do anything
-    # but we already raised an error!
-    addSon(result, header.sons[i])
-  idTablePut(gInstTypes, header, result)
-  var newbody = ReplaceTypeVarsT(cl, lastSon(body))
-  newbody.flags = newbody.flags + t.flags + body.flags
-  newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n)
-  addSon(result, newbody)
-  #writeln(output, ropeToStr(Typetoyaml(newbody)));
-  checkPartialConstructedType(cl.info, newbody)
+      assert x.kind != tyGenericInvokation
+      idTablePut(cl.typeMap, body.sons[i-1], x)
+    if header == nil: header = t
+    result = searchInstTypes(gInstTypes, header)
+    if result != nil: return 
+    result = newType(tyGenericInst, t.sons[0].owner)
+    for i in countup(0, sonsLen(t) - 1): 
+      # if one of the params is not concrete, we cannot do anything
+      # but we already raised an error!
+      addSon(result, header.sons[i])
+    idTablePut(gInstTypes, header, result)
+    var newbody = ReplaceTypeVarsT(cl, lastSon(body))
+    newbody.flags = newbody.flags + t.flags + body.flags
+    newbody.n = ReplaceTypeVarsN(cl, lastSon(body).n)
+    addSon(result, newbody)
+    checkPartialConstructedType(cl.info, newbody)
   
 proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType = 
   result = t
   if t == nil: return 
   case t.kind
-  of tyGenericParam: 
+  of tyGenericParam:
     result = lookupTypeVar(cl, t)
+    if result.kind == tyGenericInvokation:
+      result = handleGenericInvokation(cl, result)
   of tyGenericInvokation: 
     result = handleGenericInvokation(cl, t)
   of tyGenericBody: 
@@ -151,9 +190,10 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
       result.n = ReplaceTypeVarsN(cl, result.n)
       if result.Kind in GenericTypes:
         LocalError(cl.info, errCannotInstantiateX, TypeToString(t, preferName))
-        #writeln(output, ropeToStr(Typetoyaml(result)))
-        #checkConstructedType(cl.info, result)
-
+      if result.kind == tyProc and result.sons[0] != nil:
+        if result.sons[0].kind == tyEmpty:
+          result.sons[0] = nil
+  
 proc generateTypeInstance*(p: PContext, pt: TIdTable, arg: PNode, 
                            t: PType): PType = 
   var cl: TReplTypeVars
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 9acf83a46..1e93385d9 100755
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -137,6 +137,8 @@ proc concreteType(mapping: TIdTable, t: PType): PType =
         # example code that triggers it:
         # proc sort[T](cmp: proc(a, b: T): int = cmp)
       if result.kind != tyGenericParam: break
+  of tyGenericInvokation:
+    assert false
   else: 
     result = t                # Note: empty is valid here
   
@@ -388,8 +390,10 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
   of tyGenericInvokation: 
     assert(f.sons[0].kind == tyGenericBody)
     if a.kind == tyGenericInvokation: 
-      InternalError("typeRel: tyGenericInvokation -> tyGenericInvokation")
-    if (a.kind == tyGenericInst): 
+      #InternalError("typeRel: tyGenericInvokation -> tyGenericInvokation")
+      # simply no match for now:
+      nil
+    elif a.kind == tyGenericInst:
       if (f.sons[0].containerID == a.sons[0].containerID) and
           (sonsLen(a) - 1 == sonsLen(f)): 
         assert(a.sons[0].kind == tyGenericBody)
@@ -404,7 +408,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
         # we steal the generic parameters from the tyGenericBody:
         for i in countup(1, sonsLen(f) - 1):
           var x = PType(idTableGet(mapping, f.sons[0].sons[i - 1]))
-          if x == nil or x.kind == tyGenericParam:
+          if x == nil or x.kind in {tyGenericInvokation, tyGenericParam}:
             InternalError("wrong instantiated type!")
           idTablePut(mapping, f.sons[i], x)
   of tyGenericParam: 
@@ -413,8 +417,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
       if sonsLen(f) == 0: 
         # no constraints
         var concrete = concreteType(mapping, a)
-        if concrete != nil: 
-          #MessageOut('putting: ' + f.sym.name.s);
+        if concrete != nil:
           idTablePut(mapping, f, concrete)
           result = isGeneric
       else: 
diff --git a/compiler/types.nim b/compiler/types.nim
index 692b7f61b..d8d0caf35 100755
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -728,7 +728,16 @@ proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool =
       else: 
         for i in countup(0, sonsLen(n) - 1): 
           result = typeAllowedNode(marker, n.sons[i], kind)
-          if not result: return 
+          if not result: break
+
+proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
+                last: TTypeKind): bool =
+  var a = a
+  for k, i in pattern.items:
+    if a.kind != k: return false
+    if i >= a.sonslen or a.sons[i] == nil: return false
+    a = a.sons[i]
+  result = a.kind == last
   
 proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
   assert(kind in {skVar, skConst, skParam, skResult})
@@ -751,13 +760,14 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
   of tyProc: 
     for i in countup(1, sonsLen(t) - 1): 
       result = typeAllowedAux(marker, t.sons[i], skParam)
-      if not result: return 
-    if t.sons[0] != nil: result = typeAllowedAux(marker, t.sons[0], skResult)
+      if not result: break 
+    if result and t.sons[0] != nil:
+      result = typeAllowedAux(marker, t.sons[0], skResult)
   of tyExpr, tyStmt, tyTypeDesc: 
     result = true
   of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation: 
     result = false            #InternalError('shit found');
-  of tyEmpty, tyNil: 
+  of tyEmpty, tyNil:
     result = kind == skConst
   of tyString, tyBool, tyChar, tyEnum, tyInt..tyFloat128, tyCString, tyPointer: 
     result = true
@@ -781,13 +791,13 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
   of tyArrayConstr, tyTuple, tySet: 
     for i in countup(0, sonsLen(t) - 1): 
       result = typeAllowedAux(marker, t.sons[i], kind)
-      if not result: return 
+      if not result: break 
   of tyObject: 
     for i in countup(0, sonsLen(t) - 1): 
       result = typeAllowedAux(marker, t.sons[i], skVar)
-      if not result: return 
-    if t.n != nil: result = typeAllowedNode(marker, t.n, skVar)
-  
+      if not result: break 
+    if result and t.n != nil: result = typeAllowedNode(marker, t.n, skVar)
+    
 proc typeAllowed(t: PType, kind: TSymKind): bool = 
   var marker = InitIntSet()
   result = typeAllowedAux(marker, t, kind)
diff --git a/contributors.txt b/contributors.txt
index 37978dc3f..e51914e26 100755
--- a/contributors.txt
+++ b/contributors.txt
@@ -2,6 +2,7 @@ Comex
 Eric Doughty-Papassideris
 Keita Haga
 Philippe Lhoste
+Zahary Karadjov
 Mario Ray Mahardhika
 Alex Mitchell
 Dominik Picheta
diff --git a/doc/manual.txt b/doc/manual.txt
index f9a0b5dfc..2002a2461 100755
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -433,6 +433,15 @@ have no side-effect can be used in constant expressions too:
     constEval = contains("abc", 'b') # computed at compile time!

 

 

+The rules for compile-time computability are: 

+

+1. Literals are compile-time computable.

+2. Procedure calls of the form ``p(X)`` are compile-time computable if

+   ``p`` is a proc without side-effects (see the `noSideEffect pragma`_ 

+   for details) and if ``X`` is a (possibly empty) list of compile-time 

+   computable arguments.

+

+

 Types

 -----

 

@@ -2900,17 +2909,17 @@ structure:
 

 Pure pragma

 -----------

-An object type can be marked with the `pure`:idx: pragma so that its type 
+An object type can be marked with the `pure`:idx: pragma so that its type 

 field which is used for runtime type identification is omitted. This is

 necessary for binary compatibility with other compiled languages.

-
-
-NoStackFrame pragma
--------------------
-A proc can be marked with the `noStackFrame`:idx: pragma to tell the compiler
-it should not generate a stack frame for the proc. There are also no exit
-statements like ``return result;`` generated. This is useful for procs that 
-only consist of an assembler statement.
+

+

+NoStackFrame pragma

+-------------------

+A proc can be marked with the `noStackFrame`:idx: pragma to tell the compiler

+it should not generate a stack frame for the proc. There are also no exit

+statements like ``return result;`` generated. This is useful for procs that 

+only consist of an assembler statement.

 

 

 error pragma

diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim
index 32042695d..b5e9e1a0f 100755
--- a/lib/core/typeinfo.nim
+++ b/lib/core/typeinfo.nim
@@ -104,13 +104,17 @@ proc toAny*[T](x: var T): TAny {.inline.} =
 proc kind*(x: TAny): TAnyKind {.inline.} = 
   ## get the type kind
   result = TAnyKind(ord(x.rawType.kind))
+
+proc size*(x: TAny): int {.inline.} =
+  ## returns the size of `x`'s type.
+  result = x.rawType.size
   
 proc baseTypeKind*(x: TAny): TAnyKind {.inline.} = 
   ## get the base type's kind; ``akNone`` is returned if `x` has no base type.
   if x.rawType.base != nil:
     result = TAnyKind(ord(x.rawType.base.kind))
 
-proc baseTypeSize*(x: TAny): int =
+proc baseTypeSize*(x: TAny): int {.inline.} =
   ## returns the size of `x`'s basetype.
   if x.rawType.base != nil:
     result = x.rawType.base.size
@@ -339,8 +343,8 @@ proc getInt64*(x: TAny): int64 =
 
 proc getBiggestInt*(x: TAny): biggestInt =
   ## retrieve the integer value out of `x`. `x` needs to represent
-  ## some integer, a bool, a char or an enum. The value might be
-  ## sign-extended to ``biggestInt``.
+  ## some integer, a bool, a char, an enum or a small enough bit set.
+  ## The value might be sign-extended to ``biggestInt``.
   var t = skipRange(x.rawtype)
   case t.kind
   of tyInt: result = biggestInt(cast[ptr int](x.value)[])
@@ -350,7 +354,7 @@ proc getBiggestInt*(x: TAny): biggestInt =
   of tyInt64: result = biggestInt(cast[ptr int64](x.value)[])
   of tyBool: result = biggestInt(cast[ptr bool](x.value)[])
   of tyChar: result = biggestInt(cast[ptr char](x.value)[])
-  of tyEnum:
+  of tyEnum, tySet:
     case t.size
     of 1: result = ze64(cast[ptr int8](x.value)[])
     of 2: result = ze64(cast[ptr int16](x.value)[])
@@ -361,7 +365,7 @@ proc getBiggestInt*(x: TAny): biggestInt =
 
 proc setBiggestInt*(x: TAny, y: biggestInt) =
   ## sets the integer value of `x`. `x` needs to represent
-  ## some integer, a bool, a char or an enum.
+  ## some integer, a bool, a char, an enum or a small enough bit set.
   var t = skipRange(x.rawtype)
   case t.kind
   of tyInt: cast[ptr int](x.value)[] = int(y)
@@ -371,7 +375,7 @@ proc setBiggestInt*(x: TAny, y: biggestInt) =
   of tyInt64: cast[ptr int64](x.value)[] = int64(y)
   of tyBool: cast[ptr bool](x.value)[] = y != 0
   of tyChar: cast[ptr char](x.value)[] = chr(y.int)
-  of tyEnum:
+  of tyEnum, tySet:
     case t.size
     of 1: cast[ptr int8](x.value)[] = toU8(y.int)
     of 2: cast[ptr int16](x.value)[] = toU16(y.int)
diff --git a/lib/pure/actors.nim b/lib/pure/actors.nim
index 285e3241d..4576cb602 100644
--- a/lib/pure/actors.nim
+++ b/lib/pure/actors.nim
@@ -30,7 +30,7 @@ proc spawn*[TIn, TOut](action: proc(
     self: PActor[TIn, TOut]){.thread.}): PActor[TIn, TOut] =
   ## creates an actor; that is a thread with an inbox. The caller MUST call
   ## ``join`` because that also frees the associated resources with the actor.
-  result = allocShared0(sizeof(result[]))
+  result = cast[PActor[TIn, TOut]](allocShared0(sizeof(result[])))
   open(result.i)
   createThread(result.t, action, result)
 
@@ -52,8 +52,8 @@ proc recv*[TIn, TOut](a: PActor[TIn, TOut]): TTask[TIn, TOut] =
   ## receives a task from `a`'s inbox.
   result = recv(a.i)
 
-proc send*[TIn, TOut, X, Y](sender: PActor[X, Z], 
-                            receiver: PActor[TIn, TOut], msg: TIn) =
+proc send*[TIn, TOut, X, Y](receiver: PActor[TIn, TOut], msg: TIn,
+                            sender: PActor[X, Y]) =
   ## sends a message to `a`'s inbox.
   var t: TTask[TIn, TOut]
   t.receiver = addr(sender.i)
@@ -99,9 +99,9 @@ proc poolWorker[TIn, TOut](self: PActor[TIn, TOut]) {.thread.} =
     var m = self.recv
     if m.shutDown: break
     when TOut is void:
-      action(m.data)
+      m.action(m.data)
     else:
-      self.repy(action(m.data))
+      self.repy(m.action(m.data))
 
 proc createActorPool*[TIn, TOut](a: var TActorPool[TIn, TOut], poolSize = 4) =
   ## creates an actor pool.
@@ -109,21 +109,20 @@ proc createActorPool*[TIn, TOut](a: var TActorPool[TIn, TOut], poolSize = 4) =
   when TOut isnot void:
     open(a.outputs)
   for i in 0 .. < a.actors.len:
-    a.actors[i] = spawn(poolWorker)
+    a.actors[i] = spawn(poolWorker[TIn, TOut])
 
 proc join*[TIn, TOut](a: var TActorPool[TIn, TOut]) =
   ## waits for each actor in the actor pool `a` to finish and frees the
   ## resources attached to `a`.
   var t: TTask[TIn, TOut]
   t.shutdown = true
-  for i in 0 .. < a.actors.len: send(a.actors[i], t)
+  for i in 0 .. < a.actors.len: send(a.actors[i].i, t)
   for i in 0 .. < a.actors.len: join(a.actors[i])
   when TOut isnot void:
     close(a.outputs)
   a.actors = nil
 
 template setupTask =
-  var t: TTask[TIn, TOut]
   t.action = action
   shallowCopy(t.data, input)
 
@@ -132,7 +131,7 @@ template schedule =
   # it remains 'hot' ;-). Round-robin hurts for keeping threads hot.
   for i in 0..high(a.actors):
     if a.actors[i].i.ready:
-      a.actors[i].send(t)
+      a.actors[i].i.send(t)
       return
   # no thread ready :-( --> send message to the thread which has the least
   # messages pending:
@@ -142,27 +141,29 @@ template schedule =
     var curr = a.actors[i].i.peek
     if curr == 0:
       # ok, is ready now:
-      a.actors[i].send(t)
+      a.actors[i].i.send(t)
       return
     if curr < minVal:
       minVal = curr
       minIdx = i
-  a.actors[minIdx].send(t)
+  a.actors[minIdx].i.send(t)
 
-proc spawn*[TIn, TOut](p: var TActorPool[TIn, TOut],
-                       action: proc (input: TIn): TOut {.thread.}, 
-                       input: TIn): ptr TChannel[TOut] =
-  ## uses the actor pool to run `action` concurrently. `spawn` is guaranteed
-  ## to not block.
+proc spawn*[TIn, TOut](p: var TActorPool[TIn, TOut], input: TIn,
+                       action: proc (input: TIn): TOut {.thread.}
+                       ): ptr TChannel[TOut] =
+  ## uses the actor pool to run ``action(input)`` concurrently.
+  ## `spawn` is guaranteed to not block.
+  var t: TTask[TIn, TOut]
   setupTask()
   result = addr(p.outputs)
+  t.receiver = result
   schedule()
 
-proc spawn*[TIn](p: var TActorPool[TIn, void],
-                 action: proc (input: TIn) {.thread.}, 
-                 input: TIn) =
-  ## uses the actor pool to run `action` concurrently. `spawn` is guaranteed
-  ## to not block.
+proc spawn*[TIn](p: var TActorPool[TIn, void], input: TIn,
+                 action: proc (input: TIn) {.thread.}) =
+  ## uses the actor pool to run ``action(input)`` concurrently.
+  ## `spawn` is guaranteed to not block.
+  var t: TTask[TIn, void]
   setupTask()
   schedule()
   
@@ -171,7 +172,7 @@ when isMainModule:
     a: TActorPool[int, void]
   createActorPool(a)
   for i in 0 .. < 300:
-    a.spawn(proc (x: int) {.thread.} = echo x)
+    a.spawn(i, proc (x: int) {.thread.} = echo x)
 
   when false:
     proc treeDepth(n: PNode): int {.thread.} =
diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim
index 67644e156..3e85a9ee6 100755
--- a/lib/pure/parsecfg.nim
+++ b/lib/pure/parsecfg.nim
@@ -323,6 +323,7 @@ proc getKeyValPair(c: var TCfgParser, kind: TCfgEventKind): TCfgEvent =
       if c.tok.kind == tkSymbol: 
         result.value = c.tok.literal
       else: 
+        reset result
         result.kind = cfgError
         result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal)
       rawGetTok(c, c.tok)
diff --git a/lib/system/threads.nim b/lib/system/threads.nim
index 2079762f8..9fbea2e1a 100755
--- a/lib/system/threads.nim
+++ b/lib/system/threads.nim
@@ -252,8 +252,10 @@ type
       object of TGcThread ## Nimrod thread. A thread is a heavy object (~14K)
                           ## that **must not** be part of a message! Use
                           ## a ``TThreadId`` for that.
-    dataFn: proc (m: TArg)
-    when TArg isnot void:
+    when TArg is void:
+      dataFn: proc ()
+    else:
+      dataFn: proc (m: TArg)
       data: TArg
   TThreadId*[TArg] = ptr TThread[TArg] ## the current implementation uses
                                        ## a pointer as a thread ID.
@@ -273,7 +275,7 @@ template ThreadProcWrapperBody(closure: expr) =
   when defined(registerThread):
     t.stackBottom = addr(t)
     registerThread(t)
-  if TArg is void: t.dataFn()
+  when TArg is void: t.dataFn()
   else: t.dataFn(t.data)
   when defined(registerThread): unregisterThread(t)
   when defined(deallocOsPages): deallocOsPages()
diff --git a/todo.txt b/todo.txt
index ad80e4812..d8f0ac65a 100755
--- a/todo.txt
+++ b/todo.txt
@@ -6,6 +6,11 @@ Version 0.8.14
 - fix the 'const' issues
 - test the sort implementation again
 - optional indentation for 'case' statement
+- taint mode
+- const ptr/ref
+- 'let x = y'
+- {.error.} pragma for proc headers
+
 
 version 0.9.0
 =============
@@ -27,6 +32,14 @@ Bugs
   - bug: memset() without type field initialization?
   - special case the generic assign that needs to care about case objects
 
+- bug: returning a tyVar does not mean it is save to return it:
+  proc forward[T](x: var T): var T = result = x
+  proc p(): var int = 
+    var x: int
+    result = forward(x)
+
+- bug: DLL generation is broken
+
 
 version 0.9.XX
 ==============