summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ccgexprs.nim2
-rw-r--r--compiler/jsgen.nim19
-rw-r--r--compiler/pragmas.nim55
-rw-r--r--compiler/semexprs.nim9
-rw-r--r--compiler/semgnrc.nim13
-rw-r--r--compiler/seminst.nim7
-rw-r--r--compiler/sempass2.nim34
-rw-r--r--compiler/semstmts.nim10
-rw-r--r--compiler/sigmatch.nim5
-rw-r--r--compiler/transf.nim12
-rw-r--r--compiler/types.nim3
-rw-r--r--doc/manual/ffi.txt26
-rw-r--r--lib/deprecated/pure/ftpclient.nim4
-rw-r--r--lib/pure/algorithm.nim2
-rw-r--r--lib/pure/collections/sequtils.nim16
-rw-r--r--lib/pure/net.nim8
-rw-r--r--lib/pure/oids.nim3
-rw-r--r--lib/pure/unittest.nim30
-rw-r--r--lib/system.nim4
-rw-r--r--lib/upcoming/asyncdispatch.nim10
-rw-r--r--tests/ccgbugs/twrong_rc_for_refarray.nim26
-rw-r--r--tests/effects/tsidee4.nim6
-rw-r--r--tests/generics/ttempl_in_generic.nim8
-rw-r--r--tests/iter/tcomplex_openarray.nim33
-rw-r--r--tests/js/tunittests.nim4
-rw-r--r--tests/stdlib/tnet_ll.nim3
-rw-r--r--tests/stdlib/tparseuints.nim2
-rw-r--r--tests/vm/tconst_float_as_int.nim3
-rw-r--r--todo.txt1
-rw-r--r--web/assets/news/images/survey/dev_os.pngbin0 -> 68341 bytes
-rw-r--r--web/assets/news/images/survey/do_you_use_nim.pngbin0 -> 28789 bytes
-rw-r--r--web/assets/news/images/survey/editors.pngbin0 -> 28665 bytes
-rw-r--r--web/assets/news/images/survey/nim_at_work.pngbin0 -> 61209 bytes
-rw-r--r--web/assets/news/images/survey/nim_found.pngbin0 -> 68570 bytes
-rw-r--r--web/assets/news/images/survey/nim_time.pngbin0 -> 101792 bytes
-rw-r--r--web/assets/news/images/survey/nim_time_rust.pngbin0 -> 35888 bytes
-rw-r--r--web/assets/news/images/survey/nim_versions.pngbin0 -> 32490 bytes
-rw-r--r--web/assets/news/images/survey/planning_to_use_at_work.pngbin0 -> 65840 bytes
-rw-r--r--web/assets/news/images/survey/project_size.pngbin0 -> 29199 bytes
-rw-r--r--web/assets/news/images/survey/project_size_nim_rust.pngbin0 -> 44455 bytes
-rw-r--r--web/assets/news/images/survey/project_size_work.pngbin0 -> 39499 bytes
-rw-r--r--web/assets/news/images/survey/reliability.pngbin0 -> 29235 bytes
-rw-r--r--web/assets/news/images/survey/target_os.pngbin0 -> 72162 bytes
-rw-r--r--web/assets/news/images/survey/upgrades_broke_things.pngbin0 -> 71148 bytes
-rw-r--r--web/news/nim_community_survey_results.rst317
45 files changed, 574 insertions, 101 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index f9fa1a0f6..6c96f209e 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -670,6 +670,8 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
     #if e[0].kind != nkBracketExpr:
     #  message(e.info, warnUser, "CAME HERE " & renderTree(e))
     expr(p, e.sons[0], d)
+    if e.sons[0].typ.skipTypes(abstractInst).kind == tyRef:
+      d.s = OnHeap
   else:
     var a: TLoc
     let typ = skipTypes(e.sons[0].typ, abstractInst)
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index a0b54812f..80bcd2b0e 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -8,7 +8,7 @@
 #
 
 # This is the JavaScript code generator.
-# Soon also a PHP code generator. ;-)
+# Also a PHP code generator. ;-)
 
 discard """
 The JS code generator contains only 2 tricks:
@@ -1280,14 +1280,15 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
       assert(typ.kind == tyProc)
       genPatternCall(p, n, pat, typ, r)
       return
-  gen(p, n.sons[1], r)
-  if r.typ == etyBaseIndex:
-    if r.address == nil:
-      globalError(n.info, "cannot invoke with infix syntax")
-    r.res = "$1[$2]" % [r.address, r.res]
-    r.address = nil
-    r.typ = etyNone
-  add(r.res, "." | "->")
+  if n.len != 1:
+    gen(p, n.sons[1], r)
+    if r.typ == etyBaseIndex:
+      if r.address == nil:
+        globalError(n.info, "cannot invoke with infix syntax")
+      r.res = "$1[$2]" % [r.address, r.res]
+      r.address = nil
+      r.typ = etyNone
+    add(r.res, "." | "->")
   var op: TCompRes
   if p.target == targetPHP:
     op.kind = resCallee
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 1f93f5317..db5f8e727 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -90,43 +90,38 @@ proc pragmaAsm*(c: PContext, n: PNode): char =
       else:
         invalidPragma(it)
 
-proc setExternName(s: PSym, extname: string) =
-  s.loc.r = rope(extname % s.name.s)
+proc setExternName(s: PSym, extname: string, info: TLineInfo) =
+  # special cases to improve performance:
+  if extname == "$1":
+    s.loc.r = rope(s.name.s)
+  elif '$' notin extname:
+    s.loc.r = rope(extname)
+  else:
+    try:
+      s.loc.r = rope(extname % s.name.s)
+    except ValueError:
+      localError(info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)")
   if gCmd == cmdPretty and '$' notin extname:
     # note that '{.importc.}' is transformed into '{.importc: "$1".}'
     s.loc.flags.incl(lfFullExternalName)
 
-proc makeExternImport(s: PSym, extname: string) =
-  setExternName(s, extname)
+proc makeExternImport(s: PSym, extname: string, info: TLineInfo) =
+  setExternName(s, extname, info)
   incl(s.flags, sfImportc)
   excl(s.flags, sfForward)
 
-proc validateExternCName(s: PSym, info: TLineInfo) =
-  ## Validates that the symbol name in s.loc.r is a valid C identifier.
-  ##
-  ## Valid identifiers are those alphanumeric including the underscore not
-  ## starting with a number. If the check fails, a generic error will be
-  ## displayed to the user.
-  let target = $s.loc.r
-  if target.len < 1 or target[0] notin IdentStartChars or
-      not target.allCharsInSet(IdentChars):
-    localError(info, errGenerated, "invalid exported symbol")
-
 proc makeExternExport(s: PSym, extname: string, info: TLineInfo) =
-  setExternName(s, extname)
-  # XXX to fix make it work with nimrtl.
-  #if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC}:
-  #  validateExternCName(s, info)
+  setExternName(s, extname, info)
   incl(s.flags, sfExportc)
 
-proc processImportCompilerProc(s: PSym, extname: string) =
-  setExternName(s, extname)
+proc processImportCompilerProc(s: PSym, extname: string, info: TLineInfo) =
+  setExternName(s, extname, info)
   incl(s.flags, sfImportc)
   excl(s.flags, sfForward)
   incl(s.loc.flags, lfImportCompilerProc)
 
-proc processImportCpp(s: PSym, extname: string) =
-  setExternName(s, extname)
+proc processImportCpp(s: PSym, extname: string, info: TLineInfo) =
+  setExternName(s, extname, info)
   incl(s.flags, sfImportc)
   incl(s.flags, sfInfixCall)
   excl(s.flags, sfForward)
@@ -134,8 +129,8 @@ proc processImportCpp(s: PSym, extname: string) =
   incl(m.flags, sfCompileToCpp)
   extccomp.gMixedMode = true
 
-proc processImportObjC(s: PSym, extname: string) =
-  setExternName(s, extname)
+proc processImportObjC(s: PSym, extname: string, info: TLineInfo) =
+  setExternName(s, extname, info)
   incl(s.flags, sfImportc)
   incl(s.flags, sfNamedParamCall)
   excl(s.flags, sfForward)
@@ -623,10 +618,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
       of wExportc:
         makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info)
         incl(sym.flags, sfUsed) # avoid wrong hints
-      of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"))
+      of wImportc: makeExternImport(sym, getOptionalStr(c, it, "$1"), it.info)
       of wImportCompilerProc:
-        processImportCompilerProc(sym, getOptionalStr(c, it, "$1"))
-      of wExtern: setExternName(sym, expectStrLit(c, it))
+        processImportCompilerProc(sym, getOptionalStr(c, it, "$1"), it.info)
+      of wExtern: setExternName(sym, expectStrLit(c, it), it.info)
       of wImmediate:
         if sym.kind in {skTemplate, skMacro}:
           incl(sym.flags, sfImmediate)
@@ -637,9 +632,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
         if sym.kind == skTemplate: incl(sym.flags, sfDirty)
         else: invalidPragma(it)
       of wImportCpp:
-        processImportCpp(sym, getOptionalStr(c, it, "$1"))
+        processImportCpp(sym, getOptionalStr(c, it, "$1"), it.info)
       of wImportObjC:
-        processImportObjC(sym, getOptionalStr(c, it, "$1"))
+        processImportObjC(sym, getOptionalStr(c, it, "$1"), it.info)
       of wAlign:
         if sym.typ == nil: invalidPragma(it)
         var align = expectIntLit(c, it)
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index fc31829ba..e3552f94e 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -701,9 +701,6 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
         # error correction, prevents endless for loop elimination in transf.
         # See bug #2051:
         result.sons[0] = newSymNode(errorSym(c, n))
-      if sfNoSideEffect notin callee.flags:
-        if {sfImportc, sfSideEffect} * callee.flags != {}:
-          incl(c.p.owner.flags, sfSideEffect)
 
 proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode
 
@@ -804,9 +801,6 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
     else:
       result = m.call
       instGenericConvertersSons(c, result, m)
-    # we assume that a procedure that calls something indirectly
-    # has side-effects:
-    if tfNoSideEffect notin t.flags: incl(c.p.owner.flags, sfSideEffect)
   elif t != nil and t.kind == tyTypeDesc:
     if n.len == 1: return semObjConstr(c, n, flags)
     return semConv(c, n)
@@ -1040,9 +1034,6 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
 
     markUsed(n.info, s)
     styleCheckUse(n.info, 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)
     result = newSymNode(s, n.info)
     # We cannot check for access to outer vars for example because it's still
     # not sure the symbol really ends up being used:
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index 9ea3efd0c..b8451865e 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -202,24 +202,25 @@ proc semGenericStmt(c: PContext, n: PNode,
     if s != nil:
       incl(s.flags, sfUsed)
       mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles}
-      let scOption = if s.name.id in ctx.toMixin: scForceOpen else: scOpen
+      let sc = symChoice(c, fn, s,
+            if s.name.id in ctx.toMixin: scForceOpen else: scOpen)
       case s.kind
       of skMacro:
-        if macroToExpand(s):
+        if macroToExpand(s) and sc.safeLen <= 1:
           styleCheckUse(fn.info, s)
           result = semMacroExpr(c, n, n, s, {efNoSemCheck})
           result = semGenericStmt(c, result, flags, ctx)
         else:
-          n.sons[0] = symChoice(c, fn, s, scOption)
+          n.sons[0] = sc
           result = n
         mixinContext = true
       of skTemplate:
-        if macroToExpand(s):
+        if macroToExpand(s) and sc.safeLen <= 1:
           styleCheckUse(fn.info, s)
           result = semTemplateExpr(c, n, s, {efNoSemCheck})
           result = semGenericStmt(c, result, flags, ctx)
         else:
-          n.sons[0] = symChoice(c, fn, s, scOption)
+          n.sons[0] = sc
           result = n
         # BUGFIX: we must not return here, we need to do first phase of
         # symbol lookup. Also since templates and macros can do scope injections
@@ -230,7 +231,7 @@ proc semGenericStmt(c: PContext, n: PNode,
         # Leave it as an identifier.
         discard
       of skProc, skMethod, skIterator, skConverter, skModule:
-        result.sons[0] = symChoice(c, fn, s, scOption)
+        result.sons[0] = sc
         # do not check of 's.magic==mRoof' here because it might be some
         # other '^' but after overload resolution the proper one:
         if ctx.bracketExpr != nil and n.len == 2 and s.name.s == "^":
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 460db4f7c..a57b8e520 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -172,9 +172,10 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
       popInfoContext()
 
 proc sideEffectsCheck(c: PContext, s: PSym) =
-  if {sfNoSideEffect, sfSideEffect} * s.flags ==
-      {sfNoSideEffect, sfSideEffect}:
-    localError(s.info, errXhasSideEffects, s.name.s)
+  when false:
+    if {sfNoSideEffect, sfSideEffect} * s.flags ==
+        {sfNoSideEffect, sfSideEffect}:
+      localError(s.info, errXhasSideEffects, s.name.s)
 
 proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
                           allowMetaTypes = false): PType =
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index b12ab5e96..6d2e82ef0 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -59,7 +59,7 @@ type
     init: seq[int] # list of initialized variables
     guards: TModel # nested guards
     locked: seq[PNode] # locked locations
-    gcUnsafe, isRecursive, isToplevel: bool
+    gcUnsafe, isRecursive, isToplevel, hasSideEffect: bool
     maxLockLevel, currLockLevel: TLockLevel
   PEffects = var TEffects
 
@@ -192,6 +192,14 @@ proc markGcUnsafe(a: PEffects; reason: PNode) =
       a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent("<unknown>"),
                                         a.owner, reason.info)
 
+when true:
+  template markSideEffect(a: PEffects; reason: typed) =
+    a.hasSideEffect = true
+else:
+  template markSideEffect(a: PEffects; reason: typed) =
+    a.hasSideEffect = true
+    markGcUnsafe(a, reason)
+
 proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet) =
   let u = s.gcUnsafetyReason
   if u != nil and not cycleCheck.containsOrIncl(u.id):
@@ -226,12 +234,16 @@ proc useVar(a: PEffects, n: PNode) =
         message(n.info, warnUninit, s.name.s)
       # prevent superfluous warnings about the same variable:
       a.init.add s.id
-  if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet}:
+  if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet} and
+      s.magic != mNimVm:
     if s.guard != nil: guardGlobal(a, n, s.guard)
     if {sfGlobal, sfThread} * s.flags == {sfGlobal} and
         (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem):
       #if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
       markGcUnsafe(a, s)
+    else:
+      markSideEffect(a, s)
+
 
 type
   TIntersection = seq[tuple[id, count: int]] # a simple count table
@@ -495,6 +507,8 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
   if notGcSafe(s.typ) and sfImportc notin s.flags:
     if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
     markGcUnsafe(tracked, s)
+  if tfNoSideEffect notin s.typ.flags:
+    markSideEffect(tracked, s)
   mergeLockLevels(tracked, n, s.getLockLevel)
 
 proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
@@ -550,12 +564,16 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
       if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
         if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
         markGcUnsafe(tracked, a)
+      elif tfNoSideEffect notin op.flags and not isOwnedProcVar(a, tracked.owner):
+        markSideEffect(tracked, a)
     else:
       mergeEffects(tracked, effectList.sons[exceptionEffects], n)
       mergeTags(tracked, effectList.sons[tagEffects], n)
       if notGcSafe(op):
         if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
         markGcUnsafe(tracked, a)
+      elif tfNoSideEffect notin op.flags:
+        markSideEffect(tracked, a)
   notNilCheck(tracked, n, paramType)
 
 proc breaksBlock(n: PNode): bool =
@@ -684,6 +702,7 @@ proc track(tracked: PEffects, n: PNode) =
         if a.sym == tracked.owner: tracked.isRecursive = true
         # even for recursive calls we need to check the lock levels (!):
         mergeLockLevels(tracked, n, a.sym.getLockLevel)
+        if sfSideEffect in a.sym.flags: markSideEffect(tracked, a)
       else:
         mergeLockLevels(tracked, n, op.lockLevel)
       var effectList = op.n.sons[0]
@@ -702,6 +721,10 @@ proc track(tracked: PEffects, n: PNode) =
           if not (a.kind == nkSym and a.sym == tracked.owner):
             if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
             markGcUnsafe(tracked, a)
+        if tfNoSideEffect notin op.flags and not importedFromC(a):
+          # and it's not a recursive call:
+          if not (a.kind == nkSym and a.sym == tracked.owner):
+            markSideEffect(tracked, a)
     for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i))
     if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
       # may not look like an assignment, but it is:
@@ -912,8 +935,15 @@ proc trackProc*(s: PSym, body: PNode) =
     else:
       listGcUnsafety(s, onlyWarning=true)
       #localError(s.info, warnGcUnsafe2, s.name.s)
+  if sfNoSideEffect in s.flags and t.hasSideEffect:
+    when false:
+      listGcUnsafety(s, onlyWarning=false)
+    else:
+      localError(s.info, errXhasSideEffects, s.name.s)
   if not t.gcUnsafe:
     s.typ.flags.incl tfGcSafe
+  if not t.hasSideEffect:
+    s.typ.flags.incl tfNoSideEffect
   if s.typ.lockLevel == UnspecifiedLockLevel:
     s.typ.lockLevel = t.maxLockLevel
   elif t.maxLockLevel > s.typ.lockLevel:
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 5d1770a32..5f9989ea2 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -304,8 +304,14 @@ proc semTry(c: PContext, n: PNode): PNode =
 proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
   result = fitNode(c, typ, n)
   if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
-    changeType(result.sons[1], typ, check=true)
-    result = result.sons[1]
+    let r1 = result.sons[1]
+    if r1.kind in {nkCharLit..nkUInt64Lit} and typ.skipTypes(abstractRange).kind in {tyFloat..tyFloat128}:
+      result = newFloatNode(nkFloatLit, BiggestFloat r1.intVal)
+      result.info = n.info
+      result.typ = typ
+    else:
+      changeType(r1, typ, check=true)
+      result = r1
   elif not sameType(result.typ, typ):
     changeType(result, typ, check=false)
 
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index ce4f893ea..ec429968c 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -221,13 +221,14 @@ proc cmpCandidates*(a, b: TCandidate): int =
   if result != 0: return
   result = a.convMatches - b.convMatches
   if result != 0: return
-  result = a.calleeScope - b.calleeScope
-  if result != 0: return
   # the other way round because of other semantics:
   result = b.inheritancePenalty - a.inheritancePenalty
   if result != 0: return
   # prefer more specialized generic over more general generic:
   result = complexDisambiguation(a.callee, b.callee)
+  # only as a last resort, consider scoping:
+  if result != 0: return
+  result = a.calleeScope - b.calleeScope
 
 proc writeMatches*(c: TCandidate) =
   writeLine(stdout, "exact matches: " & $c.exactMatches)
diff --git a/compiler/transf.nim b/compiler/transf.nim
index d64276cfb..fc400c524 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -474,12 +474,14 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
 
 type
   TPutArgInto = enum
-    paDirectMapping, paFastAsgn, paVarAsgn
+    paDirectMapping, paFastAsgn, paVarAsgn, paComplexOpenarray
 
 proc putArgInto(arg: PNode, formal: PType): TPutArgInto =
   # This analyses how to treat the mapping "formal <-> arg" in an
   # inline context.
   if skipTypes(formal, abstractInst).kind in {tyOpenArray, tyVarargs}:
+    if arg.kind == nkStmtListExpr:
+      return paComplexOpenarray
     return paDirectMapping    # XXX really correct?
                               # what if ``arg`` has side-effects?
   case arg.kind
@@ -569,6 +571,14 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
       assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
       idNodeTablePut(newC.mapping, formal, arg)
       # XXX BUG still not correct if the arg has a side effect!
+    of paComplexOpenarray:
+      let typ = newType(tySequence, formal.owner)
+      addSonSkipIntLit(typ, formal.typ.sons[0])
+      var temp = newTemp(c, typ, formal.info)
+      addVar(v, temp)
+      add(stmtList, newAsgnStmt(c, temp, arg.PTransNode))
+      idNodeTablePut(newC.mapping, formal, temp)
+
   var body = iter.getBody.copyTree
   pushInfoContext(n.info)
   # XXX optimize this somehow. But the check "c.inlining" is not correct:
diff --git a/compiler/types.nim b/compiler/types.nim
index ff60730f0..312e36ae5 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -48,6 +48,8 @@ proc isOrdinalType*(t: PType): bool
 proc enumHasHoles*(t: PType): bool
 
 const
+  # TODO: Remove tyTypeDesc from each abstractX and (where necessary)
+  # replace with typedescX
   abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal,
                    tyConst, tyMutable, tyTypeDesc}
   abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal,
@@ -61,6 +63,7 @@ const
 
   skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable,
                tyTypeDesc}
+  # typedescX is used if we're sure tyTypeDesc should be included (or skipped)
   typedescPtrs* = abstractPtrs + {tyTypeDesc}
   typedescInst* = abstractInst + {tyTypeDesc}
 
diff --git a/doc/manual/ffi.txt b/doc/manual/ffi.txt
index 5055f18af..d7d9596d2 100644
--- a/doc/manual/ffi.txt
+++ b/doc/manual/ffi.txt
@@ -16,12 +16,20 @@ spelled*:
 .. code-block::
   proc printf(formatstr: cstring) {.header: "<stdio.h>", importc: "printf", varargs.}
 
-Note that this pragma is somewhat of a misnomer: Other backends will provide
+Note that this pragma is somewhat of a misnomer: Other backends do provide
 the same feature under the same name. Also, if one is interfacing with C++
 the `ImportCpp pragma <manual.html#implementation-specific-pragmas-importcpp-pragma>`_ and
 interfacing with Objective-C the `ImportObjC pragma
 <manual.html#implementation-specific-pragmas-importobjc-pragma>`_ can be used.
 
+The string literal passed to ``importc`` can be a format string:
+
+.. code-block:: Nim
+  proc p(s: cstring) {.importc: "prefix$1".}
+
+In the example the external name of ``p`` is set to ``prefixp``. Only ``$1``
+is available and a literal dollar sign must be written as ``$$``.
+
 
 Exportc pragma
 --------------
@@ -33,9 +41,19 @@ name is the Nim identifier *exactly as spelled*:
 .. code-block:: Nim
   proc callme(formatstr: cstring) {.exportc: "callMe", varargs.}
 
-Note that this pragma is somewhat of a misnomer: Other backends will provide
+Note that this pragma is somewhat of a misnomer: Other backends do provide
 the same feature under the same name.
 
+The string literal passed to ``exportc`` can be a format string:
+
+.. code-block:: Nim
+  proc p(s: string) {.exportc: "prefix$1".} =
+    echo s
+
+In the example the external name of ``p`` is set to ``prefixp``. Only ``$1``
+is available and a literal dollar sign must be written as ``$$``.
+
+
 
 Extern pragma
 -------------
@@ -46,7 +64,9 @@ mangling. The string literal passed to ``extern`` can be a format string:
   proc p(s: string) {.extern: "prefix$1".} =
     echo s
 
-In the example the external name of ``p`` is set to ``prefixp``.
+In the example the external name of ``p`` is set to ``prefixp``. Only ``$1``
+is available and a literal dollar sign must be written as ``$$``.
+
 
 
 Bycopy pragma
diff --git a/lib/deprecated/pure/ftpclient.nim b/lib/deprecated/pure/ftpclient.nim
index 1188c0795..ed2f14450 100644
--- a/lib/deprecated/pure/ftpclient.nim
+++ b/lib/deprecated/pure/ftpclient.nim
@@ -129,10 +129,10 @@ proc ftpClient*(address: string, port = Port(21),
   result.csock = socket()
   if result.csock == invalidSocket: raiseOSError(osLastError())
 
-template blockingOperation(sock: Socket, body: stmt) {.immediate.} =
+template blockingOperation(sock: Socket, body: untyped) =
   body
 
-template blockingOperation(sock: asyncio.AsyncSocket, body: stmt) {.immediate.} =
+template blockingOperation(sock: asyncio.AsyncSocket, body: untyped) =
   sock.setBlocking(true)
   body
   sock.setBlocking(false)
diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim
index eee4fab22..b83daf245 100644
--- a/lib/pure/algorithm.nim
+++ b/lib/pure/algorithm.nim
@@ -231,7 +231,7 @@ template sortedByIt*(seq1, op: untyped): untyped =
   ##
   ##   echo people.sortedByIt((it.age, it.name))
   ##
-  var result {.gensym.} = sorted(seq1, proc(x, y: type(seq1[0])): int =
+  var result = sorted(seq1, proc(x, y: type(seq1[0])): int =
     var it {.inject.} = x
     let a = op
     it = y
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index e277ee9e8..f458b7636 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -371,7 +371,7 @@ template filterIt*(seq1, pred: untyped): untyped =
   ##      notAcceptable = filterIt(temperatures, it > 50 or it < -10)
   ##    assert acceptable == @[-2.0, 24.5, 44.31]
   ##    assert notAcceptable == @[-272.15, 99.9, -113.44]
-  var result {.gensym.} = newSeq[type(seq1[0])]()
+  var result = newSeq[type(seq1[0])]()
   for it {.inject.} in items(seq1):
     if pred: result.add(it)
   result
@@ -420,7 +420,7 @@ template allIt*(seq1, pred: untyped): bool =
   ##   let numbers = @[1, 4, 5, 8, 9, 7, 4]
   ##   assert allIt(numbers, it < 10) == true
   ##   assert allIt(numbers, it < 9) == false
-  var result {.gensym.} = true
+  var result = true
   for it {.inject.} in items(seq1):
     if not pred:
       result = false
@@ -451,7 +451,7 @@ template anyIt*(seq1, pred: untyped): bool =
   ##   let numbers = @[1, 4, 5, 8, 9, 7, 4]
   ##   assert anyIt(numbers, it > 8) == true
   ##   assert anyIt(numbers, it > 9) == false
-  var result {.gensym.} = false
+  var result = false
   for it {.inject.} in items(seq1):
     if pred:
       result = true
@@ -512,7 +512,7 @@ template foldl*(sequence, operation: untyped): untyped =
   ##   assert concatenation == "nimiscool"
   let s = sequence
   assert s.len > 0, "Can't fold empty sequences"
-  var result {.gensym.}: type(s[0])
+  var result: type(s[0])
   result = s[0]
   for i in 1..<s.len:
     let
@@ -537,7 +537,7 @@ template foldl*(sequence, operation, first): untyped =
   ##     numbers = @[0, 8, 1, 5]
   ##     digits = foldl(numbers, a & (chr(b + ord('0'))), "")
   ##   assert digits == "0815"
-  var result {.gensym.}: type(first)
+  var result: type(first)
   result = first
   for x in items(sequence):
     let
@@ -574,7 +574,7 @@ template foldr*(sequence, operation: untyped): untyped =
   ##   assert concatenation == "nimiscool"
   let s = sequence
   assert s.len > 0, "Can't fold empty sequences"
-  var result {.gensym.}: type(s[0])
+  var result: type(s[0])
   result = sequence[s.len - 1]
   for i in countdown(s.len - 2, 0):
     let
@@ -598,7 +598,7 @@ template mapIt*(seq1, typ, op: untyped): untyped =
   ##   assert strings == @["4", "8", "12", "16"]
   ## **Deprecated since version 0.12.0:** Use the ``mapIt(seq1, op)``
   ##   template instead.
-  var result {.gensym.}: seq[typ] = @[]
+  var result: seq[typ] = @[]
   for it {.inject.} in items(seq1):
     result.add(op)
   result
@@ -662,7 +662,7 @@ template newSeqWith*(len: int, init: untyped): untyped =
   ##   import random
   ##   var seqRand = newSeqWith(20, random(10))
   ##   echo seqRand
-  var result {.gensym.} = newSeq[type(init)](len)
+  var result = newSeq[type(init)](len)
   for i in 0 .. <len:
     result[i] = init
   result
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index 9501f6dc7..bd208761b 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -205,6 +205,10 @@ proc newSocket*(fd: SocketHandle, domain: Domain = AF_INET,
   if buffered:
     result.currPos = 0
 
+  # Set SO_NOSIGPIPE on OS X.
+  when defined(macosx):
+    setSockOptInt(fd, SOL_SOCKET, SO_NOSIGPIPE, 1)
+
 proc newSocket*(domain, sockType, protocol: cint, buffered = true): Socket =
   ## Creates a new socket.
   ##
@@ -342,8 +346,6 @@ when defineSsl:
     result = SSLContext(context: newCTX, extraInternalIndex: 0,
         referencedData: initSet[int]())
     result.extraInternalIndex = getExtraDataIndex(result)
-    # The PSK callback functions assume the internal index is 0.
-    assert result.extraInternalIndex == 0
 
     let extraInternal = new(SslContextExtraInternal)
     result.setExtraData(result.extraInternalIndex, extraInternal)
@@ -392,6 +394,8 @@ when defineSsl:
     ##
     ## Only used in PSK ciphersuites.
     ctx.getExtraInternal().clientGetPskFunc = fun
+    assert ctx.extraInternalIndex == 0,
+          "The pskClientCallback assumes the extraInternalIndex is 0"
     ctx.context.SSL_CTX_set_psk_client_callback(
         if fun == nil: nil else: pskClientCallback)
 
diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim
index fca10dab6..e4c97b260 100644
--- a/lib/pure/oids.nim
+++ b/lib/pure/oids.nim
@@ -74,8 +74,7 @@ proc genOid*(): Oid =
 
   var t = gettime(nil)
 
-  var i = int32(incr)
-  atomicInc(incr)
+  var i = int32(atomicInc(incr))
 
   if fuzz == 0:
     # racy, but fine semantically:
diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim
index 92ddc3e75..0fc2e441e 100644
--- a/lib/pure/unittest.nim
+++ b/lib/pure/unittest.nim
@@ -77,6 +77,15 @@ checkpoints = @[]
 proc shouldRun(testName: string): bool =
   result = true
 
+proc startSuite(name: string) =
+  template rawPrint() = echo("\n[Suite] ", name) 
+  when not defined(ECMAScript):
+    if colorOutput:
+      styledEcho styleBright, fgBlue, "\n[Suite] ", fgWhite, name
+    else: rawPrint()
+  else: rawPrint()
+
+
 template suite*(name, body) {.dirty.} =
   ## Declare a test suite identified by `name` with optional ``setup``
   ## and/or ``teardown`` section.
@@ -103,9 +112,11 @@ template suite*(name, body) {.dirty.} =
   ##
   ## .. code-block::
   ##
-  ##  [OK] 2 + 2 = 4
-  ##  [OK] (2 + -2) != 4
+  ##  [Suite] test suite for addition
+  ##    [OK] 2 + 2 = 4
+  ##    [OK] (2 + -2) != 4
   block:
+    bind startSuite
     template setup(setupBody: untyped) {.dirty.} =
       var testSetupIMPLFlag = true
       template testSetupIMPL: untyped {.dirty.} = setupBody
@@ -114,14 +125,16 @@ template suite*(name, body) {.dirty.} =
       var testTeardownIMPLFlag = true
       template testTeardownIMPL: untyped {.dirty.} = teardownBody
 
+    let testInSuiteImplFlag = true
+    startSuite name
     body
 
-proc testDone(name: string, s: TestStatus) =
+proc testDone(name: string, s: TestStatus, indent: bool) =
   if s == FAILED:
     programResult += 1
-
+  let prefix = if indent: "  " else: ""
   if outputLevel != PRINT_NONE and (outputLevel == PRINT_ALL or s == FAILED):
-    template rawPrint() = echo("[", $s, "] ", name)
+    template rawPrint() = echo(prefix, "[", $s, "] ", name)
     when not defined(ECMAScript):
       if colorOutput and not defined(ECMAScript):
         var color = case s
@@ -129,7 +142,7 @@ proc testDone(name: string, s: TestStatus) =
                     of FAILED: fgRed
                     of SKIPPED: fgYellow
                     else: fgWhite
-        styledEcho styleBright, color, "[", $s, "] ", fgWhite, name
+        styledEcho styleBright, color, prefix, "[", $s, "] ", fgWhite, name
       else:
         rawPrint()
     else:
@@ -168,7 +181,7 @@ template test*(name, body) {.dirty.} =
       fail()
 
     finally:
-      testDone name, testStatusIMPL
+      testDone name, testStatusIMPL, declared(testInSuiteImplFlag)
 
 proc checkpoint*(msg: string) =
   ## Set a checkpoint identified by `msg`. Upon test failure all
@@ -198,8 +211,9 @@ template fail* =
   ##
   ## outputs "Checkpoint A" before quitting.
   bind checkpoints
+  let prefix = if declared(testInSuiteImplFlag): "    " else: ""
   for msg in items(checkpoints):
-    echo msg
+    echo prefix, msg
 
   when not defined(ECMAScript):
     if abortOnError: quit(1)
diff --git a/lib/system.nim b/lib/system.nim
index 82980d9da..356248e6c 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -3232,7 +3232,7 @@ proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[int]): seq[T] =
   when low(a) < 0:
     {.error: "Slicing for arrays with negative indices is unsupported.".}
   var L = x.b - x.a + 1
-  newSeq(result, L)
+  result = newSeq[T](L)
   for i in 0.. <L: result[i] = a[i + x.a]
 
 proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[int], b: openArray[T]) =
@@ -3681,4 +3681,4 @@ when defined(nimconfig):
 when defined(windows) and appType == "console" and not defined(nimconfig):
   proc setConsoleOutputCP(codepage: cint): cint {.stdcall, dynlib: "kernel32",
     importc: "SetConsoleOutputCP".}
-  discard setConsoleOutputCP(65001) # 65001 - utf-8 codepage
\ No newline at end of file
+  discard setConsoleOutputCP(65001) # 65001 - utf-8 codepage
diff --git a/lib/upcoming/asyncdispatch.nim b/lib/upcoming/asyncdispatch.nim
index 162ac5e08..19c9815d2 100644
--- a/lib/upcoming/asyncdispatch.nim
+++ b/lib/upcoming/asyncdispatch.nim
@@ -1233,7 +1233,7 @@ when defined(windows) or defined(nimdoc):
 
     registerWaitableHandle(p, hProcess, flags, pcd, proccb)
 
-  proc newEvent*(): AsyncEvent =
+  proc newAsyncEvent*(): AsyncEvent =
     ## Creates new ``AsyncEvent`` object.
     var sa = SECURITY_ATTRIBUTES(
       nLength: sizeof(SECURITY_ATTRIBUTES).cint,
@@ -1314,7 +1314,7 @@ else:
       readCB: Callback
       writeCB: Callback
 
-    AsyncEvent = SelectEvent
+    AsyncEvent* = SelectEvent
 
     PDispatcher* = ref object of PDispatcherBase
       selector: Selector[AsyncData]
@@ -1419,7 +1419,7 @@ else:
               if adata.writeCB == cb:
                 adata.writeCB = nil
                 update = true
-        
+
         when supportedPlatform:
           if (customSet * events) != {}:
             let cb = keys[i].data.readCB
@@ -1686,11 +1686,11 @@ else:
 
   proc setEvent*(ev: AsyncEvent) =
     ## Sets new ``AsyncEvent`` to signaled state.
-    setEvent(SelectEvent(ev))
+    ioselectors.setEvent(SelectEvent(ev))
 
   proc close*(ev: AsyncEvent) =
     ## Closes ``AsyncEvent``
-    close(SelectEvent(ev))
+    ioselectors.close(SelectEvent(ev))
 
   proc addEvent*(ev: AsyncEvent, cb: Callback) =
     ## Start watching for event ``ev``, and call callback ``cb``, when
diff --git a/tests/ccgbugs/twrong_rc_for_refarray.nim b/tests/ccgbugs/twrong_rc_for_refarray.nim
new file mode 100644
index 000000000..99bdac5e1
--- /dev/null
+++ b/tests/ccgbugs/twrong_rc_for_refarray.nim
@@ -0,0 +1,26 @@
+discard """
+  output: '''m[0][0] = 1.0
+m[0][0] = 2.0'''
+"""
+# bug #4653
+type
+  Vector = ref array[2, float64]
+  Matrix = ref array[2, Vector]
+
+proc newVector(): Vector =
+  new(result)
+
+proc newMatrix(): Matrix =
+  new(result)
+  for ix in 0 .. 1:
+    result[ix] = newVector()
+
+let m = newMatrix()
+
+m[0][0] = 1.0
+echo "m[0][0] = ", m[0][0]
+
+GC_fullCollect()
+
+m[0][0] = 2.0
+echo "m[0][0] = ", m[0][0]
diff --git a/tests/effects/tsidee4.nim b/tests/effects/tsidee4.nim
index 2cb88a23e..ecc79580c 100644
--- a/tests/effects/tsidee4.nim
+++ b/tests/effects/tsidee4.nim
@@ -1,13 +1,13 @@
 discard """
   file: "tsidee4.nim"
-  line: 15
-  errormsg: "type mismatch"
+  line: 12
+  errormsg: "'noSideEffect' can have side effects"
 """
 
 var
   global: int
 
-proc dontcare(x: int): int = return x
+proc dontcare(x: int): int = return global
 
 proc noSideEffect(x, y: int, p: proc (a: int): int {.noSideEffect.}): int {.noSideEffect.} =
   return x + y + dontcare(x)
diff --git a/tests/generics/ttempl_in_generic.nim b/tests/generics/ttempl_in_generic.nim
new file mode 100644
index 000000000..f04b9d216
--- /dev/null
+++ b/tests/generics/ttempl_in_generic.nim
@@ -0,0 +1,8 @@
+
+# bug #4600
+template foo(x: untyped): untyped = echo 1
+template foo(x,y: untyped): untyped = echo 2
+
+proc bar1[T](x: T) = foo(x)
+proc bar2(x: float) = foo(x,x)
+proc bar3[T](x: T) = foo(x,x)
diff --git a/tests/iter/tcomplex_openarray.nim b/tests/iter/tcomplex_openarray.nim
new file mode 100644
index 000000000..6fc191e90
--- /dev/null
+++ b/tests/iter/tcomplex_openarray.nim
@@ -0,0 +1,33 @@
+
+# bug #3221
+
+import algorithm, math, sequtils
+
+
+iterator permutations[T](ys: openarray[T]): seq[T] =
+  var
+    d = 1
+    c = newSeq[int](ys.len)
+    xs = newSeq[T](ys.len)
+  for i, y in ys: xs[i] = y
+  yield xs
+  block outer:
+    while true:
+      while d > 1:
+        dec d
+        c[d] = 0
+      while c[d] >= d:
+        inc d
+        if d >= ys.len: break outer
+      let i = if (d and 1) == 1: c[d] else: 0
+      swap xs[i], xs[d]
+      yield xs
+      inc c[d]
+
+proc dig_vectors(): void =
+  var v_nums: seq[int]
+  v_nums = newSeq[int](1)
+  for perm in permutations(toSeq(0 .. 1)):
+    v_nums[0] = 1
+
+dig_vectors()
diff --git a/tests/js/tunittests.nim b/tests/js/tunittests.nim
index 4b09c99a9..7c2e70563 100644
--- a/tests/js/tunittests.nim
+++ b/tests/js/tunittests.nim
@@ -1,5 +1,7 @@
 discard """
-  output: '''[OK] >:)'''
+  output: '''
+[Suite] Bacon
+  [OK] >:)'''
 """
 
 import unittest
diff --git a/tests/stdlib/tnet_ll.nim b/tests/stdlib/tnet_ll.nim
index 4d4df7c13..2ac272fd1 100644
--- a/tests/stdlib/tnet_ll.nim
+++ b/tests/stdlib/tnet_ll.nim
@@ -1,5 +1,8 @@
 discard """

   action: run

+  output: '''

+[Suite] inet_ntop tests

+'''

 """

 

 when defined(windows):

diff --git a/tests/stdlib/tparseuints.nim b/tests/stdlib/tparseuints.nim
index 5be3bcbd0..6b228d933 100644
--- a/tests/stdlib/tparseuints.nim
+++ b/tests/stdlib/tparseuints.nim
@@ -1,5 +1,7 @@
 discard """
   action: run
+  output: '''
+[Suite] parseutils'''
 """
 import unittest, strutils
 
diff --git a/tests/vm/tconst_float_as_int.nim b/tests/vm/tconst_float_as_int.nim
new file mode 100644
index 000000000..ed84ec194
--- /dev/null
+++ b/tests/vm/tconst_float_as_int.nim
@@ -0,0 +1,3 @@
+
+# bug #4619
+const x: float = 0
diff --git a/todo.txt b/todo.txt
index 86bffcc3d..106f2bb34 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,6 +1,7 @@
 version 1.0 battle plan
 =======================
 
+- iters for js
 - fix "high priority" bugs
 - try to fix as many compiler crashes as reasonable
 
diff --git a/web/assets/news/images/survey/dev_os.png b/web/assets/news/images/survey/dev_os.png
new file mode 100644
index 000000000..088918dc3
--- /dev/null
+++ b/web/assets/news/images/survey/dev_os.png
Binary files differdiff --git a/web/assets/news/images/survey/do_you_use_nim.png b/web/assets/news/images/survey/do_you_use_nim.png
new file mode 100644
index 000000000..257148325
--- /dev/null
+++ b/web/assets/news/images/survey/do_you_use_nim.png
Binary files differdiff --git a/web/assets/news/images/survey/editors.png b/web/assets/news/images/survey/editors.png
new file mode 100644
index 000000000..816ad515f
--- /dev/null
+++ b/web/assets/news/images/survey/editors.png
Binary files differdiff --git a/web/assets/news/images/survey/nim_at_work.png b/web/assets/news/images/survey/nim_at_work.png
new file mode 100644
index 000000000..f00ab1a94
--- /dev/null
+++ b/web/assets/news/images/survey/nim_at_work.png
Binary files differdiff --git a/web/assets/news/images/survey/nim_found.png b/web/assets/news/images/survey/nim_found.png
new file mode 100644
index 000000000..a0a65b813
--- /dev/null
+++ b/web/assets/news/images/survey/nim_found.png
Binary files differdiff --git a/web/assets/news/images/survey/nim_time.png b/web/assets/news/images/survey/nim_time.png
new file mode 100644
index 000000000..23bc4a136
--- /dev/null
+++ b/web/assets/news/images/survey/nim_time.png
Binary files differdiff --git a/web/assets/news/images/survey/nim_time_rust.png b/web/assets/news/images/survey/nim_time_rust.png
new file mode 100644
index 000000000..9b861608a
--- /dev/null
+++ b/web/assets/news/images/survey/nim_time_rust.png
Binary files differdiff --git a/web/assets/news/images/survey/nim_versions.png b/web/assets/news/images/survey/nim_versions.png
new file mode 100644
index 000000000..ba382c93d
--- /dev/null
+++ b/web/assets/news/images/survey/nim_versions.png
Binary files differdiff --git a/web/assets/news/images/survey/planning_to_use_at_work.png b/web/assets/news/images/survey/planning_to_use_at_work.png
new file mode 100644
index 000000000..be3a50467
--- /dev/null
+++ b/web/assets/news/images/survey/planning_to_use_at_work.png
Binary files differdiff --git a/web/assets/news/images/survey/project_size.png b/web/assets/news/images/survey/project_size.png
new file mode 100644
index 000000000..ad1359d0c
--- /dev/null
+++ b/web/assets/news/images/survey/project_size.png
Binary files differdiff --git a/web/assets/news/images/survey/project_size_nim_rust.png b/web/assets/news/images/survey/project_size_nim_rust.png
new file mode 100644
index 000000000..41e3ec8b1
--- /dev/null
+++ b/web/assets/news/images/survey/project_size_nim_rust.png
Binary files differdiff --git a/web/assets/news/images/survey/project_size_work.png b/web/assets/news/images/survey/project_size_work.png
new file mode 100644
index 000000000..fab6e52f2
--- /dev/null
+++ b/web/assets/news/images/survey/project_size_work.png
Binary files differdiff --git a/web/assets/news/images/survey/reliability.png b/web/assets/news/images/survey/reliability.png
new file mode 100644
index 000000000..1767e9803
--- /dev/null
+++ b/web/assets/news/images/survey/reliability.png
Binary files differdiff --git a/web/assets/news/images/survey/target_os.png b/web/assets/news/images/survey/target_os.png
new file mode 100644
index 000000000..a36915af1
--- /dev/null
+++ b/web/assets/news/images/survey/target_os.png
Binary files differdiff --git a/web/assets/news/images/survey/upgrades_broke_things.png b/web/assets/news/images/survey/upgrades_broke_things.png
new file mode 100644
index 000000000..28a8ee3f0
--- /dev/null
+++ b/web/assets/news/images/survey/upgrades_broke_things.png
Binary files differdiff --git a/web/news/nim_community_survey_results.rst b/web/news/nim_community_survey_results.rst
new file mode 100644
index 000000000..49656f20a
--- /dev/null
+++ b/web/news/nim_community_survey_results.rst
@@ -0,0 +1,317 @@
+Nim Community Survey Results
+============================
+
+.. container:: metadata
+
+  Posted by Dominik Picheta on 20/08/2016
+
+We have recently closed the 2016 Nim Community Survey. I am happy to
+say that we have received exactly 790 responses, huge thanks go to the people
+that took the time to respond. We're very thankful for this very valuable
+feedback.
+
+This survey was inspired in part by the
+`2016 State of Rust <https://blog.rust-lang.org/2016/06/30/State-of-Rust-Survey-2016.html>`_
+survey. You will note that many of the questions were modelled after
+Rust's survey. One of the reasons for doing this was to allow us to easily
+compare our results against the results obtained in the Rust survey. In
+addition, we of course also liked many of their questions.
+
+Our survey ran from the 23rd of June 2016 until the 8th of August 2016. The
+response numbers are impressive considering Nim's community size; at 790 they
+make up just over 25% of the Rust survey's responses.
+
+The goal of this survey was to primarily determine how our community is using
+Nim, in order to better understand how we should be improving it. In particular,
+we wanted to know what people feel is missing from Nim in the lead up to
+version 1.0. We have also asked our respondents about how well the Nim tools
+worked, the challenges of adopting Nim, the resources that they used to learn
+Nim and more.
+
+It is my hope that we will be able to run a similar survey in a years time,
+doing so should give us an idea of whether we are improving.
+With these general facts in mind, let's begin looking at specific questions.
+
+How did you find out about Nim?
+-------------------------------
+
+The rationale for the first question was simple, we wanted to know where our
+respondents found out about Nim. This is an interesting question for us, as
+we do occassionally get users asking us why it took so long for them to hear
+about Nim. It allows us to see how effective each website is at spreading the
+word about Nim.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/nim_found.png">
+    <img src="../assets/news/images/survey/nim_found.png" alt="How did you find out about Nim?" style="width:100%"/>
+  </a>
+
+The majority of our respondents found Nim via Reddit, HackerNews or a search
+engine such as Google. These results are not altogether surprising. There were
+also a lot of "Other" responses, some of which were a bit more
+interesting. These included multiple mentions of habrahabr.ru, Dr. Dobb's,
+and lobste.rs.
+
+Do you use Nim?
+---------------
+
+Just like the Rust survey creators, we wanted to ensure that our survey was
+open to both Nim users as well people who never used Nim. In addition to
+those two groups, we have also included a third group of people: ex-Nim
+users. All three are interesting, for many different reasons.
+Nim users can tell us how they are using Nim and also how Nim's
+tooling can improve. Ex-Nim users give us an
+idea of why they stopped using Nim. Finally, respondents who never used Nim
+can tell us the reasons for not adopting it.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/do_you_use_nim.png">
+    <img src="../assets/news/images/survey/do_you_use_nim.png" alt="Do you use Nim?" style="width:100%"/>
+  </a>
+
+It's nice to see that we have such a good range of respondents. The Rust survey
+had a much larger number of Rust users amongst their respondents, with
+no distinction between users that never used Rust and users that stopped using
+Rust.
+
+.. raw::html
+
+  <a href="https://blog.rust-lang.org/images/2016-06-Survey/do_you_use_rust.png">
+    <img src="https://blog.rust-lang.org/images/2016-06-Survey/do_you_use_rust.png" alt="Do you use Rust?" style="width:100%"/>
+  </a>
+
+Should we consider your answers to be invalid?
+----------------------------------------------
+
+This was something I thought would be interesting to have, after I saw it
+being used in another survey. While it does pinpoint possibly
+invalid respondents, I have opted against filtering those out. Mainly because
+that would require re-creating each of the charts generated by Google Forms
+manually.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/reliability.png">
+    <img src="../assets/news/images/survey/reliability.png" alt="Should we consider your answers to be invalid?" style="width:100%"/>
+  </a>
+
+According to the responses to this question, around 94% of our responses
+can be considered reliable.
+
+Nim users
+---------
+
+The following questions were answered only by the 38.9% of our respondents
+who identified themselves as Nim users.
+
+How long have you been using Nim?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/nim_time.png">
+    <img src="../assets/news/images/survey/nim_time.png" alt="How long have you been using Nim?" style="width:100%"/>
+  </a>
+
+A large proportion of our Nim users were new. This is good news as it means that
+our community is growing, with a large proportion of new Nim users that could
+become long-term Nimians. In total, more than 35% of Nim users can be considered
+new having used Nim for less than 3 months. With 18% of Nim users that can
+be considered very new having used Nim for less than a month.
+This could suggest that 18% of our users have only just found out about Nim in
+the last week or so and have not yet got the chance to use it extensively.
+
+The high percentages of long term Nim users are encouraging.
+They suggest
+that many users are continuing to use Nim after making it through the first
+few months. The sharp drop at 7-9 months is interesting, but may simply be
+due to the fact that there were fewer newcomers during that period, or it
+could be because our respondents are more likely to estimate that they have
+been using Nim for a year or half a year rather than the awkward 7-9 months.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/nim_time_rust.png">
+    <img src="../assets/news/images/survey/nim_time_rust.png" alt="Time using Nim and Rust" style="width:100%"/>
+  </a>
+
+The results for Nim and Rust are actually remarkably similar. They both show a
+drop at 7-9 months, although Rust's isn't as dramatic. Nim on the other hand
+has a significantly higher percentage of new Nim users.
+
+Do you use Nim at work?
+~~~~~~~~~~~~~~~~~~~~~~~
+
+An important aspect of a language's adoption is whether it is being used for
+"real" work. We wanted to know how many people are using Nim in their day
+jobs and under what circumstances it is used.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/nim_at_work.png">
+    <img src="../assets/news/images/survey/nim_at_work.png" alt="Do you use Nim at work?" style="width:100%"/>
+  </a>
+
+While a vast majority of our users are not using Nim at work, more than 25%
+of them are. It's encouraging to see such a high number already, even before
+we have released version 1.0. In fact, this percentage is likely close to 30%,
+because many of the "Other" responses mention using Nim for the likes of
+internal tools or small scripts to help with the respondent's work.
+
+.. raw::html
+
+  <a href="https://blog.rust-lang.org/images/2016-06-Survey/rust_at_work.png">
+    <img src="https://blog.rust-lang.org/images/2016-06-Survey/rust_at_work.png" alt="Do you use Rust at work?" style="width:100%"/>
+  </a>
+
+Interestingly, a larger percentage of Nim users are using Nim at work than
+Rust users. The sample sizes are of course vastly different, but it's still an
+interesting result. Combined, nearly 1/5th of Rust users are using Rust
+commercially whereas more than a quarter of Nim users are using Nim
+commercially.
+
+Approximately how large are all the Nim projects that you work on?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Finding out how large the Nim projects worked on by Nim users are is also
+very valuable.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/project_size.png">
+    <img src="../assets/news/images/survey/project_size.png" alt="Nim project size for all users" style="width:100%"/>
+  </a>
+
+This shows us that currently Nim is primarily being used for small scripts and
+applications, with nearly 60% of the projects consisting of less than 1,000
+lines of code. This makes sense as many of our users are not using Nim
+professionally, but are doing so in their spare time.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/project_size_work.png">
+    <img src="../assets/news/images/survey/project_size_work.png" alt="Nim project size for work users" style="width:100%"/>
+  </a>
+
+The numbers for part-time and full-time work users of Nim tell a different
+story. Over 70% of the projects written by full-time users are between 10,001
+and 100,000 lines of code. Part-time users show a slightly different trend,
+with many more small projects, the majority being between 1,000 and
+10,000 lines of code.
+
+Overall it's good to see that there is a few large projects out there which are
+composed of more than 100,000 lines of code. We expect to see the amount of
+large projects to grow with time, especially with version 1.0 on the way.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/project_size_nim_rust.png">
+    <img src="../assets/news/images/survey/project_size_nim_rust.png" alt="Nim project size for work users (Nim vs. Rust)" style="width:100%"/>
+  </a>
+
+In comparison to Rust the proportion of project sizes for full-time users is
+vastly different. This is likely due to our small sample size. Project sizes for
+part-time users between Rust and Nim are somewhat similar, with differences of
+around 10% for each project size.
+
+Do you plan to try to use Nim at work?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/planning_to_use_at_work.png">
+    <img src="../assets/news/images/survey/planning_to_use_at_work.png" alt="Planning to use Nim at work?" style="width:100%"/>
+  </a>
+
+It's also encouraging to see that over 50% of Nim users are planning to use
+Nim at work! This is slightly more than Rust's 40% and should help Nim's
+adoption into even more areas.
+
+Nim and its tools
+~~~~~~~~~~~~~~~~~
+
+In this section of the survey, we wanted to find out the tools that Nim
+users are utilising when developing Nim applications.
+
+What editor(s) do you use when writing Nim?
+___________________________________________
+
+Programmers are very specific when it comes to their editor of choice, because
+of that it's good to know which editor is most popular among our community.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/editors.png">
+    <img src="../assets/news/images/survey/editors.png" alt="Editors used by Nim users" style="width:100%"/>
+  </a>
+
+Looks like Vim is the winner with almost 30%. Followed by Sublime Text and
+Visual Studio Code. Aporia, the Nim IDE, gets a respectable 15.5%. There was
+also more than
+17% of answers which included "Other" editors, such as: Notepad++, Geany, gedit,
+and Kate.
+
+What operating system(s) do you compile for and run your Nim projects on?
+_________________________________________________________________________
+
+This question gave us information about the most popular target operating
+systems, as well as some of the more obscure ones. We have asked this question
+to find out the platforms on which Nim applications run on most frequently.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/target_os.png">
+    <img src="../assets/news/images/survey/target_os.png" alt="Target operating systems" style="width:100%"/>
+  </a>
+
+This question allowed multiple choices, so each percentage is out of the total
+number of respondents for this question. For example, 80.7% of the
+respondents selected "Linux" but only 26.6% selected OS X.
+
+This makes Linux by far the most popular target for Nim applications.
+Some "Other" targets included: BSD (OpenBSD, FreeBSD), iOS, Android, and
+JavaScript.
+It's great to see Nim being used on such a wide variety of platforms.
+
+What operating system(s) do you develop Nim projects on?
+________________________________________________________
+
+With this question, we wanted to know what operating systems are used for
+development.
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/dev_os.png">
+    <img src="../assets/news/images/survey/dev_os.png" alt="Development operating systems" style="width:100%"/>
+  </a>
+
+This question also allowed multiple choices and ended up with very similar
+results.
+
+You can see that Linux is also the most popular developmental
+platform for Nim. But it's more popular as a target platform.
+
+Which version(s) of Nim do you use for your applications?
+_________________________________________________________
+
+.. raw::html
+
+  <a href="../assets/news/images/survey/nim_versions.png">
+    <img src="../assets/news/images/survey/nim_versions.png" alt="Version use" style="width:100%"/>
+  </a>
+
+At the time of this survey, version 0.14.2 was the latest stable release.
+It's no wonder that it is the most commonly used release of Nim. It's good to
+see that the older versions are not used as often. The high use of ``Git HEAD (devel)``
+(nightly builds) isn't surprising, Nim is still evolving rapidly and our
+release schedule is not regular or frequent.
+
+Once we go past the 1.0 release, we expect to see much less use of the unstable
+``devel`` branch.
+
+
+
+
+