summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2016-07-14 01:11:47 +0200
committerAraq <rumpf_a@web.de>2016-07-14 01:11:47 +0200
commit928ac1e9945582bf443ecc8a54aa5be76f17ecbd (patch)
tree264003f79787a89ab55e97dd6366dc3e83ab2c9e
parentc48102254a47bfbdbd4deb0d31c4d8cd91ce938b (diff)
parent491e8d04ec3d1631f5bde71148649b05c27d8b7d (diff)
downloadNim-928ac1e9945582bf443ecc8a54aa5be76f17ecbd.tar.gz
Merge branch 'devel' of github.com:nim-lang/Nim into devel
-rw-r--r--compiler/ast.nim1
-rw-r--r--compiler/ccgtypes.nim11
-rw-r--r--compiler/commands.nim3
-rw-r--r--compiler/docgen.nim108
-rw-r--r--compiler/docgen2.nim17
-rw-r--r--compiler/extccomp.nim2
-rw-r--r--compiler/jsgen.nim42
-rw-r--r--compiler/jstypes.nim3
-rw-r--r--compiler/lexer.nim11
-rw-r--r--compiler/main.nim15
-rw-r--r--compiler/modules.nim13
-rw-r--r--compiler/msgs.nim4
-rw-r--r--compiler/options.nim10
-rw-r--r--compiler/scriptconfig.nim8
-rw-r--r--compiler/semexprs.nim9
-rw-r--r--compiler/semstmts.nim10
-rw-r--r--compiler/sigmatch.nim4
-rw-r--r--compiler/types.nim7
-rw-r--r--compiler/vmgen.nim4
-rw-r--r--config/nim.cfg9
-rw-r--r--doc/advopt.txt1
-rw-r--r--lib/pure/collections/queues.nim2
-rw-r--r--lib/pure/collections/tables.nim33
-rw-r--r--lib/pure/json.nim2
-rw-r--r--lib/system/gc.nim22
-rw-r--r--lib/system/nimscript.nim15
-rw-r--r--tests/js/tstring_assignment.nim11
-rw-r--r--tests/metatype/tmodulo.nim20
-rw-r--r--tests/newconfig/mymath.nim4
-rw-r--r--tests/newconfig/tfoo.nim6
-rw-r--r--tests/newconfig/tfoo.nims2
-rw-r--r--tests/overload/tissue4475.nim6
-rw-r--r--tests/types/tassignemptytuple.nim11
-rw-r--r--web/news/version_0_15_released.rst10
34 files changed, 361 insertions, 75 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 2b4de75cc..5d587f35a 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -965,7 +965,6 @@ const
 var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things
 var
   gMainPackageId*: int
-  gMainPackageNotes*: TNoteKinds
 
 proc isCallExpr*(n: PNode): bool =
   result = n.kind in nkCallKinds
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index a10f3b838..34a16c859 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -150,6 +150,9 @@ proc mapType(typ: PType): TCTypeKind =
   of tyCString: result = ctCString
   of tyInt..tyUInt64:
     result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
+  of tyStatic:
+    if typ.n != nil: result = mapType(lastSon typ)
+    else: internalError("mapType")
   else: internalError("mapType")
 
 proc mapReturnType(typ: PType): TCTypeKind =
@@ -256,6 +259,11 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
   of tyInt..tyUInt64:
     result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind])
   of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0])
+  of tyStatic:
+    if typ.n != nil: result = getSimpleTypeDesc(m, lastSon typ)
+    else: internalError("tyStatic for getSimpleTypeDesc")
+  of tyGenericInst:
+    result = getSimpleTypeDesc(m, lastSon typ)
   else: result = nil
 
 proc pushType(m: BModule, typ: PType) =
@@ -1025,6 +1033,9 @@ proc genTypeInfo(m: BModule, t: PType): Rope =
   of tyEmpty, tyVoid: result = rope"0"
   of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
     genTypeInfoAuxBase(m, t, t, result, rope"0")
+  of tyStatic:
+    if t.n != nil: result = genTypeInfo(m, lastSon t)
+    else: internalError("genTypeInfo(" & $t.kind & ')')
   of tyProc:
     if t.callConv != ccClosure:
       genTypeInfoAuxBase(m, t, t, result, rope"0")
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 22512c563..b468dd6b8 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -181,9 +181,11 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass,
   case whichKeyword(substr(arg, i))
   of wOn:
     incl(gNotes, n)
+    incl(gMainPackageNotes, n)
     incl(enableNotes, n)
   of wOff:
     excl(gNotes, n)
+    excl(gMainPackageNotes, n)
     incl(disableNotes, n)
     excl(ForeignPackageNotes, n)
   else: localError(info, errOnOrOffExpectedButXFound, arg)
@@ -548,6 +550,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
     gNotes = NotesVerbosity[gVerbosity]
     incl(gNotes, enableNotes)
     excl(gNotes, disableNotes)
+    gMainPackageNotes = gNotes
   of "parallelbuild":
     expectArg(switch, arg, pass, info)
     gNumberOfProcessors = parseInt(arg)
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index fab759848..67092780b 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -14,7 +14,7 @@
 import
   ast, strutils, strtabs, options, msgs, os, ropes, idents,
   wordrecg, syntaxes, renderer, lexer, rstast, rst, rstgen, times, highlite,
-  importer, sempass2, json, xmltree, cgi, typesrenderer
+  importer, sempass2, json, xmltree, cgi, typesrenderer, astalgo
 
 type
   TSections = array[TSymKind, Rope]
@@ -25,9 +25,32 @@ type
     indexValFilename: string
     analytics: string  # Google Analytics javascript, "" if doesn't exist
     seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML.
+    jArray: JsonNode
+    types: TStrTable
 
   PDoc* = ref TDocumentor ## Alias to type less.
 
+proc whichType(d: PDoc; n: PNode): PSym =
+  if n.kind == nkSym:
+    if d.types.strTableContains(n.sym):
+      result = n.sym
+  else:
+    for i in 0..<safeLen(n):
+      let x = whichType(d, n[i])
+      if x != nil: return x
+
+proc attachToType(d: PDoc; p: PSym): PSym =
+  let params = p.ast.sons[paramsPos]
+  # first check the first parameter, then the return type,
+  # then the other parameter:
+  template check(i) =
+    result = whichType(d, params[i])
+    if result != nil: return result
+
+  if params.len > 1: check(1)
+  if params.len > 0: check(0)
+  for i in 2..<params.len: check(i)
+
 proc compilerMsgHandler(filename: string, line, col: int,
                         msgKind: rst.MsgKind, arg: string) {.procvar.} =
   # translate msg kind:
@@ -81,6 +104,8 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
 
   result.seenSymbols = newStringTable(modeCaseInsensitive)
   result.id = 100
+  result.jArray = newJArray()
+  initStrTable result.types
 
 proc dispA(dest: var Rope, xml, tex: string, args: openArray[Rope]) =
   if gCmd != cmdRst2tex: addf(dest, xml, args)
@@ -226,10 +251,27 @@ proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
     result = esc(d.target, "`")
     for i in 0.. <n.len: result.add(getName(d, n[i], splitAfter))
     result.add esc(d.target, "`")
+  of nkOpenSymChoice, nkClosedSymChoice:
+    result = getName(d, n[0], splitAfter)
   else:
     internalError(n.info, "getName()")
     result = ""
 
+proc getNameIdent(n: PNode): PIdent =
+  case n.kind
+  of nkPostfix: result = getNameIdent(n.sons[1])
+  of nkPragmaExpr: result = getNameIdent(n.sons[0])
+  of nkSym: result = n.sym.name
+  of nkIdent: result = n.ident
+  of nkAccQuoted:
+    var r = ""
+    for i in 0.. <n.len: r.add(getNameIdent(n[i]).s)
+    result = getIdent(r)
+  of nkOpenSymChoice, nkClosedSymChoice:
+    result = getNameIdent(n[0])
+  else:
+    result = nil
+
 proc getRstName(n: PNode): PRstNode =
   case n.kind
   of nkPostfix: result = getRstName(n.sons[1])
@@ -239,6 +281,8 @@ proc getRstName(n: PNode): PRstNode =
   of nkAccQuoted:
     result = getRstName(n.sons[0])
     for i in 1 .. <n.len: result.text.add(getRstName(n[i]).text)
+  of nkOpenSymChoice, nkClosedSymChoice:
+    result = getRstName(n[0])
   else:
     internalError(n.info, "getRstName()")
     result = nil
@@ -395,6 +439,12 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
        tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr:
       dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
             [rope(esc(d.target, literal))])
+
+  if k in routineKinds and nameNode.kind == nkSym:
+    let att = attachToType(d, nameNode.sym)
+    if att != nil:
+      dispA(result, """<span class="attachedType" style="visibility:hidden">$1</span>""", "",
+        [rope esc(d.target, att.name.s)])
   inc(d.id)
   let
     plainNameRope = rope(xmltree.escape(plainName.strip))
@@ -438,8 +488,10 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
 
   setIndexTerm(d[], symbolOrId, name, linkTitle,
     xmltree.escape(plainDocstring.docstringSummary))
+  if k == skType and nameNode.kind == nkSym:
+    d.types.strTableAdd nameNode.sym
 
-proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
+proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
   if not isVisible(nameNode): return
   var
     name = getName(d, nameNode)
@@ -499,46 +551,44 @@ proc generateDoc*(d: PDoc, n: PNode) =
   of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
   else: discard
 
-proc generateJson(d: PDoc, n: PNode, jArray: JsonNode = nil): JsonNode =
+proc add(d: PDoc; j: JsonNode) =
+  if j != nil: d.jArray.add j
+
+proc generateJson*(d: PDoc, n: PNode) =
   case n.kind
   of nkCommentStmt:
     if n.comment != nil and startsWith(n.comment, "##"):
       let stripped = n.comment.substr(2).strip
-      result = %{ "comment": %stripped }
+      d.add %{ "comment": %stripped }
   of nkProcDef:
     when useEffectSystem: documentRaises(n)
-    result = genJSONItem(d, n, n.sons[namePos], skProc)
+    d.add genJsonItem(d, n, n.sons[namePos], skProc)
   of nkMethodDef:
     when useEffectSystem: documentRaises(n)
-    result = genJSONItem(d, n, n.sons[namePos], skMethod)
+    d.add genJsonItem(d, n, n.sons[namePos], skMethod)
   of nkIteratorDef:
     when useEffectSystem: documentRaises(n)
-    result = genJSONItem(d, n, n.sons[namePos], skIterator)
+    d.add genJsonItem(d, n, n.sons[namePos], skIterator)
   of nkMacroDef:
-    result = genJSONItem(d, n, n.sons[namePos], skMacro)
+    d.add genJsonItem(d, n, n.sons[namePos], skMacro)
   of nkTemplateDef:
-    result = genJSONItem(d, n, n.sons[namePos], skTemplate)
+    d.add genJsonItem(d, n, n.sons[namePos], skTemplate)
   of nkConverterDef:
     when useEffectSystem: documentRaises(n)
-    result = genJSONItem(d, n, n.sons[namePos], skConverter)
+    d.add genJsonItem(d, n, n.sons[namePos], skConverter)
   of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
     for i in countup(0, sonsLen(n) - 1):
       if n.sons[i].kind != nkCommentStmt:
         # order is always 'type var let const':
-        result = genJSONItem(d, n.sons[i], n.sons[i].sons[0],
+        d.add genJsonItem(d, n.sons[i], n.sons[i].sons[0],
                 succ(skType, ord(n.kind)-ord(nkTypeSection)))
   of nkStmtList:
-    result = if jArray != nil: jArray else: newJArray()
-
     for i in countup(0, sonsLen(n) - 1):
-      var r = generateJson(d, n.sons[i], result)
-      if r != nil:
-        result.add(r)
-
+      generateJson(d, n.sons[i])
   of nkWhenStmt:
     # generate documentation for the first branch only:
-    if not checkForFalse(n.sons[0].sons[0]) and jArray != nil:
-      discard generateJson(d, lastSon(n.sons[0]), jArray)
+    if not checkForFalse(n.sons[0].sons[0]):
+      generateJson(d, lastSon(n.sons[0]))
   else: discard
 
 proc genSection(d: PDoc, kind: TSymKind) =
@@ -607,6 +657,19 @@ proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
   else:
     writeRope(content, getOutFile(filename, outExt), useWarning)
 
+proc writeOutputJson*(d: PDoc, filename, outExt: string,
+                      useWarning = false) =
+  let content = $d.jArray
+  if optStdout in gGlobalOptions:
+    write(stdout, content)
+  else:
+    var f: File
+    if open(f, getOutFile(filename, outExt), fmWrite):
+      write(f, content)
+      close(f)
+    else:
+      discard "fixme: error report"
+
 proc commandDoc*() =
   var ast = parseFile(gProjectMainIdx)
   if ast == nil: return
@@ -636,13 +699,14 @@ proc commandRst2TeX*() =
   splitter = "\\-"
   commandRstAux(gProjectFull, TexExt)
 
-proc commandJSON*() =
+proc commandJson*() =
   var ast = parseFile(gProjectMainIdx)
   if ast == nil: return
   var d = newDocumentor(gProjectFull, options.gConfigVars)
   d.hasToc = true
-  var json = generateJson(d, ast)
-  var content = rope(pretty(json))
+  generateJson(d, ast)
+  let json = d.jArray
+  let content = rope(pretty(json))
 
   if optStdout in gGlobalOptions:
     writeRope(stdout, content)
diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim
index 27de06811..f83166f2b 100644
--- a/compiler/docgen2.nim
+++ b/compiler/docgen2.nim
@@ -29,11 +29,26 @@ proc close(p: PPassContext, n: PNode): PNode =
     except IOError:
       discard
 
+proc closeJson(p: PPassContext, n: PNode): PNode =
+  var g = PGen(p)
+  let useWarning = sfMainModule notin g.module.flags
+  if gWholeProject or sfMainModule in g.module.flags:
+    writeOutputJson(g.doc, g.module.filename, ".json", useWarning)
+    try:
+      generateIndex(g.doc)
+    except IOError:
+      discard
+
 proc processNode(c: PPassContext, n: PNode): PNode =
   result = n
   var g = PGen(c)
   generateDoc(g.doc, n)
 
+proc processNodeJson(c: PPassContext, n: PNode): PNode =
+  result = n
+  var g = PGen(c)
+  generateJson(g.doc, n)
+
 proc myOpen(module: PSym): PPassContext =
   var g: PGen
   new(g)
@@ -44,6 +59,8 @@ proc myOpen(module: PSym): PPassContext =
   result = g
 
 const docgen2Pass* = makePass(open = myOpen, process = processNode, close = close)
+const docgen2JsonPass* = makePass(open = myOpen, process = processNodeJson,
+                                  close = closeJson)
 
 proc finishDoc2Pass*(project: string) =
   discard
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index b2ee9c7f1..eb9aac490 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -754,7 +754,7 @@ proc callCCompiler*(projectfile: string) =
           "lib", quoteShell(libpath)])
     if optCompileOnly notin gGlobalOptions:
       execExternalProgram(linkCmd,
-                          if gVerbosity > 1: hintExecuting else: hintLinking)
+        if optListCmd in gGlobalOptions or gVerbosity > 1: hintExecuting else: hintLinking)
   else:
     linkCmd = ""
   if optGenScript in gGlobalOptions:
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 09eafe128..fe0f6df53 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -48,6 +48,7 @@ type
     etyNull,                  # null type
     etyProc,                  # proc type
     etyBool,                  # bool type
+    etySeq,                   # Nim seq or string type
     etyInt,                   # JavaScript's int
     etyFloat,                 # JavaScript's float
     etyString,                # JavaScript's string
@@ -156,15 +157,18 @@ proc mapType(typ: PType): TJSTypeKind =
   of tyBool: result = etyBool
   of tyFloat..tyFloat128: result = etyFloat
   of tySet: result = etyObject # map a set to a table
-  of tyString, tySequence: result = etyInt # little hack to get right semantics
+  of tyString, tySequence: result = etySeq
   of tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, tyBigNum,
      tyVarargs:
     result = etyObject
   of tyNil: result = etyNull
   of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvocation,
      tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor,
-     tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses, tyVoid:
+     tyExpr, tyStmt, tyTypeDesc, tyTypeClasses, tyVoid:
     result = etyNone
+  of tyStatic:
+    if t.n != nil: result = mapType(lastSon t)
+    else: result = etyNone
   of tyProc: result = etyProc
   of tyCString: result = etyString
 
@@ -817,7 +821,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
     addf(p.body, "$#[$#] = chr($#);$n", [a.rdLoc, b.rdLoc, c.rdLoc])
     return
 
-  let xtyp = mapType(p, x.typ)
+  var xtyp = mapType(p, x.typ)
 
   if x.kind == nkHiddenDeref and x.sons[0].kind == nkCall and xtyp != etyObject:
     gen(p, x.sons[0], a)
@@ -829,7 +833,18 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
 
   gen(p, y, b)
 
+  # we don't care if it's an etyBaseIndex (global) of a string, it's
+  # still a string that needs to be copied properly:
+  if x.typ.skipTypes(abstractInst).kind in {tySequence, tyString}:
+    xtyp = etySeq
   case xtyp
+  of etySeq:
+    if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
+      addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
+    else:
+      useMagic(p, "nimCopy")
+      addf(p.body, "$1 = nimCopy(null, $2, $3);$n",
+           [a.rdLoc, b.res, genTypeInfo(p, y.typ)])
   of etyObject:
     if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
       addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
@@ -1049,6 +1064,8 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
       else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
   of nkObjDownConv:
     gen(p, n.sons[0], r)
+  of nkHiddenDeref:
+    gen(p, n.sons[0].sons[0], r)
   else: internalError(n.sons[0].info, "genAddr: " & $n.sons[0].kind)
 
 proc thisParam(p: PProc; typ: PType): PType =
@@ -1221,6 +1238,7 @@ proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
                     r: var TCompRes) =
   var i = 0
   var j = 1
+  r.kind = resExpr
   while i < pat.len:
     case pat[i]
     of '@':
@@ -1234,10 +1252,18 @@ proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
       genOtherArg(p, n, j, typ, generated, r)
       inc j
       inc i
+    of '\31':
+      # unit separator
+      add(r.res, "#")
+      inc i
+    of '\29':
+      # group separator
+      add(r.res, "@")
+      inc i
     else:
       let start = i
       while i < pat.len:
-        if pat[i] notin {'@', '#'}: inc(i)
+        if pat[i] notin {'@', '#', '\31', '\29'}: inc(i)
         else: break
       if i - 1 >= start:
         add(r.res, substr(pat, start, i - 1))
@@ -1404,6 +1430,12 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
       result = putToSeq("null", indirect)
   of tySequence, tyString, tyCString, tyPointer, tyProc:
     result = putToSeq("null", indirect)
+  of tyStatic:
+    if t.n != nil:
+      result = createVar(p, lastSon t, indirect)
+    else:
+      internalError("createVar: " & $t.kind)
+      result = nil
   else:
     internalError("createVar: " & $t.kind)
     result = nil
@@ -1419,7 +1451,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
     discard mangleName(v, p.target)
     gen(p, n, a)
     case mapType(p, v.typ)
-    of etyObject:
+    of etyObject, etySeq:
       if needsNoCopy(p, n):
         s = a.res
       else:
diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim
index 8d109e48a..cf1679ee4 100644
--- a/compiler/jstypes.nim
+++ b/compiler/jstypes.nim
@@ -165,4 +165,7 @@ proc genTypeInfo(p: PProc, typ: PType): Rope =
   of tyEnum: genEnumInfo(p, t, result)
   of tyObject: genObjectInfo(p, t, result)
   of tyTuple: genTupleInfo(p, t, result)
+  of tyStatic:
+    if t.n != nil: result = genTypeInfo(p, lastSon t)
+    else: internalError("genTypeInfo(" & $t.kind & ')')
   else: internalError("genTypeInfo(" & $t.kind & ')')
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index 8b201431e..0a96ed0ba 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -735,7 +735,8 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
       if  c == '\226' and
           buf[pos+1] == '\128' and
           buf[pos+2] == '\147':  # It's a 'magic separator' en-dash Unicode
-        if buf[pos + magicIdentSeparatorRuneByteWidth] notin SymChars:
+        if buf[pos + magicIdentSeparatorRuneByteWidth] notin SymChars or
+            isMagicIdentSeparatorRune(buf, pos+magicIdentSeparatorRuneByteWidth) or pos == L.bufpos:
           lexMessage(L, errInvalidToken, "–")
           break
         inc(pos, magicIdentSeparatorRuneByteWidth)
@@ -747,7 +748,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
       h = h !& ord(c)
       inc(pos)
     of '_':
-      if buf[pos+1] notin SymChars:
+      if buf[pos+1] notin SymChars or isMagicIdentSeparatorRune(buf, pos+1):
         lexMessage(L, errInvalidToken, "_")
         break
       inc(pos)
@@ -1056,7 +1057,8 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
       inc(L.bufpos)
     of '_':
       inc(L.bufpos)
-      if L.buf[L.bufpos] notin SymChars:
+      if L.buf[L.bufpos] notin SymChars+{'_'} and not
+          isMagicIdentSeparatorRune(L.buf, L.bufpos):
         tok.tokType = tkSymbol
         tok.ident = getIdent("_")
       else:
@@ -1077,6 +1079,9 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
       tok.tokType = tkCharLit
     of '0'..'9':
       getNumber(L, tok)
+      let c = L.buf[L.bufpos]
+      if c in SymChars+{'_'}:
+        lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
     else:
       if c in OpChars:
         getOperator(L, tok)
diff --git a/compiler/main.nim b/compiler/main.nim
index b1b9006bd..0db66b53e 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -46,10 +46,11 @@ proc commandCheck =
   rodPass()
   compileProject()
 
-proc commandDoc2 =
+proc commandDoc2(json: bool) =
   msgs.gErrorMax = high(int)  # do not stop after first error
   semanticPasses()
-  registerPass(docgen2Pass)
+  if json: registerPass(docgen2JsonPass)
+  else: registerPass(docgen2Pass)
   #registerPass(cleanupPass())
   compileProject()
   finishDoc2Pass(gProjectName)
@@ -281,7 +282,7 @@ proc mainCommand* =
     gCmd = cmdDoc
     loadConfigs(DocConfig)
     defineSymbol("nimdoc")
-    commandDoc2()
+    commandDoc2(false)
   of "rst2html":
     gCmd = cmdRst2html
     loadConfigs(DocConfig)
@@ -296,7 +297,13 @@ proc mainCommand* =
     loadConfigs(DocConfig)
     wantMainModule()
     defineSymbol("nimdoc")
-    commandJSON()
+    commandJson()
+  of "jsondoc2":
+    gCmd = cmdDoc
+    loadConfigs(DocConfig)
+    wantMainModule()
+    defineSymbol("nimdoc")
+    commandDoc2(true)
   of "buildindex":
     gCmd = cmdDoc
     loadConfigs(DocConfig)
diff --git a/compiler/modules.nim b/compiler/modules.nim
index 03b9dc9f0..d653e8b8f 100644
--- a/compiler/modules.nim
+++ b/compiler/modules.nim
@@ -105,12 +105,13 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile =
     resetModule(fileIdx)
     return Yes
 
-  if gMemCacheData[fileIdx].needsRecompile != Maybe:
-    return gMemCacheData[fileIdx].needsRecompile
+  # cycle detection: We claim that a cycle does no harm.
+  if gMemCacheData[fileIdx].needsRecompile == Probing:
+    return No
+    #return gMemCacheData[fileIdx].needsRecompile
 
-  if optForceFullMake in gGlobalOptions or
-     hashChanged(fileIdx):
-       markDirty
+  if optForceFullMake in gGlobalOptions or hashChanged(fileIdx):
+    markDirty()
 
   if gMemCacheData[fileIdx].deps != nil:
     gMemCacheData[fileIdx].needsRecompile = Probing
@@ -118,7 +119,7 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile =
       let d = checkDepMem(dep)
       if d in {Yes, Recompiled}:
         # echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d
-        markDirty
+        markDirty()
 
   gMemCacheData[fileIdx].needsRecompile = No
   return No
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 098370e41..83914753f 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -518,7 +518,6 @@ const
                                          warnGcUnsafe,
                                          hintPath,
                                          hintDependency,
-                                         hintExecuting,
                                          hintCodeBegin, hintCodeEnd,
                                          hintSource, hintStackTrace,
                                          hintGCStats},
@@ -530,7 +529,7 @@ const
 
 var
   ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic,
-    hintQuitCalled}
+    hintQuitCalled, hintExecuting}
   filenameToIndexTbl = initTable[string, int32]()
   fileInfos*: seq[TFileInfo] = @[]
   systemFileIdx*: int32
@@ -621,6 +620,7 @@ var
   gHintCounter*: int = 0
   gWarnCounter*: int = 0
   gErrorMax*: int = 1         # stop after gErrorMax errors
+  gMainPackageNotes*: TNoteKinds = NotesVerbosity[1]
 
 proc unknownLineInfo*(): TLineInfo =
   result.line = int16(-1)
diff --git a/compiler/options.nim b/compiler/options.nim
index 7797a4c82..fca945393 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -151,6 +151,7 @@ const
 var
   gConfigVars* = newStringTable(modeStyleInsensitive)
   gDllOverrides = newStringTable(modeCaseInsensitive)
+  gModuleOverrides* = newStringTable(modeStyleInsensitive)
   gPrefixDir* = "" # Overrides the default prefix dir in getPrefixDir proc.
   libpath* = ""
   gProjectName* = "" # holds a name like 'nim'
@@ -374,6 +375,13 @@ proc rawFindFile2(f: string): string =
     it = PStrEntry(it.next)
   result = ""
 
+template patchModule() {.dirty.} =
+  if result.len > 0 and gModuleOverrides.len > 0:
+    let key = getPackageName(result) & "_" & splitFile(result).name
+    if gModuleOverrides.hasKey(key):
+      let ov = gModuleOverrides[key]
+      if ov.len > 0: result = ov
+
 proc findFile*(f: string): string {.procvar.} =
   if f.isAbsolute:
     result = if f.existsFile: f else: ""
@@ -385,6 +393,7 @@ proc findFile*(f: string): string {.procvar.} =
         result = f.rawFindFile2
         if result.len == 0:
           result = f.toLower.rawFindFile2
+  patchModule()
 
 proc findModule*(modulename, currentModule: string): string =
   # returns path to module
@@ -403,6 +412,7 @@ proc findModule*(modulename, currentModule: string): string =
   result = currentPath / m
   if not existsFile(result):
     result = findFile(m)
+  patchModule()
 
 proc libCandidates*(s: string, dest: var seq[string]) =
   var le = strutils.find(s, '(')
diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim
index ca42cc8fa..dcb92227d 100644
--- a/compiler/scriptconfig.nim
+++ b/compiler/scriptconfig.nim
@@ -13,7 +13,7 @@
 import
   ast, modules, passes, passaux, condsyms,
   options, nimconf, lists, sem, semdata, llstream, vm, vmdef, commands, msgs,
-  os, times, osproc, wordrecg
+  os, times, osproc, wordrecg, strtabs
 
 # we support 'cmpIgnoreStyle' natively for efficiency:
 from strutils import cmpIgnoreStyle
@@ -122,6 +122,12 @@ proc setupVM*(module: PSym; scriptName: string): PEvalContext =
   cbconf warningImpl:
     processSpecificNote(a.getString 0, wWarning, passPP, unknownLineInfo(),
       a.getString 1)
+  cbconf patchFile:
+    let key = a.getString(0) & "_" & a.getString(1)
+    var val = a.getString(2).addFileExt(NimExt)
+    if not isAbsolute(val):
+      val = vthisDir / val
+    gModuleOverrides[key] = val
 
 proc runNimScript*(scriptName: string; freshDefines=true) =
   passes.gIncludeFile = includeModule
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index f8723bf64..17feab85d 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1065,8 +1065,11 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
     result = newSymNode(s, n.info)
     result.typ = makeTypeDesc(c, s.typ)
   of skField:
-    if c.p != nil and c.p.selfSym != nil:
-      var ty = skipTypes(c.p.selfSym.typ, {tyGenericInst, tyVar, tyPtr, tyRef})
+    var p = c.p
+    while p != nil and p.selfSym == nil:
+      p = p.next
+    if p != nil and p.selfSym != nil:
+      var ty = skipTypes(p.selfSym.typ, {tyGenericInst, tyVar, tyPtr, tyRef})
       while tfBorrowDot in ty.flags: ty = ty.skipTypes({tyDistinct})
       var check: PNode = nil
       if ty.kind == tyObject:
@@ -1079,7 +1082,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
             markUsed(n.info, f)
             styleCheckUse(n.info, f)
             result = newNodeIT(nkDotExpr, n.info, f.typ)
-            result.add makeDeref(newSymNode(c.p.selfSym))
+            result.add makeDeref(newSymNode(p.selfSym))
             result.add newSymNode(f) # we now have the correct field
             if check != nil:
               check.sons[0] = result
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 0fb770875..40462a1da 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -411,6 +411,13 @@ proc semUsing(c: PContext; n: PNode): PNode =
     if a.sons[length-1].kind != nkEmpty:
       localError(a.info, "'using' sections cannot contain assignments")
 
+proc hasEmpty(typ: PType): bool =
+  if typ.kind in {tySequence, tyArray, tySet}:
+    result = typ.lastSon.kind == tyEmpty
+  elif typ.kind == tyTuple:
+    for s in typ.sons:
+      result = result or hasEmpty(s)
+
 proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
   var b: PNode
   result = copyNode(n)
@@ -445,8 +452,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
           #changeType(def.skipConv, typ, check=true)
       else:
         typ = skipIntLit(def.typ)
-        if typ.kind in {tySequence, tyArray, tySet} and
-           typ.lastSon.kind == tyEmpty:
+        if hasEmpty(typ):
           localError(def.info, errCannotInferTypeOfTheLiteral,
                      ($typ.kind).substr(2).toLower)
     else:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 511a44954..8c8c83d0f 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -1746,8 +1746,8 @@ proc matches*(c: PContext, n, nOrig: PNode, m: var TCandidate) =
       if formal.ast == nil:
         if formal.typ.kind == tyVarargs:
           var container = newNodeIT(nkBracket, n.info, arrayConstr(c, n.info))
-          addSon(m.call, implicitConv(nkHiddenStdConv, formal.typ,
-                                      container, m, c))
+          setSon(m.call, formal.position + 1,
+                 implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
         else:
           # no default value
           m.state = csNoMatch
diff --git a/compiler/types.nim b/compiler/types.nim
index 4d6bf0502..a87f9470f 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -541,7 +541,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
     else:
       result.add typeToString(t.sons[0])
   of tyRange:
-    result = "range " & rangeToStr(t.n)
+    result = "range "
+    if t.n != nil and t.n.kind == nkRange:
+      result.add rangeToStr(t.n)
     if prefer != preferExported:
       result.add("(" & typeToString(t.sons[0]) & ")")
   of tyProc:
@@ -1315,6 +1317,9 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
   of tyTypeDesc:
     result = computeSizeAux(typ.base, a)
   of tyForward: return szIllegalRecursion
+  of tyStatic:
+    if typ.n != nil: result = computeSizeAux(lastSon(typ), a)
+    else: result = szUnknownSize
   else:
     #internalError("computeSizeAux()")
     result = szUnknownSize
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index abb88b7b9..f0434617b 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -1686,10 +1686,10 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     of skType:
       genTypeLit(c, s.typ, dest)
     of skGenericParam:
-      if c.prc.sym.kind == skMacro:
+      if c.prc.sym != nil and c.prc.sym.kind == skMacro:
         genRdVar(c, n, dest, flags)
       else:
-        internalError(n.info, "cannot generate code for: " & s.name.s)
+        globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
     else:
       globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
   of nkCallKinds:
diff --git a/config/nim.cfg b/config/nim.cfg
index 93b847784..0cc014a93 100644
--- a/config/nim.cfg
+++ b/config/nim.cfg
@@ -23,10 +23,6 @@ arm.linux.gcc.linkerexe = "arm-linux-gcc"
 mips.linux.gcc.exe = "mips-openwrt-linux-gcc"
 mips.linux.gcc.linkerexe = "mips-openwrt-linux-gcc"
 
-@if not nimfix:
-  cs:partial
-@end
-
 path="$lib/deprecated/core"
 path="$lib/deprecated/pure"
 path="$lib/pure/collections"
@@ -168,10 +164,5 @@ vcc.options.always = "/nologo"
 vcc.options.speed = "/O2 /arch:SSE2"
 vcc.options.size = "/O1"
 
-# Configuration for the Digital Mars C/C++ compiler:
-@if windows:
-  dmc.path = r"$nimrod\dist\dm\bin"
-@end
-
 # Configuration for the Tiny C Compiler:
 tcc.options.always = "-w"
diff --git a/doc/advopt.txt b/doc/advopt.txt
index 02aada4fb..02e69c5b8 100644
--- a/doc/advopt.txt
+++ b/doc/advopt.txt
@@ -6,6 +6,7 @@ Advanced commands:
   //rst2html                convert a reStructuredText file to HTML
   //rst2tex                 convert a reStructuredText file to TeX
   //jsondoc                 extract the documentation to a json file
+  //jsondoc2                extract documentation to a json file (uses doc2)
   //buildIndex              build an index for the whole documentation
   //run                     run the project (with Tiny C backend; buggy!)
   //genDepend               generate a DOT file containing the
diff --git a/lib/pure/collections/queues.nim b/lib/pure/collections/queues.nim
index 911816518..399e4d413 100644
--- a/lib/pure/collections/queues.nim
+++ b/lib/pure/collections/queues.nim
@@ -152,11 +152,13 @@ proc add*[T](q: var Queue[T], item: T) =
   q.data[q.wr] = item
   q.wr = (q.wr + 1) and q.mask
 
+proc default[T](t: typedesc[T]): T {.inline.} = discard
 proc pop*[T](q: var Queue[T]): T {.inline, discardable.} =
   ## Remove and returns the first (oldest) element of the queue `q`.
   emptyCheck(q)
   dec q.count
   result = q.data[q.rd]
+  q.data[q.rd] = default(type(result))
   q.rd = (q.rd + 1) and q.mask
 
 proc enqueue*[T](q: var Queue[T], item: T) =
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index e454a43cb..941516956 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -16,6 +16,39 @@
 ## semantics, this means that ``=`` performs a copy of the hash table.
 ## For **reference** semantics use the ``Ref`` variant: ``TableRef``,
 ## ``OrderedTableRef``, ``CountTableRef``.
+## To give an example, when `a` is a Table, then `var b = a` gives `b`
+## as a new independent table. b is initialised with the contents of `a`.
+## Changing `b` does not affect `a` and vice versa:
+##
+## .. code-block::
+##   import tables
+##
+##   var
+##     a = {1: "one", 2: "two"}.toTable  # creates a Table
+##     b = a
+##
+##   echo a, b  # output: {1: one, 2: two}{1: one, 2: two}
+##
+##   b[3] = "three"
+##   echo a, b  # output: {1: one, 2: two}{1: one, 2: two, 3: three}
+##   echo a == b  # output: false
+##
+## On the other hand, when `a` is a TableRef instead, then changes to `b` also affect `a`.
+## Both `a` and `b` reference the same data structure:
+##
+## .. code-block::
+##   import tables
+##
+##   var
+##     a = {1: "one", 2: "two"}.newTable  # creates a TableRef
+##     b = a
+##
+##   echo a, b  # output: {1: one, 2: two}{1: one, 2: two}
+##
+##   b[3] = "three"
+##   echo a, b  # output: {1: one, 2: two, 3: three}{1: one, 2: two, 3: three}
+##   echo a == b  # output: true
+##
 ##
 ## If you are using simple standard types like ``int`` or ``string`` for the
 ## keys of the table you won't have any problems, but as soon as you try to use
diff --git a/lib/pure/json.nim b/lib/pure/json.nim
index 5198f5e00..b8e4a6563 100644
--- a/lib/pure/json.nim
+++ b/lib/pure/json.nim
@@ -1127,7 +1127,7 @@ proc parseJson(p: var JsonParser): JsonNode =
     discard getTok(p)
     while p.tok != tkCurlyRi:
       if p.tok != tkString:
-        raiseParseErr(p, "string literal as key expected")
+        raiseParseErr(p, "string literal as key")
       var key = p.a
       discard getTok(p)
       eat(p, tkColon)
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index 3e71b4fe0..a36dbf02b 100644
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -452,10 +452,13 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
   gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
   # now it is buffered in the ZCT
   res.typ = typ
-  when leakDetector and not hasThreadSupport:
-    if framePtr != nil and framePtr.prev != nil:
-      res.filename = framePtr.prev.filename
-      res.line = framePtr.prev.line
+  when leakDetector:
+    res.filename = nil
+    res.line = 0
+    when not hasThreadSupport:
+      if framePtr != nil and framePtr.prev != nil:
+        res.filename = framePtr.prev.filename
+        res.line = framePtr.prev.line
   # refcount is zero, color is black, but mark it to be in the ZCT
   res.refcount = ZctFlag
   sysAssert(isAllocatedPtr(gch.region, res), "newObj: 3")
@@ -503,10 +506,13 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
   sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
   # now it is buffered in the ZCT
   res.typ = typ
-  when leakDetector and not hasThreadSupport:
-    if framePtr != nil and framePtr.prev != nil:
-      res.filename = framePtr.prev.filename
-      res.line = framePtr.prev.line
+  when leakDetector:
+    res.filename = nil
+    res.line = 0
+    when not hasThreadSupport:
+      if framePtr != nil and framePtr.prev != nil:
+        res.filename = framePtr.prev.filename
+        res.line = framePtr.prev.line
   res.refcount = rcIncrement # refcount is 1
   sysAssert(isAllocatedPtr(gch.region, res), "newObj: 3")
   when logGC: writeCell("new cell", res)
diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim
index db6d72d7b..cc96bcba8 100644
--- a/lib/system/nimscript.nim
+++ b/lib/system/nimscript.nim
@@ -65,6 +65,21 @@ proc hint*(name: string; val: bool) =
   let v = if val: "on" else: "off"
   hintImpl(name & "]:" & v, "hint[" & name & "]:" & v)
 
+proc patchFile*(package, filename, replacement: string) =
+  ## Overrides the location of a given file belonging to the
+  ## passed package.
+  ## If the ``replacement`` is not an absolute path, the path
+  ## is interpreted to be local to the Nimscript file that contains
+  ## the call to ``patchFile``, Nim's ``--path`` is not used at all
+  ## to resolve the filename!
+  ##
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   patchFile("stdlib", "asyncdispatch", "patches/replacement")
+  discard
+
 proc getCommand*(): string =
   ## Gets the Nim command that the compiler has been invoked with, for example
   ## "c", "js", "build", "help".
diff --git a/tests/js/tstring_assignment.nim b/tests/js/tstring_assignment.nim
new file mode 100644
index 000000000..bdd93e6b5
--- /dev/null
+++ b/tests/js/tstring_assignment.nim
@@ -0,0 +1,11 @@
+discard """
+  output: '''true'''
+"""
+
+# bug #4471
+when true:
+  let s1 = "123"
+  var s2 = s1
+  s2.setLen(0)
+  # fails - s1.len == 0
+  echo s1.len == 3
diff --git a/tests/metatype/tmodulo.nim b/tests/metatype/tmodulo.nim
new file mode 100644
index 000000000..08bcc7935
--- /dev/null
+++ b/tests/metatype/tmodulo.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''1 mod 7'''
+"""
+
+# bug #3706
+
+type Modulo[M: static[int]] = distinct int
+
+proc modulo(a: int, M: static[int]): Modulo[M] = Modulo[M](a %% M)
+
+proc `+`[M: static[int]](a, b: Modulo[M]): Modulo[M] = (a.int + b.int).modulo(M)
+
+proc `$`*[M: static[int]](a: Modulo[M]): string = $(a.int) & " mod " & $(M)
+
+when isMainModule:
+  let
+    a = 3.modulo(7)
+    b = 5.modulo(7)
+  echo a + b
+
diff --git a/tests/newconfig/mymath.nim b/tests/newconfig/mymath.nim
new file mode 100644
index 000000000..5668b448b
--- /dev/null
+++ b/tests/newconfig/mymath.nim
@@ -0,0 +1,4 @@
+
+
+proc ln*(x: float): float =
+  return 0.5
diff --git a/tests/newconfig/tfoo.nim b/tests/newconfig/tfoo.nim
index d593d4a75..2e10167b1 100644
--- a/tests/newconfig/tfoo.nim
+++ b/tests/newconfig/tfoo.nim
@@ -1,10 +1,12 @@
 discard """
   cmd: "nim default $file"
-  output: '''hello world!'''
+  output: '''hello world! 0.5'''
   msg: '''[NimScript] exec: gcc -v'''
 """
 
 when not defined(definedefine):
   {.fatal: "wrong nim script configuration".}
 
-echo "hello world!"
+import math
+
+echo "hello world! ", ln 2.0
diff --git a/tests/newconfig/tfoo.nims b/tests/newconfig/tfoo.nims
index 8d1461c78..057c0ed92 100644
--- a/tests/newconfig/tfoo.nims
+++ b/tests/newconfig/tfoo.nims
@@ -10,6 +10,8 @@ import ospaths
 
 warning("uninit", off)
 hint("processing", off)
+#--verbosity:2
+patchFile("stdlib", "math", "mymath")
 
 task listDirs, "lists every subdirectory":
   for x in listDirs("."):
diff --git a/tests/overload/tissue4475.nim b/tests/overload/tissue4475.nim
new file mode 100644
index 000000000..34618cac5
--- /dev/null
+++ b/tests/overload/tissue4475.nim
@@ -0,0 +1,6 @@
+# Bug: https://github.com/nim-lang/Nim/issues/4475
+# Fix: https://github.com/nim-lang/Nim/pull/4477
+
+proc test(x: varargs[string], y: int) = discard
+
+test(y = 1)
diff --git a/tests/types/tassignemptytuple.nim b/tests/types/tassignemptytuple.nim
new file mode 100644
index 000000000..bdfc653a5
--- /dev/null
+++ b/tests/types/tassignemptytuple.nim
@@ -0,0 +1,11 @@
+discard """
+  file: "tassignemptytuple.nim"
+  line: 11
+  errormsg: "cannot infer the type of the tuple"
+"""
+
+var
+  foo: seq[int]
+  bar: tuple[a: seq[int], b: set[char]]
+
+(foo, bar) = (@[], (@[], {}))
diff --git a/web/news/version_0_15_released.rst b/web/news/version_0_15_released.rst
index e940a2da8..0dfde1ce2 100644
--- a/web/news/version_0_15_released.rst
+++ b/web/news/version_0_15_released.rst
@@ -49,6 +49,16 @@ Compiler Additions
 - The ``-d/--define`` flag can now optionally take a value to be used
   by code at compile time.
 
+Nimscript Additions
+-------------------
+
+- Finally it's possible to dis/enable specific hints and warnings in
+  Nimscript via the procs ``warning`` and ``hint``.
+- Nimscript exports  a proc named ``patchFile`` which can be used to
+  patch modules or include files for different Nimble packages, including
+  the ``stdlib`` package.
+
+
 Language Additions
 ------------------