summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorDominik Picheta <dominikpicheta@googlemail.com>2014-02-11 23:50:58 +0000
committerDominik Picheta <dominikpicheta@googlemail.com>2014-02-11 23:50:58 +0000
commitb3a090661991a4364b866dd6b950afeafa5c2ac3 (patch)
treecc203331adba91d1e33b18883997d08b74f8f739
parent728be67afb54fc9645ba36edd2b5e430ccf443de (diff)
parent02cf019ab63e1be23c0a4856b6591e1c41d57f4e (diff)
downloadNim-b3a090661991a4364b866dd6b950afeafa5c2ac3.tar.gz
Merge branch 'devel' into newasync
-rw-r--r--compiler/ccgexprs.nim2
-rw-r--r--compiler/sem.nim1
-rw-r--r--compiler/semdata.nim2
-rw-r--r--compiler/semexprs.nim9
-rw-r--r--compiler/sigmatch.nim77
-rw-r--r--compiler/vm.nim2
-rw-r--r--compiler/vmgen.nim21
-rw-r--r--doc/manual.txt114
-rw-r--r--doc/tut1.txt10
-rw-r--r--doc/tut2.txt4
-rw-r--r--lib/pure/collections/sets.nim4
-rw-r--r--tests/generics/tinferredgenericprocs.nim20
-rw-r--r--tests/sets/tsets_lt.nim12
-rw-r--r--tests/stdlib/testequivalence.nim (renamed from tests/sets/testequivalence.nim)0
-rw-r--r--tests/stdlib/tsets.nim17
15 files changed, 194 insertions, 101 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 031ab8d70..01f23850b 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1376,7 +1376,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       getTemp(p, getSysType(tyInt), i) # our counter
       initLocExpr(p, e.sons[1], a)
       initLocExpr(p, e.sons[2], b)
-      if d.k == locNone: getTemp(p, a.t, d)
+      if d.k == locNone: getTemp(p, getSysType(tyBool), d)
       lineF(p, cpsStmts, lookupOpr[op],
            [rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b)])
     of mEqSet:
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 00ac79716..845d4ae71 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -332,6 +332,7 @@ proc myOpen(module: PSym): PPassContext =
   c.semOperand = semOperand
   c.semConstBoolExpr = semConstBoolExpr
   c.semOverloadedCall = semOverloadedCall
+  c.semGenerateInstance = generateInstance
   c.semTypeNode = semTypeNode
   pushProcCon(c, module)
   pushOwner(c.module)
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index c9d95e1bf..0bc52d6b7 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -81,6 +81,8 @@ type
     semOverloadedCall*: proc (c: PContext, n, nOrig: PNode,
                               filter: TSymKinds): PNode {.nimcall.}
     semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.}
+    semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable,
+                                info: TLineInfo): PSym
     includedFiles*: TIntSet    # used to detect recursive include files
     userPragmas*: TStrTable
     evalContext*: PEvalContext
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index a8a16672d..3fe1367ec 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -204,7 +204,14 @@ proc semConv(c: PContext, n: PNode): PNode =
   if not isSymChoice(op):
     let status = checkConvertible(c, result.typ, op.typ)
     case status
-    of convOK: discard
+    of convOK:
+      # handle SomeProcType(SomeGenericProc)
+      # XXX: This needs fixing. checkConvertible uses typeRel internally, but
+      # doesn't bother to perform the work done in paramTypeMatchAux/fitNode
+      # so we are redoing the typeRel work here. Why does semConv exist as a
+      # separate proc from fitNode?
+      if op.kind == nkSym and op.sym.isGenericRoutine:
+        result.sons[1] = fitNode(c, result.typ, result.sons[1])
     of convNotNeedeed:
       message(n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString)
     of convNotLegal:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 335ceafeb..227228f6e 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -51,6 +51,8 @@ type
     isSubtype,
     isSubrange,              # subrange of the wanted type; no type conversion
                              # but apart from that counts as ``isSubtype``
+    isInferred,              # generic proc was matched against a concrete type
+    isInferredConvertible,   # same as above, but requiring proc CC conversion
     isGeneric,
     isFromIntLit,            # conversion *from* int literal; proven safe
     isEqual
@@ -338,10 +340,40 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
 proc allowsNil(f: PType): TTypeRelation {.inline.} =
   result = if tfNotNil notin f.flags: isSubtype else: isNone
 
-proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
-  proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
-    result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
+proc inconsistentVarTypes(f, a: PType): bool {.inline.} =
+  result = f.kind != a.kind and (f.kind == tyVar or a.kind == tyVar)
+
+proc procParamTypeRel(c: var TCandidate, f, a: PType,
+                      result: var TTypeRelation) =
+  var
+    m: TTypeRelation
+    f = f
+    
+  if a.isMetaType:
+    if f.isMetaType:
+      # we are matching a generic proc (as proc param)
+      # to another generic type appearing in the proc
+      # sigunature. there is a change that the target
+      # type is already fully-determined, so we are 
+      # going to try resolve it
+      f = generateTypeInstance(c.c, c.bindings, c.call.info, f)
+      if f == nil or f.isMetaType:
+        # no luck resolving the type, so the inference fails
+        result = isNone
+        return
+    let reverseRel = typeRel(c, a, f)
+    if reverseRel == isGeneric:
+      m = isInferred
+  else:
+    m = typeRel(c, f, a)
+
+  if m <= isSubtype or inconsistentVarTypes(f, a):
+    result = isNone
+    return
+  else:
+    result = minRel(m, result)
 
+proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
   case a.kind
   of tyProc:
     if sonsLen(f) != sonsLen(a): return
@@ -350,18 +382,10 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
     result = isEqual      # start with maximum; also correct for no
                           # params at all
     for i in countup(1, sonsLen(f)-1):
-      var m = typeRel(c, f.sons[i], a.sons[i])
-      if m <= isSubtype or inconsistentVarTypes(f.sons[i], a.sons[i]):
-        return isNone
-      else: result = minRel(m, result)
+      procParamTypeRel(c, f.sons[i], a.sons[i], result)
     if f.sons[0] != nil:
       if a.sons[0] != nil:
-        var m = typeRel(c, f.sons[0], a.sons[0])
-        # Subtype is sufficient for return types!
-        if m < isSubtype or inconsistentVarTypes(f.sons[0], a.sons[0]):
-          return isNone
-        elif m == isSubtype: result = isConvertible
-        else: result = minRel(m, result)
+        procParamTypeRel(c, f.sons[0], a.sons[0], result)
       else:
         return isNone
     elif a.sons[0] != nil:
@@ -376,7 +400,8 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
     elif f.callConv != a.callConv:
       # valid to pass a 'nimcall' thingie to 'closure':
       if f.callConv == ccClosure and a.callConv == ccDefault:
-        result = isConvertible
+        result = if result != isInferred: isConvertible
+                 else: isInferredConvertible
       else:
         return isNone
     when useEffectSystem:
@@ -402,18 +427,8 @@ proc typeRangeRel(f, a: PType): TTypeRelation {.noinline.} =
 
 proc matchUserTypeClass*(c: PContext, m: var TCandidate,
                          ff, a: PType): TTypeRelation =
-  #if f.n == nil:
-  #  let r = typeRel(m, f, a)
-  #  return if r == isGeneric: arg else: nil
-
   var body = ff.skipTypes({tyUserTypeClassInst})
 
-  # var prev = PType(idTableGet(m.bindings, f))
-  # if prev != nil:
-  #   if sameType(prev, a): return arg
-  #   else: return nil
-
-  # pushInfoContext(arg.info)
   openScope(c)
   inc c.inTypeClass
 
@@ -462,7 +477,6 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
       else: discard
     
   return isGeneric
-  # put(m.bindings, f, a)
 
 proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
   # typeRel can be used to establish various relationships between types:
@@ -988,7 +1002,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
     arg = argSemantized
     argType = argType
     c = m.c
-
+    
   if tfHasStatic in fMaybeStatic.flags:
     # XXX: When implicit statics are the default
     # this will be done earlier - we just have to
@@ -1022,6 +1036,13 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
     inc(m.subtypeMatches)
     #result = copyTree(arg)
     result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
+  of isInferred, isInferredConvertible:
+    var prc = if arg.kind in nkLambdaKinds: arg[0].sym
+              else: arg.sym
+    let inferred = c.semGenerateInstance(c, prc, m.bindings, arg.info)
+    result = newSymNode(inferred, arg.info)
+    if r == isInferredConvertible:
+      result = implicitConv(nkHiddenStdConv, f, result, m, c)
   of isGeneric:
     inc(m.genericMatches)
     if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}:
@@ -1035,10 +1056,10 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
         result = argOrig
     else:
       result = copyTree(arg)
-      result.typ = getInstantiatedType(c, arg, m, f) 
+      result.typ = getInstantiatedType(c, arg, m, f)
       # BUG: f may not be the right key!
       if skipTypes(result.typ, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
-        result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) 
+        result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
         # BUGFIX: use ``result.typ`` and not `f` here
   of isFromIntLit:
     # too lazy to introduce another ``*matches`` field, so we conflate
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 10ac7aaaf..81e712047 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -441,7 +441,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
       decodeBImm(nkIntLit)
       #assert regs[rb].kind == nkBracket
       # also used by mNLen:
-      regs[ra].intVal = regs[rb].skipMeta.len - imm
+      regs[ra].intVal = regs[rb].skipMeta.safeLen - imm
     of opcLenStr:
       decodeBImm(nkIntLit)
       if regs[rb].kind == nkNilLit:
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index d0e8dacf3..a6d044e24 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -216,10 +216,12 @@ proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister =
   internalAssert tmp >= 0
   result = TRegister(tmp)
 
-proc clearDest(n: PNode; dest: var TDest) {.inline.} =
+proc clearDest(c: PCtx; n: PNode; dest: var TDest) {.inline.} =
   # stmt is different from 'void' in meta programming contexts.
   # So we only set dest to -1 if 'void':
-  if n.typ.isNil or n.typ.kind == tyEmpty: dest = -1
+  if dest >= 0 and (n.typ.isNil or n.typ.kind == tyEmpty):
+    c.freeTemp(dest)
+    dest = -1
 
 proc isNotOpr(n: PNode): bool =
   n.kind in nkCallKinds and n.sons[0].kind == nkSym and
@@ -259,7 +261,7 @@ proc genWhile(c: PCtx; n: PNode) =
 proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
   withBlock(n.sons[0].sym):
     c.gen(n.sons[1], dest)
-  clearDest(n, dest)
+  c.clearDest(n, dest)
 
 proc genBreak(c: PCtx; n: PNode) =
   let L1 = c.xjmp(n, opcJmp)
@@ -297,14 +299,16 @@ proc genIf(c: PCtx, n: PNode; dest: var TDest) =
         else:
           c.gen(it.sons[0], tmp)
           elsePos = c.xjmp(it.sons[0], opcFJmp, tmp) # if false
+      c.clearDest(n, dest)
       c.gen(it.sons[1], dest) # then part
       if i < sonsLen(n)-1:
         endings.add(c.xjmp(it.sons[1], opcJmp, 0))
       c.patch(elsePos)
     else:
+      c.clearDest(n, dest)
       c.gen(it.sons[0], dest)
   for endPos in endings: c.patch(endPos)
-  clearDest(n, dest)
+  c.clearDest(n, dest)
 
 proc genAndOr(c: PCtx; n: PNode; opc: TOpcode; dest: var TDest) =
   #   asgn dest, a
@@ -385,8 +389,8 @@ proc genCase(c: PCtx; n: PNode; dest: var TDest) =
         if i < sonsLen(n)-1:
           endings.add(c.xjmp(it.lastSon, opcJmp, 0))
         c.patch(elsePos)
+      c.clearDest(n, dest)
   for endPos in endings: c.patch(endPos)
-  clearDest(n, dest)
 
 proc genType(c: PCtx; typ: PType): int =
   for i, t in c.types:
@@ -400,6 +404,7 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
   var endings: seq[TPosition] = @[]
   let elsePos = c.xjmp(n, opcTry, 0)
   c.gen(n.sons[0], dest)
+  c.clearDest(n, dest)
   c.patch(elsePos)
   for i in 1 .. <n.len:
     let it = n.sons[i]
@@ -415,6 +420,7 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
         # general except section:
         c.gABx(it, opcExcept, 0, 0)
       c.gen(it.lastSon, dest)
+      c.clearDest(n, dest)
       if i < sonsLen(n)-1:
         endings.add(c.xjmp(it, opcJmp, 0))
       c.patch(endExcept)
@@ -425,8 +431,8 @@ proc genTry(c: PCtx; n: PNode; dest: var TDest) =
   c.gABx(fin, opcFinally, 0, 0)
   if fin.kind == nkFinally:
     c.gen(fin.sons[0], dest)
+    c.clearDest(n, dest)
   c.gABx(fin, opcFinallyEnd, 0, 0)
-  clearDest(n, dest)
 
 proc genRaise(c: PCtx; n: PNode) =
   let dest = genx(c, n.sons[0])
@@ -860,7 +866,6 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
   of mNGenSym: genBinaryABC(c, n, dest, opcGenSym)
   of mMinI, mMaxI, mMinI64, mMaxI64, mAbsF64, mMinF64, mMaxF64, mAbsI, mAbsI64:
     c.genCall(n, dest)
-    clearDest(n, dest)
   of mExpandToAst:
     if n.len != 2:
       globalError(n.info, errGenerated, "expandToAst requires 1 argument")
@@ -1281,7 +1286,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
       genMagic(c, n, dest)
     else:
       genCall(c, n, dest)
-      clearDest(n, dest)
+      clearDest(c, n, dest)
   of nkCharLit..nkInt64Lit:
     if isInt16Lit(n):
       if dest < 0: dest = c.getTemp(n.typ)
diff --git a/doc/manual.txt b/doc/manual.txt
index 16e025ee0..fb357f7d3 100644
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -1701,11 +1701,11 @@ algorithm returns true:
     result = isOrdinal(t) or t.kind in {float, float32, float64}
 
   proc isExplicitlyConvertible(a, b: PType): bool =
+    result = false
     if isImplicitlyConvertible(a, b): return true
     if typeEqualsOrDistinct(a, b): return true
     if isIntegralType(a) and isIntegralType(b): return true
     if isSubtype(a, b) or isSubtype(b, a): return true
-    return false
     
 The convertible relation can be relaxed by a user-defined type 
 `converter`:idx:.
@@ -1774,7 +1774,7 @@ Example:
 
 .. code-block:: nimrod
   proc p(x, y: int): int = 
-    return x + y
+    result = x + y
 
   discard p(3, 4) # discard the return value of `p`
 
@@ -1789,7 +1789,7 @@ been declared with the `discardable`:idx: pragma:
 
 .. code-block:: nimrod
   proc p(x, y: int): int {.discardable.} = 
-    return x + y
+    result = x + y
     
   p(3, 4) # now valid
 
@@ -2440,7 +2440,7 @@ A procedure cannot modify its parameters (unless the parameters have the type
 .. code-block:: nimrod
   proc `$` (x: int): string =
     # converts an integer to a string; this is a prefix operator.
-    return intToStr(x)
+    result = intToStr(x)
 
 Operators with one parameter are prefix operators, operators with two
 parameters are infix operators. (However, the parser distinguishes these from
@@ -2454,7 +2454,7 @@ notation. (Thus an operator can have more than two parameters):
 .. code-block:: nimrod
   proc `*+` (a, b, c: int): int =
     # Multiply and add
-    return a * b + c
+    result = a * b + c
 
   assert `*+`(3, 4, 6) == `*`(a, `+`(b, c))
 
@@ -2500,7 +2500,7 @@ different; for this a special setter syntax is needed:
   
   proc host*(s: TSocket): int {.inline.} =
     ## getter of hostAddr
-    return s.FHost
+    s.FHost
 
   var
     s: TSocket
@@ -2650,11 +2650,12 @@ return values. This can be done in a cleaner way by returning a tuple:
 
 .. code-block:: nimrod
   proc divmod(a, b: int): tuple[res, remainder: int] =
-    return (a div b, a mod b)
+    (a div b, a mod b)
 
   var t = divmod(8, 5)
+
   assert t.res == 1
-  assert t.remainder = 3
+  assert t.remainder == 3
 
 One can use `tuple unpacking`:idx: to access the tuple's fields:
 
@@ -2726,7 +2727,7 @@ dispatch.
 
   method eval(e: ref TPlusExpr): int =
     # watch out: relies on dynamic binding
-    return eval(e.a) + eval(e.b)
+    result = eval(e.a) + eval(e.b)
   
   proc newLit(x: int): ref TLiteral =
     new(result)
@@ -2925,7 +2926,7 @@ parameters of an outer factory proc:
 
 .. code-block:: nimrod
   proc mycount(a, b: int): iterator (): int =
-    return iterator (): int =
+    result = iterator (): int =
       var x = a
       while x <= b:
         yield x
@@ -3375,9 +3376,9 @@ module to illustrate this:
     ## requires `x` and `y` to be of the same tuple type
     ## generic ``==`` operator for tuples that is lifted from the components
     ## of `x` and `y`.
+    result = true
     for a, b in fields(x, y):
-      if a != b: return false
-    return true
+      if a != b: result = false
 
 Alternatively, the ``distinct`` type modifier can be applied to the type class 
 to allow each param matching the type class to bind to a different type. 
@@ -3999,9 +4000,9 @@ predicate:
 
   proc re(pattern: semistatic[string]): TRegEx =
     when isStatic(pattern):
-      return precompiledRegex(pattern)
+      result = precompiledRegex(pattern)
     else:
-      return compile(pattern)
+      result = compile(pattern)
 
 Static params can also appear in the signatures of generic types:
 
@@ -4508,7 +4509,7 @@ This is best illustrated by an example:
   proc p*(x: A.T1): A.T1 =
     # this works because the compiler has already
     # added T1 to A's interface symbol table
-    return x + 1
+    result = x + 1
 
 
 Import statement
@@ -5136,51 +5137,54 @@ Example:
 .. code-block:: nimrod
   {.deadCodeElim: on.}
 
-NoForward pragma
-----------------
-The `noforward`:idx: pragma can be used to turn on and off a special compilation
-mode that to large extent eliminates the need for forward declarations. In this
-mode, the proc definitions may appear out of order and the compiler will postpone
-their semantic analysis and compilation until it actually needs to generate code
-using the definitions. In this regard, this mode is similar to the modus operandi
-of dynamic scripting languages, where the function calls are not resolved until
-the code is executed. Here is the detailed algorithm taken by the compiler:
-
-1. When a callable symbol is first encountered, the compiler will only note the
-symbol callable name and it will add it to the appropriate overload set in the
-current scope. At this step, it won't try to resolve any of the type expressions
-used in the signature of the symbol (so they can refer to other not yet defined
-symbols).
-
-2. When a top level call is encountered (usually at the very end of the module),
-the compiler will try to determine the actual types of all of the symbols in the
-matching overload set. This is a potentially recursive process as the signatures
-of the symbols may include other call expressions, whoose types will be resolved
-at this point too.
-
-3. Finally, after the best overload is picked, the compiler will start compiling
-the body of the respective symbol. This in turn will lead the compiler to discover
-more call expresions that need to be resolved and steps 2 and 3 will be repeated
-as necessary.
-
-Please note that if a callable symbol is never used in this scenario, its body
-will never be compiled. This is the default behavior leading to best compilation
-times, but if exhaustive compilation of all definitions is required, using 
-``nimrod check`` provides this option as well.
 
-Example:
+..
+  NoForward pragma
+  ----------------
+  The `noforward`:idx: pragma can be used to turn on and off a special compilation
+  mode that to large extent eliminates the need for forward declarations. In this
+  mode, the proc definitions may appear out of order and the compiler will postpone
+  their semantic analysis and compilation until it actually needs to generate code
+  using the definitions. In this regard, this mode is similar to the modus operandi
+  of dynamic scripting languages, where the function calls are not resolved until
+  the code is executed. Here is the detailed algorithm taken by the compiler:
 
-.. code-block:: nimrod
+  1. When a callable symbol is first encountered, the compiler will only note the
+  symbol callable name and it will add it to the appropriate overload set in the
+  current scope. At this step, it won't try to resolve any of the type expressions
+  used in the signature of the symbol (so they can refer to other not yet defined
+  symbols).
+
+  2. When a top level call is encountered (usually at the very end of the module),
+  the compiler will try to determine the actual types of all of the symbols in the
+  matching overload set. This is a potentially recursive process as the signatures
+  of the symbols may include other call expressions, whoose types will be resolved
+  at this point too.
+
+  3. Finally, after the best overload is picked, the compiler will start compiling
+  the body of the respective symbol. This in turn will lead the compiler to discover
+  more call expresions that need to be resolved and steps 2 and 3 will be repeated
+  as necessary.
+
+  Please note that if a callable symbol is never used in this scenario, its body
+  will never be compiled. This is the default behavior leading to best compilation
+  times, but if exhaustive compilation of all definitions is required, using 
+  ``nimrod check`` provides this option as well.
+
+  Example:
+
+  .. code-block:: nimrod
+
+    {.noforward: on.}
 
-  {.noforward: on.}
+    proc foo(x: int) =
+      bar x
 
-  proc foo(x: int) =
-    bar x
+    proc bar(x: int) =
+      echo x
 
-  proc bar(x: int) =
-    echo x
+    foo(10)
 
-  foo(10)
 
 Pragma pragma
 -------------
@@ -5199,7 +5203,7 @@ Example:
     {.pragma: rtl, importc, dynlib: "client.dll", cdecl.}
     
   proc p*(a, b: int): int {.rtl.} = 
-    return a+b
+    result = a+b
 
 In the example a new pragma named ``rtl`` is introduced that either imports
 a symbol from a dynamic library or exports the symbol for dynamic library
diff --git a/doc/tut1.txt b/doc/tut1.txt
index b70f40f4a..5a20629a2 100644
--- a/doc/tut1.txt
+++ b/doc/tut1.txt
@@ -690,8 +690,8 @@ Nimrod provides the ability to overload procedures similar to C++:
 .. code-block:: nimrod
   proc toString(x: int): string = ...
   proc toString(x: bool): string =
-    if x: return "true"
-    else: return "false"
+    if x: result = "true"
+    else: result = "false"
 
   echo(toString(13))   # calls the toString(x: int) proc
   echo(toString(true)) # calls the toString(x: bool) proc
@@ -1569,7 +1569,7 @@ This is best illustrated by an example:
   proc p*(x: A.T1): A.T1 =
     # this works because the compiler has already
     # added T1 to A's interface symbol table
-    return x + 1
+    result = x + 1
 
 
 A symbol of a module *can* be *qualified* with the ``module.symbol`` syntax. If
@@ -1600,11 +1600,11 @@ rules apply:
 
 .. code-block:: nimrod
   # Module A
-  proc x*(a: int): string = return $a
+  proc x*(a: int): string = result = $a
 
 .. code-block:: nimrod
   # Module B
-  proc x*(a: string): string = return $a
+  proc x*(a: string): string = result = $a
 
 .. code-block:: nimrod
   # Module C
diff --git a/doc/tut2.txt b/doc/tut2.txt
index 6738c5551..ea6733c07 100644
--- a/doc/tut2.txt
+++ b/doc/tut2.txt
@@ -126,7 +126,7 @@ The syntax for type conversions is ``destination_type(expression_to_convert)``
 
 .. code-block:: nimrod
   proc getID(x: TPerson): int =
-    return TStudent(x).id
+    TStudent(x).id
 
 The ``EInvalidObjectConversion`` exception is raised if ``x`` is not a
 ``TStudent``.
@@ -238,7 +238,7 @@ is needed:
   
   proc host*(s: TSocket): int {.inline.} =
     ## getter of hostAddr
-    return s.FHost
+    s.FHost
 
   var
     s: TSocket
diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim
index e6ab617e5..ad3fe7218 100644
--- a/lib/pure/collections/sets.nim
+++ b/lib/pure/collections/sets.nim
@@ -241,3 +241,7 @@ proc `<=`*[A](s, t: TSet[A]): bool =
       
 proc `==`*[A](s, t: TSet[A]): bool =
   s.counter == t.counter and s <= t
+
+proc map*[A, B](data: TSet[A], op: proc (x: A): B {.closure.}): TSet[B] =
+  result = initSet[B]()
+  for item in data: result.incl(op(item))
diff --git a/tests/generics/tinferredgenericprocs.nim b/tests/generics/tinferredgenericprocs.nim
new file mode 100644
index 000000000..ac445fd32
--- /dev/null
+++ b/tests/generics/tinferredgenericprocs.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''123
+1
+2
+3'''
+"""
+
+# https://github.com/Araq/Nimrod/issues/797
+proc foo[T](s:T):string = $s
+
+type IntStringProc = proc(x: int): string 
+
+var f1 = IntStringProc(foo)
+var f2: proc(x: int): string = foo
+var f3: IntStringProc = foo
+
+echo f1(1), f2(2), f3(3)
+
+for x in map([1,2,3], foo): echo x
+
diff --git a/tests/sets/tsets_lt.nim b/tests/sets/tsets_lt.nim
new file mode 100644
index 000000000..6d0b3a60c
--- /dev/null
+++ b/tests/sets/tsets_lt.nim
@@ -0,0 +1,12 @@
+discard """
+  output: '''true
+true
+true'''
+"""
+
+var s, s1: set[char]
+s = {'a'..'d'}
+s1 = {'a'..'c'}
+echo s1 < s
+echo s1 * s == {'a'..'c'}
+echo s1 <= s
diff --git a/tests/sets/testequivalence.nim b/tests/stdlib/testequivalence.nim
index 7c5d9e3e9..7c5d9e3e9 100644
--- a/tests/sets/testequivalence.nim
+++ b/tests/stdlib/testequivalence.nim
diff --git a/tests/stdlib/tsets.nim b/tests/stdlib/tsets.nim
new file mode 100644
index 000000000..656c5b3f2
--- /dev/null
+++ b/tests/stdlib/tsets.nim
@@ -0,0 +1,17 @@
+discard """
+  output: '''true
+true'''
+"""
+
+import sets
+var
+  a = initSet[int]()
+  b = initSet[int]()
+  c = initSet[string]()
+
+for i in 0..5: a.incl(i)
+for i in 1..6: b.incl(i)
+for i in 0..5: c.incl($i)
+
+echo map(a, proc(x: int): int = x + 1) == b
+echo map(a, proc(x: int): string = $x) == c