summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim7
-rw-r--r--compiler/ccgexprs.nim60
-rw-r--r--compiler/ccgliterals.nim2
-rw-r--r--compiler/ccgstmts.nim17
-rw-r--r--compiler/ccgtypes.nim5
-rw-r--r--compiler/cgen.nim93
-rw-r--r--compiler/cgendata.nim11
-rw-r--r--compiler/closureiters.nim24
-rw-r--r--compiler/commands.nim12
-rw-r--r--compiler/condsyms.nim3
-rw-r--r--compiler/destroyer.nim25
-rw-r--r--compiler/dfa.nim14
-rw-r--r--compiler/docgen.nim2
-rw-r--r--compiler/importer.nim2
-rw-r--r--compiler/incremental.nim5
-rw-r--r--compiler/layouter.nim11
-rw-r--r--compiler/lexer.nim5
-rw-r--r--compiler/lineinfos.nim5
-rw-r--r--compiler/lookups.nim2
-rw-r--r--compiler/main.nim141
-rw-r--r--compiler/modulegraphs.nim29
-rw-r--r--compiler/modules.nim2
-rw-r--r--compiler/msgs.nim9
-rw-r--r--compiler/nim.nim3
-rw-r--r--compiler/options.nim6
-rw-r--r--compiler/parser.nim56
-rw-r--r--compiler/pathutils.nim17
-rw-r--r--compiler/pragmas.nim8
-rw-r--r--compiler/reorder.nim2
-rw-r--r--compiler/rod.nim2
-rw-r--r--compiler/rodimpl.nim59
-rw-r--r--compiler/scriptconfig.nim4
-rw-r--r--compiler/sem.nim9
-rw-r--r--compiler/semasgn.nim17
-rw-r--r--compiler/semcall.nim31
-rw-r--r--compiler/semexprs.nim63
-rw-r--r--compiler/semfold.nim24
-rw-r--r--compiler/semgnrc.nim23
-rw-r--r--compiler/semmagic.nim38
-rw-r--r--compiler/sempass2.nim7
-rw-r--r--compiler/semstmts.nim21
-rw-r--r--compiler/semtempl.nim22
-rw-r--r--compiler/semtypes.nim16
-rw-r--r--compiler/semtypinst.nim5
-rw-r--r--compiler/sigmatch.nim23
-rw-r--r--compiler/sizealignoffsetimpl.nim48
-rw-r--r--compiler/suggest.nim4
-rw-r--r--compiler/syntaxes.nim30
-rw-r--r--compiler/transf.nim29
-rw-r--r--compiler/types.nim4
-rw-r--r--compiler/vm.nim25
-rw-r--r--compiler/vmdef.nim3
-rw-r--r--compiler/vmdeps.nim5
-rw-r--r--compiler/vmgen.nim30
-rw-r--r--compiler/vmops.nim15
-rw-r--r--compiler/wordrecg.nim12
56 files changed, 675 insertions, 472 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 5fc8e5978..6a73df3c7 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -565,13 +565,9 @@ const
   routineKinds* = {skProc, skFunc, skMethod, skIterator,
                    skConverter, skMacro, skTemplate}
   tfIncompleteStruct* = tfVarargs
-  tfUncheckedArray* = tfVarargs
   tfUnion* = tfNoSideEffect
   tfGcSafe* = tfThread
   tfObjHasKids* = tfEnumHasHoles
-  tfOldSchoolExprStmt* = tfVarargs # for now used to distinguish \
-    # 'varargs[expr]' from 'varargs[untyped]'. Eventually 'expr' will be
-    # deprecated and this mess can be cleaned up.
   tfReturnsNew* = tfInheritable
   skError* = skUnknown
 
@@ -660,7 +656,8 @@ type
     mNHint, mNWarning, mNError,
     mInstantiationInfo, mGetTypeInfo,
     mNimvm, mIntDefine, mStrDefine, mRunnableExamples,
-    mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf
+    mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf,
+    mSymIsInstantiationOf
 
 # things that we can evaluate safely at compile time, even if not asked for it:
 const
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 6678a07ca..388ab806e 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -173,21 +173,6 @@ proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
     linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
   elif dest.storage == OnHeap:
     # location is on heap
-    # now the writer barrier is inlined for performance:
-    #
-    #    if afSrcIsNotNil in flags:
-    #      UseMagic(p.module, 'nimGCref')
-    #      lineF(p, cpsStmts, 'nimGCref($1);$n', [rdLoc(src)])
-    #    elif afSrcIsNil notin flags:
-    #      UseMagic(p.module, 'nimGCref')
-    #      lineF(p, cpsStmts, 'if ($1) nimGCref($1);$n', [rdLoc(src)])
-    #    if afDestIsNotNil in flags:
-    #      UseMagic(p.module, 'nimGCunref')
-    #      lineF(p, cpsStmts, 'nimGCunref($1);$n', [rdLoc(dest)])
-    #    elif afDestIsNil notin flags:
-    #      UseMagic(p.module, 'nimGCunref')
-    #      lineF(p, cpsStmts, 'if ($1) nimGCunref($1);$n', [rdLoc(dest)])
-    #    lineF(p, cpsStmts, '$1 = $2;$n', [rdLoc(dest), rdLoc(src)])
     if canFormAcycle(dest.t):
       linefmt(p, cpsStmts, "#asgnRef((void**) $1, $2);$n",
               addrLoc(p.config, dest), rdLoc(src))
@@ -872,7 +857,7 @@ proc genArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
   var ty = skipTypes(a.t, abstractVarRange + abstractPtrs + tyUserTypeClasses)
   var first = intLiteral(firstOrd(p.config, ty))
   # emit range check:
-  if optBoundsCheck in p.options and tfUncheckedArray notin ty.flags:
+  if optBoundsCheck in p.options and ty.kind != tyUncheckedArray:
     if not isConstExpr(y):
       # semantic pass has already checked for const index expressions
       if firstOrd(p.config, ty) == 0:
@@ -909,11 +894,10 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
       rdLoc(a), rdLoc(b), rdLoc(arr))
   of tyArray:
     let first = intLiteral(firstOrd(p.config, ty))
-    if tfUncheckedArray notin ty.flags:
-      linefmt(p, cpsStmts,
-        "if ($2-$1 != -1 && " &
-        "($2-$1 < -1 || $1 < $3 || $1 > $4 || $2 < $3 || $2 > $4)) #raiseIndexError();$n",
-        rdCharLoc(a), rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty)))
+    linefmt(p, cpsStmts,
+      "if ($2-$1 != -1 && " &
+      "($2-$1 < -1 || $1 < $3 || $1 > $4 || $2 < $3 || $2 > $4)) #raiseIndexError();$n",
+      rdCharLoc(a), rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty)))
   of tySequence, tyString:
     linefmt(p, cpsStmts,
       "if ($2-$1 != -1 && " &
@@ -1156,7 +1140,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
   getIntTemp(p, tmpL)
   lineCg(p, cpsStmts, "$1 = $2->$3++;$n", tmpL.r, rdLoc(a), lenField(p))
   dest.r = ropecg(p.module, "$1$3[$2]", rdLoc(a), tmpL.r, dataField(p))
-  genAssignment(p, dest, b, {needToCopy, afDestIsNil})
+  genAssignment(p, dest, b, {needToCopy})
   gcUsage(p.config, e)
 
 proc genReset(p: BProc, n: PNode) =
@@ -1395,7 +1379,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
       elem.storage = OnHeap # we know that sequences are on the heap
       initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.sons[1].typ, abstractInst)), a.storage)
       arr.r = ropecg(p.module, "$1[$2]", rdLoc(a), intLiteral(i))
-      genAssignment(p, elem, arr, {afDestIsNil, needToCopy})
+      genAssignment(p, elem, arr, {needToCopy})
   else:
     var i: TLoc
     getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i)
@@ -1406,7 +1390,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
     elem.storage = OnHeap # we know that sequences are on the heap
     initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.sons[1].typ, abstractInst)), a.storage)
     arr.r = ropecg(p.module, "$1[$2]", rdLoc(a), rdLoc(i))
-    genAssignment(p, elem, arr, {afDestIsNil, needToCopy})
+    genAssignment(p, elem, arr, {needToCopy})
     lineF(p, cpsStmts, "}$n", [])
 
 
@@ -1581,8 +1565,17 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     else: putIntoDest(p, d, e, rope(lengthOrd(p.config, typ)))
   else: internalError(p.config, e.info, "genArrayLen()")
 
+proc makePtrType(baseType: PType): PType =
+  result = newType(tyPtr, baseType.owner)
+  addSonSkipIntLit(result, baseType)
+
+proc makeAddr(n: PNode): PNode =
+  result = newTree(nkHiddenAddr, n)
+  result.typ = makePtrType(n.typ)
+
 proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
   if p.config.selectedGc == gcDestructors:
+    e.sons[1] = makeAddr(e[1])
     genCall(p, e, d)
     return
   var a, b, call: TLoc
@@ -1964,6 +1957,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   of mAppendStrStr: genStrAppend(p, e, d)
   of mAppendSeqElem:
     if p.config.selectedGc == gcDestructors:
+      e.sons[1] = makeAddr(e[1])
       genCall(p, e, d)
     else:
       genSeqElemAppend(p, e, d)
@@ -2031,8 +2025,11 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     let n = lowerings.wrapProcForSpawn(p.module.g.graph, p.module.module, e, e.typ, nil, nil)
     expr(p, n, d)
   of mParallel:
-    let n = semparallel.liftParallel(p.module.g.graph, p.module.module, e)
-    expr(p, n, d)
+    when defined(leanCompiler):
+      quit "compiler built without support for the 'parallel' statement"
+    else:
+      let n = semparallel.liftParallel(p.module.g.graph, p.module.module, e)
+      expr(p, n, d)
   of mDeepCopy:
     var a, b: TLoc
     let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1]
@@ -2429,15 +2426,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
     if ex.kind != nkEmpty:
       genLineDir(p, n)
       var a: TLoc
-      if ex.kind in nkCallKinds and (ex[0].kind != nkSym or
-                                     ex[0].sym.magic == mNone):
-        # bug #6037: do not assign to a temp in C++ mode:
-        incl a.flags, lfSingleUse
-        genCall(p, ex, a)
-        if lfSingleUse notin a.flags:
-          line(p, cpsStmts, a.r & ";\L")
-      else:
-        initLocExpr(p, ex, a)
+      initLocExprSingleUse(p, ex, a)
+      line(p, cpsStmts, "(void)(" & a.r & ");\L")
   of nkAsmStmt: genAsmStmt(p, n)
   of nkTryStmt:
     if p.module.compileToCpp and optNoCppExceptions notin p.config.globalOptions:
diff --git a/compiler/ccgliterals.nim b/compiler/ccgliterals.nim
index 34677ec06..ccfa49a1d 100644
--- a/compiler/ccgliterals.nim
+++ b/compiler/ccgliterals.nim
@@ -69,7 +69,7 @@ proc genStringLiteralV2(m: BModule; n: PNode): Rope =
     addf(m.s[cfsData], "static const NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
           [result, rope(len(n.strVal)), pureLit])
   else:
-    result = m.tmpBase & rope(id)
+    result = m.tmpBase & rope(id+1)
 
 proc genStringLiteralV2Const(m: BModule; n: PNode): Rope =
   let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 5ebe0323d..3665a7e85 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -509,7 +509,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
          # for closure support weird loop bodies are generated:
       if loopBody.len == 2 and loopBody.sons[0].kind == nkEmpty:
         loopBody = loopBody.sons[1]
-      genComputedGoto(p, loopBody) # TODO foobar
+      genComputedGoto(p, loopBody)
     else:
       p.breakIdx = startBlock(p, "while (1) {$n")
       p.blocks[p.breakIdx].isLoop = true
@@ -874,14 +874,15 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
 
   discard pop(p.nestedTryStmts)
 
-  if not catchAllPresent and t[^1].kind == nkFinally:
-    # finally requires catch all presence
-    startBlock(p, "catch (...) {$n")
-    genSimpleBlock(p, t[^1][0])
-    line(p, cpsStmts, ~"throw;$n")
-    endBlock(p)
-
   if t[^1].kind == nkFinally:
+    # c++ does not have finally, therefore code needs to be generated twice
+    if not catchAllPresent:
+      # finally requires catch all presence
+      startBlock(p, "catch (...) {$n")
+      genStmts(p, t[^1][0])
+      line(p, cpsStmts, ~"throw;$n")
+      endBlock(p)
+
     genSimpleBlock(p, t[^1][0])
 
 proc genTry(p: BProc, t: PNode, d: var TLoc) =
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 75566fb38..bbfd72354 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -492,7 +492,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
     # with heavily templatized C++ code:
     if not isImportedCppType(rectype):
       let fieldType = field.loc.lode.typ.skipTypes(abstractInst)
-      if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
+      if fieldType.kind == tyUncheckedArray:
         addf(result, "$1 $2[SEQ_DECL_SIZE];$n",
             [getTypeDescAux(m, fieldType.elemType, check), sname])
       elif fieldType.kind == tySequence and m.config.selectedGC != gcDestructors:
@@ -1188,6 +1188,7 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
   let owner = t.skipTypes(typedescPtrs).owner.getModule
   if owner != m.module:
     # make sure the type info is created in the owner module
+    assert m.g.modules[owner.position] != nil
     discard genTypeInfo(m.g.modules[owner.position], origType, info)
     # reference the type info as extern here
     discard cgsym(m, "TNimType")
@@ -1213,8 +1214,8 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
       let x = fakeClosureType(m, t.owner)
       genTupleInfo(m, x, x, result, info)
   of tySequence:
+    genTypeInfoAux(m, t, t, result, info)
     if m.config.selectedGC != gcDestructors:
-      genTypeInfoAux(m, t, t, result, info)
       if m.config.selectedGC >= gcMarkAndSweep:
         let markerProc = genTraverseProc(m, origType, sig)
         addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index ab5584786..199a93be2 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -14,7 +14,10 @@ import
   nversion, nimsets, msgs, std / sha1, bitsets, idents, types,
   ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth,
   condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
-  lowerings, semparallel, tables, sets, ndi, lineinfos, pathutils, transf
+  lowerings, tables, sets, ndi, lineinfos, pathutils, transf
+
+when not defined(leanCompiler):
+  import semparallel
 
 import strutils except `%` # collides with ropes.`%`
 
@@ -42,8 +45,7 @@ when options.hasTinyCBackend:
 # implementation
 
 proc addForwardedProc(m: BModule, prc: PSym) =
-  m.forwardedProcs.add(prc)
-  inc(m.g.forwardedProcsCounter)
+  m.g.forwardedProcs.add(prc)
 
 proc findPendingModule(m: BModule, s: PSym): BModule =
   var ms = getModule(s)
@@ -292,7 +294,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
 
 type
   TAssignmentFlag = enum
-    needToCopy, afDestIsNil, afDestIsNotNil, afSrcIsNil, afSrcIsNotNil
+    needToCopy
   TAssignmentFlags = set[TAssignmentFlag]
 
 proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
@@ -311,7 +313,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
       var nilLoc: TLoc
       initLoc(nilLoc, locTemp, loc.lode, OnStack)
       nilLoc.r = rope("NIM_NIL")
-      genRefAssign(p, loc, nilLoc, {afSrcIsNil})
+      genRefAssign(p, loc, nilLoc, {})
     else:
       linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc))
   else:
@@ -1391,7 +1393,6 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule
   result.preInitProc = newPreInitProc(result)
   initNodeTable(result.dataCache)
   result.typeStack = @[]
-  result.forwardedProcs = @[]
   result.typeNodesName = getTempName(result)
   result.nimTypesName = getTempName(result)
   # no line tracing for the init sections of the system module so that we
@@ -1407,49 +1408,6 @@ proc nullify[T](arr: var T) =
   for i in low(arr)..high(arr):
     arr[i] = Rope(nil)
 
-proc resetModule*(m: BModule) =
-  # between two compilations in CAAS mode, we can throw
-  # away all the data that was written to disk
-  m.headerFiles = @[]
-  m.declaredProtos = initIntSet()
-  m.forwTypeCache = initTable[SigHash, Rope]()
-  m.initProc = newProc(nil, m)
-  m.initProc.options = initProcOptions(m)
-  m.preInitProc = newPreInitProc(m)
-  initNodeTable(m.dataCache)
-  m.typeStack = @[]
-  m.forwardedProcs = @[]
-  m.typeNodesName = getTempName(m)
-  m.nimTypesName = getTempName(m)
-  if sfSystemModule in m.module.flags:
-    incl m.flags, preventStackTrace
-  else:
-    excl m.flags, preventStackTrace
-  nullify m.s
-  m.typeNodes = 0
-  m.nimTypes = 0
-  nullify m.extensionLoaders
-
-  # indicate that this is now cached module
-  # the cache will be invalidated by nullifying gModules
-  #m.fromCache = true
-  m.g = nil
-
-  # we keep only the "merge info" information for the module
-  # and the properties that can't change:
-  # m.filename
-  # m.cfilename
-  # m.isHeaderFile
-  # m.module ?
-  # m.typeCache
-  # m.declaredThings
-  # m.typeInfoMarker
-  # m.labels
-  # m.FrameDeclared
-
-proc resetCgenModules*(g: BModuleList) =
-  for m in cgenModules(g): resetModule(m)
-
 proc rawNewModule(g: BModuleList; module: PSym; conf: ConfigRef): BModule =
   result = rawNewModule(g, module, AbsoluteFile toFullPath(conf, module.position.FileIndex))
 
@@ -1528,20 +1486,6 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
   let tranformed_n = transformStmt(m.g.graph, m.module, n)
   genStmts(m.initProc, tranformed_n)
 
-proc finishModule(m: BModule) =
-  var i = 0
-  while i <= high(m.forwardedProcs):
-    # Note: ``genProc`` may add to ``m.forwardedProcs``, so we cannot use
-    # a ``for`` loop here
-    var prc = m.forwardedProcs[i]
-    if sfForward in prc.flags:
-      internalError(m.config, prc.info, "still forwarded: " & prc.name.s)
-    genProcNoForward(m, prc)
-    inc(i)
-  assert(m.g.forwardedProcsCounter >= i)
-  dec(m.g.forwardedProcsCounter, i)
-  setLen(m.forwardedProcs, 0)
-
 proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool =
   result = true
   if optForceFullMake notin m.config.globalOptions:
@@ -1637,12 +1581,26 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
   registerModuleToMain(m.g, m.module)
 
   if sfMainModule in m.module.flags:
-    if m.g.forwardedProcsCounter == 0:
+    if m.g.forwardedProcs.len == 0:
       incl m.flags, objHasKidsValid
     let disp = generateMethodDispatchers(graph)
     for x in disp: genProcAux(m, x.sym)
     genMainProc(m)
 
+proc genForwardedProcs(g: BModuleList) =
+  # Forward declared proc:s lack bodies when first encountered, so they're given
+  # a second pass here
+  # Note: ``genProcNoForward`` may add to ``forwardedProcs``
+  while g.forwardedProcs.len > 0:
+    let
+      prc = g.forwardedProcs.pop()
+      ms = getModule(prc)
+      m = g.modules[ms.position]
+    if sfForward in prc.flags:
+      internalError(m.config, prc.info, "still forwarded: " & prc.name.s)
+
+    genProcNoForward(m, prc)
+
 proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
   let g = BModuleList(backend)
   # we need to process the transitive closure because recursive module
@@ -1652,10 +1610,9 @@ proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
   let (outDir, _, _) = splitFile(config.outfile)
   if not outDir.isEmpty:
     createDir(outDir)
-  if g.generatedHeader != nil: finishModule(g.generatedHeader)
-  while g.forwardedProcsCounter > 0:
-    for m in cgenModules(g):
-      finishModule(m)
+
+  genForwardedProcs(g)
+
   for m in cgenModules(g):
     m.writeModule(pending=true)
   writeMapping(config, g.mapping)
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index 0c6097fbe..28e36364e 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -112,7 +112,7 @@ type
     mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope
     mapping*: Rope             # the generated mapping file (if requested)
     modules*: seq[BModule]     # list of all compiled modules
-    forwardedProcsCounter*: int
+    forwardedProcs*: seq[PSym] # proc:s that did not yet have a body
     generatedHeader*: BModule
     breakPointId*: int
     breakpoints*: Rope # later the breakpoints are inserted into the main proc
@@ -150,7 +150,6 @@ type
     preInitProc*: BProc       # code executed before the init proc
     typeStack*: TTypeSeq      # used for type generation
     dataCache*: TNodeTable
-    forwardedProcs*: TSymSeq  # keep forwarded procs here
     typeNodes*, nimTypes*: int # used for type info generation
     typeNodesName*, nimTypesName*: Rope # used for type info generation
     labels*: Natural          # for generating unique module-scope names
@@ -188,12 +187,12 @@ proc newProc*(prc: PSym, module: BModule): BProc =
   result.sigConflicts = initCountTable[string]()
 
 proc newModuleList*(g: ModuleGraph): BModuleList =
-  BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope](), config: g.config,
-    graph: g, nimtvDeps: @[], nimtvDeclared: initIntSet())
+  BModuleList(typeInfoMarker: initTable[SigHash, Rope](), config: g.config,
+    graph: g, nimtvDeclared: initIntSet())
 
 iterator cgenModules*(g: BModuleList): BModule =
-  for i in 0..high(g.modules):
+  for m in g.modules:
     # ultimately, we are iterating over the file ids here.
     # some "files" won't have an associated cgen module (like stdin)
     # and we must skip over them.
-    if g.modules[i] != nil: yield g.modules[i]
+    if m != nil: yield m
diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim
index 258372d76..c2d908193 100644
--- a/compiler/closureiters.nim
+++ b/compiler/closureiters.nim
@@ -462,10 +462,17 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
       result.typ = n.typ
 
       for i in 0 ..< n.len:
-        if n[i].kind == nkStmtListExpr:
+        case n[i].kind
+        of nkExprColonExpr:
+          if n[i][1].kind == nkStmtListExpr:
+            let (st, ex) = exprToStmtList(n[i][1])
+            result.add(st)
+            n[i][1] = ex
+        of nkStmtListExpr:
           let (st, ex) = exprToStmtList(n[i])
           result.add(st)
           n[i] = ex
+        else: discard
       result.add(n)
 
   of nkIfStmt, nkIfExpr:
@@ -852,15 +859,8 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
       discard
 
     of nkStmtList, nkStmtListExpr:
-      assert(isEmptyType(n.typ), "nkStmtListExpr not lowered")
-
       result = addGotoOut(result, gotoOut)
       for i in 0 ..< n.len:
-        if n[i].hasYieldsInExpressions:
-          # Lower nkStmtListExpr nodes inside `n[i]` first
-          var ns = false
-          n[i] = ctx.lowerStmtListExprs(n[i], ns)
-
         if n[i].hasYields:
           # Create a new split
           let go = newNodeI(nkGotoState, n[i].info)
@@ -1294,11 +1294,17 @@ proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode =
     ctx.stateVarSym.typ = g.createClosureIterStateType(fn)
 
   ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), fn, fn.info)
-  let n = n.toStmtList
+  var n = n.toStmtList
 
   discard ctx.newState(n, nil)
   let gotoOut = newTree(nkGotoState, g.newIntLit(n.info, -1))
 
+  var ns = false
+  n = ctx.lowerStmtListExprs(n, ns)
+
+  if n.hasYieldsInExpressions():
+    internalError(ctx.g.config, "yield in expr not lowered")
+
   # Splitting transformation
   discard ctx.transformClosureIteratorBody(n, gotoOut)
 
diff --git a/compiler/commands.nim b/compiler/commands.nim
index b39cc0b72..fa17e9851 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -642,14 +642,19 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
   of "help", "h":
     expectNoArg(conf, switch, arg, pass, info)
     helpOnError(conf, pass)
-  of "symbolfiles", "incremental":
+  of "symbolfiles": discard "ignore for backwards compat"
+  of "incremental":
+    when not defined(nimIncremental):
+      localError(conf, info, "the compiler was not built with " &
+        "incremental compilation features; bootstrap with " &
+        "-d:nimIncremental to enable")
     case arg.normalize
     of "on": conf.symbolFiles = v2Sf
     of "off": conf.symbolFiles = disabledSf
     of "writeonly": conf.symbolFiles = writeOnlySf
     of "readonly": conf.symbolFiles = readOnlySf
     of "v2": conf.symbolFiles = v2Sf
-    else: localError(conf, info, "invalid option for --symbolFiles: " & arg)
+    else: localError(conf, info, "invalid option for --incremental: " & arg)
   of "skipcfg":
     expectNoArg(conf, switch, arg, pass, info)
     incl(conf.globalOptions, optSkipSystemConfigFile)
@@ -739,6 +744,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
     of "hint": conf.globalOptions = conf.globalOptions + {optStyleHint}
     of "error": conf.globalOptions = conf.globalOptions + {optStyleError}
     else: localError(conf, info, errOffHintsError % arg)
+  of "showallmismatches":
+    processOnOffSwitchG(conf, {optShowAllMismatches}, arg, pass, info)
   of "cppcompiletonamespace":
     if arg.len > 0:
       conf.cppCustomNamespace = arg
@@ -774,6 +781,7 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser;
     # nim filename.nims  is the same as "nim e filename.nims":
     if p.key.endswith(".nims"):
       config.command = "e"
+      incl(config.globalOptions, optWasNimscript)
       config.projectName = unixToNativePath(p.key)
       config.arguments = cmdLineRest(p)
       result = true
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index 648dcd8c4..9a4c1701c 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -85,7 +85,8 @@ proc initDefines*(symbols: StringTableRef) =
   defineSymbol("nimHasUserErrors")
   defineSymbol("nimUncheckedArrayTyp")
   defineSymbol("nimHasTypeof")
-
+  defineSymbol("nimErrorProcCanHaveBody")
+  defineSymbol("nimHasInstantiationOfInMacro")
   defineSymbol("nimHasNilSeqs")
   for f in low(Feature)..high(Feature):
     defineSymbol("nimHas" & $f)
diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim
index b621e99b9..c515ba1d4 100644
--- a/compiler/destroyer.nim
+++ b/compiler/destroyer.nim
@@ -261,6 +261,11 @@ proc isLastRead(n: PNode; c: var Con): bool =
 template interestingSym(s: PSym): bool =
   s.owner == c.owner and s.kind in InterestingSyms and hasDestructor(s.typ)
 
+template isUnpackedTuple(s: PSym): bool =
+  ## we move out all elements of unpacked tuples, 
+  ## hence unpacked tuples themselves don't need to be destroyed
+  s.kind == skTemp and s.typ.kind == tyTuple
+
 proc patchHead(n: PNode) =
   if n.kind in nkCallKinds and n[0].kind == nkSym and n.len > 1:
     let s = n[0].sym
@@ -446,6 +451,13 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
       ri2.add pArg(ri[i], c, i < L and parameters[i].kind == tySink)
     #recurse(ri, ri2)
     result.add ri2
+  of nkBracketExpr:
+    if ri[0].kind == nkSym and isUnpackedTuple(ri[0].sym):
+      # unpacking of tuple: move out the elements 
+      result = genSink(c, dest.typ, dest, ri)
+    else:
+      result = genCopy(c, dest.typ, dest, ri)
+    result.add p(ri, c)
   of nkObjConstr:
     result = genSink(c, dest.typ, dest, ri)
     let ri2 = copyTree(ri)
@@ -454,6 +466,17 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
       # so these all act like 'sink' parameters:
       ri2[i].sons[1] = pArg(ri[i][1], c, isSink = true)
     result.add ri2
+  of nkTupleConstr:
+    result = genSink(c, dest.typ, dest, ri)
+    let ri2 = copyTree(ri)
+    for i in 0..<ri.len:
+      # everything that is passed to an tuple constructor is consumed,
+      # so these all act like 'sink' parameters:
+      if ri[i].kind == nkExprColonExpr:
+        ri2[i].sons[1] = pArg(ri[i][1], c, isSink = true)
+      else:
+        ri2[i] = pArg(ri[i], c, isSink = true)
+    result.add ri2
   of nkSym:
     if ri.sym.kind != skParam and isLastRead(ri, c):
       # Rule 3: `=sink`(x, z); wasMoved(z)
@@ -483,7 +506,7 @@ proc p(n: PNode; c: var Con): PNode =
       if it.kind == nkVarTuple and hasDestructor(ri.typ):
         let x = lowerTupleUnpacking(c.graph, it, c.owner)
         result.add p(x, c)
-      elif it.kind == nkIdentDefs and hasDestructor(it[0].typ):
+      elif it.kind == nkIdentDefs and hasDestructor(it[0].typ) and not isUnpackedTuple(it[0].sym):
         for j in 0..L-2:
           let v = it[j]
           doAssert v.kind == nkSym
diff --git a/compiler/dfa.nim b/compiler/dfa.nim
index 4b624e93b..415cc4ab3 100644
--- a/compiler/dfa.nim
+++ b/compiler/dfa.nim
@@ -56,6 +56,7 @@ type
     inCall, inTryStmt: int
     blocks: seq[TBlock]
     tryStmtFixups: seq[TPosition]
+    owner: PSym
 
 proc debugInfo(info: TLineInfo): string =
   result = $info.line #info.toFilename & ":" & $info.line
@@ -259,8 +260,15 @@ proc genRaise(c: var Con; n: PNode) =
   else:
     c.code.add Instr(n: n, kind: goto, dest: high(int) - c.code.len)
 
+proc genImplicitReturn(c: var Con) =
+  if c.owner.kind in {skProc, skFunc, skMethod, skIterator, skConverter} and resultPos < c.owner.ast.len:
+    gen(c, c.owner.ast.sons[resultPos])
+
 proc genReturn(c: var Con; n: PNode) =
-  if n.sons[0].kind != nkEmpty: gen(c, n.sons[0])
+  if n.sons[0].kind != nkEmpty:
+    gen(c, n.sons[0])
+  else:
+    genImplicitReturn(c)
   c.code.add Instr(n: n, kind: goto, dest: high(int) - c.code.len)
 
 const
@@ -461,11 +469,13 @@ proc dfa(code: seq[Instr]; conf: ConfigRef) =
 proc dataflowAnalysis*(s: PSym; body: PNode; conf: ConfigRef) =
   var c = Con(code: @[], blocks: @[])
   gen(c, body)
+  genImplicitReturn(c)
   when defined(useDfa) and defined(debugDfa): echoCfg(c.code)
   dfa(c.code, conf)
 
 proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph =
   ## constructs a control flow graph for ``body``.
-  var c = Con(code: @[], blocks: @[])
+  var c = Con(code: @[], blocks: @[], owner: s)
   gen(c, body)
+  genImplicitReturn(c)
   shallowCopy(result, c.code)
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index f5795e1d2..6f61d020d 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -897,7 +897,7 @@ proc genOutFile(d: PDoc): Rope =
     setIndexTerm(d[], external, "", title)
   else:
     # Modules get an automatic title for the HTML, but no entry in the index.
-    title = "Module " & extractFilename(changeFileExt(d.filename, ""))
+    title = extractFilename(changeFileExt(d.filename, ""))
 
   let bodyname = if d.hasToc and not d.isPureRst: "doc.body_toc_group"
                  elif d.hasToc: "doc.body_toc"
diff --git a/compiler/importer.nim b/compiler/importer.nim
index 60b7872fe..131b1ad8a 100644
--- a/compiler/importer.nim
+++ b/compiler/importer.nim
@@ -100,7 +100,7 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
     if s.kind != skModule:
       if s.kind != skEnumField:
         if s.kind notin ExportableSymKinds:
-          internalError(c.config, s.info, "importAllSymbols: " & $s.kind)
+          internalError(c.config, s.info, "importAllSymbols: " & $s.kind & " " & s.name.s)
         if exceptSet.isNil or s.name.id notin exceptSet:
           rawImportSymbol(c, s)
     s = nextIter(i, fromMod.tab)
diff --git a/compiler/incremental.nim b/compiler/incremental.nim
index 47637b3c1..f66a75efd 100644
--- a/compiler/incremental.nim
+++ b/compiler/incremental.nim
@@ -59,8 +59,8 @@ when nimIncremental:
     let id = row[0]
     let fullhash = hashFileCached(conf, fileIdx, AbsoluteFile fullpath)
     if id.len == 0:
-      result = int incr.db.insertID(sql"insert into filenames(fullpath, fullhash) values (?, ?)",
-        fullpath, fullhash)
+      result = int incr.db.insertID(sql"insert into filenames(nimid, fullpath, fullhash) values (?, ?, ?)",
+        int(fileIdx), fullpath, fullhash)
     else:
       if row[1] != fullhash:
         incr.db.exec(sql"update filenames set fullhash = ? where fullpath = ?", fullhash, fullpath)
@@ -102,6 +102,7 @@ when nimIncremental:
     db.exec(sql"""
       create table if not exists filenames(
         id integer primary key,
+        nimid integer not null,
         fullpath varchar(8000) not null,
         fullHash varchar(256) not null
       );
diff --git a/compiler/layouter.nim b/compiler/layouter.nim
index f96f88da1..8605ade45 100644
--- a/compiler/layouter.nim
+++ b/compiler/layouter.nim
@@ -30,7 +30,7 @@ type
     lastTok: TTokType
     inquote, lastTokWasTerse: bool
     semicolons: SemicolonKind
-    col, lastLineNumber, lineSpan, indentLevel, indWidth: int
+    col, lastLineNumber, lineSpan, indentLevel, indWidth*: int
     keepIndents*: int
     doIndentMore*: int
     content: string
@@ -41,9 +41,10 @@ type
 proc openEmitter*(em: var Emitter, cache: IdentCache;
                   config: ConfigRef, fileIdx: FileIndex) =
   let fullPath = Absolutefile config.toFullPath(fileIdx)
-  em.indWidth = getIndentWidth(fileIdx, llStreamOpen(fullPath, fmRead),
-                               cache, config)
-  if em.indWidth == 0: em.indWidth = 2
+  if em.indWidth == 0:
+    em.indWidth = getIndentWidth(fileIdx, llStreamOpen(fullPath, fmRead),
+                                cache, config)
+    if em.indWidth == 0: em.indWidth = 2
   em.config = config
   em.fid = fileIdx
   em.lastTok = tkInvalid
@@ -245,7 +246,7 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
     wr(TokTypeToStr[tok.tokType])
     if not em.inquote: wr(" ")
   of tkOpr, tkDotDot:
-    if tok.strongSpaceA == 0 and tok.strongSpaceB == 0:
+    if (tok.strongSpaceA == 0 and tok.strongSpaceB == 0) or em.inquote:
       # bug #9504: remember to not spacify a keyword:
       lastTokWasTerse = true
       # if not surrounded by whitespace, don't produce any whitespace either:
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index 877369c2a..635e6f08d 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -635,7 +635,8 @@ proc handleHexChar(L: var TLexer, xi: var int) =
     inc(L.bufpos)
   else:
     lexMessage(L, errGenerated,
-      "expected a hex digit, but found: " & L.buf[L.bufpos])
+      "expected a hex digit, but found: " & L.buf[L.bufpos] &
+        " ; maybe prepend with 0")
     # Need to progress for `nim check`
     inc(L.bufpos)
 
@@ -966,7 +967,7 @@ proc getPrecedence*(tok: TToken, strongSpaces: bool): int =
     of '?': result = 2
     else: considerAsgn(2)
   of tkDiv, tkMod, tkShl, tkShr: result = 9
-  of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5
+  of tkIn, tkNotin, tkIs, tkIsnot, tkOf, tkAs: result = 5
   of tkDotDot: result = 6
   of tkAnd: result = 4
   of tkOr, tkXor, tkPtr, tkRef: result = 3
diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim
index cd160313c..b1ecf779e 100644
--- a/compiler/lineinfos.nim
+++ b/compiler/lineinfos.nim
@@ -41,7 +41,7 @@ type
     hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
     hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
     hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
-    hintConditionAlwaysTrue, hintName, hintPattern,
+    hintConditionAlwaysTrue, hintConditionAlwaysFalse, hintName, hintPattern,
     hintExecuting, hintLinking, hintDependency,
     hintSource, hintPerformance, hintStackTrace, hintGCStats,
     hintGlobalVar,
@@ -107,6 +107,7 @@ const
     hintConf: "used config file '$1'",
     hintPath: "added path: '$1'",
     hintConditionAlwaysTrue: "condition is always true: '$1'",
+    hintConditionAlwaysFalse: "condition is always false: '$1'",
     hintName: "name should be: '$1'",
     hintPattern: "$1",
     hintExecuting: "$1",
@@ -140,7 +141,7 @@ const
     "Success", "SuccessX", "CC", "LineTooLong",
     "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
     "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
-    "Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency",
+    "Path", "CondTrue", "CondFalse", "Name", "Pattern", "Exec", "Link", "Dependency",
     "Source", "Performance", "StackTrace", "GCStats", "GlobalVar",
     "User", "UserRaw", "ExtendedContext",
   ]
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index d2e7fdcfa..2fb4e5241 100644
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -168,7 +168,7 @@ proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) =
         localError(c.config, s.info, "implementation of '$1' expected" %
             getSymRepr(c.config, s))
       inc missingImpls
-    elif {sfUsed, sfExported} * s.flags == {} and optHints in s.options:
+    elif {sfUsed, sfExported} * s.flags == {}:
       if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}:
         # XXX: implicit type params are currently skTypes
         # maybe they can be made skGenericParam as well.
diff --git a/compiler/main.nim b/compiler/main.nim
index 6c8b0343e..6afe57d87 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -15,12 +15,15 @@ when not defined(nimcore):
 import
   llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs,
   os, condsyms, times,
-  wordrecg, sem, semdata, idents, passes, docgen, extccomp,
-  cgen, jsgen, json, nversion,
+  wordrecg, sem, semdata, idents, passes, extccomp,
+  cgen, json, nversion,
   platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
-  docgen2, parser, modules, ccgutils, sigmatch, ropes,
+  parser, modules, ccgutils, sigmatch, ropes,
   modulegraphs, tables, rod, lineinfos, pathutils
 
+when not defined(leanCompiler):
+  import jsgen, docgen, docgen2
+
 from magicsys import resetSysTypes
 
 proc codegenPass(g: ModuleGraph) =
@@ -57,13 +60,14 @@ proc commandCheck(graph: ModuleGraph) =
   semanticPasses(graph)  # use an empty backend for semantic checking only
   compileProject(graph)
 
-proc commandDoc2(graph: ModuleGraph; json: bool) =
-  graph.config.errorMax = high(int)  # do not stop after first error
-  semanticPasses(graph)
-  if json: registerPass(graph, docgen2JsonPass)
-  else: registerPass(graph, docgen2Pass)
-  compileProject(graph)
-  finishDoc2Pass(graph.config.projectName)
+when not defined(leanCompiler):
+  proc commandDoc2(graph: ModuleGraph; json: bool) =
+    graph.config.errorMax = high(int)  # do not stop after first error
+    semanticPasses(graph)
+    if json: registerPass(graph, docgen2JsonPass)
+    else: registerPass(graph, docgen2Pass)
+    compileProject(graph)
+    finishDoc2Pass(graph.config.projectName)
 
 proc commandCompileToC(graph: ModuleGraph) =
   let conf = graph.config
@@ -84,15 +88,16 @@ proc commandJsonScript(graph: ModuleGraph) =
   let proj = changeFileExt(graph.config.projectFull, "")
   extccomp.runJsonBuildInstructions(graph.config, proj)
 
-proc commandCompileToJS(graph: ModuleGraph) =
-  #incl(gGlobalOptions, optSafeCode)
-  setTarget(graph.config.target, osJS, cpuJS)
-  #initDefines()
-  defineSymbol(graph.config.symbols, "ecmascript") # For backward compatibility
-  defineSymbol(graph.config.symbols, "js")
-  semanticPasses(graph)
-  registerPass(graph, JSgenPass)
-  compileProject(graph)
+when not defined(leanCompiler):
+  proc commandCompileToJS(graph: ModuleGraph) =
+    #incl(gGlobalOptions, optSafeCode)
+    setTarget(graph.config.target, osJS, cpuJS)
+    #initDefines()
+    defineSymbol(graph.config.symbols, "ecmascript") # For backward compatibility
+    defineSymbol(graph.config.symbols, "js")
+    semanticPasses(graph)
+    registerPass(graph, JSgenPass)
+    compileProject(graph)
 
 proc interactivePasses(graph: ModuleGraph) =
   initDefines(graph.config.symbols)
@@ -177,49 +182,76 @@ proc mainCommand*(graph: ModuleGraph) =
     else:
       rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc")
   of "js", "compiletojs":
-    conf.cmd = cmdCompileToJS
-    commandCompileToJS(graph)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with JS code generator"
+    else:
+      conf.cmd = cmdCompileToJS
+      commandCompileToJS(graph)
   of "doc0":
-    wantMainModule(conf)
-    conf.cmd = cmdDoc
-    loadConfigs(DocConfig, cache, conf)
-    commandDoc(cache, conf)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      wantMainModule(conf)
+      conf.cmd = cmdDoc
+      loadConfigs(DocConfig, cache, conf)
+      commandDoc(cache, conf)
   of "doc2", "doc":
-    conf.cmd = cmdDoc
-    loadConfigs(DocConfig, cache, conf)
-    defineSymbol(conf.symbols, "nimdoc")
-    commandDoc2(graph, false)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      conf.cmd = cmdDoc
+      loadConfigs(DocConfig, cache, conf)
+      defineSymbol(conf.symbols, "nimdoc")
+      commandDoc2(graph, false)
   of "rst2html":
-    conf.cmd = cmdRst2html
-    loadConfigs(DocConfig, cache, conf)
-    commandRst2Html(cache, conf)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      conf.cmd = cmdRst2html
+      loadConfigs(DocConfig, cache, conf)
+      commandRst2Html(cache, conf)
   of "rst2tex":
-    conf.cmd = cmdRst2tex
-    loadConfigs(DocTexConfig, cache, conf)
-    commandRst2TeX(cache, conf)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      conf.cmd = cmdRst2tex
+      loadConfigs(DocTexConfig, cache, conf)
+      commandRst2TeX(cache, conf)
   of "jsondoc0":
-    wantMainModule(conf)
-    conf.cmd = cmdDoc
-    loadConfigs(DocConfig, cache, conf)
-    wantMainModule(conf)
-    defineSymbol(conf.symbols, "nimdoc")
-    commandJson(cache, conf)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      wantMainModule(conf)
+      conf.cmd = cmdDoc
+      loadConfigs(DocConfig, cache, conf)
+      wantMainModule(conf)
+      defineSymbol(conf.symbols, "nimdoc")
+      commandJson(cache, conf)
   of "jsondoc2", "jsondoc":
-    conf.cmd = cmdDoc
-    loadConfigs(DocConfig, cache, conf)
-    wantMainModule(conf)
-    defineSymbol(conf.symbols, "nimdoc")
-    commandDoc2(graph, true)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      conf.cmd = cmdDoc
+      loadConfigs(DocConfig, cache, conf)
+      wantMainModule(conf)
+      defineSymbol(conf.symbols, "nimdoc")
+      commandDoc2(graph, true)
   of "ctags":
-    wantMainModule(conf)
-    conf.cmd = cmdDoc
-    loadConfigs(DocConfig, cache, conf)
-    defineSymbol(conf.symbols, "nimdoc")
-    commandTags(cache, conf)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      wantMainModule(conf)
+      conf.cmd = cmdDoc
+      loadConfigs(DocConfig, cache, conf)
+      defineSymbol(conf.symbols, "nimdoc")
+      commandTags(cache, conf)
   of "buildindex":
-    conf.cmd = cmdDoc
-    loadConfigs(DocConfig, cache, conf)
-    commandBuildIndex(cache, conf)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      conf.cmd = cmdDoc
+      loadConfigs(DocConfig, cache, conf)
+      commandBuildIndex(cache, conf)
   of "gendepend":
     conf.cmd = cmdGenDepend
     commandGenDepend(graph)
@@ -265,6 +297,7 @@ proc mainCommand*(graph: ModuleGraph) =
     conf.cmd = cmdInteractive
     commandInteractive(graph)
   of "e":
+    incl conf.globalOptions, optWasNimscript
     commandEval(graph, mainCommandArg(conf))
   of "nop", "help":
     # prevent the "success" message:
diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim
index 16704fab6..d05b301ae 100644
--- a/compiler/modulegraphs.nim
+++ b/compiler/modulegraphs.nim
@@ -63,6 +63,9 @@ type
     cacheCounters*: Table[string, BiggestInt]
     cacheTables*: Table[string, BTree[string, PNode]]
     passes*: seq[TPass]
+    onDefinition*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
+    onDefinitionResolveForward*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
+    onUsage*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
 
   TPassContext* = object of RootObj # the pass's context
   PPassContext* = ref TPassContext
@@ -78,6 +81,32 @@ type
 
 proc hash*(x: FileIndex): Hash {.borrow.}
 
+when defined(nimfind):
+  template onUse*(info: TLineInfo; s: PSym) =
+    when compiles(c.c.graph):
+      if c.c.graph.onUsage != nil: c.c.graph.onUsage(c.c.graph, s, info)
+    else:
+      if c.graph.onUsage != nil: c.graph.onUsage(c.graph, s, info)
+
+  template onDef*(info: TLineInfo; s: PSym) =
+    when compiles(c.c.graph):
+      if c.c.graph.onDefinition != nil: c.c.graph.onDefinition(c.c.graph, s, info)
+    else:
+      if c.graph.onDefinition != nil: c.graph.onDefinition(c.graph, s, info)
+
+  template onDefResolveForward*(info: TLineInfo; s: PSym) =
+    when compiles(c.c.graph):
+      if c.c.graph.onDefinitionResolveForward != nil:
+        c.c.graph.onDefinitionResolveForward(c.c.graph, s, info)
+    else:
+      if c.graph.onDefinitionResolveForward != nil:
+        c.graph.onDefinitionResolveForward(c.graph, s, info)
+
+else:
+  template onUse*(info: TLineInfo; s: PSym) = discard
+  template onDef*(info: TLineInfo; s: PSym) = discard
+  template onDefResolveForward*(info: TLineInfo; s: PSym) = discard
+
 proc stopCompile*(g: ModuleGraph): bool {.inline.} =
   result = g.doStopCompile != nil and g.doStopCompile()
 
diff --git a/compiler/modules.nim b/compiler/modules.nim
index 75e95e453..e2f322561 100644
--- a/compiler/modules.nim
+++ b/compiler/modules.nim
@@ -67,6 +67,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): P
       graph.config.mainPackageId = result.owner.id
 
     result.id = getModuleId(graph, fileIdx, AbsoluteFile toFullPath(graph.config, fileIdx))
+    registerModule(graph, result)
     discard processModule(graph, result,
       if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil)
   elif graph.isDirty(result):
@@ -128,6 +129,7 @@ proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIDX) =
 proc makeModule*(graph: ModuleGraph; filename: AbsoluteFile): PSym =
   result = graph.newModule(fileInfoIdx(graph.config, filename))
   result.id = getID()
+  registerModule(graph, result)
 
 proc makeModule*(graph: ModuleGraph; filename: string): PSym =
   result = makeModule(graph, AbsoluteFile filename)
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index dee1081f9..7e6b67cbe 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -190,10 +190,13 @@ template toFullPath*(conf: ConfigRef; info: TLineInfo): string =
 proc toMsgFilename*(conf: ConfigRef; info: TLineInfo): string =
   if info.fileIndex.int32 < 0:
     result = "???"
-  elif optListFullPaths in conf.globalOptions:
-    result = conf.m.fileInfos[info.fileIndex.int32].fullPath.string
+    return
+  let absPath = conf.m.fileInfos[info.fileIndex.int32].fullPath.string
+  let relPath = conf.m.fileInfos[info.fileIndex.int32].projPath.string
+  if optListFullPaths in conf.globalOptions:
+    result = absPath
   else:
-    result = conf.m.fileInfos[info.fileIndex.int32].projPath.string
+    result = if absPath.len < relPath.len: absPath else: relPath
 
 proc toLinenumber*(info: TLineInfo): int {.inline.} =
   result = int info.line
diff --git a/compiler/nim.nim b/compiler/nim.nim
index 5f3347255..1c4dbd3be 100644
--- a/compiler/nim.nim
+++ b/compiler/nim.nim
@@ -54,7 +54,8 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
     of cmdArgument:
       if processArgument(pass, p, argsCount, config): break
   if pass == passCmd2:
-    if optRun notin config.globalOptions and config.arguments.len > 0 and config.command.normalize != "run":
+    if {optRun, optWasNimscript} * config.globalOptions == {} and
+        config.arguments.len > 0 and config.command.normalize notin ["run", "e"]:
       rawMessage(config, errGenerated, errArgsNeedRunOption)
 
 proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
diff --git a/compiler/options.nim b/compiler/options.nim
index 1280cb59b..80d665d62 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -45,7 +45,7 @@ type                          # please make sure we have under 32 options
   TOptions* = set[TOption]
   TGlobalOption* = enum       # **keep binary compatible**
     gloptNone, optForceFullMake,
-    optDeadCodeElimUnused,    # deprecated, always on
+    optWasNimscript,
     optListCmd, optCompileOnly, optNoLinking,
     optCDebug,                # turn on debugging information
     optGenDynLib,             # generate a dynamic library
@@ -74,6 +74,7 @@ type                          # please make sure we have under 32 options
     optIdeTerse               # idetools: use terse descriptions
     optNoCppExceptions        # use C exception handling even with CPP
     optExcessiveStackTrace    # fully qualified module filenames
+    optShowAllMismatches      # show all overloading resolution candidates
     optWholeProject           # for 'doc2': output any dependency
     optMixedMode              # true if some module triggered C++ codegen
     optListFullPaths
@@ -401,7 +402,8 @@ proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in {cmdDoc,
 proc usesWriteBarrier*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc
 
 template compilationCachePresent*(conf: ConfigRef): untyped =
-  conf.symbolFiles in {v2Sf, writeOnlySf}
+  false
+#  conf.symbolFiles in {v2Sf, writeOnlySf}
 
 template optPreserveOrigSource*(conf: ConfigRef): untyped =
   optEmbedOrigSrc in conf.globalOptions
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 02083ca83..54b360a24 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -37,8 +37,7 @@ type
   TParser* = object            # A TParser object represents a file that
                                # is being parsed
     currInd: int               # current indentation level
-    firstTok, strongSpaces: bool # Has the first token been read?
-                                 # Is strongSpaces on?
+    firstTok: bool             # Has the first token been read?
     hasProgress: bool          # some while loop requires progress ensurance
     lex*: TLexer               # The lexer that is used for parsing
     tok*: TToken               # The current token
@@ -46,7 +45,7 @@ type
     inSemiStmtList*: int
     emptyNode: PNode
     when defined(nimpretty2):
-      em: Emitter
+      em*: Emitter
 
   SymbolMode = enum
     smNormal, smAllowNil, smAfterDot
@@ -102,8 +101,7 @@ proc getTok(p: var TParser) =
       emitTok(p.em, p.lex, p.tok)
 
 proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream,
-                 cache: IdentCache; config: ConfigRef;
-                 strongSpaces=false) =
+                 cache: IdentCache; config: ConfigRef) =
   ## Open a parser, using the given arguments to set up its internal state.
   ##
   initToken(p.tok)
@@ -112,13 +110,11 @@ proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream,
     openEmitter(p.em, cache, config, fileIdx)
   getTok(p)                   # read the first token
   p.firstTok = true
-  p.strongSpaces = strongSpaces
   p.emptyNode = newNode(nkEmpty)
 
 proc openParser*(p: var TParser, filename: AbsoluteFile, inputStream: PLLStream,
-                 cache: IdentCache; config: ConfigRef;
-                 strongSpaces=false) =
-  openParser(p, fileInfoIdx(config, filename), inputStream, cache, config, strongSpaces)
+                 cache: IdentCache; config: ConfigRef) =
+  openParser(p, fileInfoIdx(config, filename), inputStream, cache, config)
 
 proc closeParser(p: var TParser) =
   ## Close a parser, freeing up its resources.
@@ -286,7 +282,7 @@ proc checkBinary(p: TParser) {.inline.} =
 #|
 #| prefixOperator = operator
 #|
-#| optInd = COMMENT?
+#| optInd = COMMENT? IND?
 #| optPar = (IND{>} | IND{=})?
 #|
 #| simpleExpr = arrowExpr (OP0 optInd arrowExpr)* pragma?
@@ -706,8 +702,11 @@ proc namedParams(p: var TParser, callee: PNode,
   # progress guaranteed
   exprColonEqExprListAux(p, endTok, result)
 
-proc commandParam(p: var TParser, isFirstParam: var bool): PNode =
-  result = parseExpr(p)
+proc commandParam(p: var TParser, isFirstParam: var bool; mode: TPrimaryMode): PNode =
+  if mode == pmTypeDesc:
+    result = simpleExpr(p, mode)
+  else:
+    result = parseExpr(p)
   if p.tok.tokType == tkDo:
     result = postExprBlocks(p, result)
   elif p.tok.tokType == tkEquals and not isFirstParam:
@@ -780,7 +779,7 @@ proc primarySuffix(p: var TParser, r: PNode,
         when true:
           # progress NOT guaranteed
           p.hasProgress = false
-          addSon result, commandParam(p, isFirstParam)
+          addSon result, commandParam(p, isFirstParam, mode)
           if not p.hasProgress: break
         else:
           while p.tok.tokType != tkEof:
@@ -798,7 +797,7 @@ proc parseOperators(p: var TParser, headNode: PNode,
                     limit: int, mode: TPrimaryMode): PNode =
   result = headNode
   # expand while operators have priorities higher than 'limit'
-  var opPrec = getPrecedence(p.tok, p.strongSpaces)
+  var opPrec = getPrecedence(p.tok, false)
   let modeB = if mode == pmTypeDef: pmTypeDesc else: mode
   # the operator itself must not start on a new line:
   # progress guaranteed
@@ -815,7 +814,7 @@ proc parseOperators(p: var TParser, headNode: PNode,
     addSon(a, result)
     addSon(a, b)
     result = a
-    opPrec = getPrecedence(p.tok, p.strongSpaces)
+    opPrec = getPrecedence(p.tok, false)
 
 proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
   result = primary(p, mode)
@@ -1255,14 +1254,29 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
     if mode != pmSkipSuffix:
       result = primarySuffix(p, result, baseInd, mode)
 
+proc binaryNot(p: var TParser; a: PNode): PNode =
+  if p.tok.tokType == tkNot:
+    let notOpr = newIdentNodeP(p.tok.ident, p)
+    getTok(p)
+    optInd(p, notOpr)
+    let b = parseExpr(p)
+    result = newNodeP(nkInfix, p)
+    result.add notOpr
+    result.add a
+    result.add b
+  else:
+    result = a
+
 proc parseTypeDesc(p: var TParser): PNode =
-  #| typeDesc = simpleExpr
+  #| typeDesc = simpleExpr ('not' expr)?
   result = simpleExpr(p, pmTypeDesc)
+  result = binaryNot(p, result)
 
 proc parseTypeDefAux(p: var TParser): PNode =
-  #| typeDefAux = simpleExpr
+  #| typeDefAux = simpleExpr ('not' expr)?
   #|            | 'concept' typeClass
   result = simpleExpr(p, pmTypeDef)
+  result = binaryNot(p, result)
 
 proc makeCall(n: PNode): PNode =
   ## Creates a call if the given node isn't already a call.
@@ -1370,12 +1384,12 @@ proc parseExprStmt(p: var TParser): PNode =
       while true:
         getTok(p)
         optInd(p, result)
-        addSon(result, commandParam(p, isFirstParam))
+        addSon(result, commandParam(p, isFirstParam, pmNormal))
         if p.tok.tokType != tkComma: break
     elif p.tok.indent < 0 and isExprStart(p):
       result = newNode(nkCommand, a.info, @[a])
       while true:
-        addSon(result, commandParam(p, isFirstParam))
+        addSon(result, commandParam(p, isFirstParam, pmNormal))
         if p.tok.tokType != tkComma: break
         getTok(p)
         optInd(p, result)
@@ -2236,10 +2250,8 @@ proc parseString*(s: string; cache: IdentCache; config: ConfigRef;
   stream.lineOffset = line
 
   var parser: TParser
-  # XXX for now the builtin 'parseStmt/Expr' functions do not know about strong
-  # spaces...
   parser.lex.errorHandler = errorHandler
-  openParser(parser, AbsoluteFile filename, stream, cache, config, false)
+  openParser(parser, AbsoluteFile filename, stream, cache, config)
 
   result = parser.parseAll
   closeParser(parser)
diff --git a/compiler/pathutils.nim b/compiler/pathutils.nim
index 4873f90d6..703467bc4 100644
--- a/compiler/pathutils.nim
+++ b/compiler/pathutils.nim
@@ -73,23 +73,6 @@ iterator dirs(x: string): (int, int) =
   var it: PathIter
   while hasNext(it, x): yield next(it, x)
 
-when false:
-  iterator dirs(x: string): (int, int) =
-    var i = 0
-    var first = true
-    while i < x.len:
-      let prev = i
-      if first and x[i] in {DirSep, AltSep}:
-        # absolute path:
-        inc i
-      else:
-        while i < x.len and x[i] notin {DirSep, AltSep}: inc i
-      if i > prev:
-        yield (prev, i-1)
-      first = false
-      # skip all separators:
-      while i < x.len and x[i] in {DirSep, AltSep}: inc i
-
 proc isDot(x: string; bounds: (int, int)): bool =
   bounds[1] == bounds[0] and x[bounds[0]] == '.'
 
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 08e3c34d4..ef5223559 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -1019,8 +1019,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
         else: incl(sym.typ.flags, tfIncompleteStruct)
       of wUnchecked:
         noVal(c, it)
-        if sym.typ == nil: invalidPragma(c, it)
-        else: incl(sym.typ.flags, tfUncheckedArray)
+        if sym.typ == nil or sym.typ.kind notin {tyArray, tyUncheckedArray}:
+          invalidPragma(c, it)
+        else:
+          sym.typ.kind = tyUncheckedArray
       of wUnion:
         noVal(c, it)
         if sym.typ == nil: invalidPragma(c, it)
@@ -1060,6 +1062,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
           invalidPragma(c, it)
         else:
           sym.bitsize = expectIntLit(c, it)
+          if sym.bitsize <= 0:
+            localError(c.config, it.info, "bitsize needs to be positive")
       of wGuard:
         if sym == nil or sym.kind notin {skVar, skLet, skField}:
           invalidPragma(c, it)
diff --git a/compiler/reorder.nim b/compiler/reorder.nim
index 07462bb3e..8c4d0d307 100644
--- a/compiler/reorder.nim
+++ b/compiler/reorder.nim
@@ -1,6 +1,6 @@
 
 import
-  intsets, ast, idents, algorithm, renderer, parser, ospaths, strutils,
+  intsets, ast, idents, algorithm, renderer, parser, os, strutils,
   sequtils, msgs, modulegraphs, syntaxes, options, modulepaths, tables,
   lineinfos
 
diff --git a/compiler/rod.nim b/compiler/rod.nim
index f6fc24ec0..92489ffdd 100644
--- a/compiler/rod.nim
+++ b/compiler/rod.nim
@@ -22,6 +22,8 @@ when not nimIncremental:
 
   template storeRemaining*(g: ModuleGraph; module: PSym) = discard
 
+  template registerModule*(g: ModuleGraph; module: PSym) = discard
+
 else:
   include rodimpl
 
diff --git a/compiler/rodimpl.nim b/compiler/rodimpl.nim
index 839a9c6ca..730328642 100644
--- a/compiler/rodimpl.nim
+++ b/compiler/rodimpl.nim
@@ -321,6 +321,9 @@ proc encodeSym(g: ModuleGraph, s: PSym, result: var string) =
       result.add('\16')
       encodeVInt(s.gcUnsafetyReason.id, result)
       pushSym(w, s.gcUnsafetyReason)
+    if s.transformedBody != nil:
+      result.add('\24')
+      encodeNode(g, s.info, s.transformedBody, result)
   of skModule, skPackage:
     encodeInstantiations(g, s.usedGenerics, result)
     # we don't serialize:
@@ -363,13 +366,7 @@ proc storeType(g: ModuleGraph; t: PType) =
   db.exec(sql"insert into types(nimid, module, data) values (?, ?, ?)",
     t.id, mid, buf)
 
-proc storeNode*(g: ModuleGraph; module: PSym; n: PNode) =
-  if g.config.symbolFiles == disabledSf: return
-  var buf = newStringOfCap(160)
-  encodeNode(g, module.info, n, buf)
-  db.exec(sql"insert into toplevelstmts(module, position, data) values (?, ?, ?)",
-    abs(module.id), module.offset, buf)
-  inc module.offset
+proc transitiveClosure(g: ModuleGraph) =
   var i = 0
   while true:
     if i > 10_000:
@@ -388,9 +385,25 @@ proc storeNode*(g: ModuleGraph; module: PSym; n: PNode) =
       break
     inc i
 
+proc storeNode*(g: ModuleGraph; module: PSym; n: PNode) =
+  if g.config.symbolFiles == disabledSf: return
+  var buf = newStringOfCap(160)
+  encodeNode(g, module.info, n, buf)
+  db.exec(sql"insert into toplevelstmts(module, position, data) values (?, ?, ?)",
+    abs(module.id), module.offset, buf)
+  inc module.offset
+  transitiveClosure(g)
+
 proc recordStmt*(g: ModuleGraph; module: PSym; n: PNode) =
   storeNode(g, module, n)
 
+proc storeFilename(g: ModuleGraph; fullpath: AbsoluteFile; fileIdx: FileIndex) =
+  let id = db.getValue(sql"select id from filenames where fullpath = ?", fullpath.string)
+  if id.len == 0:
+    let fullhash = hashFileCached(g.config, fileIdx, fullpath)
+    db.exec(sql"insert into filenames(nimid, fullpath, fullhash) values (?, ?, ?)",
+        int(fileIdx), fullpath.string, fullhash)
+
 proc storeRemaining*(g: ModuleGraph; module: PSym) =
   if g.config.symbolFiles == disabledSf: return
   var stillForwarded: seq[PSym] = @[]
@@ -400,6 +413,13 @@ proc storeRemaining*(g: ModuleGraph; module: PSym) =
     else:
       stillForwarded.add s
   swap w.forwardedSyms, stillForwarded
+  transitiveClosure(g)
+  var nimid = 0
+  for x in items(g.config.m.fileInfos):
+    # don't store the "command line" entry:
+    if nimid != 0:
+      storeFilename(g, x.fullPath, FileIndex(nimid))
+    inc nimid
 
 # ---------------- decoder -----------------------------------
 
@@ -725,6 +745,9 @@ proc loadSymFromBlob(g; b; info: TLineInfo): PSym =
     if b.s[b.pos] == '\16':
       inc(b.pos)
       result.gcUnsafetyReason = loadSym(g, decodeVInt(b.s, b.pos), result.info)
+    if b.s[b.pos] == '\24':
+      inc b.pos
+      result.transformedBody = decodeNode(g, b, result.info)
   of skModule, skPackage:
     decodeInstantiations(g, b, result.info, result.usedGenerics)
   of skLet, skVar, skField, skForVar:
@@ -752,6 +775,9 @@ proc loadSym(g; id: int; info: TLineInfo): PSym =
   result = loadSymFromBlob(g, b, info)
   doAssert id == result.id, "symbol ID is not consistent!"
 
+proc registerModule*(g; module: PSym) =
+  g.incr.r.syms.add(abs module.id, module)
+
 proc loadModuleSymTab(g; module: PSym) =
   ## goal: fill  module.tab
   g.incr.r.syms.add(module.id, module)
@@ -765,7 +791,8 @@ proc loadModuleSymTab(g; module: PSym) =
       b.s.add '\0'
       s = loadSymFromBlob(g, b, module.info)
     assert s != nil
-    strTableAdd(module.tab, s)
+    if s.kind != skField:
+      strTableAdd(module.tab, s)
   if sfSystemModule in module.flags:
     g.systemModule = module
 
@@ -843,8 +870,9 @@ proc replay(g: ModuleGraph; module: PSym; n: PNode) =
         internalAssert g.config, false
   of nkImportStmt:
     for x in n:
-      internalAssert g.config, x.kind == nkStrLit
-      let imported = g.importModuleCallback(g, module, fileInfoIdx(g.config, AbsoluteFile n[0].strVal))
+      internalAssert g.config, x.kind == nkSym
+      let modpath = AbsoluteFile toFullPath(g.config, x.sym.info)
+      let imported = g.importModuleCallback(g, module, fileInfoIdx(g.config, modpath))
       internalAssert g.config, imported.id < 0
   of nkStmtList, nkStmtListExpr:
     for x in n: replay(g, module, x)
@@ -868,16 +896,23 @@ proc setupModuleCache*(g: ModuleGraph) =
   let dbfile = getNimcacheDir(g.config) / RelativeFile"rodfiles.db"
   if g.config.symbolFiles == writeOnlySf:
     removeFile(dbfile)
+  createDir getNimcacheDir(g.config)
+  let ec = encodeConfig(g)
   if not fileExists(dbfile):
     db = open(connection=string dbfile, user="nim", password="",
               database="nim")
     createDb(db)
-    db.exec(sql"insert into config(config) values (?)", encodeConfig(g))
+    db.exec(sql"insert into config(config) values (?)", ec)
   else:
     db = open(connection=string dbfile, user="nim", password="",
               database="nim")
     let oldConfig = db.getValue(sql"select config from config")
-    g.incr.configChanged = oldConfig != encodeConfig(g)
+    g.incr.configChanged = oldConfig != ec
+    # ensure the filename IDs stay consistent:
+    for row in db.rows(sql"select fullpath, nimid from filenames order by nimid"):
+      let id = fileInfoIdx(g.config, AbsoluteFile row[0])
+      doAssert id.int == parseInt(row[1])
+    db.exec(sql"update config set config = ?", ec)
   db.exec(sql"pragma journal_mode=off")
   # This MUST be turned off, otherwise it's way too slow even for testing purposes:
   db.exec(sql"pragma SYNCHRONOUS=off")
diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim
index f94533177..bfff86479 100644
--- a/compiler/scriptconfig.nim
+++ b/compiler/scriptconfig.nim
@@ -123,6 +123,7 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
   cbconf setCommand:
     conf.command = a.getString 0
     let arg = a.getString 1
+    incl(conf.globalOptions, optWasNimscript)
     if arg.len > 0:
       conf.projectName = arg
       let path =
@@ -158,6 +159,8 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
 proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
                    freshDefines=true; conf: ConfigRef) =
   rawMessage(conf, hintConf, scriptName.string)
+  let oldSymbolFiles = conf.symbolFiles
+  conf.symbolFiles = disabledSf
 
   let graph = newModuleGraph(cache, conf)
   connectCallbacks(graph)
@@ -183,3 +186,4 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
   #initDefines()
   undefSymbol(conf.symbols, "nimscript")
   undefSymbol(conf.symbols, "nimconfig")
+  conf.symbolFiles = oldSymbolFiles
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 97a47ceca..775c9f7c9 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -16,13 +16,16 @@ import
   procfind, lookups, pragmas, passes, semdata, semtypinst, sigmatch,
   intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
   evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity,
-  semparallel, lowerings, pluginsupport, plugins/active, rod, lineinfos
+  lowerings, pluginsupport, plugins/active, rod, lineinfos
 
-from modulegraphs import ModuleGraph, PPassContext
+from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward
 
 when defined(nimfix):
   import nimfix/prettybase
 
+when not defined(leanCompiler):
+  import semparallel
+
 # implementation
 
 proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.procvar.}
@@ -447,7 +450,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
   pushInfoContext(c.config, nOrig.info, sym.detailedInfo)
 
   markUsed(c.config, n.info, sym, c.graph.usageSym)
-  styleCheckUse(n.info, sym)
+  onUse(n.info, sym)
   if sym == c.p.owner:
     globalError(c.config, n.info, "recursive dependency: '$1'" % sym.name.s)
 
diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim
index 7d6ae70de..3947e4f6c 100644
--- a/compiler/semasgn.nim
+++ b/compiler/semasgn.nim
@@ -81,8 +81,8 @@ proc genAddr(c: PContext; x: PNode): PNode =
     addSon(result, x)
 
 proc newAsgnCall(c: PContext; op: PSym; x, y: PNode): PNode =
-  if sfError in op.flags:
-    localError(c.config, x.info, "usage of '$1' is a user-defined error" % op.name.s)
+  #if sfError in op.flags:
+  #  localError(c.config, x.info, "usage of '$1' is a user-defined error" % op.name.s)
   result = newNodeI(nkCall, x.info)
   result.add newSymNode(op)
   result.add genAddr(c, x)
@@ -121,8 +121,11 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
       op = field
       if op == nil:
         op = liftBody(c.c, t, c.kind, c.info)
-    markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
-    styleCheckUse(c.info, op)
+    if sfError in op.flags:
+      incl c.fn.flags, sfError
+    else:
+      markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
+    onUse(c.info, op)
     body.add newAsgnCall(c.c, op, x, y)
     result = true
 
@@ -132,7 +135,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
     let op = t.destructor
     if op != nil:
       markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
-      styleCheckUse(c.info, op)
+      onUse(c.info, op)
       body.add destructorCall(c.c, op, x)
       result = true
   of attachedAsgn:
@@ -143,7 +146,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
     let op = t.deepCopy
     if op != nil:
       markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
-      styleCheckUse(c.info, op)
+      onUse(c.info, op)
       body.add newDeepCopyCall(op, x, y)
       result = true
 
@@ -200,7 +203,7 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
       tyPtr, tyRef, tyOpt, tyUncheckedArray:
     defaultOp(c, t, body, x, y)
   of tyArray:
-    if {tfHasAsgn, tfUncheckedArray} * t.flags == {tfHasAsgn}:
+    if tfHasAsgn in t.flags:
       let i = declareCounter(c, body, firstOrd(c.c.config, t))
       let whileLoop = genWhileLoop(c, i, x)
       let elemType = t.lastSon
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 49b344274..7e0ea5490 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -138,6 +138,7 @@ proc effectProblem(f, a: PType; result: var string) =
 
 proc renderNotLValue(n: PNode): string =
   result = $n
+  let n = if n.kind == nkHiddenDeref: n[0] else: n
   if n.kind == nkHiddenCallConv and n.len > 1:
     result = $n[0] & "(" & result & ")"
   elif n.kind in {nkHiddenStdConv, nkHiddenSubConv} and n.len == 2:
@@ -166,20 +167,22 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
       prefer = preferModuleInfo
       break
 
-  when false:
-    # we pretend procs are attached to the type of the first
-    # argument in order to remove plenty of candidates. This is
-    # comparable to what C# does and C# is doing fine.
-    var filterOnlyFirst = false
+  # we pretend procs are attached to the type of the first
+  # argument in order to remove plenty of candidates. This is
+  # comparable to what C# does and C# is doing fine.
+  var filterOnlyFirst = false
+  if optShowAllMismatches notin c.config.globalOptions:
     for err in errors:
       if err.firstMismatch > 1:
         filterOnlyFirst = true
         break
 
   var candidates = ""
+  var skipped = 0
   for err in errors:
-    when false:
-      if filterOnlyFirst and err.firstMismatch == 1: continue
+    if filterOnlyFirst and err.firstMismatch == 1:
+      inc skipped
+      continue
     if err.sym.kind in routineKinds and err.sym.ast != nil:
       add(candidates, renderTree(err.sym.ast,
             {renderNoBody, renderNoComments, renderNoPragmas}))
@@ -216,7 +219,9 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
                       "' is immutable\n")
     for diag in err.diagnostics:
       candidates.add(diag & "\n")
-
+  if skipped > 0:
+    candidates.add($skipped & " other mismatching symbols have been " &
+        " suppressed; compile with --showAllMismatches:on to see them\n")
   result = (prefer, candidates)
 
 const
@@ -390,6 +395,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
         args])
 
 proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) =
+  let a = if a.kind == nkHiddenDeref: a[0] else: a
   if a.kind == nkHiddenCallConv and a.sons[0].kind == nkSym:
     let s = a.sons[0].sym
     if s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty:
@@ -450,7 +456,7 @@ proc semResolvedCall(c: PContext, x: TCandidate,
   assert x.state == csMatch
   var finalCallee = x.calleeSym
   markUsed(c.config, n.sons[0].info, finalCallee, c.graph.usageSym)
-  styleCheckUse(n.sons[0].info, finalCallee)
+  onUse(n.sons[0].info, finalCallee)
   assert finalCallee.ast != nil
   if x.hasFauxMatch:
     result = x.call
@@ -558,14 +564,17 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
   var newInst = generateInstance(c, s, m.bindings, n.info)
   newInst.typ.flags.excl tfUnresolved
   markUsed(c.config, n.info, s, c.graph.usageSym)
-  styleCheckUse(n.info, s)
+  onUse(n.info, s)
   result = newSymNode(newInst, n.info)
 
 proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
   assert n.kind == nkBracketExpr
   for i in 1..sonsLen(n)-1:
     let e = semExpr(c, n.sons[i])
-    n.sons[i].typ = e.typ.skipTypes({tyTypeDesc})
+    if e.typ == nil:
+      localError(c.config, e.info, "expression has no type")
+    else:
+      n.sons[i].typ = e.typ.skipTypes({tyTypeDesc})
   var s = s
   var a = n.sons[0]
   if a.kind == nkSym:
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 1725d7a31..669862c56 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -25,7 +25,7 @@ const
 proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
                      flags: TExprFlags = {}): PNode =
   markUsed(c.config, n.info, s, c.graph.usageSym)
-  styleCheckUse(n.info, s)
+  onUse(n.info, s)
   pushInfoContext(c.config, n.info, s.detailedInfo)
   result = evalTemplate(n, s, getCurrOwner(c), c.config, efFromHlo in flags)
   if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags)
@@ -265,7 +265,7 @@ proc semConv(c: PContext, n: PNode): PNode =
       let status = checkConvertible(c, result.typ, it.typ)
       if status in {convOK, convNotNeedeed}:
         markUsed(c.config, n.info, it.sym, c.graph.usageSym)
-        styleCheckUse(n.info, it.sym)
+        onUse(n.info, it.sym)
         markIndirect(c, it.sym)
         return it
     errorUseQualifier(c, n.info, op.sons[0].sym)
@@ -614,7 +614,8 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
   const
     FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl,
       mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap,
-      mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy}
+      mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy, mMove,
+      mWasMoved}
 
   # get the real type of the callee
   # it may be a proc var with a generic alias type, so we skip over them
@@ -640,6 +641,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
 
     return
   for i in countup(1, sonsLen(n) - 1):
+    let n = if n.kind == nkHiddenDeref: n[0] else: n
     if n.sons[i].kind == nkHiddenCallConv:
       # we need to recurse explicitly here as converters can create nested
       # calls and then they wouldn't be analysed otherwise
@@ -1036,7 +1038,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
   case s.kind
   of skConst:
     markUsed(c.config, n.info, s, c.graph.usageSym)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
     of  tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
         tyTuple, tySet, tyUInt..tyUInt64:
@@ -1061,7 +1063,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
     if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or
        (n.kind notin nkCallKinds and s.requiredParams > 0):
       markUsed(c.config, n.info, s, c.graph.usageSym)
-      styleCheckUse(n.info, s)
+      onUse(n.info, s)
       result = symChoice(c, n, s, scClosed)
     else:
       result = semMacroExpr(c, n, n, s, flags)
@@ -1070,13 +1072,13 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
        (n.kind notin nkCallKinds and s.requiredParams > 0) or
        sfCustomPragma in sym.flags:
       markUsed(c.config, n.info, s, c.graph.usageSym)
-      styleCheckUse(n.info, s)
+      onUse(n.info, s)
       result = symChoice(c, n, s, scClosed)
     else:
       result = semTemplateExpr(c, n, s, flags)
   of skParam:
     markUsed(c.config, n.info, s, c.graph.usageSym)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     if s.typ != nil and s.typ.kind == tyStatic and s.typ.n != nil:
       # XXX see the hack in sigmatch.nim ...
       return s.typ.n
@@ -1098,14 +1100,14 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
       localError(c.config, n.info, "illegal context for 'nimvm' magic")
 
     markUsed(c.config, n.info, s, c.graph.usageSym)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     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:
     # var len = 0 # but won't be called
     # genericThatUsesLen(x) # marked as taking a closure?
   of skGenericParam:
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     if s.typ.kind == tyStatic:
       result = newSymNode(s, n.info)
       result.typ = s.typ
@@ -1116,7 +1118,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
       return n
   of skType:
     markUsed(c.config, n.info, s, c.graph.usageSym)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     if s.typ.kind == tyStatic and s.typ.base.kind != tyNone and s.typ.n != nil:
       return s.typ.n
     result = newSymNode(s, n.info)
@@ -1138,7 +1140,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
             # is the access to a public field or in the same module or in a friend?
             doAssert f == s
             markUsed(c.config, n.info, f, c.graph.usageSym)
-            styleCheckUse(n.info, f)
+            onUse(n.info, f)
             result = newNodeIT(nkDotExpr, n.info, f.typ)
             result.add makeDeref(newSymNode(p.selfSym))
             result.add newSymNode(f) # we now have the correct field
@@ -1151,11 +1153,11 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
           ty = skipTypes(ty.sons[0], skipPtrs)
     # old code, not sure if it's live code:
     markUsed(c.config, n.info, s, c.graph.usageSym)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     result = newSymNode(s, n.info)
   else:
     markUsed(c.config, n.info, s, c.graph.usageSym)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     result = newSymNode(s, n.info)
 
 proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
@@ -1178,7 +1180,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
     else:
       markUsed(c.config, n.sons[1].info, s, c.graph.usageSym)
       result = semSym(c, n, s, flags)
-    styleCheckUse(n.sons[1].info, s)
+    onUse(n.sons[1].info, s)
     return
 
   n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType})
@@ -1241,7 +1243,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
         result.info = n.info
         result.typ = ty
         markUsed(c.config, n.info, f, c.graph.usageSym)
-        styleCheckUse(n.info, f)
+        onUse(n.info, f)
         return
     of tyObject, tyTuple:
       if ty.n != nil and ty.n.kind == nkRecList:
@@ -1272,7 +1274,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
       if fieldVisible(c, f):
         # is the access to a public field or in the same module or in a friend?
         markUsed(c.config, n.sons[1].info, f, c.graph.usageSym)
-        styleCheckUse(n.sons[1].info, f)
+        onUse(n.sons[1].info, f)
         n.sons[0] = makeDeref(n.sons[0])
         n.sons[1] = newSymNode(f) # we now have the correct field
         n.typ = f.typ
@@ -1286,7 +1288,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
     f = getSymFromList(ty.n, i)
     if f != nil:
       markUsed(c.config, n.sons[1].info, f, c.graph.usageSym)
-      styleCheckUse(n.sons[1].info, f)
+      onUse(n.sons[1].info, f)
       n.sons[0] = makeDeref(n.sons[0])
       n.sons[1] = newSymNode(f)
       n.typ = f.typ
@@ -1538,7 +1540,9 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
   # a = b # both are vars, means: a[] = b[]
   # a = b # b no 'var T' means: a = addr(b)
   var le = a.typ
-  if (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind != tyVar and
+  if le == nil:
+    localError(c.config, a.info, "expression has no type")
+  elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind != tyVar and
         isAssignable(c, a) == arNone) or
       skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs}:
     # Direct assignment to a discriminant is allowed!
@@ -1756,7 +1760,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
 
     macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
     markUsed(c.config, n.info, expandedSym, c.graph.usageSym)
-    styleCheckUse(n.info, expandedSym)
+    onUse(n.info, expandedSym)
 
   if isCallExpr(macroCall):
     for i in countup(1, macroCall.len-1):
@@ -1781,7 +1785,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
       let info = macroCall.sons[0].info
       macroCall.sons[0] = newSymNode(cand, info)
       markUsed(c.config, info, cand, c.graph.usageSym)
-      styleCheckUse(info, cand)
+      onUse(info, cand)
 
     # we just perform overloading resolution here:
     #n.sons[1] = semOverloadedCall(c, macroCall, macroCall, {skTemplate, skMacro})
@@ -1811,6 +1815,7 @@ proc processQuotations(c: PContext; n: var PNode, op: string,
     ids.add n
     return
 
+
   if n.kind == nkPrefix:
     checkSonsLen(n, 2, c.config)
     if n[0].kind == nkIdent:
@@ -1821,6 +1826,9 @@ proc processQuotations(c: PContext; n: var PNode, op: string,
         n.sons[0] = newIdentNode(getIdent(c.cache, examinedOp.substr(op.len)), n.info)
   elif n.kind == nkAccQuoted and op == "``":
     returnQuote n[0]
+  elif n.kind == nkIdent:
+    if n.ident.s == "result":
+      n = ids[0]
 
   for i in 0 ..< n.safeLen:
     processQuotations(c, n.sons[i], op, quotes, ids)
@@ -1832,15 +1840,18 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
   var
     quotedBlock = n[^1]
     op = if n.len == 3: expectString(c, n[1]) else: "``"
-    quotes = newSeq[PNode](1)
+    quotes = newSeq[PNode](2)
       # the quotes will be added to a nkCall statement
-      # leave some room for the callee symbol
-    ids = newSeq[PNode]()
+      # leave some room for the callee symbol and the result symbol
+    ids = newSeq[PNode](1)
       # this will store the generated param names
+      # leave some room for the result symbol
 
   if quotedBlock.kind != nkStmtList:
     localError(c.config, n.info, errXExpected, "block")
 
+  # This adds a default first field to pass the result symbol
+  ids[0] = newAnonSym(c, skParam, n.info).newSymNode
   processQuotations(c, quotedBlock, op, quotes, ids)
 
   var dummyTemplate = newProcNode(
@@ -1859,6 +1870,8 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
 
   var tmpl = semTemplateDef(c, dummyTemplate)
   quotes[0] = tmpl[namePos]
+  # This adds a call to newIdentNode("result") as the first argument to the template call
+  quotes[1] = newNode(nkCall, n.info, @[newIdentNode(getIdent(c.cache, "newIdentNode"), n.info), newStrNode(nkStrLit, "result")])
   result = newNode(nkCall, n.info, @[
      createMagic(c.graph, "getAst", mExpandToAst).newSymNode,
     newNode(nkCall, n.info, quotes)])
@@ -2254,6 +2267,7 @@ proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode =
     n.sons[0] = newSymNode(labl, n.sons[0].info)
     suggestSym(c.config, n.sons[0].info, labl, c.graph.usageSym)
     styleCheckDef(c.config, labl)
+    onDef(n[0].info, labl)
   n.sons[1] = semExpr(c, n.sons[1], flags)
   n.typ = n.sons[1].typ
   if isEmptyType(n.typ): n.kind = nkBlockStmt
@@ -2332,7 +2346,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
         {checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields}
     var s = qualifiedLookUp(c, n, checks)
     if c.matchedConcept == nil: semCaptureSym(s, c.p.owner)
-    result = semSym(c, n, s, flags)
     if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator}:
       #performProcvarCheck(c, n, s)
       result = symChoice(c, n, s, scClosed)
@@ -2340,6 +2353,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
         markIndirect(c, result.sym)
         # if isGenericRoutine(result.sym):
         #   localError(c.config, n.info, errInstantiateXExplicitly, s.name.s)
+    else:
+      result = semSym(c, n, s, flags)
   of nkSym:
     # because of the changed symbol binding, this does not mean that we
     # don't have to check the symbol for semantics here again!
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 5565e8ed9..5ec702257 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -267,12 +267,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
   of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n, g)
   of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n, g)
   of mDivF64:
-    if getFloat(b) == 0.0:
-      if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n, g)
-      elif getFloat(b).classify == fcNegZero: result = newFloatNodeT(-Inf, n, g)
-      else: result = newFloatNodeT(Inf, n, g)
-    else:
-      result = newFloatNodeT(getFloat(a) / getFloat(b), n, g)
+    result = newFloatNodeT(getFloat(a) / getFloat(b), n, g)
   of mMaxF64:
     if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n, g)
     else: result = newFloatNodeT(getFloat(b), n, g)
@@ -413,15 +408,14 @@ proc getAppType(n: PNode; g: ModuleGraph): PNode =
     result = newStrNodeT("console", n, g)
 
 proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) =
-  if tfUncheckedArray notin n.typ.flags:
-    var err = false
-    if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}:
-      err = value <% firstOrd(g.config, n.typ) or value >% lastOrd(g.config, n.typ, fixedUnsigned=true)
-    else:
-      err = value < firstOrd(g.config, n.typ) or value > lastOrd(g.config, n.typ)
-    if err:
-      localError(g.config, n.info, "cannot convert " & $value &
-                                      " to " & typeToString(n.typ))
+  var err = false
+  if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}:
+    err = value <% firstOrd(g.config, n.typ) or value >% lastOrd(g.config, n.typ, fixedUnsigned=true)
+  else:
+    err = value < firstOrd(g.config, n.typ) or value > lastOrd(g.config, n.typ)
+  if err:
+    localError(g.config, n.info, "cannot convert " & $value &
+                                    " to " & typeToString(n.typ))
 
 proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode =
   let dstTyp = skipTypes(n.typ, abstractRange)
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index a0044a0af..5972f3b55 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -76,14 +76,14 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
     result = symChoice(c, n, s, scOpen)
   of skTemplate:
     if macroToExpandSym(s):
-      styleCheckUse(n.info, s)
+      onUse(n.info, s)
       result = semTemplateExpr(c, n, s, {efNoSemCheck})
       result = semGenericStmt(c, result, {}, ctx)
     else:
       result = symChoice(c, n, s, scOpen)
   of skMacro:
     if macroToExpandSym(s):
-      styleCheckUse(n.info, s)
+      onUse(n.info, s)
       result = semMacroExpr(c, n, n, s, {efNoSemCheck})
       result = semGenericStmt(c, result, {}, ctx)
     else:
@@ -96,20 +96,20 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
         result = n
     else:
       result = newSymNodeTypeDesc(s, n.info)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
   of skParam:
     result = n
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
   of skType:
     if (s.typ != nil) and
        (s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}):
       result = newSymNodeTypeDesc(s, n.info)
     else:
       result = n
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
   else:
     result = newSymNode(s, n.info)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
 
 proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
             ctx: var GenericCtx): PNode =
@@ -172,6 +172,7 @@ proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
   let s = newSymS(skUnknown, getIdentNode(c, n), c)
   addPrelimDecl(c, s)
   styleCheckDef(c.config, n.info, s, kind)
+  onDef(n.info, s)
 
 proc semGenericStmt(c: PContext, n: PNode,
                     flags: TSemGenericFlags, ctx: var GenericCtx): PNode =
@@ -230,7 +231,7 @@ proc semGenericStmt(c: PContext, n: PNode,
       case s.kind
       of skMacro:
         if macroToExpand(s) and sc.safeLen <= 1:
-          styleCheckUse(fn.info, s)
+          onUse(fn.info, s)
           result = semMacroExpr(c, n, n, s, {efNoSemCheck})
           result = semGenericStmt(c, result, flags, ctx)
         else:
@@ -239,7 +240,7 @@ proc semGenericStmt(c: PContext, n: PNode,
         mixinContext = true
       of skTemplate:
         if macroToExpand(s) and sc.safeLen <= 1:
-          styleCheckUse(fn.info, s)
+          onUse(fn.info, s)
           result = semTemplateExpr(c, n, s, {efNoSemCheck})
           result = semGenericStmt(c, result, flags, ctx)
         else:
@@ -262,17 +263,17 @@ proc semGenericStmt(c: PContext, n: PNode,
           inc first
       of skGenericParam:
         result.sons[0] = newSymNodeTypeDesc(s, fn.info)
-        styleCheckUse(fn.info, s)
+        onUse(fn.info, s)
         first = 1
       of skType:
         # bad hack for generics:
         if (s.typ != nil) and (s.typ.kind != tyGenericParam):
           result.sons[0] = newSymNodeTypeDesc(s, fn.info)
-          styleCheckUse(fn.info, s)
+          onUse(fn.info, s)
           first = 1
       else:
         result.sons[0] = newSymNode(s, fn.info)
-        styleCheckUse(fn.info, s)
+        onUse(fn.info, s)
         first = 1
     elif fn.kind == nkDotExpr:
       result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 09d971236..2aae562f9 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -306,7 +306,13 @@ proc semOf(c: PContext, n: PNode): PNode =
         result.typ = getSysType(c.graph, n.info, tyBool)
         return result
       elif diff == high(int):
-        localError(c.config, n.info, "'$1' cannot be of this subtype" % typeToString(a))
+        if commonSuperclass(a, b) == nil:
+          localError(c.config, n.info, "'$1' cannot be of this subtype" % typeToString(a))
+        else:
+          message(c.config, n.info, hintConditionAlwaysFalse, renderTree(n))
+          result = newIntNode(nkIntLit, 0)
+          result.info = n.info
+          result.typ = getSysType(c.graph, n.info, tyBool)
   else:
     localError(c.config, n.info, "'of' takes 2 arguments")
   n.typ = getSysType(c.graph, n.info, tyBool)
@@ -329,23 +335,19 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
   of mTypeOf:
     result = semTypeOf(c, n)
   of mSizeOf:
-      # TODO there is no proper way to find out if a type cannot be queried for the size.
-      let size = getSize(c.config, n[1].typ)
-      # We just assume here that the type might come from the c backend
-      if size == szUnknownSize:
-        # Forward to the c code generation to emit a `sizeof` in the C code.
-        result = n
-      elif size >= 0:
-        result = newIntNode(nkIntLit, size)
-        result.info = n.info
-        result.typ = n.typ
-      else:
-
-        localError(c.config, n.info, "cannot evaluate 'sizeof' because its type is not defined completely")
-
-        result = nil
-
-
+    # TODO there is no proper way to find out if a type cannot be queried for the size.
+    let size = getSize(c.config, n[1].typ)
+    # We just assume here that the type might come from the c backend
+    if size == szUnknownSize:
+      # Forward to the c code generation to emit a `sizeof` in the C code.
+      result = n
+    elif size >= 0:
+      result = newIntNode(nkIntLit, size)
+      result.info = n.info
+      result.typ = n.typ
+    else:
+      localError(c.config, n.info, "cannot evaluate 'sizeof' because its type is not defined completely")
+      result = n
   of mAlignOf:
     result = newIntNode(nkIntLit, getAlign(c.config, n[1].typ))
     result.info = n.info
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index c1bdb08a8..0317fd8ba 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -9,9 +9,12 @@
 
 import
   intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
-  wordrecg, strutils, options, guards, writetracking, lineinfos, semfold,
+  wordrecg, strutils, options, guards, lineinfos, semfold,
   modulegraphs
 
+when not defined(leanCompiler):
+  import writetracking
+
 when defined(useDfa):
   import dfa
 
@@ -713,7 +716,7 @@ proc track(tracked: PEffects, n: PNode) =
       track(tracked, n.sons[i])
   of nkCallKinds:
     if getConstExpr(tracked.owner_module, n, tracked.graph) != nil:
-      return 
+      return
     # p's effects are ours too:
     var a = n.sons[0]
     let op = a.typ
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 5c7f866ce..1f2b9f0b3 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -41,8 +41,13 @@ proc semDiscard(c: PContext, n: PNode): PNode =
   checkSonsLen(n, 1, c.config)
   if n.sons[0].kind != nkEmpty:
     n.sons[0] = semExprWithType(c, n.sons[0])
-    if isEmptyType(n.sons[0].typ) or n.sons[0].typ.kind == tyNone or n.sons[0].kind == nkTypeOfExpr:
+    let sonType = n.sons[0].typ
+    let sonKind = n.sons[0].kind
+    if isEmptyType(sonType) or sonType.kind == tyNone or n.sons[0].kind == nkTypeOfExpr:
       localError(c.config, n.info, errInvalidDiscard)
+    if sonType.kind == tyProc and sonKind notin nkCallKinds:
+      # tyProc is disallowed to prevent ``discard foo`` to be valid, when ``discard foo()`` is meant.
+      localError(c.config, n.info, "illegal discard proc, did you mean: " & $n[0] & "()")
 
 proc semBreakOrContinue(c: PContext, n: PNode): PNode =
   result = n
@@ -61,7 +66,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
         incl(s.flags, sfUsed)
         n.sons[0] = x
         suggestSym(c.config, x.info, s, c.graph.usageSym)
-        styleCheckUse(x.info, s)
+        onUse(x.info, s)
       else:
         localError(c.config, n.info, errInvalidControlFlowX % s.name.s)
     else:
@@ -359,6 +364,7 @@ proc semUsing(c: PContext; n: PNode): PNode =
       for j in countup(0, length-3):
         let v = semIdentDef(c, a.sons[j], skParam)
         styleCheckDef(c.config, v)
+        onDef(a[j].info, v)
         v.typ = typ
         strTableIncl(c.signatures, v)
     else:
@@ -490,6 +496,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
         continue
       var v = semIdentDef(c, a.sons[j], symkind)
       styleCheckDef(c.config, v)
+      onDef(a[j].info, v)
       if sfGenSym notin v.flags and not isDiscardUnderscore(v):
         addInterfaceDecl(c, v)
       when oKeepVariableNames:
@@ -544,6 +551,7 @@ proc semConst(c: PContext, n: PNode): PNode =
     checkSonsLen(a, 3, c.config)
     var v = semIdentDef(c, a.sons[0], skConst)
     styleCheckDef(c.config, v)
+    onDef(a[0].info, v)
     var typ: PType = nil
     if a.sons[1].kind != nkEmpty: typ = semTypeNode(c, a.sons[1], nil)
 
@@ -587,6 +595,7 @@ proc symForVar(c: PContext, n: PNode): PSym =
   let m = if n.kind == nkPragmaExpr: n.sons[0] else: n
   result = newSymG(skForVar, m, c)
   styleCheckDef(c.config, result)
+  onDef(n.info, result)
   if n.kind == nkPragmaExpr:
     pragma(c, result, n.sons[1], forVarPragmas)
 
@@ -692,7 +701,7 @@ proc handleCaseStmtMacro(c: PContext; n: PNode): PNode =
   if r.state == csMatch:
     var match = r.calleeSym
     markUsed(c.config, n[0].info, match, c.graph.usageSym)
-    styleCheckUse(n[0].info, match)
+    onUse(n[0].info, match)
 
     # but pass 'n' to the 'match' macro, not 'n[0]':
     r.call.sons[1] = n
@@ -876,6 +885,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
         if typsym.isNil:
           s = semIdentDef(c, name[1], skType)
           styleCheckDef(c.config, s)
+          onDef(name[1].info, s)
           s.typ = newTypeS(tyObject, c)
           s.typ.sym = s
           s.flags.incl sfForward
@@ -890,6 +900,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
     else:
       s = semIdentDef(c, name, skType)
       styleCheckDef(c.config, s)
+      onDef(name.info, s)
       s.typ = newTypeS(tyForward, c)
       s.typ.sym = s             # process pragmas:
       if name.kind == nkPragmaExpr:
@@ -1621,6 +1632,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     else:
       implicitPragmas(c, s, n, validPragmas)
     styleCheckDef(c.config, s)
+    onDef(n[namePos].info, s)
   else:
     if n.sons[pragmasPos].kind != nkEmpty:
       pragma(c, s, n.sons[pragmasPos], validPragmas)
@@ -1634,6 +1646,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
         localError(c.config, n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX %
           ("'" & proto.name.s & "' from " & c.config$proto.info))
     styleCheckDef(c.config, s)
+    onDefResolveForward(n[namePos].info, proto)
     if sfForward notin proto.flags and proto.magic == mNone:
       wrongRedefinition(c, n.info, proto.name.s, proto.info)
     excl(proto.flags, sfForward)
@@ -1666,7 +1679,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
       localError(c.config, n.info, "the overloaded " & s.name.s &
         " operator has to be enabled with {.experimental: \"callOperator\".}")
 
-  if n.sons[bodyPos].kind != nkEmpty:
+  if n.sons[bodyPos].kind != nkEmpty and sfError notin s.flags:
     # for DLL generation it is annoying to check for sfImportc!
     if sfBorrow in s.flags:
       localError(c.config, n.sons[bodyPos].info, errImplOfXNotAllowed % s.name.s)
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index a64315037..14507cf9d 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -64,6 +64,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
     # for instance 'nextTry' is both in tables.nim and astalgo.nim ...
     result = newSymNode(s, n.info)
     markUsed(c.config, n.info, s, c.graph.usageSym)
+    onUse(n.info, s)
   else:
     # semantic checking requires a type; ``fitNode`` deals with it
     # appropriately
@@ -75,6 +76,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
       if a.kind != skModule:
         incl(a.flags, sfUsed)
         addSon(result, newSymNode(a, n.info))
+        onUse(n.info, a)
       a = nextOverloadIter(o, c, n)
 
 proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
@@ -160,7 +162,7 @@ proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode =
       if s.owner == c.owner and s.kind == skParam:
         incl(s.flags, sfUsed)
         result = newSymNode(s, n.info)
-        styleCheckUse(n.info, s)
+        onUse(n.info, s)
   else:
     for i in 0 ..< n.safeLen:
       result.sons[i] = onlyReplaceParams(c, n.sons[i])
@@ -208,19 +210,20 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
       # So we need only check the *current* scope.
       let s = localSearchInScope(c.c, considerQuotedIdent(c.c, ident))
       if s != nil and s.owner == c.owner and sfGenSym in s.flags:
-        styleCheckUse(n.info, s)
+        onUse(n.info, s)
         replaceIdentBySym(c.c, n, newSymNode(s, n.info))
       elif not (n.kind == nkSym and sfGenSym in n.sym.flags):
         let local = newGenSym(k, ident, c)
         addPrelimDecl(c.c, local)
         styleCheckDef(c.c.config, n.info, local)
+        onDef(n.info, local)
         replaceIdentBySym(c.c, n, newSymNode(local, n.info))
     else:
       replaceIdentBySym(c.c, n, ident)
 
 proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
   incl(s.flags, sfUsed)
-  # we do not call styleCheckUse here, as the identifier is not really
+  # we do not call onUse here, as the identifier is not really
   # resolved here. We will fixup the used identifiers later.
   case s.kind
   of skUnknown:
@@ -245,7 +248,7 @@ proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
       if s.owner == c.owner and (s.kind == skParam or sfGenSym in s.flags):
         incl(s.flags, sfUsed)
         result = newSymNode(s, n.info)
-        styleCheckUse(n.info, s)
+        onUse(n.info, s)
   else:
     for i in countup(0, safeLen(n) - 1):
       result.sons[i] = semRoutineInTemplName(c, n.sons[i])
@@ -261,6 +264,7 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
       s.ast = n
       addPrelimDecl(c.c, s)
       styleCheckDef(c.c.config, n.info, s)
+      onDef(n.info, s)
       n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
     else:
       n.sons[namePos] = ident
@@ -314,7 +318,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
       if s.owner == c.owner and s.kind == skParam:
         incl(s.flags, sfUsed)
         result = newSymNode(s, n.info)
-        styleCheckUse(n.info, s)
+        onUse(n.info, s)
       elif contains(c.toBind, s.id):
         result = symChoice(c.c, n, s, scClosed)
       elif contains(c.toMixin, s.name.id):
@@ -324,7 +328,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
         # var yz: T
         incl(s.flags, sfUsed)
         result = newSymNode(s, n.info)
-        styleCheckUse(n.info, s)
+        onUse(n.info, s)
       else:
         result = semTemplSymbol(c.c, n, s)
   of nkBind:
@@ -382,6 +386,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
         let s = newGenSym(skLabel, n.sons[0], c)
         addPrelimDecl(c.c, s)
         styleCheckDef(c.c.config, s)
+        onDef(n[0].info, s)
         n.sons[0] = newSymNode(s, n.sons[0].info)
     n.sons[1] = semTemplBody(c, n.sons[1])
     closeScope(c)
@@ -505,7 +510,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
       if s.owner == c.owner and s.kind == skParam and
           n.kind == nkAccQuoted and n.len == 1:
         incl(s.flags, sfUsed)
-        styleCheckUse(n.info, s)
+        onUse(n.info, s)
         return newSymNode(s, n.info)
       elif contains(c.toBind, s.id):
         return symChoice(c.c, n, s, scClosed)
@@ -553,6 +558,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
   else:
     s = semIdentVis(c, skTemplate, n.sons[0], {})
   styleCheckDef(c.config, s)
+  onDef(n[0].info, s)
   # check parameter list:
   #s.scope = c.currentScope
   pushOwner(c, s)
@@ -635,7 +641,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
     # semtypes.addParamOrResult). Within the pattern we have to ensure
     # to use the param with the proper type though:
     incl(s.flags, sfUsed)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     let x = c.owner.typ.n.sons[s.position+1].sym
     assert x.name == s.name
     result = newSymNode(x, n.info)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 5215a1d11..f4a1b0302 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -122,6 +122,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
       if not isPure: strTableAdd(c.module.tab, e)
     addSon(result.n, newSymNode(e))
     styleCheckDef(c.config, e)
+    onDef(e.info, e)
     if sfGenSym notin e.flags:
       if not isPure: addDecl(c, e)
       else: importPureEnumField(c, e)
@@ -377,7 +378,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
       result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
     if result != nil:
       markUsed(c.config, n.info, result, c.graph.usageSym)
-      styleCheckUse(n.info, result)
+      onUse(n.info, result)
 
       if result.kind == skParam and result.typ.kind == tyTypeDesc:
         # This is a typedesc param. is it already bound?
@@ -466,6 +467,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
         addSon(result.n, newSymNode(field))
         addSonSkipIntLit(result, typ)
       styleCheckDef(c.config, a.sons[j].info, field)
+      onDef(field.info, field)
   if result.n.len == 0: result.n = nil
 
 proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
@@ -688,7 +690,6 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
                      else: rectype.sym
     for i in countup(0, sonsLen(n)-3):
       var f = semIdentWithPragma(c, skField, n.sons[i], {sfExported})
-      styleCheckDef(c.config, n.sons[i].info, f)
       suggestSym(c.config, n.sons[i].info, f, c.graph.usageSym)
       f.typ = typ
       f.position = pos
@@ -703,6 +704,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
       if a.kind == nkEmpty: addSon(father, newSymNode(f))
       else: addSon(a, newSymNode(f))
       styleCheckDef(c.config, f)
+      onDef(f.info, f)
     if a.kind != nkEmpty: addSon(father, a)
   of nkSym:
     # This branch only valid during generic object
@@ -988,7 +990,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
 
   of tyGenericParam:
     markUsed(c.config, info, paramType.sym, c.graph.usageSym)
-    styleCheckUse(info, paramType.sym)
+    onUse(info, paramType.sym)
     if tfWildcard in paramType.flags:
       paramType.flags.excl tfWildcard
       paramType.sym.kind = skType
@@ -1110,6 +1112,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       rawAddSon(result, finalType)
       addParamOrResult(c, arg, kind)
       styleCheckDef(c.config, a.sons[j].info, arg)
+      onDef(a[j].info, arg)
 
   var r: PType
   if n.sons[0].kind != nkEmpty:
@@ -1621,8 +1624,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
         result = prev
   of nkSym:
     let s = getGenSym(c, n.sym)
-    if s.kind == skType and s.typ != nil or
-      s.kind == skParam and s.typ.kind == tyTypeDesc:
+    if s.typ != nil and (s.kind == skType or s.typ.kind == tyTypeDesc):
       var t =
         if s.kind == skType:
           s.typ
@@ -1638,7 +1640,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
         assignType(prev, t)
         result = prev
       markUsed(c.config, n.info, n.sym, c.graph.usageSym)
-      styleCheckUse(n.info, n.sym)
+      onUse(n.info, n.sym)
     else:
       if s.kind != skError: localError(c.config, n.info, errTypeExpected)
       result = newOrPrevType(tyError, prev, c)
@@ -1745,10 +1747,8 @@ proc processMagicType(c: PContext, m: PSym) =
       setMagicType(c.config, m, tyAnything, 0)
     else:
       setMagicType(c.config, m, tyExpr, 0)
-      if m.name.s == "expr": m.typ.flags.incl tfOldSchoolExprStmt
   of mStmt:
     setMagicType(c.config, m, tyStmt, 0)
-    if m.name.s == "stmt": m.typ.flags.incl tfOldSchoolExprStmt
   of mTypeDesc, mType:
     setMagicType(c.config, m, tyTypeDesc, 0)
     rawAddSon(m.typ, newTypeS(tyNone, c))
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index be6ffc586..b05fb37ae 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -30,11 +30,6 @@ proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) =
     localError(conf, info, "type 'var var' is not allowed")
   elif computeSize(conf, t) == szIllegalRecursion:
     localError(conf, info,  "illegal recursion in type '" & typeToString(t) & "'")
-
-  t = typ.skipTypes({tyGenericInst})
-  if t.kind == tyArray and tfUncheckedArray in t.flags:
-    t[0].flags.incl tfUncheckedArray # mark range of unchecked array also unchecked
-
   when false:
     if t.kind == tyObject and t.sons[0] != nil:
       if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 4dc7690ef..4adf0bed3 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -13,9 +13,9 @@
 import
   intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
   magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees,
-  linter, lineinfos
+  linter, lineinfos, lowerings, modulegraphs
 
-when defined(booting) or defined(nimsuggest):
+when (defined(booting) or defined(nimsuggest)) and not defined(leanCompiler):
   import docgen
 
 type
@@ -1210,9 +1210,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
     if f.kind == tyVarargs:
       if tfVarargs in a.flags:
         return typeRel(c, f.base, a.lastSon)
-      if tfOldSchoolExprStmt in f.sons[0].flags:
-        if f.sons[0].kind == tyExpr: return
-      elif f.sons[0].kind == tyStmt: return
+      if f.sons[0].kind == tyStmt: return
 
     template matchArrayOrSeq(aBase: PType) =
       let ff = f.base
@@ -1758,7 +1756,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
         result = isNone
 
   of tyStmt:
-    if aOrig != nil and tfOldSchoolExprStmt notin f.flags:
+    if aOrig != nil:
       put(c, f, aOrig)
     result = isGeneric
 
@@ -1857,8 +1855,14 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
       else:
         param = copyTree(arg)
       addSon(result, param)
+
+      if dest.kind in {tyVar, tyLent}:
+        dest.flags.incl tfVarIsPtr
+        result = newDeref(result)
+
       inc(m.convMatches)
-      m.genericConverter = srca == isGeneric or destIsGeneric
+      if m.genericConverter == false:
+        m.genericConverter = srca == isGeneric or destIsGeneric
       return result
 
 proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
@@ -2151,7 +2155,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
     else:
       # only one valid interpretation found:
       markUsed(m.c.config, arg.info, arg.sons[best].sym, m.c.graph.usageSym)
-      styleCheckUse(arg.info, arg.sons[best].sym)
+      onUse(arg.info, arg.sons[best].sym)
       result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
                                   argOrig)
   when false:
@@ -2215,8 +2219,7 @@ proc incrIndexType(t: PType) =
   inc t.sons[0].n.sons[1].intVal
 
 template isVarargsUntyped(x): untyped =
-  x.kind == tyVarargs and x.sons[0].kind == tyExpr and
-    tfOldSchoolExprStmt notin x.sons[0].flags
+  x.kind == tyVarargs and x.sons[0].kind == tyExpr
 
 proc matchesAux(c: PContext, n, nOrig: PNode,
                 m: var TCandidate, marker: var IntSet) =
diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim
index 573b27094..4791788fa 100644
--- a/compiler/sizealignoffsetimpl.nim
+++ b/compiler/sizealignoffsetimpl.nim
@@ -1,3 +1,12 @@
+#
+#
+#           The Nim Compiler
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+## code owner: Arne Döring
+## e-mail: arne.doering@gmx.net
 
 proc align(address, alignment: BiggestInt): BiggestInt =
   result = (address + (alignment - 1)) and not (alignment - 1)
@@ -118,9 +127,14 @@ proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, initialOffset:
       result.offset = align(offset, result.align)
 
   of nkSym:
-    computeSizeAlign(conf, n.sym.typ)
-    let size = n.sym.typ.size
-    let align = n.sym.typ.align
+    var size = szUnknownSize
+    var align = szUnknownSize
+
+    if n.sym.bitsize == 0: # 0 represents bitsize not set
+      computeSizeAlign(conf, n.sym.typ)
+      size = n.sym.typ.size.int
+      align = n.sym.typ.align.int
+
     result.align = align
     if initialOffset == szUnknownSize or size == szUnknownSize:
       n.sym.offset = szUnknownSize
@@ -309,16 +323,24 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
     var headerAlign: int16
     if typ.sons[0] != nil:
       # compute header size
-      var st = typ.sons[0]
-      while st.kind in skipPtrs:
-        st = st.sons[^1]
-      computeSizeAlign(conf, st)
-      if st.size == szIllegalRecursion:
-        typ.size = st.size
-        typ.align = st.align
-        return
-      headerSize = st.size
-      headerAlign = st.align
+
+      if conf.cmd == cmdCompileToCpp:
+        # if the target is C++ the members of this type are written
+        # into the padding byets at the end of the parent type. At the
+        # moment it is not supported to calculate that.
+        headerSize = szUnknownSize
+        headerAlign = szUncomputedSize
+      else:
+        var st = typ.sons[0]
+        while st.kind in skipPtrs:
+          st = st.sons[^1]
+        computeSizeAlign(conf, st)
+        if st.size == szIllegalRecursion:
+          typ.size = st.size
+          typ.align = st.align
+          return
+        headerSize = st.size
+        headerAlign = st.align
     elif isObjectWithTypeFieldPredicate(typ):
       # this branch is taken for RootObj
       headerSize = conf.target.intSize
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index b264415d8..dfa6e5ddb 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -115,7 +115,7 @@ proc symToSuggest(conf: ConfigRef; s: PSym, isLocal: bool, section: IdeCmd, info
       result.forth = typeToString(s.typ)
     else:
       result.forth = ""
-    when defined(nimsuggest) and not defined(noDocgen):
+    when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
       result.doc = s.extractDocComment
   let infox = if section in {ideUse, ideHighlight, ideOutline}: info else: s.info
   result.filePath = toFullPath(conf, infox)
@@ -153,7 +153,7 @@ proc `$`*(suggest: Suggest): string =
     result.add(sep)
     result.add($suggest.column)
     result.add(sep)
-    when defined(nimsuggest) and not defined(noDocgen):
+    when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
       result.add(suggest.doc.escape)
     if suggest.version == 0:
       result.add(sep)
diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim
index decdf1715..60246b9bf 100644
--- a/compiler/syntaxes.nim
+++ b/compiler/syntaxes.nim
@@ -17,10 +17,10 @@ type
   TFilterKind* = enum
     filtNone, filtTemplate, filtReplace, filtStrip
   TParserKind* = enum
-    skinStandard, skinStrongSpaces, skinEndX
+    skinStandard, skinEndX
 
 const
-  parserNames*: array[TParserKind, string] = ["standard", "strongspaces",
+  parserNames*: array[TParserKind, string] = ["standard",
                                               "endx"]
   filterNames*: array[TFilterKind, string] = ["none", "stdtmpl", "replace",
                                               "strip"]
@@ -34,14 +34,14 @@ template config(p: TParsers): ConfigRef = p.parser.lex.config
 
 proc parseAll*(p: var TParsers): PNode =
   case p.skin
-  of skinStandard, skinStrongSpaces:
+  of skinStandard:
     result = parser.parseAll(p.parser)
   of skinEndX:
     internalError(p.config, "parser to implement")
 
 proc parseTopLevelStmt*(p: var TParsers): PNode =
   case p.skin
-  of skinStandard, skinStrongSpaces:
+  of skinStandard:
     result = parser.parseTopLevelStmt(p.parser)
   of skinEndX:
     internalError(p.config, "parser to implement")
@@ -153,21 +153,23 @@ proc openParsers*(p: var TParsers, fileIdx: FileIndex, inputstream: PLLStream;
   else: s = inputstream
   case p.skin
   of skinStandard, skinEndX:
-    parser.openParser(p.parser, fileIdx, s, cache, config, false)
-  of skinStrongSpaces:
-    parser.openParser(p.parser, fileIdx, s, cache, config, true)
+    parser.openParser(p.parser, fileIdx, s, cache, config)
 
 proc closeParsers*(p: var TParsers) =
   parser.closeParser(p.parser)
 
-proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode {.procvar.} =
-  var
-    p: TParsers
-    f: File
+proc setupParsers*(p: var TParsers; fileIdx: FileIndex; cache: IdentCache;
+                   config: ConfigRef): bool =
+  var f: File
   let filename = toFullPathConsiderDirty(config, fileIdx)
   if not open(f, filename.string):
     rawMessage(config, errGenerated, "cannot open file: " & filename.string)
-    return
+    return false
   openParsers(p, fileIdx, llStreamOpen(f), cache, config)
-  result = parseAll(p)
-  closeParsers(p)
+  result = true
+
+proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode {.procvar.} =
+  var p: TParsers
+  if setupParsers(p, fileIdx, cache, config):
+    result = parseAll(p)
+    closeParsers(p)
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 800d56b3a..7b2979dea 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -24,7 +24,8 @@ import
   sempass2, lowerings, destroyer, liftlocals,
   modulegraphs, lineinfos
 
-proc transformBody*(g: ModuleGraph, prc: PSym, cache = true): PNode
+proc transformBody*(g: ModuleGraph, prc: PSym, cache = true;
+                    noDestructors = false): PNode
 
 import closureiters, lambdalifting
 
@@ -48,7 +49,7 @@ type
     inlining: int            # > 0 if we are in inlining context (copy vars)
     nestedProcs: int         # > 0 if we are in a nested proc
     contSyms, breakSyms: seq[PSym]  # to transform 'continue' and 'break'
-    deferDetected, tooEarly, needsDestroyPass: bool
+    deferDetected, tooEarly, needsDestroyPass, noDestructors: bool
     graph: ModuleGraph
   PTransf = ref TTransfContext
 
@@ -130,7 +131,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
   let s = n.sym
   if s.typ != nil and s.typ.callConv == ccClosure:
     if s.kind in routineKinds:
-      discard transformBody(c.graph, s)
+      discard transformBody(c.graph, s, true, c.noDestructors)
     if s.kind == skIterator:
       if c.tooEarly: return n
       else: return liftIterSym(c.graph, n, getCurrOwner(c))
@@ -159,7 +160,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
       return
     tc = tc.next
   result = b
-  
+
 proc transformSym(c: PTransf, n: PNode): PTransNode =
   result = PTransNode(transformSymAux(c, n))
 
@@ -243,7 +244,7 @@ proc newLabel(c: PTransf, n: PNode): PSym =
   result.name = getIdent(c.graph.cache, genPrefix & $result.id)
 
 proc transformBlock(c: PTransf, n: PNode): PTransNode =
-  var labl: PSym 
+  var labl: PSym
   if c.inlining > 0:
     labl = newLabel(c, n[0])
     idNodeTablePut(c.transCon.mapping, n[0].sym, newSymNode(labl))
@@ -611,7 +612,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
       add(stmtList, newAsgnStmt(c, nkFastAsgn, temp, arg.PTransNode))
       idNodeTablePut(newC.mapping, formal, temp)
 
-  let body = transformBody(c.graph, iter)
+  let body = transformBody(c.graph, iter, true, c.noDestructors)
   pushInfoContext(c.graph.config, n.info)
   inc(c.inlining)
   add(stmtList, transform(c, body))
@@ -1029,7 +1030,8 @@ template liftDefer(c, root) =
   if c.deferDetected:
     liftDeferAux(root)
 
-proc transformBody*(g: ModuleGraph, prc: PSym, cache = true): PNode =
+proc transformBody*(g: ModuleGraph, prc: PSym, cache = true;
+                    noDestructors = false): PNode =
   assert prc.kind in routineKinds
 
   if prc.transformedBody != nil:
@@ -1037,22 +1039,22 @@ proc transformBody*(g: ModuleGraph, prc: PSym, cache = true): PNode =
   elif nfTransf in prc.ast[bodyPos].flags or prc.kind in {skTemplate}:
     result = prc.ast[bodyPos]
   else:
-
     prc.transformedBody = newNode(nkEmpty) # protects from recursion
     var c = openTransf(g, prc.getModule, "")
+    c.noDestructors = noDestructors
     result = liftLambdas(g, prc, prc.ast[bodyPos], c.tooEarly)
     result = processTransf(c, result, prc)
     liftDefer(c, result)
     result = liftLocalsIfRequested(prc, result, g.cache, g.config)
-    if c.needsDestroyPass: #and newDestructors:
+    if c.needsDestroyPass and not noDestructors:
       result = injectDestructorCalls(g, prc, result)
 
     if prc.isIterator:
       result = g.transformClosureIterator(prc, result)
-  
+
     incl(result.flags, nfTransf)
 
-    let cache = cache or prc.typ.callConv == ccInline 
+    let cache = cache or prc.typ.callConv == ccInline
     if cache:
       # genProc for inline procs will be called multiple times from diffrent modules,
       # it is important to transform exactly once to get sym ids and locations right
@@ -1072,7 +1074,8 @@ proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
       result = injectDestructorCalls(g, module, result)
     incl(result.flags, nfTransf)
 
-proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode =
+proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode;
+                    noDestructors = false): PNode =
   if nfTransf in n.flags:
     result = n
   else:
@@ -1081,6 +1084,6 @@ proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode =
     liftDefer(c, result)
     # expressions are not to be injected with destructor calls as that
     # the list of top level statements needs to be collected before.
-    if c.needsDestroyPass:
+    if c.needsDestroyPass and not noDestructors:
       result = injectDestructorCalls(g, module, result)
     incl(result.flags, nfTransf)
diff --git a/compiler/types.nim b/compiler/types.nim
index 5b14015c1..b163ca4e9 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -1086,8 +1086,8 @@ proc inheritanceDiff*(a, b: PType): int =
   # | returns: +x iff `a` is the x'th direct subclass of `b`
   # | returns: `maxint` iff `a` and `b` are not compatible at all
   if a == b or a.kind == tyError or b.kind == tyError: return 0
-  assert a.kind == tyObject
-  assert b.kind == tyObject
+  assert a.kind in {tyObject} + skipPtrs
+  assert b.kind in {tyObject} + skipPtrs
   var x = a
   result = 0
   while x != nil:
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 05ee3b90e..7e7ec8903 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -503,7 +503,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcAsgnFloat64FromInt:
       let rb = instr.regB
       ensureKind(rkFloat)
-      regs[ra].floatVal = cast[float64](int64(regs[rb].intVal))      
+      regs[ra].floatVal = cast[float64](int64(regs[rb].intVal))
     of opcAsgnComplex:
       asgnComplex(regs[ra], regs[instr.regB])
     of opcAsgnRef:
@@ -945,10 +945,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       let a = regs[rb].node
       if a.kind == nkSym:
         regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit)
-                        else: 
+                        else:
                           let ast = a.sym.ast.shallowCopy
                           for i in 0..<a.sym.ast.len:
-                            ast[i] = a.sym.ast[i]                        
+                            ast[i] = a.sym.ast[i]
                           ast[bodyPos] = transformBody(c.graph, a.sym)
                           ast.copyTree()
     of opcSymOwner:
@@ -960,6 +960,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         regs[ra].node.flags.incl nfIsRef
       else:
         stackTrace(c, tos, pc, "node is not a symbol")
+    of opcSymIsInstantiationOf:
+      decodeBC(rkInt)
+      let a = regs[rb].node
+      let b = regs[rc].node
+      if a.kind == nkSym and a.sym.kind in skProcKinds and 
+         b.kind == nkSym and b.sym.kind in skProcKinds:
+        regs[ra].intVal =
+          if sfFromGeneric in a.sym.flags and a.sym.owner == b.sym: 1
+          else: 0
+      else:    
+        stackTrace(c, tos, pc, "node is not a proc symbol") 
     of opcEcho:
       let rb = instr.regB
       if rb == 1:
@@ -1228,7 +1239,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcOf:
       decodeBC(rkInt)
       let typ = c.types[regs[rc].intVal.int]
-      regs[ra].intVal = ord(inheritanceDiff(regs[rb].node.typ, typ) >= 0)
+      regs[ra].intVal = ord(inheritanceDiff(regs[rb].node.typ, typ) <= 0)
     of opcIs:
       decodeBC(rkInt)
       let t1 = regs[rb].node.typ.skipTypes({tyTypeDesc})
@@ -1822,7 +1833,7 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
       "NimScript: attempt to call non-routine: " & sym.name.s)
 
 proc evalStmt*(c: PCtx, n: PNode) =
-  let n = transformExpr(c.graph, c.module, n)
+  let n = transformExpr(c.graph, c.module, n, noDestructors = true)
   let start = genStmt(c, n)
   # execute new instructions; this redundant opcEof check saves us lots
   # of allocations in 'execute':
@@ -1830,7 +1841,7 @@ proc evalStmt*(c: PCtx, n: PNode) =
     discard execute(c, start)
 
 proc evalExpr*(c: PCtx, n: PNode): PNode =
-  let n = transformExpr(c.graph, c.module, n)
+  let n = transformExpr(c.graph, c.module, n, noDestructors = true)
   let start = genExpr(c, n)
   assert c.code[start].opcode != opcEof
   result = execute(c, start)
@@ -1877,7 +1888,7 @@ const evalPass* = makePass(myOpen, myProcess, myClose)
 proc evalConstExprAux(module: PSym;
                       g: ModuleGraph; prc: PSym, n: PNode,
                       mode: TEvalMode): PNode =
-  let n = transformExpr(g, module, n)
+  let n = transformExpr(g, module, n, noDestructors = true)
   setupGlobalCtx(module, g)
   var c = PCtx g.vm
   let oldMode = c.mode
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index 25ace3cdd..493078f74 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -147,7 +147,8 @@ type
     opcTypeTrait,
     opcMarshalLoad, opcMarshalStore,
     opcToNarrowInt,
-    opcSymOwner
+    opcSymOwner,
+    opcSymIsInstantiationOf
 
   TBlock* = object
     label*: PSym
diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim
index 8aac5fb87..f160a3096 100644
--- a/compiler/vmdeps.nim
+++ b/compiler/vmdeps.nim
@@ -157,7 +157,10 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
   of tyObject:
     if inst:
       result = newNodeX(nkObjectTy)
-      result.add t.sym.ast[2][0].copyTree  # copy object pragmas
+      if t.sym.ast != nil:
+        result.add t.sym.ast[2][0].copyTree  # copy object pragmas
+      else:
+        result.add newNodeI(nkEmpty, info)
       if t.sons[0] == nil:
         result.add newNodeI(nkEmpty, info)
       else:  # handle parent object
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index ea0fb35ff..e52f460d2 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -182,7 +182,10 @@ const
   HighRegisterPressure = 40
 
 proc bestEffort(c: PCtx): TLineInfo =
-  (if c.prc == nil: c.module.info else: c.prc.sym.info)
+  if c.prc != nil and c.prc.sym != nil:
+    c.prc.sym.info
+  else:
+    c.module.info
 
 proc getTemp(cc: PCtx; tt: PType): TRegister =
   let typ = tt.skipTypesOrNil({tyStatic})
@@ -776,7 +779,7 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
   let src = n.sons[1].typ.skipTypes(abstractRange)#.kind
   let dst = n.sons[0].typ.skipTypes(abstractRange)#.kind
   let src_size = getSize(c.config, src)
-  let dst_size = getSize(c.config, dst) 
+  let dst_size = getSize(c.config, dst)
   if c.config.target.intSize < 8:
     signedIntegers.incl(tyInt)
     unsignedIntegers.incl(tyUInt)
@@ -820,7 +823,7 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
     c.freeTemp(tmp)
 
   elif src_size == dst_size and src.kind in {tyFloat, tyFloat32, tyFloat64} and
-                           dst.kind in allowedIntegers:         
+                           dst.kind in allowedIntegers:
     let tmp = c.genx(n[1])
     if dest < 0: dest = c.getTemp(n[0].typ)
     if src.kind == tyFloat32:
@@ -1095,7 +1098,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     var tmp = c.genx(n.sons[1])
     var idx = c.getTemp(getSysType(c.graph, n.info, tyInt))
     var typ = n.sons[2].typ
-    if m == mOf: typ = typ.skipTypes(abstractPtrs-{tyTypeDesc})
+    if m == mOf: typ = typ.skipTypes(abstractPtrs)
     c.gABx(n, opcLdImmInt, idx, c.genType(typ))
     c.gABC(n, if m == mOf: opcOf else: opcIs, dest, tmp, idx)
     c.freeTemp(tmp)
@@ -1112,13 +1115,14 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mEcho:
     unused(c, n, dest)
     let n = n[1].skipConv
-    let x = c.getTempRange(n.len, slotTempUnknown)
-    internalAssert c.config, n.kind == nkBracket
-    for i in 0..<n.len:
-      var r: TRegister = x+i
-      c.gen(n.sons[i], r)
-    c.gABC(n, opcEcho, x, n.len)
-    c.freeTempRange(x, n.len)
+    if n.kind == nkBracket:
+      # can happen for nim check, see bug #9609
+      let x = c.getTempRange(n.len, slotTempUnknown)
+      for i in 0..<n.len:
+        var r: TRegister = x+i
+        c.gen(n.sons[i], r)
+      c.gABC(n, opcEcho, x, n.len)
+      c.freeTempRange(x, n.len)
   of mAppendStrCh:
     unused(c, n, dest)
     genBinaryStmtVar(c, n, opcAddStrCh)
@@ -1144,6 +1148,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mGetImpl: genUnaryABC(c, n, dest, opcGetImpl)
   of mGetImplTransf: genUnaryABC(c, n, dest, opcGetImplTransf)
   of mSymOwner: genUnaryABC(c, n, dest, opcSymOwner)
+  of mSymIsInstantiationOf: genBinaryABC(c, n, dest, opcSymIsInstantiationOf)
   of mNChild: genBinaryABC(c, n, dest, opcNChild)
   of mNSetChild: genVoidABC(c, n, dest, opcNSetChild)
   of mNDel: genVoidABC(c, n, dest, opcNDel)
@@ -2150,7 +2155,8 @@ proc genProc(c: PCtx; s: PSym): int =
     s.ast.sons[miscPos] = x
     # thanks to the jmp we can add top level statements easily and also nest
     # procs easily:
-    let body = transformBody(c.graph, s, cache = not isCompileTimeProc(s))
+    let body = transformBody(c.graph, s, cache = not isCompileTimeProc(s),
+                             noDestructors = true)
     let procStart = c.xjmp(body, opcJmp, 0)
     var p = PProc(blocks: @[], sym: s)
     let oldPrc = c.prc
diff --git a/compiler/vmops.nim b/compiler/vmops.nim
index 83e65279a..f87ab4508 100644
--- a/compiler/vmops.nim
+++ b/compiler/vmops.nim
@@ -11,7 +11,7 @@
 #import vmdeps, vm
 from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
   arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc,
-  floor, ceil, fmod
+  floor, ceil, `mod`, fmod
 
 from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir
 
@@ -21,9 +21,6 @@ template mathop(op) {.dirty.} =
 template osop(op) {.dirty.} =
   registerCallback(c, "stdlib.os." & astToStr(op), `op Wrapper`)
 
-template ospathsop(op) {.dirty.} =
-  registerCallback(c, "stdlib.ospaths." & astToStr(op), `op Wrapper`)
-
 template systemop(op) {.dirty.} =
   registerCallback(c, "stdlib.system." & astToStr(op), `op Wrapper`)
 
@@ -107,10 +104,14 @@ proc registerAdditionalOps*(c: PCtx) =
   wrap1f_math(ceil)
   wrap2f_math(fmod)
 
+  proc `mod Wrapper`(a: VmArgs) {.nimcall.} =
+    setResult(a, `mod`(getFloat(a, 0), getFloat(a, 1)))
+  registerCallback(c, "stdlib.math.mod", `mod Wrapper`)
+
   when defined(nimcore):
-    wrap2s(getEnv, ospathsop)
-    wrap1s(existsEnv, ospathsop)
-    wrap2svoid(putEnv, ospathsop)
+    wrap2s(getEnv, osop)
+    wrap1s(existsEnv, osop)
+    wrap2svoid(putEnv, osop)
     wrap1s(dirExists, osop)
     wrap1s(fileExists, osop)
     wrap2svoid(writeFile, systemop)
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index 800b5dc18..41bdc9fcb 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -69,13 +69,13 @@ type
     wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wLocks,
     wPartial, wExplain, wLiftLocals,
 
-    wAuto, wBool, wCatch, wChar, wClass,
+    wAuto, wBool, wCatch, wChar, wClass, wCompl
     wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast,
     wExplicit, wExtern, wFalse, wFloat, wFriend,
     wGoto, wInt, wLong, wMutable, wNamespace, wNew, wOperator,
-    wPrivate, wProtected, wPublic, wRegister, wReinterpret_cast,
+    wPrivate, wProtected, wPublic, wRegister, wReinterpret_cast, wRestrict,
     wShort, wSigned, wSizeof, wStatic_cast, wStruct, wSwitch,
-    wThis, wThrow, wTrue, wTypedef, wTypeid, wTypename,
+    wThis, wThrow, wTrue, wTypedef, wTypeid, wTypeof, wTypename,
     wUnion, wPacked, wUnsigned, wVirtual, wVoid, wVolatile, wWchar_t,
 
     wAlignas, wAlignof, wConstexpr, wDecltype, wNullptr, wNoexcept,
@@ -156,14 +156,14 @@ const
     "asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked",
     "guard", "locks", "partial", "explain", "liftlocals",
 
-    "auto", "bool", "catch", "char", "class",
+    "auto", "bool", "catch", "char", "class", "compl",
     "const_cast", "default", "delete", "double",
     "dynamic_cast", "explicit", "extern", "false",
     "float", "friend", "goto", "int", "long", "mutable",
     "namespace", "new", "operator",
-    "private", "protected", "public", "register", "reinterpret_cast",
+    "private", "protected", "public", "register", "reinterpret_cast", "restrict",
     "short", "signed", "sizeof", "static_cast", "struct", "switch",
-    "this", "throw", "true", "typedef", "typeid",
+    "this", "throw", "true", "typedef", "typeid", "typeof",
     "typename", "union", "packed", "unsigned", "virtual", "void", "volatile",
     "wchar_t",