summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2011-04-01 15:07:16 +0200
committerAraq <rumpf_a@web.de>2011-04-01 15:07:16 +0200
commit4741e8f9a1d1148d58e129626952219e14ede255 (patch)
treedb2eca2249ccc3230dc6c0a7359986198cab4048
parentdc669155e39007f1b584eef247dff90523f836bf (diff)
downloadNim-4741e8f9a1d1148d58e129626952219e14ede255.tar.gz
ugh, maybe broke git
-rwxr-xr-xdoc/grammar.txt6
-rwxr-xr-xlib/pure/hashes.nim38
-rwxr-xr-xlib/pure/httpclient.nim5
-rwxr-xr-xlib/pure/json.nim14
-rwxr-xr-xlib/pure/os.nim6
-rwxr-xr-xlib/pure/parsexml.nim2
-rwxr-xr-xlib/pure/xmlparser.nim4
-rwxr-xr-xlib/pure/xmltree.nim19
-rwxr-xr-xlib/system.nim69
-rwxr-xr-xlib/wrappers/gtk/gtk2.nim5
-rwxr-xr-xrod/ast.nim6
-rwxr-xr-xrod/pnimsyn.nim67
-rwxr-xr-xrod/rnimsyn.nim76
-rwxr-xr-xrod/seminst.nim2
-rwxr-xr-xrod/semstmts.nim171
-rwxr-xr-xrod/semtypes.nim77
-rwxr-xr-xrod/sigmatch.nim42
-rw-r--r--tests/accept/compile/tconstraints.nim15
-rw-r--r--tests/accept/compile/tgenericmatcher.nim19
-rw-r--r--tests/accept/compile/tgenericrefs.nim24
-rw-r--r--tests/accept/run/tfielditerator.nim46
-rw-r--r--tests/accept/run/tkoeniglookup.nim17
-rw-r--r--tests/reject/tconstraints.nim18
-rwxr-xr-xtodo.txt9
-rwxr-xr-xtools/buildsh.tmpl2
25 files changed, 587 insertions, 172 deletions
diff --git a/doc/grammar.txt b/doc/grammar.txt
index c84caec49..062698690 100755
--- a/doc/grammar.txt
+++ b/doc/grammar.txt
@@ -137,7 +137,11 @@ pragma ::= '{.' optInd (colonExpr [comma])* optPar ('.}' | '}')
 param ::= symbol (comma symbol)* (':' typeDesc ['=' expr] | '=' expr)
 paramList ::= ['(' [param (comma param)*] optPar ')'] [':' typeDesc]
 
-genericParam ::= symbol [':' typeDesc] ['=' expr]
+genericConstraint ::= 'object' | 'tuple' | 'enum' | 'proc' | 'ref' | 'ptr' 
+                    | 'var' | 'distinct' | primary
+genericConstraints ::= genericConstraint ( '|' optInd genericConstraint )*
+
+genericParam ::= symbol [':' genericConstraints] ['=' expr]
 genericParams ::= '[' genericParam (comma genericParam)* optPar ']'
 
 
diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim
index 1593119bd..87d672ae7 100755
--- a/lib/pure/hashes.nim
+++ b/lib/pure/hashes.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2008 Andreas Rumpf
+#        (c) Copyright 2011 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -30,14 +30,10 @@ proc finishHash(h: THash): THash {.inline.} =
 
 proc hashData*(Data: Pointer, Size: int): THash = 
   ## hashes an array of bytes of size `size`
-  var 
-    h: THash
-    p: cstring
-    i, s: int
-  h = 0
-  p = cast[cstring](Data)
-  i = 0
-  s = size
+  var h: THash = 0
+  var p = cast[cstring](Data)
+  var i = 0
+  var s = size
   while s > 0: 
     h = concHash(h, ord(p[i]))
     Inc(i)
@@ -62,20 +58,16 @@ proc hash*(x: char): THash {.inline.} =
 
 proc hash*(x: string): THash = 
   ## efficient hashing of strings
-  var h: THash
-  h = 0
+  var h: THash = 0
   for i in 0..x.len-1: 
     h = concHash(h, ord(x[i]))
   result = finishHash(h)
   
 proc hashIgnoreStyle*(x: string): THash = 
   ## efficient hashing of strings; style is ignored
-  var 
-    h: THash
-    c: Char
-  h = 0
+  var h: THash = 0
   for i in 0..x.len-1: 
-    c = x[i]
+    var c = x[i]
     if c == '_': 
       continue                # skip _
     if c in {'A'..'Z'}: 
@@ -85,13 +77,17 @@ proc hashIgnoreStyle*(x: string): THash =
 
 proc hashIgnoreCase*(x: string): THash = 
   ## efficient hashing of strings; case is ignored
-  var 
-    h: THash
-    c: Char
-  h = 0
+  var h: THash = 0
   for i in 0..x.len-1: 
-    c = x[i]
+    var c = x[i]
     if c in {'A'..'Z'}: 
       c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
     h = concHash(h, ord(c))
   result = finishHash(h)
+  
+proc hash*[T: tuple](x: T): THash = 
+  ## efficient hashing of tuples.
+  for f in fields(x):
+    result = concHash(result, hash(f))
+  result = finishHash(result)
+
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 092d8e5c6..39ceb5f68 100755
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -237,10 +237,7 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "",
   var r = parseUrl(url)
   
   var headers = copy($httpMethod, len("http"))
-  if r.path != "":
-    headers.add(" /" & r.path & r.query)
-  else:
-    headers.add(" /")
+  headers.add(" /" & r.path & r.query)
   headers.add(" HTTP/1.1\c\L")
   
   add(headers, "Host: " & r.hostname & "\c\L")
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 7fbc8bfcf..c90c071b6 100755
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -700,6 +700,18 @@ proc `$`*(node: PJsonNode): String =
   result = ""
   toPretty(result, node, 1, False)
 
+iterator items*(node: PJsonNode): PJSonNode =
+  ## Iterator for the items of `node`. `node` has to be a JArray.
+  assert node.kind == JArray
+  for i in items(node.elems):
+    yield i
+
+iterator pairs*(node: PJsonNode): tuple[key: string, val: PJsonNode] =
+  ## Iterator for the child elements of `node`. `node` has to be a JObject.
+  assert node.kind == JObject
+  for key, val in items(node.fields):
+    yield (key, val)
+
 proc eat(p: var TJsonParser, tok: TTokKind) = 
   if p.tok == tok: discard getTok(p)
   else: raiseParseErr(p, tokToStr[tok])
@@ -711,7 +723,7 @@ proc parseJson(p: var TJsonParser): PJsonNode =
     result = newJString(p.a)
     discard getTok(p)
   of tkInt:
-    result = newJInt(parseInt(p.a))
+    result = newJInt(parseBiggestInt(p.a))
     discard getTok(p)
   of tkFloat:
     result = newJFloat(parseFloat(p.a))
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index f7d22ca06..d9b81365f 100755
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -1130,6 +1130,12 @@ proc getConfigDir*(): string {.rtl, extern: "nos$1".} =
   when defined(windows): return getEnv("APPDATA") & "\\"
   else: return getEnv("HOME") & "/.config/"
 
+proc getTempDir*(): string {.rtl, extern: "nos$1".} =
+  ## Returns the temporary directory of the current user for applications to
+  ## save temporary files in.
+  when defined(windows): return getEnv("TEMP") & "\\"
+  else: return "/tmp/"
+
 when defined(windows):
   # Since we support GUI applications with Nimrod, we sometimes generate
   # a WinMain entry proc. But a WinMain proc has no access to the parsed
diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim
index 8551dda90..c49986087 100755
--- a/lib/pure/parsexml.nim
+++ b/lib/pure/parsexml.nim
@@ -586,11 +586,11 @@ proc next*(my: var TXmlParser) =
   of stateNormal:
     getTok(my)  
   of stateStart:
+    my.state = stateNormal
     getTok(my)
     if my.kind == xmlPI and my.a == "xml": 
       # just skip the first ``<?xml >`` processing instruction
       getTok(my)
-    my.state = stateNormal
   of stateAttr:
     # parse an attribute key-value pair:
     if my.buf[my.bufpos] == '>':
diff --git a/lib/pure/xmlparser.nim b/lib/pure/xmlparser.nim
index ad28bf618..8c5c5f5ab 100755
--- a/lib/pure/xmlparser.nim
+++ b/lib/pure/xmlparser.nim
@@ -68,11 +68,11 @@ proc parse(x: var TXmlParser, errors: var seq[string]): PXmlNode =
   of xmlElementOpen: 
     result = newElement(x.elementName)
     next(x)
-    result.attr = newStringTable()
+    result.attrs = newStringTable()
     while true: 
       case x.kind
       of xmlAttribute:
-        result.attr[x.attrKey] = x.attrValue
+        result.attrs[x.attrKey] = x.attrValue
         next(x)
       of xmlElementClose:
         next(x)
diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim
index 57988698b..41765b87a 100755
--- a/lib/pure/xmltree.nim
+++ b/lib/pure/xmltree.nim
@@ -98,17 +98,17 @@ iterator items*(n: PXmlNode): PXmlNode {.inline.} =
   assert n.k == xnElement
   for i in 0 .. n.len-1: yield n[i]
 
-proc attr*(n: PXmlNode): PXmlAttributes {.inline.} = 
+proc attrs*(n: PXmlNode): PXmlAttributes {.inline.} = 
   ## gets the attributes belonging to `n`.
   assert n.k == xnElement
   result = n.fAttr
   
-proc `attr=`*(n: PXmlNode, attr: PXmlAttributes) {.inline.} = 
+proc `attrs=`*(n: PXmlNode, attr: PXmlAttributes) {.inline.} = 
   ## sets the attributes belonging to `n`.
   assert n.k == xnElement
   n.fAttr = attr
 
-proc attrLen*(n: PXmlNode): int {.inline.} = 
+proc attrsLen*(n: PXmlNode): int {.inline.} = 
   ## returns the number of `n`'s attributes.
   assert n.k == xnElement
   if not isNil(n.fAttr): result = len(n.fAttr)
@@ -262,3 +262,16 @@ macro `<>`*(x: expr): expr =
   ##
   result = xmlConstructor(x)
 
+proc child*(n: PXmlNode, name: string): PXmlNode =
+  ## Finds the first child element of `n` with a name of `name`.
+  ## Returns `nil` on failure.
+  assert n.kind == xnElement
+  for i in items(n):
+    if i.kind == xnElement:
+      if i.tag == name:
+        return i
+
+proc attr*(n: PXmlNode, name: string): string =
+  ## Finds the first attribute of `n` with a name of `name`.
+  assert n.kind == xnElement
+  return n.attrs[name]
diff --git a/lib/system.nim b/lib/system.nim
index 09b85d32b..daf0c5423 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -765,7 +765,7 @@ proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} =
   setLen(x, xl + y.len)
   for i in 0..high(y): x[xl+i] = y[i]
 
-proc del* [T](x: var seq[T], i: int) {.noSideEffect.} = 
+proc del*[T](x: var seq[T], i: int) {.noSideEffect.} = 
   ## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
   ## This is an O(1) operation.
   var xl = x.len
@@ -1111,15 +1111,6 @@ iterator items*(a: cstring): char {.inline.} =
     yield a[i]
     inc(i)
 
-iterator enumerate*[TContainer, TItem](a: TContainer): tuple[
-                    index: int, item: TItem] {.inline.} = 
-  ## iterates over each item of `a` via `items` and yields an additional
-  ## counter/index starting from 0.
-  var j = 0
-  for it in items(a): 
-    yield (j, a)
-    inc j
-
 proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil".}
 proc isNil*[T](x: ref T): bool {.noSideEffect, magic: "IsNil".}
 proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil".}
@@ -1170,7 +1161,7 @@ when not defined(NimrodVM):
 
 proc find*[T, S: typeDesc](a: T, item: S): int {.inline.}=
   ## Returns the first index of `item` in `a` or -1 if not found. This requires
-  ## appropriate `items` and `==` procs to work.
+  ## appropriate `items` and `==` operations to work.
   for i in items(a):
     if i == item: return
     inc(result)
@@ -1200,6 +1191,62 @@ proc each*[T](data: var openArray[T], op: proc (x: var T)) =
   ## `op` to every item in `data`.
   for i in 0..data.len-1: op(data[i])
 
+iterator fields*(x: tuple[]): expr {.magic: "Fields", noSideEffect.}
+  ## iterates over every field of `x`. Warning: This is really transforms
+  ## the 'for' and unrolls the loop. The current implementation also has a bug
+  ## that affects symbol binding in the loop body.
+iterator fields*(x, y: tuple[]): tuple[a, b: expr] {.
+  magic: "Fields", noSideEffect.}
+  ## iterates over every field of `x` and `y`.
+  ## Warning: This is really transforms the 'for' and unrolls the loop. 
+  ## The current implementation also has a bug that affects symbol binding
+  ## in the loop body.
+iterator fieldPairs*(x: tuple[]): expr {.magic: "FieldPairs", noSideEffect.}
+  ## iterates over every field of `x`. Warning: This is really transforms
+  ## the 'for' and unrolls the loop. The current implementation also has a bug
+  ## that affects symbol binding in the loop body.
+iterator fieldPairs*(x, y: tuple[]): tuple[a, b: expr] {.
+  magic: "FieldPairs", noSideEffect.}
+  ## iterates over every field of `x` and `y`.
+  ## Warning: This is really transforms the 'for' and unrolls the loop. 
+  ## The current implementation also has a bug that affects symbol binding
+  ## in the loop body.
+
+proc `==`*[T: tuple](x, y: T): bool = 
+  ## generic ``==`` operator that is lifted from the components
+  ## of `x` and `y`.
+  for a, b in fields(x, y):
+    if a != b: return false
+  return true
+
+proc `<=`*[T: tuple](x, y: T): bool = 
+  ## generic ``<=`` operator that is lifted from the components
+  ## of `x` and `y`. This implementation uses `cmp`.
+  for a, b in fields(x, y):
+    var c = cmp(a, b)
+    if c < 0: return true
+    if c > 0: return false
+  return true
+
+proc `<`*[T: tuple](x, y: T): bool = 
+  ## generic ``<`` operator that is lifted from the components
+  ## of `x` and `y`. This implementation uses `cmp`.
+  for a, b in fields(x, y):
+    var c = cmp(a, b)
+    if c < 0: return true
+    if c > 0: return false
+  return false
+
+proc `$`*[T: tuple](x: T): string = 
+  ## generic ``$`` operator that is lifted from the components of `x`.
+  result = "("
+  for name, value in fieldPairs(x):
+    if result.len > 1: result.add(", ")
+    result.add(name)
+    result.add(": ")
+    result.add($value)
+  result.add(")")
+
 # ----------------- GC interface ---------------------------------------------
 
 proc GC_disable*() {.rtl, inl.}
diff --git a/lib/wrappers/gtk/gtk2.nim b/lib/wrappers/gtk/gtk2.nim
index 7bfed2d64..f1e4ec13f 100755
--- a/lib/wrappers/gtk/gtk2.nim
+++ b/lib/wrappers/gtk/gtk2.nim
@@ -1059,7 +1059,7 @@ type
   TResponseType* = int32
   PDialog* = ptr TDialog
   TDialog* = object of TWindow
-    vbox*: PWidget
+    vbox*: PBox
     action_area*: PWidget
     separator*: PWidget
 
@@ -16866,6 +16866,9 @@ proc set_do_overwrite_confirmation*(chooser: PFileChooser,
     do_overwrite_confirmation: gboolean){.cdecl, dynlib: lib, 
     importc: "gtk_file_chooser_set_do_overwrite_confirmation".}
 
+proc get_realized*(w: PWidget): gboolean {.cdecl, dynlib: lib,
+                                           importc: "gtk_widget_get_realized".}
+
 proc nimrod_init*() = 
   var 
     cmdLine{.importc: "cmdLine".}: array[0..255, cstring]
diff --git a/rod/ast.nim b/rod/ast.nim
index e19192f1f..fb610f565 100755
--- a/rod/ast.nim
+++ b/rod/ast.nim
@@ -237,7 +237,7 @@ type
     tyGenericParam,      # ``a`` in the example
     tyDistinct,
     tyEnum,
-    tyOrdinal,
+    tyOrdinal,           # misnamed: should become 'tyConstraint'
     tyArray,
     tyObject,
     tyTuple,
@@ -329,7 +329,9 @@ type
     mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr, 
     mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, 
     mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT, 
-    mConTArr, mConTT, mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem, 
+    mConTArr, mConTT, mSlice, 
+    mFields, mFieldPairs,
+    mAppendStrCh, mAppendStrStr, mAppendSeqElem, 
     mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, mAssert, 
     mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, mNewString, mReset, 
     mArray, mOpenArray, mRange, mSet, mSeq, 
diff --git a/rod/pnimsyn.nim b/rod/pnimsyn.nim
index fb2b7429e..869d968b6 100755
--- a/rod/pnimsyn.nim
+++ b/rod/pnimsyn.nim
@@ -1014,12 +1014,77 @@ proc parseAsm(p: var TParser): PNode =
     return 
   getTok(p)
 
+proc parseGenericConstraint(p: var TParser): PNode = 
+  case p.tok.tokType
+  of tkObject:
+    result = newNodeP(nkObjectTy, p)
+    getTok(p)
+  of tkTuple:
+    result = newNodeP(nkTupleTy, p)
+    getTok(p)
+  of tkEnum: 
+    result = newNodeP(nkEnumTy, p)
+    getTok(p)
+  of tkProc:
+    result = newNodeP(nkProcTy, p)
+    getTok(p)
+  of tkVar:
+    result = newNodeP(nkVarTy, p)
+    getTok(p)
+  of tkPtr:
+    result = newNodeP(nkPtrTy, p)
+    getTok(p)
+  of tkRef:
+    result = newNodeP(nkRefTy, p)
+    getTok(p)
+  of tkDistinct:
+    result = newNodeP(nkDistinctTy, p)
+    getTok(p)
+  else: result = primary(p)
+
+proc parseGenericConstraintList(p: var TParser): PNode = 
+  result = parseGenericConstraint(p)
+  while p.tok.tokType == tkOpr:
+    var a = result
+    result = newNodeP(nkInfix, p)
+    addSon(result, newIdentNodeP(p.tok.ident, p))
+    addSon(result, a)
+    getTok(p)
+    optInd(p, result)
+    addSon(result, parseGenericConstraint(p))
+
+proc parseGenericParam(p: var TParser): PNode = 
+  var a: PNode
+  result = newNodeP(nkIdentDefs, p)
+  while true: 
+    case p.tok.tokType
+    of tkSymbol, tkAccent: 
+      a = parseSymbol(p)
+      if a.kind == nkEmpty: return 
+    else: break 
+    addSon(result, a)
+    if p.tok.tokType != tkComma: break 
+    getTok(p)
+    optInd(p, a)
+  if p.tok.tokType == tkColon: 
+    getTok(p)
+    optInd(p, result)
+    addSon(result, parseGenericConstraintList(p))
+  else: 
+    addSon(result, ast.emptyNode)
+  if p.tok.tokType == tkEquals: 
+    getTok(p)
+    optInd(p, result)
+    addSon(result, parseExpr(p))
+  else: 
+    addSon(result, ast.emptyNode)
+
 proc parseGenericParamList(p: var TParser): PNode = 
   result = newNodeP(nkGenericParams, p)
   getTok(p)
   optInd(p, result)
   while (p.tok.tokType == tkSymbol) or (p.tok.tokType == tkAccent): 
-    var a = parseIdentColonEquals(p, {withBothOptional})
+    var a = parseGenericParam(p)
     addSon(result, a)
     if p.tok.tokType != tkComma: break 
     getTok(p)
diff --git a/rod/rnimsyn.nim b/rod/rnimsyn.nim
index 2c97876b1..01d3e066c 100755
--- a/rod/rnimsyn.nim
+++ b/rod/rnimsyn.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nimrod Compiler
-#        (c) Copyright 2010 Andreas Rumpf
+#        (c) Copyright 2011 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -839,17 +839,29 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     putWithSpace(g, tkType, "type")
     gsub(g, n.sons[0])
   of nkRefTy: 
-    putWithSpace(g, tkRef, "ref")
-    gsub(g, n.sons[0])
+    if sonsLen(n) > 0:
+      putWithSpace(g, tkRef, "ref")
+      gsub(g, n.sons[0])
+    else:
+      put(g, tkRef, "ref")
   of nkPtrTy: 
-    putWithSpace(g, tkPtr, "ptr")
-    gsub(g, n.sons[0])
+    if sonsLen(n) > 0:
+      putWithSpace(g, tkPtr, "ptr")
+      gsub(g, n.sons[0])
+    else:
+      put(g, tkPtr, "ptr")
   of nkVarTy: 
-    putWithSpace(g, tkVar, "var")
-    gsub(g, n.sons[0])
+    if sonsLen(n) > 0:
+      putWithSpace(g, tkVar, "var")
+      gsub(g, n.sons[0])
+    else:
+      put(g, tkVar, "var")
   of nkDistinctTy: 
-    putWithSpace(g, tkDistinct, "distinct")
-    gsub(g, n.sons[0])
+    if sonsLen(n) > 0:
+      putWithSpace(g, tkDistinct, "distinct")
+      gsub(g, n.sons[0])
+    else:
+      put(g, tkDistinct, "distinct")
   of nkTypeDef: 
     gsub(g, n.sons[0])
     gsub(g, n.sons[1])
@@ -858,11 +870,14 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       putWithSpace(g, tkEquals, "=")
       gsub(g, n.sons[2])
   of nkObjectTy: 
-    putWithSpace(g, tkObject, "object")
-    gsub(g, n.sons[0])
-    gsub(g, n.sons[1])
-    gcoms(g)
-    gsub(g, n.sons[2])
+    if sonsLen(n) > 0:
+      putWithSpace(g, tkObject, "object")
+      gsub(g, n.sons[0])
+      gsub(g, n.sons[1])
+      gcoms(g)
+      gsub(g, n.sons[2])
+    else:
+      put(g, tkObject, "object")
   of nkRecList: 
     indentNL(g)
     for i in countup(0, sonsLen(n) - 1): 
@@ -875,17 +890,23 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     putWithSpace(g, tkOf, "of")
     gsub(g, n.sons[0])
   of nkProcTy: 
-    putWithSpace(g, tkProc, "proc")
-    gsub(g, n.sons[0])
-    gsub(g, n.sons[1])
+    if sonsLen(n) > 0:
+      putWithSpace(g, tkProc, "proc")
+      gsub(g, n.sons[0])
+      gsub(g, n.sons[1])
+    else:
+      put(g, tkProc, "proc")
   of nkEnumTy: 
-    putWithSpace(g, tkEnum, "enum")
-    gsub(g, n.sons[0])
-    gcoms(g)
-    indentNL(g)
-    gcommaAux(g, n, g.indent, 1)
-    gcoms(g)                  # BUGFIX: comment for the last enum field
-    dedent(g)
+    if sonsLen(n) > 0:
+      putWithSpace(g, tkEnum, "enum")
+      gsub(g, n.sons[0])
+      gcoms(g)
+      indentNL(g)
+      gcommaAux(g, n, g.indent, 1)
+      gcoms(g)                  # BUGFIX: comment for the last enum field
+      dedent(g)
+    else:
+      put(g, tkEnum, "enum")
   of nkEnumFieldDef: 
     gsub(g, n.sons[0])
     put(g, tkSpaces, Space)
@@ -1033,9 +1054,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
       gsub(g, n.sons[0])
   of nkTupleTy: 
     put(g, tkTuple, "tuple")
-    put(g, tkBracketLe, "[")
-    gcomma(g, n)
-    put(g, tkBracketRi, "]")
+    if sonsLen(n) > 0:
+      put(g, tkBracketLe, "[")
+      gcomma(g, n)
+      put(g, tkBracketRi, "]")
   else: 
     #nkNone, nkMetaNode, nkTableConstr, nkExplicitTypeListCall: 
     InternalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
diff --git a/rod/seminst.nim b/rod/seminst.nim
index 2f26026ad..99fd1fb87 100755
--- a/rod/seminst.nim
+++ b/rod/seminst.nim
@@ -118,7 +118,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   c.p = oldP                  # restore
   c.module = oldMod
   dec(c.InstCounter)
-    
+  
 proc instGenericContainer(c: PContext, n: PNode, header: PType): PType = 
   var cl: TReplTypeVars
   InitIdTable(cl.symMap)
diff --git a/rod/semstmts.nim b/rod/semstmts.nim
index 176fdad1b..b2fae3f31 100755
--- a/rod/semstmts.nim
+++ b/rod/semstmts.nim
@@ -358,49 +358,120 @@ proc semConst(c: PContext, n: PNode): PNode =
     addSon(b, copyTree(def))
     addSon(result, b)
 
+proc transfFieldLoopBody(n: PNode, forLoop: PNode,
+                         tupleType: PType,
+                         tupleIndex, first: int): PNode = 
+  case n.kind
+  of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n
+  of nkIdent:
+    result = n
+    var L = sonsLen(forLoop)
+    # field name:
+    if first > 0:
+      if n.ident.id == forLoop[0].ident.id:
+        if tupleType.n == nil: 
+          # ugh, there are no field names:
+          result = newStrNode(nkStrLit, "")
+        else:
+          result = newStrNode(nkStrLit, tupleType.n.sons[tupleIndex].sym.name.s)
+        return
+    # other fields:
+    for i in first..L-3:
+      if n.ident.id == forLoop[i].ident.id:
+        var call = forLoop.sons[L-2]
+        var tupl = call.sons[i+1-first]
+        result = newNodeI(nkBracketExpr, n.info)
+        result.add(tupl)
+        result.add(newIntNode(nkIntLit, tupleIndex))
+        break
+  else:
+    result = copyNode(n)
+    newSons(result, sonsLen(n))
+    for i in countup(0, sonsLen(n)-1):
+      result.sons[i] = transfFieldLoopBody(n.sons[i], forLoop,
+                                           tupleType, tupleIndex, first)
+
+proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = 
+  # so that 'break' etc. work as expected, we produce 
+  # a 'while true: stmt; break' loop ...
+  result = newNodeI(nkWhileStmt, n.info)
+  var trueSymbol = StrTableGet(magicsys.systemModule.Tab, getIdent"true")
+  if trueSymbol == nil: GlobalError(n.info, errSystemNeeds, "true")
+
+  result.add(newSymNode(trueSymbol, n.info))
+  var stmts = newNodeI(nkStmtList, n.info)
+  result.add(stmts)
+  
+  var length = sonsLen(n)
+  var call = n.sons[length-2]
+  if length-2 != sonsLen(call)-1 + ord(m==mFieldPairs):
+    GlobalError(n.info, errWrongNumberOfVariables)
+  
+  var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar)
+  if tupleTypeA.kind != tyTuple: InternalError(n.info, "no tuple type!")
+  for i in 1..call.len-1:
+    var tupleTypeB = skipTypes(call.sons[i].typ, abstractVar)
+    if not SameType(tupleTypeA, tupleTypeB):
+      typeMismatch(call.sons[i], tupleTypeA, tupleTypeB)
+  
+  Inc(c.p.nestedLoopCounter)
+  var loopBody = n.sons[length-1]
+  for i in 0..sonsLen(tupleTypeA)-1:
+    openScope(c.tab)
+    var body = transfFieldLoopBody(loopBody, n, tupleTypeA, i,
+                                   ord(m==mFieldPairs))
+    stmts.add(SemStmt(c, body))
+    closeScope(c.tab)
+  Dec(c.p.nestedLoopCounter)
+  var b = newNodeI(nkBreakStmt, n.info)
+  b.add(ast.emptyNode)
+  stmts.add(b)
+  
+proc createCountupNode(c: PContext, rangeNode: PNode): PNode = 
+  # convert ``in 3..5`` to ``in countup(3, 5)``
+  checkSonsLen(rangeNode, 2)
+  result = newNodeI(nkCall, rangeNode.info)
+  var countUp = StrTableGet(magicsys.systemModule.Tab, getIdent"countup")
+  if countUp == nil: GlobalError(rangeNode.info, errSystemNeeds, "countup")
+  newSons(result, 3)
+  result.sons[0] = newSymNode(countup)
+  result.sons[1] = rangeNode.sons[0]
+  result.sons[2] = rangeNode.sons[1]
+
 proc semFor(c: PContext, n: PNode): PNode = 
-  var 
-    v, countup: PSym
-    iter: PType
-    countupNode, call: PNode
   result = n
   checkMinSonsLen(n, 3)
   var length = sonsLen(n)
   openScope(c.tab)
-  if n.sons[length - 2].kind == nkRange: 
-    checkSonsLen(n.sons[length - 2], 2) 
-    # convert ``in 3..5`` to ``in countup(3, 5)``
-    countupNode = newNodeI(nkCall, n.sons[length - 2].info)
-    countUp = StrTableGet(magicsys.systemModule.Tab, getIdent("countup"))
-    if countUp == nil: GlobalError(countupNode.info, errSystemNeeds, "countup")
-    newSons(countupNode, 3)
-    countupnode.sons[0] = newSymNode(countup)
-    countupNode.sons[1] = n.sons[length - 2].sons[0]
-    countupNode.sons[2] = n.sons[length - 2].sons[1]
-    n.sons[length - 2] = countupNode
-  n.sons[length - 2] = semExprWithType(c, n.sons[length - 2], {efWantIterator})
-  call = n.sons[length - 2]
-  if (call.kind != nkCall) or (call.sons[0].kind != nkSym) or
-      (call.sons[0].sym.kind != skIterator): 
+  if n.sons[length-2].kind == nkRange:
+    n.sons[length-2] = createCountupNode(c, n.sons[length-2])
+  n.sons[length-2] = semExprWithType(c, n.sons[length-2], {efWantIterator})
+  var call = n.sons[length-2]
+  if call.kind != nkCall or call.sons[0].kind != nkSym or
+      call.sons[0].sym.kind != skIterator: 
     GlobalError(n.sons[length - 2].info, errIteratorExpected)
-  iter = skipTypes(n.sons[length - 2].typ, {tyGenericInst})
-  if iter.kind != tyTuple: 
-    if length != 3: GlobalError(n.info, errWrongNumberOfVariables)
-    v = newSymS(skForVar, n.sons[0], c)
-    v.typ = iter
-    n.sons[0] = newSymNode(v)
-    addDecl(c, v)
-  else: 
-    if length-2 != sonsLen(iter): GlobalError(n.info, errWrongNumberOfVariables)
-    for i in countup(0, length - 3): 
-      v = newSymS(skForVar, n.sons[i], c)
-      v.typ = iter.sons[i]
-      n.sons[i] = newSymNode(v)
+  elif call.sons[0].sym.magic != mNone:
+    result = semForFields(c, n, call.sons[0].sym.magic)
+  else:
+    var iter = skipTypes(n.sons[length-2].typ, {tyGenericInst})
+    if iter.kind != tyTuple: 
+      if length != 3: GlobalError(n.info, errWrongNumberOfVariables)
+      var v = newSymS(skForVar, n.sons[0], c)
+      v.typ = iter
+      n.sons[0] = newSymNode(v)
       addDecl(c, v)
-  Inc(c.p.nestedLoopCounter)
-  n.sons[length - 1] = SemStmt(c, n.sons[length - 1])
+    else: 
+      if length-2 != sonsLen(iter): 
+        GlobalError(n.info, errWrongNumberOfVariables)
+      for i in countup(0, length - 3): 
+        var v = newSymS(skForVar, n.sons[i], c)
+        v.typ = iter.sons[i]
+        n.sons[i] = newSymNode(v)
+        addDecl(c, v)
+    Inc(c.p.nestedLoopCounter)
+    n.sons[length-1] = SemStmt(c, n.sons[length-1])
+    Dec(c.p.nestedLoopCounter)
   closeScope(c.tab)
-  Dec(c.p.nestedLoopCounter)
 
 proc semRaise(c: PContext, n: PNode): PNode = 
   result = n
@@ -436,34 +507,6 @@ proc semTry(c: PContext, n: PNode): PNode =
     # last child of an nkExcept/nkFinally branch is a statement:
     a.sons[length - 1] = semStmtScope(c, a.sons[length - 1])
 
-proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = 
-  result = copyNode(n)
-  if n.kind != nkGenericParams: InternalError(n.info, "semGenericParamList")
-  for i in countup(0, sonsLen(n)-1): 
-    var a = n.sons[i]
-    if a.kind != nkIdentDefs: illFormedAst(n)
-    var L = sonsLen(a)
-    var def = a.sons[L-1]
-    var typ: PType
-    if a.sons[L-2].kind != nkEmpty: typ = semTypeNode(c, a.sons[L-2], nil)
-    elif def.kind != nkEmpty: typ = newTypeS(tyExpr, c)
-    else: typ = nil
-    for j in countup(0, L-3): 
-      var s: PSym
-      if (typ == nil) or (typ.kind == tyTypeDesc): 
-        s = newSymS(skType, a.sons[j], c)
-        s.typ = newTypeS(tyGenericParam, c)
-      else: 
-        # not a type param, but an expression
-        s = newSymS(skGenericParam, a.sons[j], c)
-        s.typ = typ
-      if def.kind != nkEmpty: s.ast = def
-      s.typ.sym = s
-      if father != nil: addSon(father, s.typ)
-      s.position = i
-      addSon(result, newSymNode(s))
-      addDecl(c, s)
-
 proc addGenericParamListToScope(c: PContext, n: PNode) = 
   if n.kind != nkGenericParams: 
     InternalError(n.info, "addGenericParamListToScope")
@@ -741,7 +784,7 @@ proc semIterator(c: PContext, n: PNode): PNode =
   var t = s.typ
   if t.sons[0] == nil: 
     LocalError(n.info, errXNeedsReturnType, "iterator")
-  if n.sons[codePos].kind == nkEmpty: 
+  if n.sons[codePos].kind == nkEmpty and s.magic == mNone: 
     LocalError(n.info, errImplOfXexpected, s.name.s)
   
 proc semProc(c: PContext, n: PNode): PNode = 
diff --git a/rod/semtypes.nim b/rod/semtypes.nim
index 90a774645..79511b716 100755
--- a/rod/semtypes.nim
+++ b/rod/semtypes.nim
@@ -173,12 +173,12 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
   else: 
     GlobalError(n.info, errXExpectsOneTypeParam, "ordinal")
   
-proc semTypeIdent(c: PContext, n: PNode): PSym = 
+proc semTypeIdent(c: PContext, n: PNode): PSym =
   result = qualifiedLookup(c, n, {checkAmbiguity, checkUndeclared})
-  if (result != nil): 
+  if result != nil:
     markUsed(n, result)
     if result.kind != skType: GlobalError(n.info, errTypeExpected)
-  else: 
+  else:
     GlobalError(n.info, errIdentifierExpected)
   
 proc semTuple(c: PContext, n: PNode, prev: PType): PType = 
@@ -441,8 +441,6 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
     if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags: 
       addInheritedFields(c, check, pos, concreteBase)
     else:
-      debug base
-      debug concreteBase
       localError(n.sons[1].info, errInheritanceOnlyWithNonFinalObjects)
   if n.kind != nkObjectTy: InternalError(n.info, "semObjectNode")
   result = newOrPrevType(tyObject, prev, c)
@@ -632,10 +630,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
 proc setMagicType(m: PSym, kind: TTypeKind, size: int) = 
   m.typ.kind = kind
   m.typ.align = size
-  m.typ.size = size           #m.typ.sym := nil;
+  m.typ.size = size
   
 proc processMagicType(c: PContext, m: PSym) = 
-  case m.magic                #registerSysType(m.typ);
+  case m.magic
   of mInt: setMagicType(m, tyInt, intSize)
   of mInt8: setMagicType(m, tyInt8, 1)
   of mInt16: setMagicType(m, tyInt16, 2)
@@ -656,13 +654,70 @@ proc processMagicType(c: PContext, m: PSym) =
   of mEmptySet: 
     setMagicType(m, tySet, 1)
     addSon(m.typ, newTypeS(tyEmpty, c))
-  of mIntSetBaseType: 
-    setMagicType(m, tyRange, intSize) #intSetBaseType := m.typ;
-    return 
+  of mIntSetBaseType: setMagicType(m, tyRange, intSize)
   of mNil: setMagicType(m, tyNil, ptrSize)
   of mExpr: setMagicType(m, tyExpr, 0)
   of mStmt: setMagicType(m, tyStmt, 0)
   of mTypeDesc: setMagicType(m, tyTypeDesc, 0)
-  of mArray, mOpenArray, mRange, mSet, mSeq, mOrdinal: return 
+  of mArray, mOpenArray, mRange, mSet, mSeq, mOrdinal: nil 
   else: GlobalError(m.info, errTypeExpected)
   
+proc newConstraint(c: PContext, k: TTypeKind): PType = 
+  result = newTypeS(tyOrdinal, c)
+  result.addSon(newTypeS(k, c))
+  
+proc semGenericConstraints(c: PContext, n: PNode, result: PType) = 
+  case n.kind
+  of nkProcTy: result.addSon(newConstraint(c, tyProc))
+  of nkEnumTy: result.addSon(newConstraint(c, tyEnum))
+  of nkObjectTy: result.addSon(newConstraint(c, tyObject))
+  of nkTupleTy: result.addSon(newConstraint(c, tyTuple))
+  of nkDistinctTy: result.addSon(newConstraint(c, tyDistinct))
+  of nkVarTy: result.addSon(newConstraint(c, tyVar))
+  of nkPtrTy: result.addSon(newConstraint(c, tyPtr))
+  of nkRefTy: result.addSon(newConstraint(c, tyRef))
+  of nkInfix: 
+    semGenericConstraints(c, n.sons[1], result)
+    semGenericConstraints(c, n.sons[2], result)
+  else:
+    result.addSon(semTypeNode(c, n, nil))
+
+proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = 
+  result = copyNode(n)
+  if n.kind != nkGenericParams: InternalError(n.info, "semGenericParamList")
+  for i in countup(0, sonsLen(n)-1): 
+    var a = n.sons[i]
+    if a.kind != nkIdentDefs: illFormedAst(n)
+    var L = sonsLen(a)
+    var def = a.sons[L-1]
+    var typ: PType
+    if a.sons[L-2].kind != nkEmpty: 
+      typ = newTypeS(tyGenericParam, c)
+      semGenericConstraints(c, a.sons[L-2], typ)
+    elif def.kind != nkEmpty: typ = newTypeS(tyExpr, c)
+    else: typ = nil
+    for j in countup(0, L-3): 
+      var s: PSym
+      if typ == nil:
+        s = newSymS(skType, a.sons[j], c)
+        s.typ = newTypeS(tyGenericParam, c)
+      else:
+        case typ.kind
+        of tyTypeDesc: 
+          s = newSymS(skType, a.sons[j], c)
+          s.typ = newTypeS(tyGenericParam, c)
+        of tyExpr:
+          # not a type param, but an expression
+          s = newSymS(skGenericParam, a.sons[j], c)
+          s.typ = typ
+        else:
+          s = newSymS(skType, a.sons[j], c)
+          s.typ = typ
+      if def.kind != nkEmpty: s.ast = def
+      s.typ.sym = s
+      if father != nil: addSon(father, s.typ)
+      s.position = i
+      addSon(result, newSymNode(s))
+      addDecl(c, s)
+
+  
diff --git a/rod/sigmatch.nim b/rod/sigmatch.nim
index 8144cff0b..1e61ddfe0 100755
--- a/rod/sigmatch.nim
+++ b/rod/sigmatch.nim
@@ -32,7 +32,10 @@ type
                              # for example
   
   TTypeRelation* = enum      # order is important!
-    isNone, isConvertible, isIntConv, isSubtype, isGeneric, isEqual
+    isNone, isConvertible, isIntConv, isSubtype, 
+    isLifted, # match, but do not change argument type to formal's type!
+    isGeneric, 
+    isEqual
 
 proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} = 
   c.exactMatches = 0
@@ -144,8 +147,8 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
   else: 
     var k = skipTypes(a, {tyRange}).kind
     if k == f.kind: result = isSubtype
-    elif (f.kind == tyInt) and (k in {tyInt..tyInt32}): result = isIntConv
-    elif (k >= min) and (k <= max): result = isConvertible
+    elif f.kind == tyInt and k in {tyInt..tyInt32}: result = isIntConv
+    elif k >= min and k <= max: result = isConvertible
     else: result = isNone
   
 proc handleFloatRange(f, a: PType): TTypeRelation = 
@@ -159,7 +162,7 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
   
 proc isObjectSubtype(a, f: PType): bool = 
   var t = a
-  while (t != nil) and (t.id != f.id): t = base(t)
+  while t != nil and t.id != f.id: t = base(t)
   result = t != nil
 
 proc minRel(a, b: TTypeRelation): TTypeRelation = 
@@ -182,11 +185,15 @@ proc tupleRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
         var x = f.n.sons[i].sym
         var y = a.n.sons[i].sym
         if x.name.id != y.name.id: return isNone
+  elif sonsLen(f) == 0:
+    idTablePut(mapping, f, a)
+    result = isLifted
+
+proc constraintRel(mapping: var TIdTable, f, a: PType): TTypeRelation = 
+  result = isNone
+  if f.kind == a.kind: result = isGeneric
 
 proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation = 
-  var 
-    x, concrete: PType
-    m: TTypeRelation
   # is a subtype of f?
   result = isNone
   assert(f != nil)
@@ -272,9 +279,11 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
         if result < isGeneric: result = isNone
     else: nil
   of tyOrdinal: 
-    if isOrdinalType(a): 
-      if a.kind == tyOrdinal: x = a.sons[0]
-      else: x = a
+    if f.sons[0].kind != tyGenericParam: 
+      # some constraint:
+      result = constraintRel(mapping, f.sons[0], a)
+    elif isOrdinalType(a): 
+      var x = if a.kind == tyOrdinal: a.sons[0] else: a
       result = typeRel(mapping, f.sons[0], x)
       if result < isGeneric: result = isNone
   of tyForward: InternalError("forward type in typeRel()")
@@ -319,6 +328,7 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
         # return type!
         result = isEqual      # start with maximum; also correct for no
                               # params at all
+        var m: TTypeRelation
         for i in countup(1, sonsLen(f) - 1): 
           m = typeRel(mapping, f.sons[i], a.sons[i])
           if (m == isNone) and
@@ -392,26 +402,25 @@ proc typeRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
       if result != isNone: 
         # we steal the generic parameters from the tyGenericBody:
         for i in countup(1, sonsLen(f) - 1): 
-          x = PType(idTableGet(mapping, f.sons[0].sons[i - 1]))
+          var x = PType(idTableGet(mapping, f.sons[0].sons[i - 1]))
           if (x == nil) or (x.kind == tyGenericParam): 
             InternalError("wrong instantiated type!")
           idTablePut(mapping, f.sons[i], x)
   of tyGenericParam: 
-    x = PType(idTableGet(mapping, f))
+    var x = PType(idTableGet(mapping, f))
     if x == nil: 
       if sonsLen(f) == 0: 
         # no constraints
-        concrete = concreteType(mapping, a)
+        var concrete = concreteType(mapping, a)
         if concrete != nil: 
           #MessageOut('putting: ' + f.sym.name.s);
           idTablePut(mapping, f, concrete)
           result = isGeneric
       else: 
-        InternalError(f.sym.info, "has constraints: " & f.sym.name.s) 
         # check constraints:
         for i in countup(0, sonsLen(f) - 1): 
           if typeRel(mapping, f.sons[i], a) >= isSubtype: 
-            concrete = concreteType(mapping, a)
+            var concrete = concreteType(mapping, a)
             if concrete != nil: 
               idTablePut(mapping, f, concrete)
               result = isGeneric
@@ -484,6 +493,9 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
   of isSubtype: 
     inc(m.subtypeMatches)
     result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
+  of isLifted:
+    inc(m.genericMatches)
+    result = copyTree(arg)
   of isGeneric: 
     inc(m.genericMatches)
     result = copyTree(arg)
diff --git a/tests/accept/compile/tconstraints.nim b/tests/accept/compile/tconstraints.nim
new file mode 100644
index 000000000..7aef0d645
--- /dev/null
+++ b/tests/accept/compile/tconstraints.nim
@@ -0,0 +1,15 @@
+
+
+proc myGenericProc[T: object|tuple|int|ptr|ref|distinct](x: T): string = 
+  result = $x
+
+type
+  TMyObj = tuple[x, y: int]
+
+var
+  x: TMyObj
+
+assert myGenericProc(232) == "232"
+assert myGenericProc(x) == "(x: 0, y: 0)"
+
+
diff --git a/tests/accept/compile/tgenericmatcher.nim b/tests/accept/compile/tgenericmatcher.nim
new file mode 100644
index 000000000..eaf3da67c
--- /dev/null
+++ b/tests/accept/compile/tgenericmatcher.nim
@@ -0,0 +1,19 @@
+
+type
+  TMatcherKind = enum
+    mkTerminal, mkSequence, mkAlternation, mkRepeat
+  TMatcher[T] = object
+    case kind: TMatcherKind
+    of mkTerminal:
+      value: T
+    of mkSequence, mkAlternation:
+      matchers: seq[TMatcher[T]]
+    of mkRepeat:
+      matcher: PMatcher[T]
+      min, max: int
+  PMatcher[T] = ref TMatcher[T]
+
+var 
+  m: PMatcher[int]
+
+
diff --git a/tests/accept/compile/tgenericrefs.nim b/tests/accept/compile/tgenericrefs.nim
new file mode 100644
index 000000000..b0e77cef5
--- /dev/null
+++ b/tests/accept/compile/tgenericrefs.nim
@@ -0,0 +1,24 @@
+# Compiles:
+
+type 
+  TA[T] = object
+  PA[T] = ref TA[T]
+var a: PA[string]
+
+# Compiles unless you use var a: PA[string]
+type 
+  PA = ref TA
+  TA[T] = object
+
+
+# Cannot instanciate:
+type 
+  TA[T] = object
+    a: PA[T]
+  PA[T] = ref TA[T]
+
+type 
+  PA[T] = ref TA[T]
+  TA[T] = object
+
+
diff --git a/tests/accept/run/tfielditerator.nim b/tests/accept/run/tfielditerator.nim
new file mode 100644
index 000000000..2919aab41
--- /dev/null
+++ b/tests/accept/run/tfielditerator.nim
@@ -0,0 +1,46 @@
+discard """
+  output: '''
+a char: true
+a char: false
+an int: 5
+an int: 6
+a string: abc
+false
+true
+true
+false
+true
+a: a
+b: b
+x: 5
+y: 6
+z: abc
+'''
+"""
+
+type
+  TMyTuple = tuple[a, b: char, x, y: int, z: string]
+
+proc p(x: char) = echo "a char: ", x <= 'a'
+proc p(x: int) = echo "an int: ", x
+proc p(x: string) = echo "a string: ", x
+
+var x: TMyTuple = ('a', 'b', 5, 6, "abc")
+var y: TMyTuple = ('A', 'b', 5, 9, "abc")
+
+for f in fields(x): 
+  p f
+
+for a, b in fields(x, y):
+  echo a == b
+
+for key, val in fieldPairs(x):
+  echo key, ": ", val
+
+assert x != y
+assert x == x
+assert(not (x < x))
+assert x <= x
+assert y < x
+assert y <= x
+
diff --git a/tests/accept/run/tkoeniglookup.nim b/tests/accept/run/tkoeniglookup.nim
new file mode 100644
index 000000000..07c5b46be
--- /dev/null
+++ b/tests/accept/run/tkoeniglookup.nim
@@ -0,0 +1,17 @@
+discard """
+  output: '''x: 0 y: 0'''
+"""
+
+proc ToString*[T](x: T): string = return $x
+
+
+type
+  TMyObj = object
+    x, y: int
+
+proc `$`*(a: TMyObj): bool = 
+  result = "x: " & a.x & " y: " & a.y
+
+var a: TMyObj
+echo toString(a)
+
diff --git a/tests/reject/tconstraints.nim b/tests/reject/tconstraints.nim
new file mode 100644
index 000000000..aafe86911
--- /dev/null
+++ b/tests/reject/tconstraints.nim
@@ -0,0 +1,18 @@
+discard """
+  line: 15
+  errormsg: "type mismatch: got (int)"
+"""
+
+proc myGenericProc[T: object|tuple|ptr|ref|distinct](x: T): string = 
+  result = $x
+
+type
+  TMyObj = tuple[x, y: int]
+
+var
+  x: TMyObj
+
+assert myGenericProc(232) == "232"
+assert myGenericProc(x) == "(x: 0, y: 0)"
+
+
diff --git a/todo.txt b/todo.txt
index 3853d0f20..09a9117dd 100755
--- a/todo.txt
+++ b/todo.txt
@@ -1,13 +1,8 @@
-- 'nimrod def': does not always work
-
 - thread support: threadvar on Windows seems broken; 
   add --deadlock_prevention:on|off switch
 - built-in serialization
 
 - deprecate ^ and make it available as operator
-- test branch coverage
-- checked exceptions
-- slicing
 
 
 High priority (version 0.9.0)
@@ -61,6 +56,10 @@ Low priority
 - nested tuple unpacking; no auto-unpacking in 'for' loops!
 - better error messages for used keywords as identifiers
 - case statement branches should support constant sets
+- 'nimrod def': does not always work
+- test branch coverage
+- checked exceptions
+- slicing
 
 
 Library
diff --git a/tools/buildsh.tmpl b/tools/buildsh.tmpl
index e763a5c05..8893f4da0 100755
--- a/tools/buildsh.tmpl
+++ b/tools/buildsh.tmpl
@@ -12,7 +12,7 @@ ucpu=`uname -m`
 uos=`uname`
 
 #  add(result, "# convert to lower case:\n")
-upcu=`echo $ucpu | tr "[:upper:]" "[:lower:]"`
+ucpu=`echo $ucpu | tr "[:upper:]" "[:lower:]"`
 uos=`echo $uos | tr "[:upper:]" "[:lower:]"`
 
 case $uos in