summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler/ast.nim6
-rwxr-xr-xcompiler/ccgexprs.nim8
-rwxr-xr-xcompiler/ccgtypes.nim4
-rwxr-xr-xcompiler/cgen.nim2
-rwxr-xr-xcompiler/docgen.nim2
-rwxr-xr-xcompiler/ecmasgen.nim4
-rwxr-xr-xcompiler/evals.nim5
-rwxr-xr-xcompiler/llvmgen.nim2
-rwxr-xr-xcompiler/msgs.nim4
-rwxr-xr-xcompiler/sem.nim4
-rwxr-xr-xcompiler/semexprs.nim88
-rwxr-xr-xcompiler/seminst.nim1
-rwxr-xr-xcompiler/semstmts.nim9
-rwxr-xr-xcompiler/semthreads.nim6
-rwxr-xr-xcompiler/semtypes.nim8
-rwxr-xr-xcompiler/transf.nim4
-rwxr-xr-xcompiler/types.nim20
-rwxr-xr-xlib/pure/smtp.nim12
-rwxr-xr-xlib/pure/streams.nim2
-rwxr-xr-xlib/pure/strtabs.nim10
-rwxr-xr-xlib/wrappers/gtk/glib2.nim2
-rw-r--r--tests/accept/run/teventemitter.nim23
-rw-r--r--tests/accept/run/tvarres1.nim15
-rw-r--r--tests/accept/run/tvarres2.nim20
-rw-r--r--tests/reject/tvarres1.nim17
-rw-r--r--tests/reject/tvarres2.nim16
-rwxr-xr-xtodo.txt8
27 files changed, 234 insertions, 68 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index fe601759d..f176f6eb1 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -186,8 +186,8 @@ type
     nkReturnToken         # token used for interpretation
   TNodeKinds* = set[TNodeKind]
 
-type 
-  TSymFlag* = enum    # already 30 flags! 
+type
+  TSymFlag* = enum    # already 29 flags! 
     sfUsed,           # read access of sym (for warnings) or simply used
     sfStar,           # symbol has * visibility
     sfMinus,          # symbol has - visibility
@@ -204,7 +204,6 @@ type
     sfRegister,       # variable should be placed in a register
     sfPure,           # object is "pure" that means it has no type-information
     
-    sfResult,         # variable is 'result' in proc
     sfNoSideEffect,   # proc has no side effects
     sfSideEffect,     # proc may have side effects; cannot prove it has none
     sfMainModule,     # module is the main module
@@ -293,6 +292,7 @@ type
     skType,               # a type
     skConst,              # a constant
     skVar,                # a variable
+    skResult,             # special 'result' variable
     skProc,               # a proc
     skMethod,             # a method
     skIterator,           # an iterator
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index d9ad0573a..e92673909 100755
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -136,7 +136,7 @@ proc getStorageLoc(n: PNode): TStorageLoc =
     case n.sym.kind
     of skParam, skForVar, skTemp:
       result = OnStack
-    of skVar:
+    of skVar, skResult:
       if sfGlobal in n.sym.flags: result = OnHeap
       else: result = OnStack
     of skConst: 
@@ -206,6 +206,10 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
 proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
   # This function replaces all other methods for generating
   # the assignment operation in C.
+  if src.t != nil and src.t.kind == tyPtr:
+    # little HACK to suppor the new 'var T' as return type:
+    appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
+    return
   var ty = skipTypes(dest.t, abstractVarRange)
   case ty.kind
   of tyRef:
@@ -1648,7 +1652,7 @@ proc expr(p: BProc, e: PNode, d: var TLoc) =
         genComplexConst(p, sym, d)
     of skEnumField:
       putIntoDest(p, d, e.typ, toRope(sym.position))
-    of skVar:
+    of skVar, skResult:
       if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
       if ((sym.loc.r == nil) or (sym.loc.t == nil)):
         InternalError(e.info, "expr: var not init " & sym.name.s)
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index a1f772379..ddaeed729 100755
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -37,7 +37,7 @@ proc mangleName(s: PSym): PRope =
       case s.kind
       of skProc, skMethod, skConverter, skConst: 
         result = toRope("@")
-      of skVar: 
+      of skVar, skResult: 
         if sfGlobal in s.flags: result = toRope("@")
         else: result = toRope("%")
       of skForVar, skTemp, skParam, skType, skEnumField, skModule: 
@@ -153,7 +153,7 @@ proc getGlobalTempName(): PRope =
 
 proc ccgIntroducedPtr(s: PSym): bool = 
   var pt = s.typ
-  assert(not (sfResult in s.flags))
+  assert skResult != s.kind
   case pt.Kind
   of tyObject: 
     # XXX quick hack floatSize*2 for the pegs module under 64bit
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 68e377f8b..b89d2d7fc 100755
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -534,7 +534,7 @@ proc cgsym(m: BModule, name: string): PRope =
   if sym != nil: 
     case sym.kind
     of skProc, skMethod, skConverter: genProc(m, sym)
-    of skVar: genVarPrototype(m, sym)
+    of skVar, skResult: genVarPrototype(m, sym)
     of skType: discard getTypeDesc(m, sym.typ)
     else: InternalError("cgsym: " & name)
   else:
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index fc019790a..0c5d41b47 100755
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -810,7 +810,7 @@ proc generateDoc(d: PDoc, n: PNode) =
 
 proc genSection(d: PDoc, kind: TSymKind) = 
   const sectionNames: array[skModule..skTemplate, string] = [
-    "Imports", "Types", "Consts", "Vars", "Procs", "Methods", 
+    "Imports", "Types", "Consts", "Vars", "Vars", "Procs", "Methods", 
     "Iterators", "Converters", "Macros", "Templates"
   ]
   if d.section[kind] == nil: return 
diff --git a/compiler/ecmasgen.nim b/compiler/ecmasgen.nim
index 592a24043..2e66f61c9 100755
--- a/compiler/ecmasgen.nim
+++ b/compiler/ecmasgen.nim
@@ -832,7 +832,7 @@ proc genAddr(p: var TProc, n: PNode, r: var TCompRes) =
     s = n.sons[0].sym
     if s.loc.r == nil: InternalError(n.info, "genAddr: 3")
     case s.kind
-    of skVar: 
+    of skVar, skResult: 
       if mapType(n.typ) == etyObject: 
         # make addr() a no-op:
         r.kind = etyNone
@@ -863,7 +863,7 @@ proc genSym(p: var TProc, n: PNode, r: var TCompRes) =
   if s.loc.r == nil: 
     InternalError(n.info, "symbol has no generated name: " & s.name.s)
   case s.kind
-  of skVar, skParam, skTemp: 
+  of skVar, skParam, skTemp, skResult: 
     var k = mapType(s.typ)
     if k == etyBaseIndex: 
       r.kind = etyBaseIndex
diff --git a/compiler/evals.nim b/compiler/evals.nim
index 4372e3179..9aa67de3e 100755
--- a/compiler/evals.nim
+++ b/compiler/evals.nim
@@ -293,7 +293,7 @@ proc evalVariable(c: PStackFrame, sym: PSym, flags: TEvalFlags): PNode =
   # which can be modified.
   var x = c
   while x != nil: 
-    if sfResult in sym.flags: 
+    if sym.kind == skResult:
       result = x.params[0]
       if result == nil: result = emptyNode
       return
@@ -425,7 +425,8 @@ proc evalSwap(c: PEvalContext, n: PNode): PNode =
 proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = 
   case n.sym.kind
   of skProc, skConverter, skMacro: result = n.sym.ast.sons[codePos]
-  of skVar, skForVar, skTemp: result = evalVariable(c.tos, n.sym, flags)
+  of skVar, skForVar, skTemp, skResult: 
+    result = evalVariable(c.tos, n.sym, flags)
   of skParam: 
     # XXX what about LValue?
     result = c.tos.params[n.sym.position + 1]
diff --git a/compiler/llvmgen.nim b/compiler/llvmgen.nim
index f8acb624a..b45f37e14 100755
--- a/compiler/llvmgen.nim
+++ b/compiler/llvmgen.nim
@@ -393,7 +393,7 @@ proc UseMagic(m: BModule, name: string) =
   if sym != nil: 
     case sym.kind
     of skProc, skMethod, skConverter: genProc(m, sym)
-    of skVar: genVarPrototype(m, sym)
+    of skVar, skResult: genVarPrototype(m, sym)
     of skType: discard getTypeDesc(m, sym.typ)
     else: InternalError("useMagic: " & name)
   elif not (sfSystemModule in m.module.flags): 
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index b2ead1d9e..27b5c7f67 100755
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -56,7 +56,8 @@ type
     errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig, 
     errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects, 
     errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX, 
-    errCannotInstantiateX, errExprHasNoAddress, errVarForOutParamNeeded, 
+    errCannotInstantiateX, errExprHasNoAddress, errXStackEscape,
+    errVarForOutParamNeeded, 
     errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX, 
     errAmbiguousCallXYZ, errWrongNumberOfArguments, errXCannotBePassedToProcVar, 
     errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed, 
@@ -227,6 +228,7 @@ const
     errIllegalRecursionInTypeX: "illegal recursion in type \'$1\'", 
     errCannotInstantiateX: "cannot instantiate: \'$1\'", 
     errExprHasNoAddress: "expression has no address", 
+    errXStackEscape: "address of '$1' may not escape its stack frame",
     errVarForOutParamNeeded: "for a \'var\' type a variable needs to be passed",
     errPureTypeMismatch: "type mismatch", 
     errTypeMismatch: "type mismatch: got (", 
diff --git a/compiler/sem.nim b/compiler/sem.nim
index c2fbfff72..5d2e1069f 100755
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -50,6 +50,10 @@ proc addResult(c: PContext, t: PType, info: TLineInfo)
 proc addResultNode(c: PContext, n: PNode)
 proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
 
+proc ParamsTypeCheck(c: PContext, typ: PType) {.inline.} =
+  if not typeAllowed(typ, skConst):
+    GlobalError(typ.n.info, errXisNoType, typeToString(typ))
+
 proc semConstExpr(c: PContext, n: PNode): PNode = 
   result = semExprWithType(c, n)
   if result == nil: 
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 879a42d81..959a48267 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -21,20 +21,31 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode =
 
 proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
 
+proc newDeref(n: PNode): PNode {.inline.} =  
+  result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
+  addSon(result, n)
+
 proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = 
   result = semExpr(c, n, flags)
   if result.kind == nkEmpty: 
     # do not produce another redundant error message:
     raiseRecoverableError()
   if result.typ != nil: 
-    if result.typ.kind == tyVar: 
-      var d = newNodeIT(nkHiddenDeref, result.info, result.typ.sons[0])
-      addSon(d, result)
-      result = d
+    if result.typ.kind == tyVar: result = newDeref(result)
   else:
     GlobalError(n.info, errExprXHasNoType, 
                 renderTree(result, {renderNoComments}))
 
+proc semExprWithTypeNoDeref(c: PContext, n: PNode, 
+                            flags: TExprFlags = {}): PNode = 
+  result = semExpr(c, n, flags)
+  if result.kind == nkEmpty: 
+    # do not produce another redundant error message:
+    raiseRecoverableError()
+  if result.typ == nil:
+    GlobalError(n.info, errExprXHasNoType, 
+                renderTree(result, {renderNoComments}))
+
 proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
   result = symChoice(c, n, s)
   
@@ -67,7 +78,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
       result = newSymNode(s, n.info)
   of skMacro: result = semMacroExpr(c, n, s)
   of skTemplate: result = semTemplateExpr(c, n, s)
-  of skVar:
+  of skVar, skResult:
     markUsed(n, s)
     # if a proc accesses a global variable, it is not side effect free:
     if sfGlobal in s.flags: incl(c.p.owner.flags, sfSideEffect)
@@ -330,33 +341,37 @@ type
   TAssignableResult = enum 
     arNone,                   # no l-value and no discriminant
     arLValue,                 # is an l-value
+    arLocalLValue,            # is an l-value, but local var; must not escape
+                              # its stack frame!
     arDiscriminant            # is a discriminant
 
-proc isAssignable(n: PNode): TAssignableResult = 
+proc isAssignable(c: PContext, n: PNode): TAssignableResult = 
   result = arNone
   case n.kind
-  of nkSym: 
-    if n.sym.kind in {skVar, skTemp}: result = arLValue
+  of nkSym:
+    if n.sym.kind in {skVar, skResult, skTemp}:
+      if c.p.owner.id == n.sym.owner.id: result = arLocalLValue
+      else: result = arLValue
   of nkDotExpr: 
     if skipTypes(n.sons[0].typ, abstractInst).kind in {tyVar, tyPtr, tyRef}: 
       result = arLValue
     else: 
-      result = isAssignable(n.sons[0])
-    if result == arLValue and sfDiscriminant in n.sons[1].sym.flags: 
+      result = isAssignable(c, n.sons[0])
+    if result != arNone and sfDiscriminant in n.sons[1].sym.flags: 
       result = arDiscriminant
   of nkBracketExpr: 
     if skipTypes(n.sons[0].typ, abstractInst).kind in {tyVar, tyPtr, tyRef}: 
       result = arLValue
-    else: 
-      result = isAssignable(n.sons[0])
+    else:
+      result = isAssignable(c, n.sons[0])
   of nkHiddenStdConv, nkHiddenSubConv, nkConv: 
     # Object and tuple conversions are still addressable, so we skip them
     if skipTypes(n.typ, abstractPtrs).kind in {tyOpenArray, tyTuple, tyObject}: 
-      result = isAssignable(n.sons[1])
+      result = isAssignable(c, n.sons[1])
   of nkHiddenDeref, nkDerefExpr: 
     result = arLValue
   of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr: 
-    result = isAssignable(n.sons[0])
+    result = isAssignable(c, n.sons[0])
   else: 
     nil
 
@@ -367,7 +382,7 @@ proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
   else: 
     result = newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ))
     addSon(result, n)
-    if isAssignable(n) != arLValue: 
+    if isAssignable(c, n) notin {arLValue, arLocalLValue}:
       localError(n.info, errVarForOutParamNeeded)
 
 proc analyseIfAddressTaken(c: PContext, n: PNode): PNode = 
@@ -403,7 +418,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
     for i in countup(1, sonsLen(n) - 1): 
       if i < sonsLen(t) and t.sons[i] != nil and
           skipTypes(t.sons[i], abstractInst).kind == tyVar: 
-        if isAssignable(n.sons[i]) != arLValue: 
+        if isAssignable(c, n.sons[i]) notin {arLValue, arLocalLValue}: 
           LocalError(n.sons[i].info, errVarForOutParamNeeded)
     return
   for i in countup(1, sonsLen(n) - 1): 
@@ -751,7 +766,30 @@ proc propertyWriteAccess(c: PContext, n, a: PNode): PNode =
   else:
     globalError(n.Info, errUndeclaredFieldX, id.s)
 
-proc semAsgn(c: PContext, n: PNode): PNode = 
+proc takeImplicitAddr(c: PContext, n: PNode): PNode =
+  case n.kind
+  of nkHiddenAddr, nkAddr: return n
+  of nkHiddenDeref, nkDerefExpr: return n.sons[0]
+  of nkBracketExpr:
+    if len(n) == 1: return n.sons[0]
+  else: nil
+  var valid = isAssignable(c, n)
+  if valid != arLValue:
+    if valid == arLocalLValue:
+      GlobalError(n.info, errXStackEscape, renderTree(n, {renderNoComments}))
+    else:
+      GlobalError(n.info, errExprHasNoAddress)
+  result = newNodeIT(nkHiddenAddr, n.info, makePtrType(c, n.typ))
+  result.add(n)
+  
+proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
+  if le.kind == nkHiddenDeref:
+    var x = le.sons[0]
+    if x.typ.kind == tyVar and x.kind == nkSym and x.sym.kind == skResult:
+      n.sons[0] = x # 'result[]' --> 'result'
+      n.sons[1] = takeImplicitAddr(c, ri)
+
+proc semAsgn(c: PContext, n: PNode): PNode =
   checkSonsLen(n, 2)
   var a = n.sons[0]
   case a.kind
@@ -762,8 +800,8 @@ proc semAsgn(c: PContext, n: PNode): PNode =
     if a == nil: 
       return propertyWriteAccess(c, n, n[0])
   of nkBracketExpr: 
-    # a[i..j] = x
-    # --> `[..]=`(a, i, j, x)
+    # a[i] = x
+    # --> `[]=`(a, i, x)
     a = semSubscript(c, a, {efLValue})
     if a == nil:
       result = buildOverloadedSubscripts(n.sons[0], inAsgn=true)
@@ -772,15 +810,19 @@ proc semAsgn(c: PContext, n: PNode): PNode =
   else: 
     a = semExprWithType(c, a, {efLValue})
   n.sons[0] = a
-  n.sons[1] = semExprWithType(c, n.sons[1])
+  # a = b # both are vars, means: a[] = b[]
+  # a = b # b no 'var T' means: a = addr(b)
   var le = a.typ
-  if skipTypes(le, {tyGenericInst}).kind != tyVar and IsAssignable(a) == arNone: 
+  if skipTypes(le, {tyGenericInst}).kind != tyVar and 
+      IsAssignable(c, a) == arNone: 
     # Direct assignment to a discriminant is allowed!
     localError(a.info, errXCannotBeAssignedTo, 
                renderTree(a, {renderNoComments}))
-  else: 
+  else:
+    n.sons[1] = semExprWithType(c, n.sons[1])
     n.sons[1] = fitNode(c, le, n.sons[1])
     fixAbstractType(c, n)
+    asgnToResultVar(c, n, n.sons[0], n.sons[1])
   result = n
 
 proc lookUpForDefined(c: PContext, i: PIdent, onlyCurrentScope: bool): PSym =
@@ -1144,7 +1186,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     result = n
     checkSonsLen(n, 1)
     n.sons[0] = semExprWithType(c, n.sons[0])
-    if isAssignable(n.sons[0]) != arLValue: 
+    if isAssignable(c, n.sons[0]) notin {arLValue, arLocalLValue}: 
       GlobalError(n.info, errExprHasNoAddress)
     n.typ = makePtrType(c, n.sons[0].typ)
   of nkHiddenAddr, nkHiddenDeref:
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 6cb325290..a73a0d9bf 100755
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -100,6 +100,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
     result.typ = newTypeS(tyProc, c)
     addSon(result.typ, nil)
   result.typ.callConv = fn.typ.callConv
+  ParamsTypeCheck(c, result.typ)
   var oldPrc = GenericCacheGet(c, entry)
   if oldPrc == nil:
     # add it here, so that recursive generic procs are possible:
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index a341ce64d..3444ccfca 100755
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -164,7 +164,7 @@ proc SemReturn(c: PContext, n: PNode): PNode =
     addSon(a, n.sons[0])
     n.sons[0] = semAsgn(c, a)
     # optimize away ``result = result``:
-    if n[0][1].kind == nkSym and sfResult in n[0][1].sym.flags: 
+    if n[0][1].kind == nkSym and n[0][1].sym.kind == skResult: 
       n.sons[0] = ast.emptyNode
   
 proc SemYield(c: PContext, n: PNode): PNode = 
@@ -544,10 +544,9 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
   
 proc addResult(c: PContext, t: PType, info: TLineInfo) = 
   if t != nil: 
-    var s = newSym(skVar, getIdent"result", getCurrOwner())
+    var s = newSym(skResult, getIdent"result", getCurrOwner())
     s.info = info
     s.typ = t
-    incl(s.flags, sfResult)
     incl(s.flags, sfUsed)
     addDecl(c, s)
     c.p.resultSym = s
@@ -569,7 +568,8 @@ proc semLambda(c: PContext, n: PNode): PNode =
   if n.sons[paramsPos].kind != nkEmpty: 
     semParamList(c, n.sons[ParamsPos], nil, s)
     addParams(c, s.typ.n)
-  else: 
+    ParamsTypeCheck(c, s.typ)
+  else:
     s.typ = newTypeS(tyProc, c)
     addSon(s.typ, nil)
   s.typ.callConv = ccClosure
@@ -664,6 +664,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     if sfBorrow in s.flags: 
       LocalError(n.sons[codePos].info, errImplOfXNotAllowed, s.name.s)
     if n.sons[genericParamsPos].kind == nkEmpty: 
+      ParamsTypeCheck(c, s.typ)
       pushProcCon(c, s)
       if (s.typ.sons[0] != nil) and (kind != skIterator): 
         addResult(c, s.typ.sons[0], n.info)
diff --git a/compiler/semthreads.nim b/compiler/semthreads.nim
index 7355c3bfc..60c54b43e 100755
--- a/compiler/semthreads.nim
+++ b/compiler/semthreads.nim
@@ -107,7 +107,7 @@ proc analyseSym(c: PProcCtx, n: PNode): TThreadOwner =
   result = c.mapping[v.id]
   if result != toUndefined: return
   case v.kind
-  of skVar:
+  of skVar, skResult:
     result = toNil
     if sfGlobal in v.flags:
       if sfThreadVar in v.flags: 
@@ -192,9 +192,13 @@ proc analyseCall(c: PProcCtx, n: PNode): TThreadOwner =
     if prc.ast.sons[codePos].kind == nkEmpty and 
        {sfNoSideEffect, sfThread, sfImportc} * prc.flags == {}:
       Message(n.info, warnAnalysisLoophole, renderTree(n))
+      if result == toUndefined: result = toNil
     if prc.typ.sons[0] != nil:
       if prc.ast.len > resultPos:
         result = newCtx.mapping[prc.ast.sons[resultPos].sym.id]
+        # if the proc body does not set 'result', nor 'return's something
+        # explicitely, it returns a binary zero, so 'toNil' is correct:
+        if result == toUndefined: result = toNil
       else:
         result = toNil
     else:
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 44d264c1c..fb7f46007 100755
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -480,8 +480,8 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
   # n.sons[0] contains the pragmas (if any). We process these later...
   checkSonsLen(n, 3)
   if n.sons[1].kind != nkEmpty: 
-    base = semTypeNode(c, n.sons[1].sons[0], nil)
-    var concreteBase = skipGenericInvokation(skipTypes(base, skipPtrs))
+    base = skipTypes(semTypeNode(c, n.sons[1].sons[0], nil), skipPtrs)
+    var concreteBase = skipGenericInvokation(base)
     if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags: 
       addInheritedFields(c, check, pos, concreteBase)
     else:
@@ -528,10 +528,10 @@ proc addTypeVarsOfGenericBody(c: PContext, t: PType, genericParams: PNode,
   
 proc paramType(c: PContext, n, genericParams: PNode, cl: var TIntSet): PType = 
   result = semTypeNode(c, n, nil)
-  if (genericParams != nil) and (sonsLen(genericParams) == 0): 
+  if genericParams != nil and sonsLen(genericParams) == 0: 
     result = addTypeVarsOfGenericBody(c, result, genericParams, cl)
     #if result.kind == tyGenericInvokation: debug(result)
-  
+
 proc semProcTypeNode(c: PContext, n, genericParams: PNode, 
                      prev: PType): PType = 
   var 
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 93b69a597..78814edd8 100755
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -526,12 +526,12 @@ proc gatherVars(c: PTransf, n: PNode, marked: var TIntSet, owner: PSym,
                 container: PNode) = 
   # gather used vars for closure generation
   case n.kind
-  of nkSym: 
+  of nkSym:
     var s = n.sym
     var found = false
     case s.kind
     of skVar: found = sfGlobal notin s.flags
-    of skTemp, skForVar, skParam: found = true
+    of skTemp, skForVar, skParam, skResult: found = true
     else: nil
     if found and owner.id != s.owner.id and not ContainsOrIncl(marked, s.id): 
       incl(s.flags, sfInClosure)
diff --git a/compiler/types.nim b/compiler/types.nim
index 83426bed7..2e4262ecc 100755
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -758,8 +758,8 @@ proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind): bool =
           result = typeAllowedNode(marker, n.sons[i], kind)
           if not result: return 
   
-proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool = 
-  assert(kind in {skVar, skConst, skParam})
+proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
+  assert(kind in {skVar, skConst, skParam, skResult})
   # if we have already checked the type, return true, because we stop the
   # evaluation if something is wrong:
   result = true
@@ -773,13 +773,14 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
     of tyVar: 
       result = false          # ``var var`` is always an invalid type:
     of tyOpenArray: 
-      result = (kind == skParam) and typeAllowedAux(marker, t2, kind)
-    else: result = (kind != skConst) and typeAllowedAux(marker, t2, kind)
+      result = kind == skParam and typeAllowedAux(marker, t2, kind)
+    else:
+      result = kind in {skParam, skResult} and typeAllowedAux(marker, t2, kind)
   of tyProc: 
     for i in countup(1, sonsLen(t) - 1): 
       result = typeAllowedAux(marker, t.sons[i], skParam)
       if not result: return 
-    if t.sons[0] != nil: result = typeAllowedAux(marker, t.sons[0], skVar)
+    if t.sons[0] != nil: result = typeAllowedAux(marker, t.sons[0], skResult)
   of tyExpr, tyStmt, tyTypeDesc: 
     result = true
   of tyGenericBody, tyGenericParam, tyForward, tyNone, tyGenericInvokation: 
@@ -799,10 +800,11 @@ proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind): bool =
     result = (kind == skParam) and typeAllowedAux(marker, t.sons[0], skVar)
   of tySequence: 
     result = (kind != skConst) and typeAllowedAux(marker, t.sons[0], skVar) or
-        (t.sons[0].kind == tyEmpty)
-  of tyArray: 
-    result = typeAllowedAux(marker, t.sons[1], skVar)
-  of tyPtr, tyRef: 
+        t.sons[0].kind == tyEmpty
+  of tyArray:
+    result = typeAllowedAux(marker, t.sons[1], skVar) or
+        t.sons[1].kind == tyEmpty
+  of tyPtr, tyRef:
     result = typeAllowedAux(marker, t.sons[0], skVar)
   of tyArrayConstr, tyTuple, tySet: 
     for i in countup(0, sonsLen(t) - 1): 
diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim
index bddcdfb04..0dd9f3eca 100755
--- a/lib/pure/smtp.nim
+++ b/lib/pure/smtp.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2010 Dominik Picheta
+#        (c) Copyright 2011 Dominik Picheta
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -87,7 +87,7 @@ proc checkReply(smtp: TSMTP, reply: string) =
 proc connect*(address: string, port = 25, 
               ssl = false, debug = false): TSMTP =
   ## Establishes a connection with a SMTP server.
-  ## May fail with EInvalidReply or with a socket errors.
+  ## May fail with EInvalidReply or with a socket error.
 
   if not ssl:
     result.sock = socket()
@@ -125,7 +125,6 @@ proc sendmail*(smtp: TSMTP, fromaddr: string,
   ## Sends `msg` from `fromaddr` to `toaddr`. 
   ## Messages may be formed using ``createMessage`` by converting the
   ## TMessage into a string.
-  ## This function sends the QUIT command when finished.
 
   smtp.debugSend("MAIL FROM:<" & fromaddr & ">\c\L")
   smtp.checkReply("250")
@@ -139,8 +138,9 @@ proc sendmail*(smtp: TSMTP, fromaddr: string,
   smtp.debugSend(msg & "\c\L")
   smtp.debugSend(".\c\L")
   smtp.checkReply("250")
-  
-  # quit
+
+proc close*(smtp: TSMTP) =
+  ## Disconnects from the SMTP server and closes the socket.
   smtp.debugSend("QUIT\c\L")
   if not smtp.ssl:
     smtp.sock.close()
@@ -201,6 +201,6 @@ when isMainModule:
   smtp.auth("someone", "password")
   smtp.sendmail("someone@gmail.com", 
                 @["someone@yahoo.com", "someone@gmail.com"], $msg)
-  
+  smtp.close()
   
 
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index 242e40d83..62cb385d4 100755
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2009 Andreas Rumpf
+#        (c) Copyright 2011 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim
index 2028daa50..584282fbc 100755
--- a/lib/pure/strtabs.nim
+++ b/lib/pure/strtabs.nim
@@ -92,6 +92,14 @@ proc `[]`*(t: PStringTable, key: string): string {.rtl, extern: "nstGet".} =
   if index >= 0: result = t.data[index].val
   else: result = ""
 
+proc modGet*(t: PStringTable, key: string): var string {.
+             rtl, extern: "nstTake".} =
+  ## retrieves the location at ``t[key]``. If `key` is not in `t`, the
+  ## ``EInvalidValue`` exception is raised.
+  var index = RawGet(t, key)
+  if index >= 0: result = t.data[index].val
+  else: raise newException(EInvalidValue, "key does not exist: " & key)
+
 proc hasKey*(t: PStringTable, key: string): bool {.rtl, extern: "nst$1".} =
   ## returns true iff `key` is in the table `t`.
   result = rawGet(t, key) >= 0
@@ -213,4 +221,6 @@ when isMainModule:
   assert x["k"] == "v"
   assert x["11"] == "22"
   assert x["565"] == "67"
+  x.modGet("11") = "23"
+  assert x["11"] == "23"
 
diff --git a/lib/wrappers/gtk/glib2.nim b/lib/wrappers/gtk/glib2.nim
index acb85c194..9947e2a4b 100755
--- a/lib/wrappers/gtk/glib2.nim
+++ b/lib/wrappers/gtk/glib2.nim
@@ -4505,3 +4505,5 @@ proc G_TYPE_GSTRING*(): GType =
 proc g_thread_init*(vtable: pointer) {.
   cdecl, dynlib: gobjectlib, importc: "g_thread_init".}
 
+proc g_timeout_add*(interval: guint, function, data: gpointer): guint {.
+  cdecl, dynlib: gliblib, importc: "g_timeout_add".}
diff --git a/tests/accept/run/teventemitter.nim b/tests/accept/run/teventemitter.nim
new file mode 100644
index 000000000..6ebe994b1
--- /dev/null
+++ b/tests/accept/run/teventemitter.nim
@@ -0,0 +1,23 @@
+import tables
+import lists
+type
+    TEventArgs = object of TObject
+type
+    TEventEmitter = object of TObject
+        events*: TTable[string, TDoublyLinkedList[proc(e : TEventArgs)]]
+proc on*(emitter : var TEventEmitter, event : string, func : proc(e : TEventArgs)) =
+    if hasKey(emitter.events, event) == false:
+        var list: TDoublyLinkedList[proc(e : TEventArgs)]
+        add(emitter.events,event,list) #if not, add it.
+    append(emitter.events[event], func) #adds the function to the event's list. I get a error here too.
+        
+proc emit*(emitter : TEventEmitter, event : string, args : TEventArgs) =
+    for func in items(emitter.events[event]):
+        func(args) #call function with args.
+proc initEmitter(emitter : TEventEmitter) =
+     emitter.events = initTable[string, TSinglyLinkedList[TObject]]()
+
+var ee : TEventEmitter
+ee.on("print", proc(e : TEventArgs) = echo("pie"))
+ee.emit("print")
+
diff --git a/tests/accept/run/tvarres1.nim b/tests/accept/run/tvarres1.nim
new file mode 100644
index 000000000..a48c961df
--- /dev/null
+++ b/tests/accept/run/tvarres1.nim
@@ -0,0 +1,15 @@
+discard """
+  output: "45"
+"""
+
+var
+  g = 5
+
+proc p(): var int = 
+  var bla = addr(g) #: array [0..7, int]
+  result = bla[]
+  
+p() = 45
+
+echo g
+
diff --git a/tests/accept/run/tvarres2.nim b/tests/accept/run/tvarres2.nim
new file mode 100644
index 000000000..119560e7b
--- /dev/null
+++ b/tests/accept/run/tvarres2.nim
@@ -0,0 +1,20 @@
+discard """
+  output: "45 hallo"
+"""
+
+type
+  TKachel = tuple[i: int, s: string]
+  TSpielwiese = object
+    k: seq[TKachel]
+
+var
+  spielwiese: TSpielwiese
+newSeq(spielwiese.k, 64)
+
+proc at*(s: var TSpielwiese, x, y: int): var TKachel =
+  result = s.k[y * 8 + x]
+
+spielwiese.at(3, 4) = (45, "hallo")
+
+echo spielwiese.at(3,4)[0], " ", spielwiese.at(3,4)[1]
+
diff --git a/tests/reject/tvarres1.nim b/tests/reject/tvarres1.nim
new file mode 100644
index 000000000..de4a505d3
--- /dev/null
+++ b/tests/reject/tvarres1.nim
@@ -0,0 +1,17 @@
+discard """
+  file: "tvarres1.nim"
+  line: 12
+  errormsg: "address of 'bla' may not escape its stack frame"
+"""
+
+var
+  g = 5
+
+proc p(): var int = 
+  var bla: int
+  result = bla
+  
+p() = 45
+
+echo g
+
diff --git a/tests/reject/tvarres2.nim b/tests/reject/tvarres2.nim
new file mode 100644
index 000000000..6bda844fc
--- /dev/null
+++ b/tests/reject/tvarres2.nim
@@ -0,0 +1,16 @@
+discard """
+  file: "tvarres1.nim"
+  line: 11
+  errormsg: "expression has no address"
+"""
+
+var
+  g = 5
+
+proc p(): var int = 
+  result = 89
+  
+p() = 45
+
+echo g
+
diff --git a/todo.txt b/todo.txt
index 635f5f566..45b7e47b3 100755
--- a/todo.txt
+++ b/todo.txt
@@ -1,8 +1,11 @@
 Version 0.8.14
 ==============
 
-- ``var T`` as a return type; easy to prove that location does not escape its
-  stack frame
+- ``var T`` as a return type:
+  * for iterators
+  * add ``modGet`` for generics
+  * documentation
+  * provide ``mod`` as an alternative syntax for ``var``
 - document Nimrod's two phase symbol lookup for generics
 - optional indentation for 'case' statement
 - make threadvar efficient again on linux after testing
@@ -41,7 +44,6 @@ version 0.9.XX
   proc specialization in the code gen
 - resizing of strings/sequences could take into account the memory that
   is allocated
-- typeAllowed() for parameters...
 - find a way to reintroduce the cleanup() pass for C code generation: this
   is hard because of partial evaluation --> symbol files will fix this as
   a side effect