summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2013-08-30 12:44:27 +0200
committerAraq <rumpf_a@web.de>2013-08-30 12:44:27 +0200
commit8710118b2cb1428a6ddb7929edaeef060f360be9 (patch)
tree96772e55b0e6bb92c70044083bbb9db4d9918f13
parenta17076cf4fdfb27ee1d1f3be232b81584a99432a (diff)
parentc934a33ccd85716b66d44bca6a1764204507f33e (diff)
downloadNim-8710118b2cb1428a6ddb7929edaeef060f360be9.tar.gz
Merge branch 'master' of github.com:Araq/Nimrod
-rw-r--r--compiler/ast.nim7
-rw-r--r--compiler/evals.nim21
-rw-r--r--compiler/options.nim2
-rw-r--r--compiler/semdata.nim10
-rw-r--r--compiler/semexprs.nim2
-rw-r--r--compiler/semfold.nim16
-rw-r--r--compiler/seminst.nim49
-rw-r--r--compiler/semmagic.nim2
-rw-r--r--compiler/semstmts.nim16
-rw-r--r--compiler/semtypes.nim35
-rw-r--r--compiler/semtypinst.nim10
-rw-r--r--compiler/sigmatch.nim8
-rw-r--r--doc/manual.txt33
-rw-r--r--install.txt43
-rw-r--r--lib/pure/httpclient.nim67
-rw-r--r--lib/system.nim23
-rw-r--r--readme.md5
-rw-r--r--readme.txt5
-rw-r--r--tests/compile/tbindtypedesc.nim87
-rw-r--r--tests/compile/tgenericshardcases.nim30
-rw-r--r--tests/run/tmacrogenerics.nim39
-rw-r--r--tests/run/tstaticparams.nim9
22 files changed, 385 insertions, 134 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index bb015ea27..bb06e7163 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -626,6 +626,7 @@ type
     case kind*: TSymKind
     of skType:
       typeInstCache*: seq[PType]
+      typScope*: PScope
     of routineKinds:
       procInstCache*: seq[PInstantiation]
       scope*: PScope          # the scope where the proc was defined
@@ -799,9 +800,9 @@ const
     # imported via 'importc: "fullname"' and no format string.
 
 # creator procs:
-proc NewSym*(symKind: TSymKind, Name: PIdent, owner: PSym,
+proc newSym*(symKind: TSymKind, Name: PIdent, owner: PSym,
              info: TLineInfo): PSym
-proc NewType*(kind: TTypeKind, owner: PSym): PType
+proc newType*(kind: TTypeKind, owner: PSym): PType
 proc newNode*(kind: TNodeKind): PNode
 proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode
 proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode
@@ -1111,7 +1112,7 @@ proc copySym(s: PSym, keepId: bool = false): PSym =
   result.loc = s.loc
   result.annex = s.annex      # BUGFIX
   
-proc NewSym(symKind: TSymKind, Name: PIdent, owner: PSym,
+proc newSym(symKind: TSymKind, Name: PIdent, owner: PSym,
             info: TLineInfo): PSym = 
   # generates a symbol and initializes the hash field too
   new(result)
diff --git a/compiler/evals.nim b/compiler/evals.nim
index 3f09664a7..053068ea4 100644
--- a/compiler/evals.nim
+++ b/compiler/evals.nim
@@ -904,18 +904,15 @@ proc evalParseStmt(c: PEvalContext, n: PNode): PNode =
                        code.info.line.int)
   #result.typ = newType(tyStmt, c.module)
  
-proc evalTypeTrait*(n: PNode, context: PSym): PNode =
-  ## XXX: This should be pretty much guaranteed to be true
-  # by the type traits procs' signatures, but until the
-  # code is more mature it doesn't hurt to be extra safe
-  internalAssert n.sons.len >= 2 and n.sons[1].kind == nkSym
-
-  let typ = n.sons[1].sym.typ.skipTypes({tyTypeDesc})
-  case n.sons[0].sym.name.s.normalize
+proc evalTypeTrait*(trait, operand: PNode, context: PSym): PNode =
+  InternalAssert operand.kind == nkSym
+
+  let typ = operand.sym.typ.skipTypes({tyTypeDesc})
+  case trait.sym.name.s.normalize
   of "name":
-    result = newStrNode(nkStrLit, typ.typeToString(preferExported))
+    result = newStrNode(nkStrLit, typ.typeToString(preferName))
     result.typ = newType(tyString, context)
-    result.info = n.info
+    result.info = trait.info
   else:
     internalAssert false
 
@@ -1037,8 +1034,8 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
   of mParseStmtToAst: result = evalParseStmt(c, n)
   of mExpandToAst: result = evalExpandToAst(c, n)
   of mTypeTrait:
-    n.sons[1] = evalAux(c, n.sons[1], {})
-    result = evalTypeTrait(n, c.module)
+    let operand = evalAux(c, n.sons[1], {})
+    result = evalTypeTrait(n[0], operand, c.module)
   of mIs:
     n.sons[1] = evalAux(c, n.sons[1], {})
     result = evalIsOp(n)
diff --git a/compiler/options.nim b/compiler/options.nim
index 5f173d240..2b25b2650 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -156,6 +156,8 @@ var
 
 const oKeepVariableNames* = true
 
+const oUseLateInstantiation* = false
+
 proc mainCommandArg*: string =
   ## This is intended for commands like check or parse
   ## which will work on the main project file unless
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index b9c32a680..8b04f4af5 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -225,14 +225,14 @@ proc fillTypeS(dest: PType, kind: TTypeKind, c: PContext) =
   dest.owner = getCurrOwner()
   dest.size = - 1
 
-proc makeRangeType*(c: PContext, first, last: biggestInt, 
-                    info: TLineInfo): PType = 
+proc makeRangeType*(c: PContext; first, last: biggestInt;
+                    info: TLineInfo; intType = getSysType(tyInt)): PType =
   var n = newNodeI(nkRange, info)
-  addSon(n, newIntNode(nkIntLit, first))
-  addSon(n, newIntNode(nkIntLit, last))
+  addSon(n, newIntTypeNode(nkIntLit, first, intType))
+  addSon(n, newIntTypeNode(nkIntLit, last, intType))
   result = newTypeS(tyRange, c)
   result.n = n
-  rawAddSon(result, getSysType(tyInt)) # basetype of range
+  addSonSkipIntLit(result, intType) # basetype of range
 
 proc markIndirect*(c: PContext, s: PSym) {.inline.} =
   if s.kind in {skProc, skConverter, skMethod, skIterator}:
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 354cbcbd1..4d7ceffa9 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -113,7 +113,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
   of skGenericParam:
     if s.typ.kind == tyExpr:
       result = newSymNode(s, n.info)
-      result.typ = s.typ.lastSon
+      result.typ = s.typ
     elif s.ast != nil:
       result = semExpr(c, s.ast)
     else:
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 634ea8395..ca06ea1b6 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -561,9 +561,10 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
   case n.kind
   of nkSym: 
     var s = n.sym
-    if s.kind == skEnumField: 
+    case s.kind
+    of skEnumField:
       result = newIntNodeT(s.position, n)
-    elif s.kind == skConst: 
+    of skConst:
       case s.magic
       of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n)
       of mCompileDate: result = newStrNodeT(times.getDateStr(), n)
@@ -581,10 +582,17 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
       of mNegInf: result = newFloatNodeT(NegInf, n)
       else:
         if sfFakeConst notin s.flags: result = copyTree(s.ast)
-    elif s.kind in {skProc, skMethod}: # BUGFIX
+    of {skProc, skMethod}:
       result = n
-    elif s.kind in {skType, skGenericParam}:
+    of skType:
       result = newSymNodeTypeDesc(s, n.info)
+    of skGenericParam:
+      if s.typ.kind == tyExpr:
+        result = s.typ.n
+        result.typ = s.typ.sons[0]
+      else:
+        result = newSymNodeTypeDesc(s, n.info)
+    else: nil
   of nkCharLit..nkNilLit: 
     result = copyNode(n)
   of nkIfExpr: 
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 601072833..0cf5086a8 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -130,13 +130,50 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
       s.ast.sons[genericParamsPos].kind == nkEmpty:
     c.threadEntries.add(s)
 
+proc lateInstantiateGeneric(c: PContext, invocation: PType, info: TLineInfo): PType =
+  InternalAssert invocation.kind == tyGenericInvokation
+  
+  let cacheHit = searchInstTypes(invocation)
+  if cacheHit != nil:
+    result = cacheHit
+  else:
+    let s = invocation.sons[0].sym
+    let oldScope = c.currentScope
+    c.currentScope = s.typScope
+    openScope(c)
+    pushInfoContext(info)
+    for i in 0 .. <s.typ.n.sons.len:
+      let genericParam = s.typ.n[i].sym
+      let symKind = if genericParam.typ.kind == tyExpr: skConst
+                    else: skType
+
+      var boundSym = newSym(symKind, s.typ.n[i].sym.name, s, info)
+      boundSym.typ = invocation.sons[i+1].skipTypes({tyExpr})
+      boundSym.ast = invocation.sons[i+1].n
+      addDecl(c, boundSym)
+    # XXX: copyTree would have been unnecessary here if semTypeNode
+    # didn't modify its input parameters. Currently, it does modify
+    # at least the record lists of the passed object and tuple types
+    var instantiated = semTypeNode(c, copyTree(s.ast[2]), nil)
+    popInfoContext()
+    closeScope(c)
+    c.currentScope = oldScope
+    if instantiated != nil:
+      result = invocation
+      result.kind = tyGenericInst
+      result.sons.add instantiated
+      cacheTypeInst result
+
 proc instGenericContainer(c: PContext, info: TLineInfo, header: PType): PType =
-  var cl: TReplTypeVars
-  InitIdTable(cl.symMap)
-  InitIdTable(cl.typeMap)
-  cl.info = info
-  cl.c = c
-  result = ReplaceTypeVarsT(cl, header)
+  when oUseLateInstantiation:
+    lateInstantiateGeneric(c, header, info)
+  else:
+    var cl: TReplTypeVars
+    InitIdTable(cl.symMap)
+    InitIdTable(cl.typeMap)
+    cl.info = info
+    cl.c = c
+    result = ReplaceTypeVarsT(cl, header)
 
 proc instGenericContainer(c: PContext, n: PNode, header: PType): PType =
   result = instGenericContainer(c, n.info, header)
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 41c379133..b9ef8b008 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -40,7 +40,7 @@ proc semTypeTraits(c: PContext, n: PNode): PNode =
     (typArg.kind == skParam and typArg.typ.sonsLen > 0):
     # This is either a type known to sem or a typedesc
     # param to a regular proc (again, known at instantiation)
-    result = evalTypeTrait(n, GetCurrOwner())
+    result = evalTypeTrait(n[0], n[1], GetCurrOwner())
   else:
     # a typedesc variable, pass unmodified to evals
     result = n
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 33c0adac1..a15b3e10a 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -729,12 +729,16 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
       # like: mydata.seq
       rawAddSon(s.typ, newTypeS(tyEmpty, c))
       s.ast = a
-      inc c.InGenericContext
-      var body = semTypeNode(c, a.sons[2], nil)
-      dec c.InGenericContext
-      if body != nil:
-        body.sym = s
-        body.size = -1 # could not be computed properly
+      when oUseLateInstantiation:
+        var body: PType = nil
+        s.typScope = c.currentScope.parent
+      else:
+        inc c.InGenericContext
+        var body = semTypeNode(c, a.sons[2], nil)
+        dec c.InGenericContext
+        if body != nil:
+          body.sym = s
+          body.size = -1 # could not be computed properly
       s.typ.sons[sonsLen(s.typ) - 1] = body
       popOwner()
       closeScope(c)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 8ae23f851..b02fa7c31 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -156,7 +156,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
     LocalError(n.Info, errRangeIsEmpty)
   var a = semConstExpr(c, n[1])
   var b = semConstExpr(c, n[2])
-  if not sameType(a.typ, b.typ): 
+  if not sameType(a.typ, b.typ):
     LocalError(n.info, errPureTypeMismatch)
   elif a.typ.kind notin {tyInt..tyInt64,tyEnum,tyBool,tyChar,
                          tyFloat..tyFloat128,tyUInt8..tyUInt32}:
@@ -195,17 +195,19 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
     else:
       let e = semExprWithType(c, n.sons[1], {efDetermineType})
       if e.kind in {nkIntLit..nkUInt64Lit}:
-        indx = newTypeS(tyRange, c)
-        indx.n = newNodeI(nkRange, n.info)
-        addSon(indx.n, newIntTypeNode(e.kind, 0, e.typ))
-        addSon(indx.n, newIntTypeNode(e.kind, e.intVal-1, e.typ))
-        addSonSkipIntLit(indx, e.typ)
+        indx = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
+      elif e.kind == nkSym and e.typ.kind == tyExpr:
+        if e.sym.ast != nil: return semArray(c, e.sym.ast, nil)
+        InternalAssert c.InGenericContext > 0
+        if not isOrdinalType(e.typ.lastSon):
+          localError(n[1].info, errOrdinalTypeExpected)
+        indx = e.typ
       else:
         indx = e.typ.skipTypes({tyTypeDesc})
     addSonSkipIntLit(result, indx)
     if indx.kind == tyGenericInst: indx = lastSon(indx)
-    if indx.kind != tyGenericParam: 
-      if not isOrdinalType(indx): 
+    if indx.kind notin {tyGenericParam, tyExpr}:
+      if not isOrdinalType(indx):
         LocalError(n.sons[1].info, errOrdinalTypeExpected)
       elif enumHasHoles(indx): 
         LocalError(n.sons[1].info, errEnumXHasHoles, indx.sym.name.s)
@@ -587,6 +589,8 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
   else:
     if sfGenSym notin param.flags: addDecl(c, param)
 
+let typedescId = getIdent"typedesc"
+
 proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
                    paramType: PType, paramName: string,
                    info: TLineInfo, anon = false): PType =
@@ -634,6 +638,9 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
       result = addImplicitGeneric(c.newTypeWithSons(tyExpr, paramType.sons))
   of tyTypeDesc:
     if tfUnresolved notin paramType.flags:
+      # naked typedescs are not bindOnce types
+      if paramType.sonsLen == 0 and paramTypId != nil and
+         paramTypId.id == typedescId.id: paramTypId = nil
       result = addImplicitGeneric(c.newTypeWithSons(tyTypeDesc, paramType.sons))
   of tyDistinct:
     if paramType.sonsLen == 1:
@@ -760,7 +767,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
         r.flags.incl tfRetType
       result.sons[0] = skipIntLit(r)
       res.typ = result.sons[0]
- 
+
 proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
   checkMinSonsLen(n, 1)
   var length = sonsLen(n)
@@ -846,7 +853,10 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
         LocalError(n.info, errCannotInstantiateX, s.name.s)
         result = newOrPrevType(tyError, prev, c)
       else:
-        result = instGenericContainer(c, n, result)
+        when oUseLateInstantiation:
+          result = lateInstantiateGeneric(c, result, n.info)
+        else:
+          result = instGenericContainer(c, n, result)
 
 proc semTypeExpr(c: PContext, n: PNode): PType =
   var n = semExprWithType(c, n, {efDetermineType})
@@ -1073,8 +1083,9 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
     if constraint.kind != nkEmpty:
       typ = semTypeNode(c, constraint, nil)
       if typ.kind != tyExpr or typ.len == 0:
-        if typ.len == 0 and typ.kind == tyTypeDesc:
-          typ = newTypeS(tyGenericParam, c)
+        if typ.kind == tyTypeDesc:
+          if typ.len == 0:
+            typ = newTypeS(tyTypeDesc, c)
         else:
           typ = semGenericConstraints(c, typ)
     
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index 31fbc33e1..0c15c7248 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -31,7 +31,7 @@ proc checkConstructedType*(info: TLineInfo, typ: PType) =
       if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags: 
         localError(info, errInheritanceOnlyWithNonFinalObjects)
 
-proc searchInstTypes(key: PType): PType =
+proc searchInstTypes*(key: PType): PType =
   let genericTyp = key.sons[0]
   InternalAssert genericTyp.kind == tyGenericBody and
                  key.sons[0] == genericTyp and
@@ -55,7 +55,7 @@ proc searchInstTypes(key: PType): PType =
       
       return inst
 
-proc cacheTypeInst(inst: PType) =
+proc cacheTypeInst*(inst: PType) =
   # XXX: add to module's generics
   #      update the refcount
   let genericTyp = inst.sons[0]
@@ -208,6 +208,12 @@ proc ReplaceTypeVarsT*(cl: var TReplTypeVars, t: PType): PType =
   of tyInt:
     result = skipIntLit(t)
   else:
+    if t.kind == tyArray:
+      let idxt = t.sons[0]
+      if idxt.kind == tyExpr and 
+         idxt.sym != nil and idxt.sym.kind == skGenericParam:
+        let value = lookupTypeVar(cl, idxt).n
+        t.sons[0] = makeRangeType(cl.c, 0, value.intVal - 1, value.info)
     if containsGenericType(t):
       result = copyType(t, t.owner, false)
       incl(result.flags, tfFromGeneric)
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 27c780391..a37b47366 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -626,7 +626,8 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   of tyGenericParam, tyTypeClass:
     var x = PType(idTableGet(c.bindings, f))
     if x == nil:
-      if c.calleeSym.kind == skType and f.kind == tyGenericParam and not c.typedescMatched:
+      if c.calleeSym != nil and c.calleeSym.kind == skType and
+         f.kind == tyGenericParam and not c.typedescMatched:
         # XXX: The fact that generic types currently use tyGenericParam for 
         # their parameters is really a misnomer. tyGenericParam means "match
         # any value" and what we need is "match any type", which can be encoded
@@ -670,7 +671,9 @@ proc typeRel(c: var TCandidate, f, a: PType): TTypeRelation =
         result = isNone
     else:
       InternalAssert prev.sonsLen == 1
-      result = typeRel(c, prev.sons[0], a)
+      let toMatch = if tfUnresolved in f.flags: a
+                    else: a.sons[0]
+      result = typeRel(c, prev.sons[0], toMatch)
   of tyExpr, tyStmt:
     result = isGeneric
   of tyProxy:
@@ -772,6 +775,7 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
         if evaluated != nil:
           r = isGeneric
           arg.typ = newTypeS(tyExpr, c)
+          arg.typ.sons = @[evaluated.typ]
           arg.typ.n = evaluated
         
     if r == isGeneric:
diff --git a/doc/manual.txt b/doc/manual.txt
index d2fc7e5c9..0a2009961 100644
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -1451,7 +1451,7 @@ But it seems all this boilerplate code needs to be repeated for the ``TEuro``
 currency. This can be solved with templates_.
 
 .. code-block:: nimrod
-  template Additive(typ: typeDesc): stmt =
+  template Additive(typ: typedesc): stmt =
     proc `+` *(x, y: typ): typ {.borrow.}
     proc `-` *(x, y: typ): typ {.borrow.}
     
@@ -1459,13 +1459,13 @@ currency. This can be solved with templates_.
     proc `+` *(x: typ): typ {.borrow.}
     proc `-` *(x: typ): typ {.borrow.}
 
-  template Multiplicative(typ, base: typeDesc): stmt =
+  template Multiplicative(typ, base: typedesc): stmt =
     proc `*` *(x: typ, y: base): typ {.borrow.}
     proc `*` *(x: base, y: typ): typ {.borrow.}
     proc `div` *(x: typ, y: base): typ {.borrow.}
     proc `mod` *(x: typ, y: base): typ {.borrow.}
 
-  template Comparable(typ: typeDesc): stmt =
+  template Comparable(typ: typedesc): stmt =
     proc `<` * (x, y: typ): bool {.borrow.}
     proc `<=` * (x, y: typ): bool {.borrow.}
     proc `==` * (x, y: typ): bool {.borrow.}
@@ -3323,10 +3323,10 @@ The template body does not open a new scope. To open a new scope a ``block``
 statement can be used:
 
 .. code-block:: nimrod
-  template declareInScope(x: expr, t: typeDesc): stmt {.immediate.} = 
+  template declareInScope(x: expr, t: typedesc): stmt {.immediate.} = 
     var x: t
     
-  template declareInNewScope(x: expr, t: typeDesc): stmt {.immediate.} = 
+  template declareInNewScope(x: expr, t: typedesc): stmt {.immediate.} = 
     # open a new scope:
     block: 
       var x: t
@@ -3419,7 +3419,7 @@ In templates identifiers can be constructed with the backticks notation:
 
 .. code-block:: nimrod
 
-  template typedef(name: expr, typ: typeDesc) {.immediate.} = 
+  template typedef(name: expr, typ: typedesc) {.immediate.} = 
     type
       `T name`* {.inject.} = typ
       `P name`* {.inject.} = ref `T name`
@@ -3480,7 +3480,7 @@ template cannot be accessed in the instantiation context:
 
 .. code-block:: nimrod
   
-  template newException*(exceptn: typeDesc, message: string): expr =
+  template newException*(exceptn: typedesc, message: string): expr =
     var
       e: ref exceptn  # e is implicitly gensym'ed here
     new(e)
@@ -3728,6 +3728,25 @@ instantiation type using the param name:
   var n = TNode.new
   var tree = new(TBinaryTree[int])
 
+When multiple typedesc params are present, they act like a distinct type class
+(i.e. they will bind freely to different types). To force a bind-once behavior
+one can use a named alias or an explicit `typedesc` generic param:
+
+.. code-block:: nimrod
+
+  # `type1` and `type2` are aliases for typedesc available from system.nim
+  proc acceptOnlyTypePairs(A, B: type1; C, D: type2)
+  proc acceptOnlyTypePairs[T: typedesc, U: typedesc](A, B: T; C, D: U)
+
+Once bound, typedesc params can appear in the rest of the proc signature:
+
+.. code-block:: nimrod
+
+  template declareVariableWithType(T: typedesc, value: T) =
+    var x: T = value
+
+  declareVariableWithType int, 42
+
 When used with macros and .compileTime. procs on the other hand, the compiler
 does not need to instantiate the code multiple times, because types then can be
 manipulated using the unified internal symbol representation. In such context
diff --git a/install.txt b/install.txt
index eefdfb682..11c502235 100644
--- a/install.txt
+++ b/install.txt
@@ -62,46 +62,3 @@ Currently, the following C compilers are supported under Windows:
   | http://www.digitalmars.com/download/freecompiler.html
 
 However, most testing is done with GCC.
-
-
-
-Bootstrapping from github
--------------------------
-
-To get the source code you need either of these:
-
-* A working web browser + tar(or equivalent):
-  https://github.com/Araq/Nimrod/tarball/master
-* wget + tar:
-  ``wget --no-check-certificate "https://github.com/Araq/Nimrod/tarball/master"``
-* git: ``git clone git://github.com/Araq/Nimrod.git``
-
-After downloading the source (and extracting it), you need to 
-extract ``build/csources.zip``:
-
-* ``cd build``
-* ``unzip csources.zip``
-* ``cd ..``
-
-and then you can bootstrap with:
-
-On Windows
-~~~~~~~~~~
-
-* ``build.bat``
-* ``bin\nimrod c koch``
-* ``koch boot -d:release``
-
-If you want a 64 bit build, make sure that you have a GCC built for Win64 and
-execute ``build64.bat`` instead of ``build.bat``.
-
-
-On UNIX
-~~~~~~~
-
-* ``./build.sh``
-* ``bin/nimrod c koch``
-* ``./koch boot -d:release``
-
-Installation on UNIX can then be done with ``koch install [dir]``.
-
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 15cc6abb8..2c0e7b835 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -10,6 +10,11 @@
 ## This module implements a simple HTTP client that can be used to retrieve
 ## webpages/other data.
 ##
+##
+## **Note**: This module is not ideal, connection is not kept alive so sites with
+## many redirects are expensive. As such in the future this module may change,
+## and the current procedures will be deprecated.
+##
 ## Retrieving a website
 ## ====================
 ## 
@@ -62,8 +67,15 @@
 ## that as long as the server is sending data an exception will not be raised,
 ## if however data does not reach client within the specified timeout an ETimeout
 ## exception will then be raised.
+##
+## Proxy
+## =====
+##
+## A proxy can be specified as a param to any of these procedures, the ``newProxy``
+## constructor should be used for this purpose. However,
+## currently only basic authentication is supported.
 
-import sockets, strutils, parseurl, parseutils, strtabs
+import sockets, strutils, parseurl, parseutils, strtabs, base64
 
 type
   TResponse* = tuple[
@@ -72,6 +84,10 @@ type
     headers: PStringTable,
     body: string]
 
+  PProxy* = ref object
+    url*: TUrl
+    auth*: string
+
   EInvalidProtocol* = object of ESynch ## exception that is raised when server
                                        ## does not conform to the implemented
                                        ## protocol
@@ -239,23 +255,34 @@ when not defined(ssl):
 else:
   let defaultSSLContext = newContext(verifyMode = CVerifyNone)
 
+proc newProxy*(url: string, auth = ""): PProxy =
+  ## Constructs a new ``TProxy`` object.
+  result = PProxy(url: parseUrl(url), auth: auth)
+
 proc request*(url: string, httpMethod = httpGET, extraHeaders = "", 
               body = "",
               sslContext: PSSLContext = defaultSSLContext,
-              timeout = -1, userAgent = defUserAgent): TResponse =
+              timeout = -1, userAgent = defUserAgent,
+              proxy: PProxy = nil): TResponse =
   ## | Requests ``url`` with the specified ``httpMethod``.
   ## | Extra headers can be specified and must be seperated by ``\c\L``
   ## | An optional timeout can be specified in miliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
-  var r = parseUrl(url)
+  var r = if proxy == nil: parseUrl(url) else: proxy.url
   var headers = substr($httpMethod, len("http"))
-  headers.add(" /" & r.path & r.query)
+  if proxy == nil:
+    headers.add(" /" & r.path & r.query)
+  else:
+    headers.add(" " & url)
 
   headers.add(" HTTP/1.1\c\L")
   
   add(headers, "Host: " & r.hostname & "\c\L")
   if userAgent != "":
     add(headers, "User-Agent: " & userAgent & "\c\L")
+  if proxy != nil and proxy.auth != "":
+    let auth = base64.encode(proxy.auth, newline = "")
+    add(headers, "Proxy-Authorization: basic " & auth & "\c\L")
   add(headers, extraHeaders)
   add(headers, "\c\L")
   
@@ -299,30 +326,34 @@ proc getNewLocation(lastUrl: string, headers: PStringTable): string =
   
 proc get*(url: string, extraHeaders = "", maxRedirects = 5,
           sslContext: PSSLContext = defaultSSLContext,
-          timeout = -1, userAgent = defUserAgent): TResponse =
+          timeout = -1, userAgent = defUserAgent,
+          proxy: PProxy = nil): TResponse =
   ## | GETs the ``url`` and returns a ``TResponse`` object
   ## | This proc also handles redirection
   ## | Extra headers can be specified and must be separated by ``\c\L``.
   ## | An optional timeout can be specified in miliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
-  result = request(url, httpGET, extraHeaders, "", sslContext, timeout, userAgent)
+  result = request(url, httpGET, extraHeaders, "", sslContext, timeout,
+                   userAgent, proxy)
   var lastURL = url
   for i in 1..maxRedirects:
     if result.status.redirection():
       let redirectTo = getNewLocation(lastURL, result.headers)
       result = request(redirectTo, httpGET, extraHeaders, "", sslContext,
-                       timeout, userAgent)
+                       timeout, userAgent, proxy)
       lastUrl = redirectTo
       
 proc getContent*(url: string, extraHeaders = "", maxRedirects = 5,
                  sslContext: PSSLContext = defaultSSLContext,
-                 timeout = -1, userAgent = defUserAgent): string =
+                 timeout = -1, userAgent = defUserAgent,
+                 proxy: PProxy = nil): string =
   ## | GETs the body and returns it as a string.
   ## | Raises exceptions for the status codes ``4xx`` and ``5xx``
   ## | Extra headers can be specified and must be separated by ``\c\L``.
   ## | An optional timeout can be specified in miliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
-  var r = get(url, extraHeaders, maxRedirects, sslContext, timeout, userAgent)
+  var r = get(url, extraHeaders, maxRedirects, sslContext, timeout, userAgent,
+              proxy)
   if r.status[0] in {'4','5'}:
     raise newException(EHTTPRequestErr, r.status)
   else:
@@ -331,7 +362,8 @@ proc getContent*(url: string, extraHeaders = "", maxRedirects = 5,
 proc post*(url: string, extraHeaders = "", body = "",
            maxRedirects = 5,
            sslContext: PSSLContext = defaultSSLContext,
-           timeout = -1, userAgent = defUserAgent): TResponse =
+           timeout = -1, userAgent = defUserAgent,
+           proxy: PProxy = nil): TResponse =
   ## | POSTs ``body`` to the ``url`` and returns a ``TResponse`` object.
   ## | This proc adds the necessary Content-Length header.
   ## | This proc also handles redirection.
@@ -339,27 +371,29 @@ proc post*(url: string, extraHeaders = "", body = "",
   ## | An optional timeout can be specified in miliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
   var xh = extraHeaders & "Content-Length: " & $len(body) & "\c\L"
-  result = request(url, httpPOST, xh, body, sslContext, timeout, userAgent)
+  result = request(url, httpPOST, xh, body, sslContext, timeout, userAgent,
+                   proxy)
   var lastUrl = ""
   for i in 1..maxRedirects:
     if result.status.redirection():
       let redirectTo = getNewLocation(lastURL, result.headers)
       var meth = if result.status != "307": httpGet else: httpPost
       result = request(redirectTo, meth, xh, body, sslContext, timeout,
-                       userAgent)
+                       userAgent, proxy)
       lastUrl = redirectTo
   
 proc postContent*(url: string, extraHeaders = "", body = "",
                   maxRedirects = 5,
                   sslContext: PSSLContext = defaultSSLContext,
-                  timeout = -1, userAgent = defUserAgent): string =
+                  timeout = -1, userAgent = defUserAgent,
+                  proxy: PProxy = nil): string =
   ## | POSTs ``body`` to ``url`` and returns the response's body as a string
   ## | Raises exceptions for the status codes ``4xx`` and ``5xx``
   ## | Extra headers can be specified and must be separated by ``\c\L``.
   ## | An optional timeout can be specified in miliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
   var r = post(url, extraHeaders, body, maxRedirects, sslContext, timeout,
-               userAgent)
+               userAgent, proxy)
   if r.status[0] in {'4','5'}:
     raise newException(EHTTPRequestErr, r.status)
   else:
@@ -367,14 +401,15 @@ proc postContent*(url: string, extraHeaders = "", body = "",
   
 proc downloadFile*(url: string, outputFilename: string,
                    sslContext: PSSLContext = defaultSSLContext,
-                   timeout = -1, userAgent = defUserAgent) =
+                   timeout = -1, userAgent = defUserAgent,
+                   proxy: PProxy = nil) =
   ## | Downloads ``url`` and saves it to ``outputFilename``
   ## | An optional timeout can be specified in miliseconds, if reading from the
   ## server takes longer than specified an ETimeout exception will be raised.
   var f: TFile
   if open(f, outputFilename, fmWrite):
     f.write(getContent(url, sslContext = sslContext, timeout = timeout,
-            userAgent = userAgent))
+            userAgent = userAgent, proxy = proxy))
     f.close()
   else:
     fileError("Unable to open file")
diff --git a/lib/system.nim b/lib/system.nim
index 98c79de5f..40a9be2d4 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -54,7 +54,7 @@ type
   `nil` {.magic: "Nil".}
   expr* {.magic: Expr.} ## meta type to denote an expression (for templates)
   stmt* {.magic: Stmt.} ## meta type to denote a statement (for templates)
-  typeDesc* {.magic: TypeDesc.} ## meta type to denote a type description
+  typedesc* {.magic: TypeDesc.} ## meta type to denote a type description
   void* {.magic: "VoidType".}   ## meta type to denote the absense of any type
   auto* = expr
   any* = distinct auto
@@ -78,6 +78,17 @@ type
   TNumber* = TInteger|TReal
     ## type class matching all number types
 
+type
+  ## helper types for writing implicitly generic procs
+  T1* = expr
+  T2* = expr
+  T3* = expr
+  T4* = expr
+  T5* = expr
+  type1* = typedesc
+  type2* = typedesc
+  type3* = typedesc
+  
 proc defined*(x: expr): bool {.magic: "Defined", noSideEffect.}
   ## Special compile-time procedure that checks whether `x` is
   ## defined. `x` has to be an identifier or a qualified identifier.
@@ -1487,7 +1498,7 @@ when not defined(NimrodVM):
     proc seqToPtr[T](x: seq[T]): pointer {.noStackFrame, nosideeffect.} =
       asm """return `x`"""
   
-  proc `==` *[T: typeDesc](x, y: seq[T]): bool {.noSideEffect.} =
+  proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} =
     ## Generic equals operator for sequences: relies on a equals operator for
     ## the element type `T`.
     if seqToPtr(x) == seqToPtr(y):
@@ -1499,7 +1510,7 @@ when not defined(NimrodVM):
         if x[i] != y[i]: return false
       result = true
 
-proc find*[T, S: typeDesc](a: T, item: S): int {.inline.}=
+proc find*[T, S](a: T, item: S): int {.inline.}=
   ## Returns the first index of `item` in `a` or -1 if not found. This requires
   ## appropriate `items` and `==` operations to work.
   for i in items(a):
@@ -1802,7 +1813,7 @@ proc debugEcho*[T](x: varargs[T, `$`]) {.magic: "Echo", noSideEffect,
   ## to be free of side effects, so that it can be used for debugging routines
   ## marked as ``noSideEffect``.
 
-template newException*(exceptn: typeDesc, message: string): expr =
+template newException*(exceptn: typedesc, message: string): expr =
   ## creates an exception object of type ``exceptn`` and sets its ``msg`` field
   ## to `message`. Returns the new exception object.
   var
@@ -1815,7 +1826,7 @@ when hostOS == "standalone":
   include panicoverride
 
 when not defined(sysFatal):
-  template sysFatal(exceptn: typeDesc, message: string) =
+  template sysFatal(exceptn: typedesc, message: string) =
     when hostOS == "standalone":
       panic(message)
     else:
@@ -1824,7 +1835,7 @@ when not defined(sysFatal):
       e.msg = message
       raise e
 
-  template sysFatal(exceptn: typeDesc, message, arg: string) =
+  template sysFatal(exceptn: typedesc, message, arg: string) =
     when hostOS == "standalone":
       rawoutput(message)
       panic(arg)
diff --git a/readme.md b/readme.md
index 59546653b..f74f81283 100644
--- a/readme.md
+++ b/readme.md
@@ -6,8 +6,7 @@ documentation.
 Compiling the Nimrod compiler is quite straightforward. Because
 the Nimrod compiler itself is written in the Nimrod programming language
 the C source of an older version of the compiler are needed to bootstrap the
-latest version. The C sources are however included with this repository under
-the build directory.
+latest version. The C sources are available in a separate repo [here](http://github.com/nimrod-code/csources).
 
 Pre-compiled snapshots of the compiler are also available on
 [Nimbuild](http://build.nimrod-code.org/). Your platform however may not 
@@ -53,7 +52,7 @@ and you can also get help in the IRC channel
 on [Freenode](irc://irc.freenode.net/nimrod) in #nimrod.
 
 ## License
-The compiler and the standard library is licensed under the MIT license, 
+The compiler and the standard library are licensed under the MIT license, 
 except for some modules where the documentation suggests otherwise. This means 
 that you can use any license for your own programs developed with Nimrod, 
 allowing you to create commercial applications.
diff --git a/readme.txt b/readme.txt
index 59546653b..f74f81283 100644
--- a/readme.txt
+++ b/readme.txt
@@ -6,8 +6,7 @@ documentation.
 Compiling the Nimrod compiler is quite straightforward. Because
 the Nimrod compiler itself is written in the Nimrod programming language
 the C source of an older version of the compiler are needed to bootstrap the
-latest version. The C sources are however included with this repository under
-the build directory.
+latest version. The C sources are available in a separate repo [here](http://github.com/nimrod-code/csources).
 
 Pre-compiled snapshots of the compiler are also available on
 [Nimbuild](http://build.nimrod-code.org/). Your platform however may not 
@@ -53,7 +52,7 @@ and you can also get help in the IRC channel
 on [Freenode](irc://irc.freenode.net/nimrod) in #nimrod.
 
 ## License
-The compiler and the standard library is licensed under the MIT license, 
+The compiler and the standard library are licensed under the MIT license, 
 except for some modules where the documentation suggests otherwise. This means 
 that you can use any license for your own programs developed with Nimrod, 
 allowing you to create commercial applications.
diff --git a/tests/compile/tbindtypedesc.nim b/tests/compile/tbindtypedesc.nim
new file mode 100644
index 000000000..dd4ef854c
--- /dev/null
+++ b/tests/compile/tbindtypedesc.nim
@@ -0,0 +1,87 @@
+discard """
+  msg: '''
+int
+float
+TFoo
+TFoo
+'''
+"""
+
+import typetraits
+
+type 
+  TFoo = object
+    x, y: int
+
+  TBar = tuple
+    x, y: int
+
+template good(e: expr) =
+  static: assert(compiles(e))
+
+template bad(e: expr) =
+  static: assert(not compiles(e))
+
+proc genericParamRepeated[T: typedesc](a: T, b: T) =
+  static:
+    echo a.name
+    echo b.name
+
+good(genericParamRepeated(int, int))
+good(genericParamRepeated(float, float))
+
+bad(genericParamRepeated(string, int))
+bad(genericParamRepeated(int, float))
+
+proc genericParamOnce[T: typedesc](a, b: T) =
+  static:
+    echo a.name
+    echo b.name
+
+good(genericParamOnce(int, int))
+good(genericParamOnce(TFoo, TFoo))
+
+bad(genericParamOnce(string, int))
+bad(genericParamOnce(TFoo, float))
+
+proc typePairs(A, B: type1; C, D: type2) = nil
+
+good(typePairs(int, int, TFoo, TFOO))
+good(typePairs(TBAR, TBar, TBAR, TBAR))
+good(typePairs(int, int, string, string))
+
+bad(typePairs(TBAR, TBar, TBar, TFoo))
+bad(typePairs(string, int, TBAR, TBAR))
+
+proc typePairs2[T: typedesc, U: typedesc](A, B: T; C, D: U) = nil
+
+good(typePairs2(int, int, TFoo, TFOO))
+good(typePairs2(TBAR, TBar, TBAR, TBAR))
+good(typePairs2(int, int, string, string))
+
+bad(typePairs2(TBAR, TBar, TBar, TFoo))
+bad(typePairs2(string, int, TBAR, TBAR))
+
+proc dontBind(a: typedesc, b: typedesc) =
+  static:
+    echo a.name
+    echo b.name
+
+good(dontBind(int, float))
+good(dontBind(TFoo, TFoo))
+
+proc dontBind2(a, b: typedesc) = nil
+
+good(dontBind2(int, float))
+good(dontBind2(TBar, int))
+
+proc bindArg(T: typedesc, U: typedesc, a, b: T, c, d: U) = nil
+
+good(bindArg(int, string, 10, 20, "test", "nest"))
+good(bindArg(int, int, 10, 20, 30, 40))
+
+bad(bindArg(int, string, 10, "test", "test", "nest"))
+bad(bindArg(int, int, 10, 20, 30, "test"))
+bad(bindArg(int, string, 10.0, 20, "test", "nest"))
+bad(bindArg(int, string, "test", "nest", 10, 20))
+
diff --git a/tests/compile/tgenericshardcases.nim b/tests/compile/tgenericshardcases.nim
new file mode 100644
index 000000000..90981c701
--- /dev/null
+++ b/tests/compile/tgenericshardcases.nim
@@ -0,0 +1,30 @@
+discard """
+  file: "tgenericshardcases.nim"
+  output: "int\nfloat\nint\nstring"
+"""
+
+import typetraits
+
+proc typeNameLen(x: typedesc): int {.compileTime.} =
+  result = x.name.len
+  
+macro selectType(a, b: typedesc): typedesc =
+  result = a
+
+type
+  Foo[T] = object
+    data1: array[high(T), int]
+    data2: array[1..typeNameLen(T), selectType(float, string)]
+
+  MyEnum = enum A, B, C,D
+
+var f1: Foo[MyEnum]
+var f2: Foo[int8]
+
+static:
+  assert high(f1.data1) == D
+  assert high(f1.data2) == 6 # length of MyEnum
+
+  assert high(f2.data1) == 127
+  assert high(f2.data2) == 4 # length of int8
+
diff --git a/tests/run/tmacrogenerics.nim b/tests/run/tmacrogenerics.nim
new file mode 100644
index 000000000..5ae59e0da
--- /dev/null
+++ b/tests/run/tmacrogenerics.nim
@@ -0,0 +1,39 @@
+discard """
+  file: "tmacrogenerics.nim"
+  msg: '''
+instantiation 1 with int and float
+instantiation 2 with float and string
+instantiation 3 with string and string
+counter: 3
+'''
+  output: "int\nfloat\nint\nstring"
+"""
+
+import typetraits, macros
+
+var counter {.compileTime.} = 0
+
+macro makeBar(A, B: typedesc): typedesc =
+  inc counter
+  echo "instantiation ", counter, " with ", A.name, " and ", B.name
+  result = A
+
+type 
+  Bar[T, U] = makeBar(T, U)
+
+var bb1: Bar[int, float]
+var bb2: Bar[float, string]
+var bb3: Bar[int, float]
+var bb4: Bar[string, string]
+
+proc match(a: int)    = echo "int"
+proc match(a: string) = echo "string"
+proc match(a: float)  = echo "float"
+
+match(bb1)
+match(bb2)
+match(bb3)
+match(bb4)
+
+static:
+  echo "counter: ", counter
diff --git a/tests/run/tstaticparams.nim b/tests/run/tstaticparams.nim
index 3e501ed8b..232748356 100644
--- a/tests/run/tstaticparams.nim
+++ b/tests/run/tstaticparams.nim
@@ -1,17 +1,22 @@
 discard """
   file: "tstaticparams.nim"
-  output: "abracadabra\ntest"
+  output: "abracadabra\ntest\n3"
 """
 
 type 
   TFoo[T; Val: expr[string]] = object
     data: array[4, T]
 
+  TBar[T; I: expr[int]] = object
+    data: array[I, T]
+
 proc takeFoo(x: TFoo) =
   echo "abracadabra"
   echo TFoo.Val
 
 var x: TFoo[int, "test"]
-
 takeFoo(x)
 
+var y: TBar[float, 4]
+echo high(y.data)
+