summary refs log tree commit diff stats
path: root/rod
diff options
context:
space:
mode:
Diffstat (limited to 'rod')
-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
7 files changed, 320 insertions, 121 deletions
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)