summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--changelog.md10
-rw-r--r--compiler/ast.nim22
-rw-r--r--compiler/astalgo.nim29
-rw-r--r--compiler/ccgexprs.nim97
-rw-r--r--compiler/ccgliterals.nim2
-rw-r--r--compiler/ccgstmts.nim10
-rw-r--r--compiler/ccgtypes.nim4
-rw-r--r--compiler/cgen.nim8
-rw-r--r--compiler/closureiters.nim17
-rw-r--r--compiler/commands.nim9
-rw-r--r--compiler/condsyms.nim2
-rw-r--r--compiler/destroyer.nim39
-rw-r--r--compiler/docgen.nim6
-rw-r--r--compiler/evaltempl.nim2
-rw-r--r--compiler/importer.nim2
-rw-r--r--compiler/jsgen.nim318
-rw-r--r--compiler/lambdalifting.nim38
-rw-r--r--compiler/lookups.nim2
-rw-r--r--compiler/lowerings.nim2
-rw-r--r--compiler/modules.nim49
-rw-r--r--compiler/msgs.nim2
-rw-r--r--compiler/pathutils.nim17
-rw-r--r--compiler/pragmas.nim23
-rw-r--r--compiler/rod.nim2
-rw-r--r--compiler/rodimpl.nim101
-rw-r--r--compiler/sem.nim2
-rw-r--r--compiler/semexprs.nim30
-rw-r--r--compiler/seminst.nim4
-rw-r--r--compiler/semmagic.nim4
-rw-r--r--compiler/sempass2.nim10
-rw-r--r--compiler/semstmts.nim7
-rw-r--r--compiler/semtypes.nim24
-rw-r--r--compiler/semtypinst.nim2
-rw-r--r--compiler/sigmatch.nim26
-rw-r--r--compiler/sizealignoffsetimpl.nim21
-rw-r--r--compiler/trees.nim3
-rw-r--r--compiler/vm.nim11
-rw-r--r--compiler/vmdef.nim3
-rw-r--r--compiler/vmgen.nim5
-rw-r--r--compiler/vmops.nim3
-rw-r--r--doc/advopt.txt1
-rw-r--r--doc/backends.rst2
-rw-r--r--doc/manual.rst10
-rw-r--r--doc/tut2.rst402
-rw-r--r--doc/tut3.rst354
-rw-r--r--examples/tunit.nim2
-rw-r--r--lib/core/allocators.nim34
-rw-r--r--lib/core/macros.nim6
-rw-r--r--lib/core/seqs.nim55
-rw-r--r--lib/core/typeinfo.nim1
-rw-r--r--lib/js/jsffi.nim67
-rw-r--r--lib/nimrtl.nim1
-rw-r--r--lib/posix/posix.nim6
-rw-r--r--lib/pure/asyncnet.nim2
-rw-r--r--lib/pure/collections/sequtils.nim160
-rw-r--r--lib/pure/httpclient.nim120
-rw-r--r--lib/pure/os.nim9
-rw-r--r--lib/pure/osproc.nim13
-rw-r--r--lib/pure/parseutils.nim4
-rw-r--r--lib/pure/random.nim4
-rw-r--r--lib/pure/times.nim80
-rw-r--r--lib/pure/unicode.nim7
-rw-r--r--lib/system.nim21
-rw-r--r--lib/system/dyncalls.nim7
-rw-r--r--lib/system/excpt.nim9
-rw-r--r--lib/system/gc.nim92
-rw-r--r--lib/system/gc2.nim41
-rw-r--r--lib/system/gc_ms.nim24
-rw-r--r--lib/system/gc_regions.nim4
-rw-r--r--lib/system/jssys.nim7
-rw-r--r--lib/system/mmdisp.nim16
-rw-r--r--lib/system/reprjs.nim4
-rw-r--r--nimsuggest/nimsuggest.nim134
-rw-r--r--testament/categories.nim36
-rw-r--r--testament/specs.nim13
-rw-r--r--testament/tester.nim127
-rw-r--r--testament/tests/shouldfail/tccodecheck.nim8
-rw-r--r--testament/tests/shouldfail/tcolumn.nim8
-rw-r--r--testament/tests/shouldfail/terrormsg.nim8
-rw-r--r--testament/tests/shouldfail/texitcode1.nim3
-rw-r--r--testament/tests/shouldfail/tfile.nim6
-rw-r--r--testament/tests/shouldfail/tline.nim8
-rw-r--r--testament/tests/shouldfail/tmaxcodesize.nim5
-rw-r--r--testament/tests/shouldfail/tmsg.nim6
-rw-r--r--testament/tests/shouldfail/tnimout.nim7
-rw-r--r--testament/tests/shouldfail/toutput.nim7
-rw-r--r--testament/tests/shouldfail/toutputsub.nim5
-rw-r--r--testament/tests/shouldfail/tsortoutput.nim11
-rw-r--r--tests/async/tasyncall.nim2
-rw-r--r--tests/async/tasyncssl.nim7
-rw-r--r--tests/async/tfuturevar.nim6
-rw-r--r--tests/casestmt/tlinearscanend.nim4
-rw-r--r--tests/ccgbugs/t6756.nim6
-rw-r--r--tests/ccgbugs/t8964.nim10
-rw-r--r--tests/ccgbugs/tcodegendecllambda.nim1
-rw-r--r--tests/ccgbugs/tgeneric_closure.nim8
-rw-r--r--tests/ccgbugs/trecursive_closure.nim4
-rw-r--r--tests/ccgbugs/tsighash_typename_regression.nim7
-rw-r--r--tests/ccgbugs/tuple_canon.nim7
-rw-r--r--tests/closure/tinfer_closure_for_nestedproc.nim42
-rw-r--r--tests/closure/tmacrobust1512.nim40
-rw-r--r--tests/closure/ttimeinfo.nim7
-rw-r--r--tests/compiles/trecursive_generic_in_compiles.nim4
-rw-r--r--tests/concepts/tconcepts_issues.nim1
-rw-r--r--tests/concepts/tmapconcept.nim2
-rw-r--r--tests/concepts/tmatrixconcept.nim2
-rw-r--r--tests/concepts/tstackconcept.nim2
-rw-r--r--tests/controlflow/tstatret.nim2
-rw-r--r--tests/converter/t7098.nim4
-rw-r--r--tests/converter/tconvcolors.nim4
-rw-r--r--tests/converter/tconvert.nim16
-rw-r--r--tests/converter/tconverter_unique_ptr.nim60
-rw-r--r--tests/converter/tgenericconverter2.nim36
-rw-r--r--tests/coroutines/texceptions.nim3
-rw-r--r--tests/coroutines/titerators.nim2
-rw-r--r--tests/cpp/t8241.nim11
-rw-r--r--tests/cpp/tnativesockets.nim1
-rw-r--r--tests/cpp/tsigbreak.nim1
-rw-r--r--tests/defaultprocparam/tdefaultprocparam.nim6
-rw-r--r--tests/destructor/t6434.nim21
-rw-r--r--tests/destructor/tatomicptrs.nim52
-rw-r--r--tests/destructor/tmove_objconstr.nim63
-rw-r--r--tests/dir with space/tspace.nim5
-rw-r--r--tests/discard/tdiscardable.nim7
-rw-r--r--tests/dll/server.nim8
-rw-r--r--tests/effects/teffects6.nim5
-rw-r--r--tests/errmsgs/treportunused.nim29
-rw-r--r--tests/errmsgs/tshow_asgn.nim2
-rw-r--r--tests/exception/t9657.nim6
-rw-r--r--tests/exprs/tifexpr_typeinference.nim4
-rw-r--r--tests/flags/tgenscript.nim1
-rw-r--r--tests/generics/t2tables.nim4
-rw-r--r--tests/generics/tgeneric3.nim10
-rw-r--r--tests/generics/tgenericvariant.nim13
-rw-r--r--tests/generics/tlateboundstatic.nim2
-rw-r--r--tests/generics/tthread_generic.nim2
-rw-r--r--tests/global/tglobalforvar.nim4
-rw-r--r--tests/init/t8314.nim10
-rw-r--r--tests/init/tuninit1.nim3
-rw-r--r--tests/iter/timplicit_auto.nim2
-rw-r--r--tests/iter/titer.nim13
-rw-r--r--tests/iter/titer_no_tuple_unpack.nim16
-rw-r--r--tests/iter/titervaropenarray.nim3
-rw-r--r--tests/iter/tpermutations.nim11
-rw-r--r--tests/iter/tshallowcopy_closures.nim8
-rw-r--r--tests/iter/twrap_walkdir.nim5
-rw-r--r--tests/iter/tyieldintry.nim15
-rw-r--r--tests/js/t9410.nim454
-rw-r--r--tests/js/tcopying.nim35
-rw-r--r--tests/js/tjsffi.nim24
-rw-r--r--tests/lexer/tident.nim14
-rw-r--r--tests/lookups/test.nim8
-rw-r--r--tests/lookups/tprefer_proc.nim4
-rw-r--r--tests/macros/tbindsym.nim2
-rw-r--r--tests/macros/tdumpastgen.nim2
-rw-r--r--tests/macros/tdumptree.nim9
-rw-r--r--tests/macros/tescape_var_into_quotedo_as_const.nim36
-rw-r--r--tests/macros/tgetimpl.nim21
-rw-r--r--tests/macros/tgettype.nim6
-rw-r--r--tests/macros/tgettype2.nim32
-rw-r--r--tests/macros/tmacrogenerics.nim8
-rw-r--r--tests/macros/tmacros_issues.nim15
-rw-r--r--tests/macros/tmacros_various.nim15
-rw-r--r--tests/macros/tmemit.nim6
-rw-r--r--tests/macros/tquotedo.nim8
-rw-r--r--tests/macros/tstaticparamsmacro.nim9
-rw-r--r--tests/metatype/tbindtypedesc.nim8
-rw-r--r--tests/metatype/tmetatype_issues.nim16
-rw-r--r--tests/metatype/tsemistatic.nim2
-rw-r--r--tests/metatype/tstaticparammacro.nim8
-rw-r--r--tests/metatype/ttypedesc3.nim10
-rw-r--r--tests/metatype/ttypetraits.nim2
-rw-r--r--tests/misc/tcmdline.nim3
-rw-r--r--tests/misc/tcolonisproc.nim6
-rw-r--r--tests/misc/tdllvar.nim6
-rw-r--r--tests/misc/tendian.nim3
-rw-r--r--tests/misc/tgetstartmilsecs.nim7
-rw-r--r--tests/misc/thallo.nim6
-rw-r--r--tests/misc/theaproots.nim4
-rw-r--r--tests/misc/tlastmod.nim15
-rw-r--r--tests/misc/tloops.nim8
-rw-r--r--tests/misc/tmandelbrot.nim57
-rw-r--r--tests/misc/tmemoization.nim2
-rw-r--r--tests/misc/tnew.nim7
-rw-r--r--tests/misc/tnewuns.nim12
-rw-r--r--tests/misc/tprep.nim8
-rw-r--r--tests/misc/tquicksort.nim9
-rw-r--r--tests/misc/tradix.nim25
-rw-r--r--tests/misc/treadln.nim11
-rw-r--r--tests/misc/treadx.nim13
-rw-r--r--tests/misc/tshadow_magic_type.nim10
-rw-r--r--tests/misc/tsizeof2.nim4
-rw-r--r--tests/misc/tstrace.nim20
-rw-r--r--tests/misc/tstrdist.nim2
-rw-r--r--tests/misc/tunsigned64mod.nim8
-rw-r--r--tests/misc/tvarious.nim4
-rw-r--r--tests/modules/t8665.nim4
-rw-r--r--tests/modules/texport2.nim9
-rw-r--r--tests/newconfig/tfoo.nim2
-rw-r--r--tests/niminaction/Chapter3/ChatApp/src/client.nim4
-rw-r--r--tests/niminaction/Chapter3/ChatApp/src/server.nim6
-rw-r--r--tests/niminaction/Chapter3/various3.nim29
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/concurrency.nim4
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim4
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/naive.nim4
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim6
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/race_condition.nim6
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/sequential_counts.nim6
-rw-r--r--tests/niminaction/Chapter7/Tweeter/src/createDatabase.nim6
-rw-r--r--tests/niminaction/Chapter7/Tweeter/src/tweeter.nim4
-rw-r--r--tests/niminaction/Chapter7/Tweeter/tests/database_test.nim4
-rw-r--r--tests/niminaction/Chapter8/canvas/canvas.nim4
-rw-r--r--tests/niminaction/Chapter8/sdl/sdl_test.nim4
-rw-r--r--tests/niminaction/Chapter8/sfml/sfml_test.nim3
-rw-r--r--tests/objects/tobjcov.nim5
-rw-r--r--tests/objects/tobject.nim4
-rw-r--r--tests/objects/tobjects.nim52
-rw-r--r--tests/objvariant/tcheckedfield1.nim4
-rw-r--r--tests/osproc/ta_in.nim4
-rw-r--r--tests/osproc/ta_out.nim11
-rw-r--r--tests/osproc/tafalse.nim4
-rw-r--r--tests/osproc/texitcode.nim1
-rw-r--r--tests/overload/tselfderef.nim5
-rw-r--r--tests/parallel/tarray_of_channels.nim12
-rw-r--r--tests/parallel/tdont_be_stupid.nim10
-rw-r--r--tests/parallel/tguard1.nim4
-rw-r--r--tests/parallel/tlet_spawn.nim5
-rw-r--r--tests/parallel/tmissing_deepcopy.nim3
-rw-r--r--tests/parallel/tsimple_array_checks.nim22
-rw-r--r--tests/pragmas/tnoreturn.nim1
-rw-r--r--tests/seq/tseq.nim24
-rw-r--r--tests/stdlib/osproctest.nim8
-rw-r--r--tests/stdlib/tcgi.nim23
-rw-r--r--tests/stdlib/tcputime.nim11
-rw-r--r--tests/stdlib/thashes.nim13
-rw-r--r--tests/stdlib/thttpcore.nim3
-rw-r--r--tests/stdlib/tjsonexternproc.nim8
-rw-r--r--tests/stdlib/tjsontestsuite.nim4
-rw-r--r--tests/stdlib/tmath2.nim85
-rw-r--r--tests/stdlib/tmemfiles1.nim3
-rw-r--r--tests/stdlib/tmemlines.nim4
-rw-r--r--tests/stdlib/tmemlinesBuf.nim11
-rw-r--r--tests/stdlib/tmemslices.nim6
-rw-r--r--tests/stdlib/tnativesockets.nim5
-rw-r--r--tests/stdlib/tnet.nim4
-rw-r--r--tests/stdlib/tosproc.nim24
-rw-r--r--tests/stdlib/tosprocterminate.nim4
-rw-r--r--tests/stdlib/tparsopt.nim8
-rw-r--r--tests/stdlib/tposix.nim5
-rw-r--r--tests/stdlib/tquit.nim6
-rw-r--r--tests/stdlib/trepr2.nim5
-rw-r--r--tests/stdlib/trstgen.nim12
-rw-r--r--tests/stdlib/tsortcall.nim6
-rw-r--r--tests/stdlib/tstreams.nim17
-rw-r--r--tests/stdlib/tstrtabs.nim91
-rw-r--r--tests/stdlib/twalker.nim13
-rw-r--r--tests/system/t7894.nim28
-rw-r--r--tests/system/talloc.nim3
-rw-r--r--tests/system/talloc2.nim3
-rw-r--r--tests/system/tio.nim12
-rw-r--r--tests/system/tnilconcats.nim7
-rw-r--r--tests/system/tparams.nim4
-rw-r--r--tests/template/tconfusinglocal.nim4
-rw-r--r--tests/template/texponential_eval.nim8
-rw-r--r--tests/template/thygienictempl.nim4
-rw-r--r--tests/template/tparams_gensymed.nim13
-rw-r--r--tests/template/tsighash_regression.nim5
-rw-r--r--tests/template/ttempl3.nim4
-rw-r--r--tests/testament/tshouldfail.nim17
-rw-r--r--tests/typerel/tnoargopenarray.nim5
-rw-r--r--tests/typerel/trettypeinference.nim2
-rw-r--r--tests/typerel/tsecondarrayproperty.nim5
-rw-r--r--tests/typerel/ttuple1.nim8
-rw-r--r--tests/types/taliasbugs.nim2
-rw-r--r--tests/types/tauto_canbe_void.nim8
-rw-r--r--tests/types/tfinalobj.nim19
-rw-r--r--tests/vm/tconsteval.nim2
-rw-r--r--tests/vm/tconsttable2.nim2
-rw-r--r--tests/vm/teval1.nim11
-rw-r--r--tests/vm/tgorge.nim7
-rwxr-xr-x[-rw-r--r--]tests/vm/tgorge.sh0
-rwxr-xr-x[-rw-r--r--]tests/vm/tgorgeex.sh0
-rw-r--r--tests/vm/tinheritance.nim2
-rw-r--r--tests/vm/tmitems.nim2
-rw-r--r--tests/vm/tsimpleglobals.nim2
-rw-r--r--tests/vm/tslurp.nim6
-rw-r--r--tests/vm/tstaticprintseq.nim2
-rw-r--r--tests/vm/tswap.nim2
-rw-r--r--tests/vm/ttouintconv.nim2
-rw-r--r--tools/kochdocs.nim2
290 files changed, 3778 insertions, 1645 deletions
diff --git a/changelog.md b/changelog.md
index 7cc2a3b63..6dbfa1a2d 100644
--- a/changelog.md
+++ b/changelog.md
@@ -27,6 +27,7 @@
 
 #### Breaking changes in the standard library
 
+- `osproc.execProcess` now also takes a `workingDir` parameter.
 
 #### Breaking changes in the compiler
 
@@ -61,6 +62,10 @@ proc enumToString*(enums: openArray[enum]): string =
 - Added `system.typeof` for more control over how `type` expressions
   can be deduced.
 
+- Added `macros.isInstantiationOf` for checking if the proc symbol
+  is instantiation of generic proc symbol.
+
+
 ### Library changes
 
 - The string output of `macros.lispRepr` proc has been tweaked
@@ -84,7 +89,9 @@ proc enumToString*(enums: openArray[enum]): string =
 ### Language additions
 
 - Vm suport for float32<->int32 and float64<->int64 casts was added.
-
+- There is a new pragma block `noSideEffect` that works like
+  the `gcsafe` pragma block.
+- added os.getCurrentProcessId()
 
 ### Language changes
 
@@ -100,5 +107,6 @@ proc enumToString*(enums: openArray[enum]): string =
   documentation.
 
 ### Compiler changes
+- The deprecated `fmod` proc is now unavailable on the VM'.
 
 ### Bugfixes
diff --git a/compiler/ast.nim b/compiler/ast.nim
index bb0f95acd..40a05e6bf 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -627,7 +627,7 @@ type
     mIsPartOf, mAstToStr, mParallel,
     mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast,
     mNewString, mNewStringOfCap, mParseBiggestFloat,
-    mMove, mWasMoved,
+    mMove, mWasMoved, mDestroy,
     mReset,
     mArray, mOpenArray, mRange, mSet, mSeq, mOpt, mVarargs,
     mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
@@ -656,14 +656,15 @@ 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
   ctfeWhitelist* = {mNone, mUnaryLt, mSucc,
     mPred, mInc, mDec, mOrd, mLengthOpenArray,
     mLengthStr, mLengthArray, mLengthSeq, mXLenStr, mXLenSeq,
-    mArrGet, mArrPut, mAsgn,
+    mArrGet, mArrPut, mAsgn, mDestroy,
     mIncl, mExcl, mCard, mChr,
     mAddI, mSubI, mMulI, mDivI, mModI,
     mAddF64, mSubF64, mMulF64, mDivF64,
@@ -756,8 +757,6 @@ type
     OnUnknown,                # location is unknown (stack, heap or static)
     OnStatic,                 # in a static section
     OnStack,                  # location is on hardware stack
-    OnStackShadowDup,         # location is on the stack but also replicated
-                              # on the shadow stack
     OnHeap                    # location is on heap or global
                               # (reference counting needed)
   TLocFlags* = set[TLocFlag]
@@ -767,7 +766,6 @@ type
     flags*: TLocFlags         # location's flags
     lode*: PNode              # Node where the location came from; can be faked
     r*: Rope                  # rope value of location (code generators)
-    dup*: Rope                # duplicated location for precise stack scans
 
   # ---------------- end of backend information ------------------------------
 
@@ -898,6 +896,8 @@ type
     loc*: TLoc
     typeInst*: PType          # for generic instantiations the tyGenericInst that led to this
                               # type.
+    uniqueId*: int            # due to a design mistake, we need to keep the real ID here as it
+                              # required by the --incremental:on mode.
 
   TPair* = object
     key*, val*: RootRef
@@ -1268,6 +1268,7 @@ proc newType*(kind: TTypeKind, owner: PSym): PType =
   result.size = -1
   result.align = -1            # default alignment
   result.id = getID()
+  result.uniqueId = result.id
   result.lockLevel = UnspecifiedLockLevel
   when debugIds:
     registerId(result)
@@ -1341,15 +1342,12 @@ proc copyType*(t: PType, owner: PSym, keepId: bool): PType =
 
 proc exactReplica*(t: PType): PType = copyType(t, t.owner, true)
 
-proc copySym*(s: PSym, keepId: bool = false): PSym =
+proc copySym*(s: PSym): PSym =
   result = newSym(s.kind, s.name, s.owner, s.info, s.options)
   #result.ast = nil            # BUGFIX; was: s.ast which made problems
   result.typ = s.typ
-  if keepId:
-    result.id = s.id
-  else:
-    result.id = getID()
-    when debugIds: registerId(result)
+  result.id = getID()
+  when debugIds: registerId(result)
   result.flags = s.flags
   result.magic = s.magic
   if s.kind == skModule:
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index b716882dc..b2671d81e 100644
--- a/compiler/astalgo.nim
+++ b/compiler/astalgo.nim
@@ -254,21 +254,26 @@ proc symToYamlAux(conf: ConfigRef; n: PSym, marker: var IntSet, indent: int,
   if n == nil:
     result = rope("null")
   elif containsOrIncl(marker, n.id):
-    result = "\"$1 @$2\"" % [rope(n.name.s), rope(
-        strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]
+    result = "\"$1\"" % [rope(n.name.s)]
   else:
     var ast = treeToYamlAux(conf, n.ast, marker, indent + 2, maxRecDepth - 1)
     result = ropeConstr(indent, [rope("kind"),
                                  makeYamlString($n.kind),
                                  rope("name"), makeYamlString(n.name.s),
-                                 rope("typ"), typeToYamlAux(conf, n.typ, marker,
-                                   indent + 2, maxRecDepth - 1),
+                                 #rope("typ"), typeToYamlAux(conf, n.typ, marker,
+                                 #  indent + 2, maxRecDepth - 1),
                                  rope("info"), lineInfoToStr(conf, n.info),
                                  rope("flags"), flagsToStr(n.flags),
                                  rope("magic"), makeYamlString($n.magic),
                                  rope("ast"), ast, rope("options"),
                                  flagsToStr(n.options), rope("position"),
-                                 rope(n.position)])
+                                 rope(n.position),
+                                 rope("k"), makeYamlString($n.loc.k),
+                                 rope("storage"), makeYamlString($n.loc.storage),
+                                 rope("flags"), makeYamlString($n.loc.flags),
+                                 rope("r"), n.loc.r,
+                                 rope("lode"), treeToYamlAux(conf, n.loc.lode, marker, indent + 2, maxRecDepth - 1)
+    ])
 
 proc typeToYamlAux(conf: ConfigRef; n: PType, marker: var IntSet, indent: int,
                    maxRecDepth: int): Rope =
@@ -394,10 +399,16 @@ proc debugTree(conf: ConfigRef; n: PNode, indent: int, maxRecDepth: int;
       of nkStrLit..nkTripleStrLit:
         addf(result, ",$N$1\"strVal\": $2", [istr, makeYamlString(n.strVal)])
       of nkSym:
-        addf(result, ",$N$1\"sym\": $2_$3",
-            [istr, rope(n.sym.name.s), rope(n.sym.id)])
-        #     [istr, symToYaml(n.sym, indent, maxRecDepth),
-        #     rope(n.sym.id)])
+        let s = n.sym
+        addf(result, ",$N$1\"sym\": $2_$3 k: $4 storage: $5 flags: $6 r: $7",
+             [istr, rope(s.name.s), rope(s.id),
+                                 rope($s.loc.k),
+                                 rope($s.loc.storage),
+                                 rope($s.loc.flags),
+                                 s.loc.r
+             ])
+#             [istr, symToYaml(conf, n.sym, indent, maxRecDepth),
+#             rope(n.sym.id)])
         if renderType and n.sym.typ != nil:
           addf(result, ",$N$1\"typ\": $2", [istr, debugType(conf, n.sym.typ, 2)])
       of nkIdent:
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 1b70ee41b..59ef05f9c 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -31,10 +31,18 @@ proc intLiteral(i: BiggestInt): Rope =
     result = ~"(IL64(-9223372036854775807) - IL64(1))"
 
 proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
-  if ty == nil: internalError(p.config, n.info, "genLiteral: ty is nil")
   case n.kind
   of nkCharLit..nkUInt64Lit:
-    case skipTypes(ty, abstractVarRange).kind
+    var k: TTypeKind
+    if ty != nil:
+      k = skipTypes(ty, abstractVarRange).kind
+    else:
+      case n.kind
+      of nkCharLit: k = tyChar
+      of nkUInt64Lit: k = tyUInt64
+      of nkInt64Lit: k = tyInt64
+      else: k = tyNil # don't go into the case variant that uses 'ty'
+    case k
     of tyChar, tyNil:
       result = intLiteral(n.intVal)
     of tyBool:
@@ -46,8 +54,8 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
       result = "(($1) $2)" % [getTypeDesc(p.module,
           ty), intLiteral(n.intVal)]
   of nkNilLit:
-    let t = skipTypes(ty, abstractVarRange)
-    if t.kind == tyProc and t.callConv == ccClosure:
+    let k = if ty == nil: tyPointer else: skipTypes(ty, abstractVarRange).kind
+    if k == tyProc and skipTypes(ty, abstractVarRange).callConv == ccClosure:
       let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
       result = p.module.tmpBase & rope(id)
       if id == p.module.labels:
@@ -59,7 +67,9 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
     else:
       result = rope("NIM_NIL")
   of nkStrLit..nkTripleStrLit:
-    case skipTypes(ty, abstractVarRange + {tyStatic, tyUserTypeClass, tyUserTypeClassInst}).kind
+    let k = if ty == nil: tyString
+            else: skipTypes(ty, abstractVarRange + {tyStatic, tyUserTypeClass, tyUserTypeClassInst}).kind
+    case k
     of tyNil:
       result = genNilStringLiteral(p.module, n.info)
     of tyString:
@@ -168,32 +178,12 @@ proc canMove(p: BProc, n: PNode): bool =
   #  echo n.info, " optimized ", n
   #  result = false
 
-proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
+proc genRefAssign(p: BProc, dest, src: TLoc) =
   if (dest.storage == OnStack and p.config.selectedGC != gcGo) or not usesWriteBarrier(p.config):
     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))
-    else:
-      linefmt(p, cpsStmts, "#asgnRefNoCycle((void**) $1, $2);$n",
-              addrLoc(p.config, dest), rdLoc(src))
+    linefmt(p, cpsStmts, "#asgnRef((void**) $1, $2);$n",
+            addrLoc(p.config, dest), rdLoc(src))
   else:
     linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n",
             addrLoc(p.config, dest), rdLoc(src))
@@ -261,7 +251,7 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
   # (for objects, etc.):
   if p.config.selectedGC == gcDestructors:
     linefmt(p, cpsStmts,
-        "$1.len = $2.len; $1.p = $2.p;$n",
+        "$1 = $2;$n",
         rdLoc(dest), rdLoc(src))
   elif needToCopy notin flags or
       tfShallow in skipTypes(dest.t, abstractVarRange).flags:
@@ -286,12 +276,12 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
   let ty = skipTypes(dest.t, abstractRange + tyUserTypeClasses + {tyStatic})
   case ty.kind
   of tyRef:
-    genRefAssign(p, dest, src, flags)
+    genRefAssign(p, dest, src)
   of tySequence:
     if p.config.selectedGC == gcDestructors:
       genGenericAsgn(p, dest, src, flags)
     elif (needToCopy notin flags and src.storage != OnStatic) or canMove(p, src.lode):
-      genRefAssign(p, dest, src, flags)
+      genRefAssign(p, dest, src)
     else:
       linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n",
               addrLoc(p.config, dest), rdLoc(src),
@@ -300,7 +290,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
     if p.config.selectedGC == gcDestructors:
       genGenericAsgn(p, dest, src, flags)
     elif (needToCopy notin flags and src.storage != OnStatic) or canMove(p, src.lode):
-      genRefAssign(p, dest, src, flags)
+      genRefAssign(p, dest, src)
     else:
       if (dest.storage == OnStack and p.config.selectedGC != gcGo) or not usesWriteBarrier(p.config):
         linefmt(p, cpsStmts, "$1 = #copyString($2);$n", dest.rdLoc, src.rdLoc)
@@ -315,16 +305,16 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
         linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n",
                addrLoc(p.config, dest), rdLoc(src))
   of tyProc:
-    if needsComplexAssignment(dest.t):
+    if containsGarbageCollectedRef(dest.t):
       # optimize closure assignment:
       let a = optAsgnLoc(dest, dest.t, "ClE_0".rope)
       let b = optAsgnLoc(src, dest.t, "ClE_0".rope)
-      genRefAssign(p, a, b, flags)
+      genRefAssign(p, a, b)
       linefmt(p, cpsStmts, "$1.ClP_0 = $2.ClP_0;$n", rdLoc(dest), rdLoc(src))
     else:
       linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
   of tyTuple:
-    if needsComplexAssignment(dest.t):
+    if containsGarbageCollectedRef(dest.t):
       if dest.t.len <= 4: genOptAsgnTuple(p, dest, src, flags)
       else: genGenericAsgn(p, dest, src, flags)
     else:
@@ -335,7 +325,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
       linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
     elif not isObjLackingTypeField(ty):
       genGenericAsgn(p, dest, src, flags)
-    elif needsComplexAssignment(ty):
+    elif containsGarbageCollectedRef(ty):
       if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4:
         discard getTypeDesc(p.module, ty)
         internalAssert p.config, ty.n != nil
@@ -345,7 +335,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
     else:
       linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
   of tyArray:
-    if needsComplexAssignment(dest.t):
+    if containsGarbageCollectedRef(dest.t):
       genGenericAsgn(p, dest, src, flags)
     else:
       linefmt(p, cpsStmts,
@@ -354,7 +344,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
   of tyOpenArray, tyVarargs:
     # open arrays are always on the stack - really? What if a sequence is
     # passed to an open array?
-    if needsComplexAssignment(dest.t):
+    if containsGarbageCollectedRef(dest.t):
       linefmt(p, cpsStmts,     # XXX: is this correct for arrays?
            "#genericAssignOpenArray((void*)$1, (void*)$2, $1Len_0, $3);$n",
            addrLoc(p.config, dest), addrLoc(p.config, src),
@@ -1148,14 +1138,14 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
     genTypeInfo(p.module, seqType, e.info)])
   # emit the write barrier if required, but we can always move here, so
   # use 'genRefAssign' for the seq.
-  genRefAssign(p, a, call, {})
+  genRefAssign(p, a, call)
   #if bt != b.t:
   #  echo "YES ", e.info, " new: ", typeToString(bt), " old: ", typeToString(b.t)
   initLoc(dest, locExpr, e.sons[2], OnHeap)
   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) =
@@ -1359,9 +1349,17 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
     getTemp(p, n.typ, tmp)
   elif d.k == locNone:
     getTemp(p, n.typ, d)
-  # generate call to newSeq before adding the elements per hand:
-  genNewSeqAux(p, dest[], intLiteral(sonsLen(n)),
-    optNilSeqs notin p.options and n.len == 0)
+
+  let l = intLiteral(sonsLen(n))
+  if p.config.selectedGC == gcDestructors:
+    let seqtype = n.typ
+    linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
+      rdLoc dest[], l, getTypeDesc(p.module, seqtype.lastSon),
+      getSeqPayloadType(p.module, seqtype))
+  else:
+    # generate call to newSeq before adding the elements per hand:
+    genNewSeqAux(p, dest[], l,
+      optNilSeqs notin p.options and n.len == 0)
   for i in countup(0, sonsLen(n) - 1):
     initLoc(arr, locExpr, n[i], OnHeap)
     arr.r = ropecg(p.module, "$1$3[$2]", rdLoc(dest[]), intLiteral(i), dataField(p))
@@ -1384,7 +1382,13 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
     getTemp(p, n.typ, d)
   # generate call to newSeq before adding the elements per hand:
   let L = int(lengthOrd(p.config, n.sons[1].typ))
-  genNewSeqAux(p, d, intLiteral(L), optNilSeqs notin p.options and L == 0)
+  if p.config.selectedGC == gcDestructors:
+    let seqtype = n.typ
+    linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
+      rdLoc d, rope L, getTypeDesc(p.module, seqtype.lastSon),
+      getSeqPayloadType(p.module, seqtype))
+  else:
+    genNewSeqAux(p, d, intLiteral(L), optNilSeqs notin p.options and L == 0)
   initLocExpr(p, n.sons[1], a)
   # bug #5007; do not produce excessive C source code:
   if L < 10:
@@ -1394,7 +1398,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)
@@ -1405,7 +1409,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", [])
 
 
@@ -2054,6 +2058,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   of mDotDot, mEqCString: genCall(p, e, d)
   of mWasMoved: genWasMoved(p, e)
   of mMove: genMove(p, e, d)
+  of mDestroy: discard "ignore calls to the default destructor"
   of mSlice:
     localError(p.config, e.info, "invalid context for 'toOpenArray'; " &
       " 'toOpenArray' is only valid within a call expression")
diff --git a/compiler/ccgliterals.nim b/compiler/ccgliterals.nim
index ccfa49a1d..904d01e81 100644
--- a/compiler/ccgliterals.nim
+++ b/compiler/ccgliterals.nim
@@ -54,7 +54,7 @@ proc genStringLiteralV1(m: BModule; n: PNode): Rope =
 proc genStringLiteralDataOnlyV2(m: BModule, s: string): Rope =
   result = getTempName(m)
   addf(m.s[cfsData], "static const struct {$n" &
-       "  NI cap; void* allocator; NIM_CHAR data[$2];$n" &
+       "  NI cap; void* allocator; NIM_CHAR data[$2+1];$n" &
        "} $1 = { $2, NIM_NIL, $3 };$n",
        [result, rope(len(s)), makeCString(s)])
 
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 3665a7e85..e83b80b7c 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -307,11 +307,13 @@ proc genSingleVar(p: BProc, a: PNode) =
 
 proc genClosureVar(p: BProc, a: PNode) =
   var immediateAsgn = a.sons[2].kind != nkEmpty
+  var v: TLoc
+  initLocExpr(p, a.sons[0], v)
+  genLineDir(p, a)
   if immediateAsgn:
-    var v: TLoc
-    initLocExpr(p, a.sons[0], v)
-    genLineDir(p, a)
     loadInto(p, a.sons[0], a.sons[2], v)
+  else:
+    constructLoc(p, v)
 
 proc genVarStmt(p: BProc, n: PNode) =
   for it in n.sons:
@@ -609,7 +611,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
       lineF(p, cpsStmts, "throw $1;$n", [e])
     else:
       lineCg(p, cpsStmts, "#raiseExceptionEx((#Exception*)$1, $2, $3, $4, $5);$n",
-          [e, makeCString(typ.sym.name.s), 
+          [e, makeCString(typ.sym.name.s),
           makeCString(if p.prc != nil: p.prc.name.s else: p.module.module.name.s),
           makeCString(toFileName(p.config, t.info)), rope(toLinenumber(t.info))])
   else:
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index bbfd72354..266f63647 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -193,8 +193,6 @@ proc isImportedCppType(t: PType): bool =
            (x.sym != nil and sfInfixCall in x.sym.flags)
 
 proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope
-proc needsComplexAssignment(typ: PType): bool =
-  result = containsGarbageCollectedRef(typ)
 
 proc isObjLackingTypeField(typ: PType): bool {.inline.} =
   result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
@@ -214,7 +212,7 @@ proc isInvalidReturnType(conf: ConfigRef; rettype: PType): bool =
     of ctStruct:
       let t = skipTypes(rettype, typedescInst)
       if rettype.isImportedCppType or t.isImportedCppType: return false
-      result = needsComplexAssignment(t) or
+      result = containsGarbageCollectedRef(t) or
           (t.kind == tyObject and not isObjLackingTypeField(t))
     else: result = false
 
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 071cd6446..3545edc88 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -294,10 +294,10 @@ 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)
+proc genRefAssign(p: BProc, dest, src: TLoc)
 
 proc isComplexValueType(t: PType): bool {.inline.} =
   let t = t.skipTypes(abstractInst + tyUserTypeClasses)
@@ -313,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:
@@ -1490,7 +1490,7 @@ proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool =
   result = true
   if optForceFullMake notin m.config.globalOptions:
     if not equalsFile(code, cfile.cname):
-      if isDefined(m.config, "nimdiff"):
+      if m.config.symbolFiles == readOnlySf: #isDefined(m.config, "nimdiff"):
         if fileExists(cfile.cname):
           copyFile(cfile.cname.string, cfile.cname.string & ".backup")
           echo "diff ", cfile.cname.string, ".backup ", cfile.cname.string
diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim
index c2d908193..5ded6d054 100644
--- a/compiler/closureiters.nim
+++ b/compiler/closureiters.nim
@@ -1009,7 +1009,7 @@ proc stateFromGotoState(n: PNode): int =
   assert(n.kind == nkGotoState)
   result = n[0].intVal.int
 
-proc tranformStateAssignments(ctx: var Ctx, n: PNode): PNode =
+proc transformStateAssignments(ctx: var Ctx, n: PNode): PNode =
   # This transforms 3 patterns:
   ########################## 1
   # yield e
@@ -1051,7 +1051,7 @@ proc tranformStateAssignments(ctx: var Ctx, n: PNode): PNode =
       result.add(retStmt)
     else:
       for i in 0 ..< n.len:
-        n[i] = ctx.tranformStateAssignments(n[i])
+        n[i] = ctx.transformStateAssignments(n[i])
 
   of nkSkip:
     discard
@@ -1071,7 +1071,7 @@ proc tranformStateAssignments(ctx: var Ctx, n: PNode): PNode =
 
   else:
     for i in 0 ..< n.len:
-      n[i] = ctx.tranformStateAssignments(n[i])
+      n[i] = ctx.transformStateAssignments(n[i])
 
 proc skipStmtList(ctx: Ctx; n: PNode): PNode =
   result = n
@@ -1220,18 +1220,20 @@ proc wrapIntoStateLoop(ctx: var Ctx, n: PNode): PNode =
   # while true:
   #   block :stateLoop:
   #     gotoState :state
+  #     local vars decl (if needed)
   #     body # Might get wrapped in try-except
   let loopBody = newNodeI(nkStmtList, n.info)
   result = newTree(nkWhileStmt, newSymNode(ctx.g.getSysSym(n.info, "true")), loopBody)
   result.info = n.info
 
+  let localVars = newNodeI(nkStmtList, n.info)
   if not ctx.stateVarSym.isNil:
     let varSect = newNodeI(nkVarSection, n.info)
     addVar(varSect, newSymNode(ctx.stateVarSym))
-    loopBody.add(varSect)
+    localVars.add(varSect)
 
     if not ctx.tempVars.isNil:
-      loopBody.add(ctx.tempVars)
+      localVars.add(ctx.tempVars)
 
   let blockStmt = newNodeI(nkBlockStmt, n.info)
   blockStmt.add(newSymNode(ctx.stateLoopLabel))
@@ -1240,7 +1242,7 @@ proc wrapIntoStateLoop(ctx: var Ctx, n: PNode): PNode =
   gs.add(ctx.newStateAccess())
   gs.add(ctx.g.newIntLit(n.info, ctx.states.len - 1))
 
-  var blockBody = newTree(nkStmtList, gs, n)
+  var blockBody = newTree(nkStmtList, gs, localVars, n)
   if ctx.hasExceptions:
     blockBody = ctx.wrapIntoTryExcept(blockBody)
 
@@ -1292,7 +1294,6 @@ proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode =
     # should folllow the same logic.
     ctx.stateVarSym = newSym(skVar, getIdent(ctx.g.cache, ":state"), fn, fn.info)
     ctx.stateVarSym.typ = g.createClosureIterStateType(fn)
-
   ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), fn, fn.info)
   var n = n.toStmtList
 
@@ -1320,7 +1321,7 @@ proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode =
     result.add(s)
     result.add(body)
 
-  result = ctx.tranformStateAssignments(result)
+  result = ctx.transformStateAssignments(result)
   result = ctx.wrapIntoStateLoop(result)
 
   # echo "TRANSFORM TO STATES: "
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 14141696f..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)
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index ab89481b8..9a4c1701c 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -86,7 +86,7 @@ proc initDefines*(symbols: StringTableRef) =
   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..51ad26f2c 100644
--- a/compiler/destroyer.nim
+++ b/compiler/destroyer.nim
@@ -117,7 +117,7 @@ Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently
 import
   intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
   strutils, options, dfa, lowerings, tables, modulegraphs,
-  lineinfos
+  lineinfos, parampatterns
 
 const
   InterestingSyms = {skVar, skResult, skLet}
@@ -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
@@ -397,9 +402,10 @@ proc passCopyToSink(n: PNode; c: var Con): PNode =
     var m = genCopy(c, n.typ, tmp, n)
     m.add p(n, c)
     result.add m
-    message(c.graph.config, n.info, hintPerformance,
-      ("passing '$1' to a sink parameter introduces an implicit copy; " &
-      "use 'move($1)' to prevent it") % $n)
+    if isLValue(n):
+      message(c.graph.config, n.info, hintPerformance,
+        ("passing '$1' to a sink parameter introduces an implicit copy; " &
+        "use 'move($1)' to prevent it") % $n)
   else:
     result.add newTree(nkAsgn, tmp, p(n, c))
   result.add tmp
@@ -446,6 +452,18 @@ 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 nkStmtListExpr:
+    result = newNodeI(nkStmtList, ri.info)
+    for i in 0..ri.len-2:
+      result.add p(ri[i], c)
+    result.add moveOrCopy(dest, ri[^1], c)
   of nkObjConstr:
     result = genSink(c, dest.typ, dest, ri)
     let ri2 = copyTree(ri)
@@ -454,6 +472,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 +512,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/docgen.nim b/compiler/docgen.nim
index 6f61d020d..67f4108e1 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -400,7 +400,13 @@ proc extractImports(n: PNode; result: PNode) =
   for i in 0..<n.safeLen: extractImports(n[i], result)
 
 proc prepareExamples(d: PDoc; n: PNode) =
+
+  var docComment = newTree(nkCommentStmt)
+  let loc = d.conf.toFileLineCol(n.info)
+  docComment.comment = "autogenerated by docgen from " & loc
+
   var runnableExamples = newTree(nkStmtList,
+      docComment,
       newTree(nkImportStmt, newStrNode(nkStrLit, d.filename)))
   runnableExamples.info = n.info
   let imports = newTree(nkStmtList)
diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim
index 43d5a8698..09a1cd436 100644
--- a/compiler/evaltempl.nim
+++ b/compiler/evaltempl.nim
@@ -47,7 +47,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
         internalAssert c.config, sfGenSym in s.flags or s.kind == skType
         var x = PSym(idTableGet(c.mapping, s))
         if x == nil:
-          x = copySym(s, false)
+          x = copySym(s)
           x.owner = c.genSymOwner
           idTablePut(c.mapping, s, x)
         result.add newSymNode(x, if c.instLines: actual.info else: templ.info)
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/jsgen.nim b/compiler/jsgen.nim
index 19bbde777..a9813f5c5 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -66,6 +66,12 @@ type
     res: Rope               # result part; index if this is an
                              # (address, index)-tuple
     address: Rope           # address of an (address, index)-tuple
+    tmpLoc: Rope            # tmp var which stores the (address, index)
+                            # pair to prevent multiple evals.
+                            # the tmp is initialized upon evaling the
+                            # address.
+                            # might be nil.
+                            # (see `maybeMakeTemp`)
 
   TBlock = object
     id: int                  # the ID of the label; positive means that it
@@ -131,16 +137,15 @@ proc newGlobals(): PGlobals =
 proc initCompRes(r: var TCompRes) =
   r.address = nil
   r.res = nil
+  r.tmpLoc = nil
   r.typ = etyNone
   r.kind = resNone
 
 proc rdLoc(a: TCompRes): Rope {.inline.} =
-  result = a.res
-  when false:
-    if a.typ != etyBaseIndex:
-      result = a.res
-    else:
-      result = "$1[$2]" % [a.address, a.res]
+  if a.typ != etyBaseIndex:
+    result = a.res
+  else:
+    result = "$1[$2]" % [a.address, a.res]
 
 proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
              options: TOptions): PProc =
@@ -447,12 +452,48 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"],
     ["", "", "$1", "$1"]]
 
+proc needsTemp(p: PProc; n: PNode): bool =
+  # check if n contains a call to determine
+  # if a temp should be made to prevent multiple evals
+  if n.kind in nkCallKinds + {nkTupleConstr, nkObjConstr, nkBracket, nkCurly}:
+    return true
+  for c in n:
+    if needsTemp(p, c):
+      return true
+
+proc maybeMakeTemp(p: PProc, n: PNode; x: TCompRes): tuple[a, tmp: Rope] =
+  var
+    a = x.rdLoc
+    b = a
+  if needsTemp(p, n):
+    # if we have tmp just use it
+    if x.tmpLoc != nil and (mapType(n.typ) == etyBaseIndex or n.kind in {nkHiddenDeref, nkDerefExpr}):
+      b = "$1[0][$1[1]]" % [x.tmpLoc]
+      (a: a, tmp: b)
+    else:
+      let tmp = p.getTemp
+      b = tmp
+      a = "($1 = $2, $1)" % [tmp, a]
+      (a: a, tmp: b)
+  else:
+    (a: a, tmp: b)
+
 proc binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
+  # $1 and $2 in the `frmt` string bind to lhs and rhs of the expr,
+  # if $3 or $4 are present they will be substituted with temps for
+  # lhs and rhs respectively
   var x, y: TCompRes
   useMagic(p, magic)
   gen(p, n.sons[1], x)
   gen(p, n.sons[2], y)
-  r.res = frmt % [x.rdLoc, y.rdLoc]
+
+  var
+    a, tmp = x.rdLoc
+    b, tmp2 = y.rdLoc
+  if "$3" in frmt: (a, tmp) = maybeMakeTemp(p, n[1], x)
+  if "$4" in frmt: (a, tmp) = maybeMakeTemp(p, n[1], x)
+
+  r.res = frmt % [a, b, tmp, tmp2]
   r.kind = resExpr
 
 proc unsignedTrimmerJS(size: BiggestInt): Rope =
@@ -473,7 +514,8 @@ proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string,
   gen(p, n.sons[2], y)
   let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size)
   if reassign:
-    r.res = "$1 = (($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, trimmer]
+    let (a, tmp) = maybeMakeTemp(p, n[1], x)
+    r.res = "$1 = (($5 $2 $3) $4)" % [a, rope op, y.rdLoc, trimmer, tmp]
   else:
     r.res = "(($1 $2 $3) $4)" % [x.rdLoc, rope op, y.rdLoc, trimmer]
 
@@ -487,9 +529,12 @@ proc ternaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
   r.kind = resExpr
 
 proc unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
+  # $1 binds to n[1], if $2 is present it will be substituted to a tmp of $1
   useMagic(p, magic)
   gen(p, n.sons[1], r)
-  r.res = frmt % [r.rdLoc]
+  var a, tmp = r.rdLoc
+  if "$2" in frmt: (a, tmp) = maybeMakeTemp(p, n[1], r)
+  r.res = frmt % [a, tmp]
   r.kind = resExpr
 
 proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
@@ -524,6 +569,14 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
   of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr,
       mCStrToStr, mStrToStr, mEnumToStr:
     arithAux(p, n, r, op)
+  of mEqRef, mEqUntracedRef:
+    if mapType(n[1].typ) != etyBaseIndex:
+      arithAux(p, n, r, op)
+    else:
+      var x, y: TCompRes
+      gen(p, n[1], x)
+      gen(p, n[2], y)
+      r.res = "($# == $# && $# == $#)" % [x.address, y.address, x.res, y.res]
   else:
     arithAux(p, n, r, op)
   r.kind = resExpr
@@ -801,6 +854,7 @@ proc genAsmOrEmitStmt(p: PProc, n: PNode) =
           # A fat pointer is disguised as an array
           r.res = r.address
           r.address = nil
+          r.typ = etyNone
         elif r.typ == etyBaseIndex:
           # Deference first
           r.res = "$1[$2]" % [r.address, r.res]
@@ -863,26 +917,42 @@ proc countJsParams(typ: PType): int =
 
 const
   nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
-    nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkTupleConstr, nkObjConstr, nkStringToCString,
+    nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkStringToCString,
     nkCStringToString, nkCall, nkPrefix, nkPostfix, nkInfix,
     nkCommand, nkHiddenCallConv, nkCallStrLit}
 
 proc needsNoCopy(p: PProc; y: PNode): bool =
-  result = (y.kind in nodeKindsNeedNoCopy) or
-      (skipTypes(y.typ, abstractInst).kind in {tyRef, tyPtr, tyLent, tyVar})
+  # if the node is a literal object constructor we have to recursively
+  # check the expressions passed into it
+  case y.kind
+  of nkObjConstr:
+    for arg in y.sons[1..^1]:
+      if not needsNoCopy(p, arg[1]):
+        return false
+  of nkTupleConstr:
+    for arg in y.sons:
+      var arg = arg
+      if arg.kind == nkExprColonExpr:
+        arg = arg[1]
+      if not needsNoCopy(p, arg):
+        return false
+  of nkBracket:
+    for arg in y.sons:
+      if not needsNoCopy(p, arg):
+        return false
+  of nodeKindsNeedNoCopy:
+    return true
+  else:
+    return (mapType(y.typ) != etyBaseIndex and
+            (skipTypes(y.typ, abstractInst).kind in
+             {tyRef, tyPtr, tyLent, tyVar, tyCString} + IntegralTypes))
+  return true
 
 proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
   var a, b: TCompRes
   var xtyp = mapType(p, x.typ)
 
-  if x.kind == nkHiddenDeref and x.sons[0].kind == nkCall and xtyp != etyObject:
-    gen(p, x.sons[0], a)
-    let tmp = p.getTemp(false)
-    lineF(p, "var $1 = $2;$n", [tmp, a.rdLoc])
-    a.res = "$1[0][$1[1]]" % [tmp]
-  else:
-    gen(p, x, a)
-
+  gen(p, x, a)
   genLineDir(p, y)
   gen(p, y, b)
 
@@ -911,13 +981,13 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
         let tmp = p.getTemp(false)
         lineF(p, "var $1 = $4; $2 = $1[0]; $3 = $1[1];$n", [tmp, a.address, a.res, b.rdLoc])
       elif b.typ == etyBaseIndex:
-        lineF(p, "$# = $#;$n", [a.res, b.rdLoc])
+        lineF(p, "$# = [$#, $#];$n", [a.res, b.address, b.res])
       else:
         internalError(p.config, x.info, "genAsgn")
     else:
       lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
   else:
-    lineF(p, "$1 = $2;$n", [a.res, b.res])
+    lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
 
 proc genAsgn(p: PProc, n: PNode) =
   genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=false)
@@ -971,17 +1041,30 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
   r.kind = resExpr
 
 proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
-  r.typ = etyNone
   gen(p, n.sons[0], r)
+  r.typ = mapType(n.typ)
   let otyp = skipTypes(n.sons[0].typ, abstractVarRange)
+
+  template mkTemp(i: int) =
+    if r.typ == etyBaseIndex:
+      if needsTemp(p, n[i]):
+        let tmp = p.getTemp
+        r.address = "($1 = $2, $1)[0]" % [tmp, r.res]
+        r.res = "$1[1]" % [tmp]
+        r.tmpLoc = tmp
+      else:
+        r.address = "$1[0]" % [r.res]
+        r.res = "$1[1]" % [r.res]
   if otyp.kind == tyTuple:
     r.res = ("$1.Field$2") %
         [r.res, getFieldPosition(p, n.sons[1]).rope]
+    mkTemp(0)
   else:
     if n.sons[1].kind != nkSym: internalError(p.config, n.sons[1].info, "genFieldAccess")
     var f = n.sons[1].sym
     if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
     r.res = "$1.$2" % [r.res, f.loc.r]
+    mkTemp(1)
   r.kind = resExpr
 
 proc genAddr(p: PProc, n: PNode, r: var TCompRes)
@@ -1039,14 +1122,15 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
   let m = if n.kind == nkHiddenAddr: n.sons[0] else: n
   gen(p, m.sons[0], a)
   gen(p, m.sons[1], b)
-  internalAssert p.config, a.typ != etyBaseIndex and b.typ != etyBaseIndex
-  r.address = a.res
+  #internalAssert p.config, a.typ != etyBaseIndex and b.typ != etyBaseIndex
+  let (x, tmp) = maybeMakeTemp(p, m[0], a)
+  r.address = x
   var typ = skipTypes(m.sons[0].typ, abstractPtrs)
   if typ.kind == tyArray: first = firstOrd(p.config, typ.sons[0])
   else: first = 0
   if optBoundsCheck in p.options:
     useMagic(p, "chckIndx")
-    r.res = "chckIndx($1, $2, $3.length+$2-1)-$2" % [b.res, rope(first), a.res]
+    r.res = "chckIndx($1, $2, $3.length+$2-1)-$2" % [b.res, rope(first), tmp]
   elif first != 0:
     r.res = "($1)-$2" % [b.res, rope(first)]
   else:
@@ -1062,13 +1146,22 @@ proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) =
   of tyTuple:
     genFieldAddr(p, n, r)
   else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
-  r.typ = etyNone
+  r.typ = mapType(n.typ)
   if r.res == nil: internalError(p.config, n.info, "genArrayAccess")
   if ty.kind == tyCString:
     r.res = "$1.charCodeAt($2)" % [r.address, r.res]
+  elif r.typ == etyBaseIndex:
+    if needsTemp(p, n[0]):
+      let tmp = p.getTemp
+      r.address = "($1 = $2, $1)[0]" % [tmp, r.rdLoc]
+      r.res = "$1[1]" % [tmp]
+      r.tmpLoc = tmp
+    else:
+      let x = r.rdLoc
+      r.address = "$1[0]" % [x]
+      r.res = "$1[1]" % [x]
   else:
     r.res = "$1[$2]" % [r.address, r.res]
-  r.address = nil
   r.kind = resExpr
 
 template isIndirect(x: PSym): bool =
@@ -1169,8 +1262,12 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
     if k == etyBaseIndex:
       r.typ = etyBaseIndex
       if {sfAddrTaken, sfGlobal} * s.flags != {}:
-        r.address = "$1[0]" % [s.loc.r]
-        r.res = "$1[1]" % [s.loc.r]
+        if isIndirect(s):
+          r.address = "$1[0][0]" % [s.loc.r]
+          r.res = "$1[0][1]" % [s.loc.r]
+        else:
+          r.address = "$1[0]" % [s.loc.r]
+          r.res = "$1[1]" % [s.loc.r]
       else:
         r.address = s.loc.r
         r.res = s.loc.r & "_Idx"
@@ -1210,14 +1307,17 @@ proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
   else:
     var a: TCompRes
     gen(p, it, a)
-    r.kind = resExpr
-    if a.typ == etyBaseIndex:
-      r.res = "$1[$2]" % [a.address, a.res]
-    elif it.kind == nkCall:
+    r.kind = a.kind
+    r.typ = mapType(p, n.typ)
+    if r.typ == etyBaseIndex:
       let tmp = p.getTemp
-      r.res = "($1 = $2, $1[0])[$1[1]]" % [tmp, a.res]
-    elif t == etyBaseIndex:
-      r.res = "$1[0]" % [a.res]
+      r.address = "($1 = $2, $1)[0]" % [tmp, a.rdLoc]
+      r.res = "$1[1]" % [tmp]
+      r.tmpLoc = tmp
+    elif a.typ == etyBaseIndex:
+      if a.tmpLoc != nil:
+        r.tmpLoc = a.tmpLoc
+      r.res = a.rdLoc
     else:
       internalError(p.config, n.info, "genDeref")
 
@@ -1242,7 +1342,7 @@ proc genArg(p: PProc, n: PNode, param: PSym, r: var TCompRes; emitted: ptr int =
     add(r.res, ", ")
     add(r.res, a.res)
     if emitted != nil: inc emitted[]
-  elif n.typ.kind in {tyVar, tyLent} and n.kind in nkCallKinds and mapType(param.typ) == etyBaseIndex:
+  elif n.typ.kind in {tyVar, tyPtr, tyRef, tyLent} and n.kind in nkCallKinds and mapType(param.typ) == etyBaseIndex:
     # this fixes bug #5608:
     let tmp = getTemp(p)
     add(r.res, "($1 = $2, $1[0]), $1[1]" % [tmp, a.rdLoc])
@@ -1366,6 +1466,14 @@ proc genCall(p: PProc, n: PNode, r: var TCompRes) =
     return
   gen(p, n.sons[0], r)
   genArgs(p, n, r)
+  if n.typ != nil:
+    let t = mapType(n.typ)
+    if t == etyBaseIndex:
+      let tmp = p.getTemp
+      r.address = "($1 = $2, $1)[0]" % [tmp, r.rdLoc]
+      r.res = "$1[1]" % [tmp]
+      r.tmpLoc = tmp
+      r.typ = t
 
 proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
   let n = n[1].skipConv
@@ -1472,12 +1580,12 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
     createObjInitList(p, t, initIntSet(), initList)
     result = ("{$1}") % [initList]
     if indirect: result = "[$1]" % [result]
-  of tyVar, tyPtr, tyLent, tyRef:
+  of tyVar, tyPtr, tyLent, tyRef, tyPointer:
     if mapType(p, t) == etyBaseIndex:
       result = putToSeq("[null, 0]", indirect)
     else:
       result = putToSeq("null", indirect)
-  of tySequence, tyOpt, tyString, tyCString, tyPointer, tyProc:
+  of tySequence, tyOpt, tyString, tyCString, tyProc:
     result = putToSeq("null", indirect)
   of tyStatic:
     if t.n != nil:
@@ -1511,10 +1619,13 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
     varCode = v.constraint.strVal
 
   if n.kind == nkEmpty:
-    lineF(p, varCode & " = $3;$n",
-               [returnType, varName, createVar(p, v.typ, isIndirect(v))])
-    if v.typ.kind in {tyVar, tyPtr, tyLent, tyRef} and mapType(p, v.typ) == etyBaseIndex:
+    if not isIndirect(v) and
+      v.typ.kind in {tyVar, tyPtr, tyLent, tyRef} and mapType(p, v.typ) == etyBaseIndex:
+      lineF(p, "var $1 = null;$n", [varName])
       lineF(p, "var $1_Idx = 0;$n", [varName])
+    else:
+      lineF(p, varCode & " = $3;$n",
+                [returnType, varName, createVar(p, v.typ, isIndirect(v))])
   else:
     gen(p, n, a)
     case mapType(p, v.typ)
@@ -1531,8 +1642,12 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
           lineF(p, varCode & " = $3, $2_Idx = $4;$n",
                    [returnType, v.loc.r, a.address, a.res])
         else:
-          lineF(p, varCode & " = [$3, $4];$n",
-                   [returnType, v.loc.r, a.address, a.res])
+          if isIndirect(v):
+            lineF(p, varCode & " = [[$3, $4]];$n",
+                     [returnType, v.loc.r, a.address, a.res])
+          else:
+            lineF(p, varCode & " = [$3, $4];$n",
+                     [returnType, v.loc.r, a.address, a.res])
       else:
         if targetBaseIndex:
           let tmp = p.getTemp
@@ -1579,7 +1694,12 @@ proc genNew(p: PProc, n: PNode) =
   var a: TCompRes
   gen(p, n.sons[1], a)
   var t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
-  lineF(p, "$1 = $2;$n", [a.res, createVar(p, t, false)])
+  if mapType(t) == etyObject:
+    lineF(p, "$1 = $2;$n", [a.rdLoc, createVar(p, t, false)])
+  elif a.typ == etyBaseIndex:
+    lineF(p, "$1 = [$3]; $2 = 0;$n", [a.address, a.res, createVar(p, t, false)])
+  else:
+    lineF(p, "$1 = [[$2], 0];$n", [a.rdLoc, createVar(p, t, false)])
 
 proc genNewSeq(p: PProc, n: PNode) =
   var x, y: TCompRes
@@ -1603,20 +1723,20 @@ proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
   if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyChar:
     r.res.add("[$1].concat(" % [a.res])
   else:
-    r.res.add("($1).concat(" % [a.res])
+    r.res.add("($1 || []).concat(" % [a.res])
 
   for i in countup(2, sonsLen(n) - 2):
     gen(p, n.sons[i], a)
     if skipTypes(n.sons[i].typ, abstractVarRange).kind == tyChar:
       r.res.add("[$1]," % [a.res])
     else:
-      r.res.add("$1," % [a.res])
+      r.res.add("$1 || []," % [a.res])
 
   gen(p, n.sons[sonsLen(n) - 1], a)
   if skipTypes(n.sons[sonsLen(n) - 1].typ, abstractVarRange).kind == tyChar:
     r.res.add("[$1])" % [a.res])
   else:
-    r.res.add("$1)" % [a.res])
+    r.res.add("$1 || [])" % [a.res])
 
 proc genToArray(p: PProc; n: PNode; r: var TCompRes) =
   # we map mArray to PHP's array constructor, a mild hack:
@@ -1701,8 +1821,12 @@ proc genReset(p: PProc, n: PNode) =
   var x: TCompRes
   useMagic(p, "genericReset")
   gen(p, n.sons[1], x)
-  addf(p.body, "$1 = genericReset($1, $2);$n", [x.res,
-                genTypeInfo(p, n.sons[1].typ)])
+  if x.typ == etyBaseIndex:
+    lineF(p, "$1 = null, $2 = 0;$n", [x.address, x.res])
+  else:
+    let (a, tmp) = maybeMakeTemp(p, n[1], x)
+    lineF(p, "$1 = genericReset($3, $2);$n", [a,
+                  genTypeInfo(p, n.sons[1].typ), tmp])
 
 proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
   var
@@ -1721,32 +1845,37 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
     else: unaryExpr(p, n, r, "subInt", "subInt($1, 1)")
   of mAppendStrCh:
     binaryExpr(p, n, r, "addChar",
-        "if ($1 != null) { addChar($1, $2); } else { $1 = [$2]; }")
+        "if ($1 != null) { addChar($3, $2); } else { $3 = [$2]; }")
   of mAppendStrStr:
     var lhs, rhs: TCompRes
     gen(p, n[1], lhs)
     gen(p, n[2], rhs)
 
     let rhsIsLit = n[2].kind in nkStrKinds
+    let (a, tmp) = maybeMakeTemp(p, n[1], lhs)
     if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:
-      r.res = "if ($1 != null) { $1 += $2; } else { $1 = $2$3; }" % [
-        lhs.rdLoc, rhs.rdLoc, if rhsIsLit: nil else: ~".slice()"]
+      r.res = "if ($1 != null) { $4 += $2; } else { $4 = $2$3; }" % [
+        a, rhs.rdLoc, if rhsIsLit: nil else: ~".slice()", tmp]
     else:
-      r.res = "if ($1 != null) { $1 = ($1).concat($2); } else { $1 = $2$3; }" % [
-          lhs.rdLoc, rhs.rdLoc, if rhsIsLit: nil else: ~".slice()"]
+      r.res = "if ($1 != null) { $4 = ($4).concat($2); } else { $4 = $2$3; }" % [
+          lhs.rdLoc, rhs.rdLoc, if rhsIsLit: nil else: ~".slice()", tmp]
     r.kind = resExpr
   of mAppendSeqElem:
     var x, y: TCompRes
     gen(p, n.sons[1], x)
     gen(p, n.sons[2], y)
-    if needsNoCopy(p, n[2]):
-      r.res = "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }" % [x.rdLoc, y.rdLoc]
+    let (a, tmp) = maybeMakeTemp(p, n[1], x)
+    if mapType(n[2].typ) == etyBaseIndex:
+      let c = "[$1, $2]" % [y.address, y.res]
+      r.res = "if ($1 != null) { $3.push($2); } else { $3 = [$2]; }" % [a, c, tmp]
+    elif needsNoCopy(p, n[2]):
+      r.res = "if ($1 != null) { $3.push($2); } else { $3 = [$2]; }" % [a, y.rdLoc, tmp]
     else:
       useMagic(p, "nimCopy")
       let c = getTemp(p, defineInLocals=false)
       lineF(p, "var $1 = nimCopy(null, $2, $3);$n",
             [c, y.rdLoc, genTypeInfo(p, n[2].typ)])
-      r.res = "if ($1 != null) { $1.push($2); } else { $1 = [$2]; }" % [x.rdLoc, c]
+      r.res = "if ($1 != null) { $3.push($2); } else { $3 = [$2]; }" % [a, c, tmp]
     r.kind = resExpr
   of mConStrStr:
     genConStrStr(p, n, r)
@@ -1756,38 +1885,56 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
     binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) <= 0)")
   of mLtStr:
     binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) < 0)")
-  of mIsNil: unaryExpr(p, n, r, "", "($1 === null)")
+  of mIsNil:
+    if mapType(n[1].typ) != etyBaseIndex:
+      unaryExpr(p, n, r, "", "($1 === null)")
+    else:
+      var x: TCompRes
+      gen(p, n[1], x)
+      r.res = "($# === null && $# === 0)" % [x.address, x.res]
   of mEnumToStr: genRepr(p, n, r)
   of mNew, mNewFinalize: genNew(p, n)
-  of mChr, mArrToSeq: gen(p, n.sons[1], r)      # nothing to do
+  of mChr: gen(p, n.sons[1], r)
+  of mArrToSeq:
+    if needsNoCopy(p, n.sons[1]):
+      gen(p, n.sons[1], r)
+    else:
+      var x: TCompRes
+      gen(p, n.sons[1], x)
+      useMagic(p, "nimCopy")
+      r.res = "nimCopy(null, $1, $2)" % [x.rdLoc, genTypeInfo(p, n.typ)]
+  of mDestroy: discard "ignore calls to the default destructor"
   of mOrd: genOrd(p, n, r)
   of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray:
-    unaryExpr(p, n, r, "", "($1 != null ? $1.length : 0)")
+    unaryExpr(p, n, r, "", "($1 != null ? $2.length : 0)")
   of mXLenStr, mXLenSeq:
     unaryExpr(p, n, r, "", "$1.length")
   of mHigh:
-    unaryExpr(p, n, r, "", "($1 != null ? ($1.length-1) : -1)")
+    unaryExpr(p, n, r, "", "($1 != null ? ($2.length-1) : -1)")
   of mInc:
     if n[1].typ.skipTypes(abstractRange).kind in tyUInt .. tyUInt64:
       binaryUintExpr(p, n, r, "+", true)
     else:
       if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 += $2")
-      else: binaryExpr(p, n, r, "addInt", "$1 = addInt($1, $2)")
+      else: binaryExpr(p, n, r, "addInt", "$1 = addInt($3, $2)")
   of ast.mDec:
     if n[1].typ.skipTypes(abstractRange).kind in tyUInt .. tyUInt64:
       binaryUintExpr(p, n, r, "-", true)
     else:
       if optOverflowCheck notin p.options: binaryExpr(p, n, r, "", "$1 -= $2")
-      else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)")
+      else: binaryExpr(p, n, r, "subInt", "$1 = subInt($3, $2)")
   of mSetLengthStr:
-    binaryExpr(p, n, r, "", "$1.length = $2")
+    binaryExpr(p, n, r, "mnewString", "($1 === null ? $3 = mnewString($2) : $3.length = $2)")
   of mSetLengthSeq:
     var x, y: TCompRes
     gen(p, n.sons[1], x)
     gen(p, n.sons[2], y)
     let t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
-    r.res = """if ($1.length < $2) { for (var i=$1.length;i<$2;++i) $1.push($3); }
-               else { $1.length = $2; }""" % [x.rdLoc, y.rdLoc, createVar(p, t, false)]
+    let (a, tmp) = maybeMakeTemp(p, n[1], x)
+    let (b, tmp2) = maybeMakeTemp(p, n[2], y)
+    r.res = """if ($1 === null) $4 = [];
+               if ($4.length < $2) { for (var i=$4.length;i<$5;++i) $4.push($3); }
+               else { $4.length = $5; }""" % [a, b, createVar(p, t, false), tmp, tmp2]
     r.kind = resExpr
   of mCard: unaryExpr(p, n, r, "SetCard", "SetCard($1)")
   of mLtSet: binaryExpr(p, n, r, "SetLt", "SetLt($1, $2)")
@@ -1855,7 +2002,10 @@ proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
   for i in countup(0, sonsLen(n) - 1):
     if i > 0: add(r.res, ", ")
     gen(p, n.sons[i], a)
-    add(r.res, a.res)
+    if a.typ == etyBaseIndex:
+      addf(r.res, "[$1, $2]", [a.address, a.res])
+    else:
+      add(r.res, a.res)
   add(r.res, "]")
 
 proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) =
@@ -1867,7 +2017,10 @@ proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) =
     var it = n.sons[i]
     if it.kind == nkExprColonExpr: it = it.sons[1]
     gen(p, it, a)
-    addf(r.res, "Field$#: $#", [i.rope, a.res])
+    if a.typ == etyBaseIndex:
+      addf(r.res, "Field$#: [$#, $#]", [i.rope, a.address, a.res])
+    else:
+      addf(r.res, "Field$#: $#", [i.rope, a.res])
   r.res.add("}")
 
 proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
@@ -1887,12 +2040,17 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
 
     let typ = val.typ.skipTypes(abstractInst)
     if (typ.kind in IntegralTypes+{tyCstring, tyRef, tyPtr} and
-          mapType(p, typ) != etyBaseIndex) or needsNoCopy(p, it.sons[1]):
+          mapType(p, typ) != etyBaseIndex) or
+          a.typ == etyBaseIndex or
+          needsNoCopy(p, it.sons[1]):
       discard
     else:
       useMagic(p, "nimCopy")
       a.res = "nimCopy(null, $1, $2)" % [a.rdLoc, genTypeInfo(p, typ)]
-    addf(initList, "$#: $#", [f.loc.r, a.res])
+    if a.typ == etyBaseIndex:
+      addf(initList, "$#: [$#, $#]", [f.loc.r, a.address, a.res])
+    else:
+      addf(initList, "$#: $#", [f.loc.r, a.res])
   let t = skipTypes(n.typ, abstractInst + skipPtrs)
   createObjInitList(p, t, fieldIDs, initList)
   r.res = ("{$1}") % [initList]
@@ -2010,11 +2168,14 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
   if prc.typ.sons[0] != nil and sfPure notin prc.flags:
     resultSym = prc.ast.sons[resultPos].sym
     let mname = mangleName(p.module, resultSym)
-    let resVar = createVar(p, resultSym.typ, isIndirect(resultSym))
-    resultAsgn = p.indentLine(("var $# = $#;$n") % [mname, resVar])
-    if resultSym.typ.kind in {tyVar, tyPtr, tyLent, tyRef} and
+    if not isindirect(resultSym) and
+      resultSym.typ.kind in {tyVar, tyPtr, tyLent, tyRef} and
         mapType(p, resultSym.typ) == etyBaseIndex:
+      resultAsgn = p.indentLine(("var $# = null;$n") % [mname])
       resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname])
+    else:
+      let resVar = createVar(p, resultSym.typ, isIndirect(resultSym))
+      resultAsgn = p.indentLine(("var $# = $#;$n") % [mname, resVar])
     gen(p, prc.ast.sons[resultPos], a)
     if mapType(p, resultSym.typ) == etyBaseIndex:
       returnStmt = "return [$#, $#];$n" % [a.address, a.res]
@@ -2106,6 +2267,13 @@ proc genCast(p: PProc, n: PNode, r: var TCompRes) =
           of 4: "0xfffffffe"
           else: ""
         r.res = "($1 - ($2 $3))" % [rope minuend, r.res, trimmer]
+  elif (src.kind == tyPtr and mapType(p, src) == etyObject) and dest.kind == tyPointer:
+    r.address = r.res
+    r.res = ~"null"
+    r.typ = etyBaseIndex
+  elif (dest.kind == tyPtr and mapType(p, dest) == etyObject) and src.kind == tyPointer:
+    r.res = r.address
+    r.typ = etyObject
 
 proc gen(p: PProc, n: PNode, r: var TCompRes) =
   r.typ = etyNone
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index c318421fa..874cb4bd0 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -258,7 +258,7 @@ proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
   # add 'new' statement:
   result.add newCall(getSysSym(g, n.info, "internalNew"), env)
   result.add makeClosure(g, iter, env, n.info)
-  
+
 proc freshVarForClosureIter*(g: ModuleGraph; s, owner: PSym): PNode =
   let envParam = getHiddenParam(g, owner)
   let obj = envParam.typ.lastSon
@@ -454,11 +454,10 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
           createUpField(c, w, up, n.info)
           w = up
   of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit,
-     nkTemplateDef, nkTypeSection:
-    discard
-  of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef:
+     nkTemplateDef, nkTypeSection, nkProcDef, nkMethodDef,
+     nkConverterDef, nkMacroDef, nkFuncDef:
     discard
-  of nkLambdaKinds, nkIteratorDef, nkFuncDef:
+  of nkLambdaKinds, nkIteratorDef:
     if n.typ != nil:
       detectCapturedVars(n[namePos], owner, c)
   of nkReturnStmt:
@@ -672,9 +671,8 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
       else:
         result = accessViaEnvVar(n, owner, d, c)
   of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom,
-     nkTemplateDef, nkTypeSection:
-    discard
-  of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef:
+     nkTemplateDef, nkTypeSection, nkProcDef, nkMethodDef, nkConverterDef,
+     nkMacroDef, nkFuncDef:
     discard
   of nkClosure:
     if n[1].kind == nkNilLit:
@@ -685,7 +683,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
         # now we know better, so patch it:
         n.sons[0] = x.sons[0]
         n.sons[1] = x.sons[1]
-  of nkLambdaKinds, nkIteratorDef, nkFuncDef:
+  of nkLambdaKinds, nkIteratorDef:
     if n.typ != nil and n[namePos].kind == nkSym:
       let oldInContainer = c.inContainer
       c.inContainer = 0
@@ -720,19 +718,37 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
 # ------------------ old stuff -------------------------------------------
 
 proc semCaptureSym*(s, owner: PSym) =
+  discard """
+    proc outer() =
+      var x: int
+      proc inner() =
+        proc innerInner() =
+          echo x
+        innerInner()
+      inner()
+    # inner() takes a closure too!
+  """
+  proc propagateClosure(start, last: PSym) =
+    var o = start
+    while o != nil and o.kind != skModule:
+      if o == last: break
+      o.typ.callConv = ccClosure
+      o = o.skipGenericOwner
+
   if interestingVar(s) and s.kind != skResult:
     if owner.typ != nil and not isGenericRoutine(owner):
       # XXX: is this really safe?
       # if we capture a var from another generic routine,
       # it won't be consider captured.
       var o = owner.skipGenericOwner
-      while o.kind != skModule and o != nil:
+      while o != nil and o.kind != skModule:
         if s.owner == o:
           if owner.typ.callConv in {ccClosure, ccDefault} or owner.kind == skIterator:
             owner.typ.callConv = ccClosure
+            propagateClosure(owner.skipGenericOwner, s.owner)
           else:
             discard "do not produce an error here, but later"
-          #echo "computing .closure for ", owner.name.s, " ", owner.info, " because of ", s.name.s
+          #echo "computing .closure for ", owner.name.s, " because of ", s.name.s
         o = o.skipGenericOwner
     # since the analysis is not entirely correct, we don't set 'tfCapturesEnv'
     # here
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/lowerings.nim b/compiler/lowerings.nim
index 603def326..d199abcc7 100644
--- a/compiler/lowerings.nim
+++ b/compiler/lowerings.nim
@@ -78,7 +78,7 @@ proc lowerTupleUnpackingForAsgn*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
   let value = n.lastSon
   result = newNodeI(nkStmtList, n.info)
 
-  var temp = newSym(skLet, getIdent(g.cache, "_"), owner, value.info, owner.options)
+  var temp = newSym(skTemp, getIdent(g.cache, "_"), owner, value.info, owner.options)
   var v = newNodeI(nkLetSection, value.info)
   let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info)
 
diff --git a/compiler/modules.nim b/compiler/modules.nim
index e2f322561..442305a06 100644
--- a/compiler/modules.nim
+++ b/compiler/modules.nim
@@ -17,18 +17,7 @@ import
 proc resetSystemArtifacts*(g: ModuleGraph) =
   magicsys.resetSysTypes(g)
 
-proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
-  # We cannot call ``newSym`` here, because we have to circumvent the ID
-  # mechanism, which we do in order to assign each module a persistent ID.
-  new(result)
-  result.id = -1             # for better error checking
-  result.kind = skModule
-  let filename = toFullPath(graph.config, fileIdx)
-  result.name = getIdent(graph.cache, splitFile(filename).name)
-  if not isNimIdentifier(result.name.s):
-    rawMessage(graph.config, errGenerated, "invalid module name: " & result.name.s)
-
-  result.info = newLineInfo(fileIdx, 1, 1)
+proc partialInitModule(result: PSym; graph: ModuleGraph; fileIdx: FileIndex; filename: string) =
   let
     pck = getPackageName(graph.config, filename)
     pck2 = if pck.len > 0: pck else: "unknown"
@@ -38,13 +27,11 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
     packSym = newSym(skPackage, getIdent(graph.cache, pck2), nil, result.info)
     initStrTable(packSym.tab)
     graph.packageSyms.strTableAdd(packSym)
-
   result.owner = packSym
   result.position = int fileIdx
 
   if int(fileIdx) >= graph.modules.len:
     setLen(graph.modules, int(fileIdx) + 1)
-  #growCache graph.modules, int fileIdx
   graph.modules[result.position] = result
 
   incl(result.flags, sfUsed)
@@ -58,16 +45,36 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
   # strTableIncl() for error corrections:
   discard strTableIncl(packSym.tab, result)
 
+proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
+  # We cannot call ``newSym`` here, because we have to circumvent the ID
+  # mechanism, which we do in order to assign each module a persistent ID.
+  new(result)
+  result.id = -1             # for better error checking
+  result.kind = skModule
+  let filename = toFullPath(graph.config, fileIdx)
+  result.name = getIdent(graph.cache, splitFile(filename).name)
+  if not isNimIdentifier(result.name.s):
+    rawMessage(graph.config, errGenerated, "invalid module name: " & result.name.s)
+  result.info = newLineInfo(fileIdx, 1, 1)
+  partialInitModule(result, graph, fileIdx, filename)
+
 proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): PSym =
   result = graph.getModule(fileIdx)
   if result == nil:
-    result = newModule(graph, fileIdx)
-    result.flags = result.flags + flags
-    if sfMainModule in result.flags:
-      graph.config.mainPackageId = result.owner.id
-
-    result.id = getModuleId(graph, fileIdx, AbsoluteFile toFullPath(graph.config, fileIdx))
-    registerModule(graph, result)
+    let filename = toFullPath(graph.config, fileIdx)
+    let (r, id) = loadModuleSym(graph, fileIdx, AbsoluteFile filename)
+    result = r
+    if result == nil:
+      result = newModule(graph, fileIdx)
+      result.flags = result.flags + flags
+      if sfMainModule in result.flags:
+        graph.config.mainPackageId = result.owner.id
+      result.id = id
+      registerModule(graph, result)
+    else:
+      partialInitModule(result, graph, fileIdx, filename)
+      result.id = id
+      assert result.id < 0
     discard processModule(graph, result,
       if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil)
   elif graph.isDirty(result):
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 4ac5a839d..7e6b67cbe 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -190,7 +190,7 @@ template toFullPath*(conf: ConfigRef; info: TLineInfo): string =
 proc toMsgFilename*(conf: ConfigRef; info: TLineInfo): string =
   if info.fileIndex.int32 < 0:
     result = "???"
-    return  
+    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:
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 ef5223559..3d8e5645b 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -38,7 +38,7 @@ const
     wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
     wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises,
     wTags, wLocks, wGcSafe, wExportNims, wUsed}
-  exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe}
+  exprPragmas* = {wLine, wLocks, wNoRewrite, wGcSafe, wNosideeffect}
   stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
     wBoundchecks, wOverflowchecks, wNilchecks, wMovechecks, wAssertions,
     wWarnings, wHints,
@@ -855,8 +855,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
         sym.flags.incl sfOverriden
       of wNosideeffect:
         noVal(c, it)
-        incl(sym.flags, sfNoSideEffect)
-        if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
+        if sym != nil:
+          incl(sym.flags, sfNoSideEffect)
+          if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect)
       of wSideeffect:
         noVal(c, it)
         incl(sym.flags, sfSideEffect)
@@ -1110,10 +1111,19 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
         else: sym.flags.incl sfUsed
       of wLiftLocals: discard
       else: invalidPragma(c, it)
-    elif sym.kind in {skVar,skLet,skParam,skField,skProc,skFunc,skConverter,skMethod,skType}:
+    elif sym != nil and sym.kind in {skVar, skLet, skParam, skField, skProc,
+                                     skFunc, skConverter, skMethod, skType}:
       n.sons[i] = semCustomPragma(c, it)
-    else:
+    elif sym != nil:
       illegalCustomPragma(c, it, sym)
+    else:
+      invalidPragma(c, it)
+
+proc mergePragmas(n, pragmas: PNode) =
+  if n[pragmasPos].kind == nkEmpty:
+    n[pragmasPos] = pragmas
+  else:
+    for p in pragmas: n.sons[pragmasPos].add p
 
 proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
                       validPragmas: TSpecialWords) =
@@ -1123,11 +1133,12 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
       if not o.isNil:
         pushInfoContext(c.config, n.info)
         var i = 0
-        while i < o.len():
+        while i < o.len:
           if singlePragma(c, sym, o, i, validPragmas):
             internalError(c.config, n.info, "implicitPragmas")
           inc i
         popInfoContext(c.config)
+        if sym.kind in routineKinds: mergePragmas(sym.ast, o)
 
     if lfExportLib in sym.loc.flags and sfExportc notin sym.flags:
       localError(c.config, n.info, ".dynlib requires .exportc")
diff --git a/compiler/rod.nim b/compiler/rod.nim
index 92489ffdd..bbd2f0c6c 100644
--- a/compiler/rod.nim
+++ b/compiler/rod.nim
@@ -16,7 +16,7 @@ when not nimIncremental:
   template storeNode*(g: ModuleGraph; module: PSym; n: PNode) = discard
   template loadNode*(g: ModuleGraph; module: PSym): PNode = newNode(nkStmtList)
 
-  template getModuleId*(g: ModuleGraph; fileIdx: FileIndex; fullpath: AbsoluteFile): int = getID()
+  proc loadModuleSym*(g: ModuleGraph; fileIdx: FileIndex; fullpath: AbsoluteFile): (PSym, int) {.inline.} = (nil, getID())
 
   template addModuleDep*(g: ModuleGraph; module, fileIdx: FileIndex; isIncludeFile: bool) = discard
 
diff --git a/compiler/rodimpl.nim b/compiler/rodimpl.nim
index c61c4ba04..147e8c3d6 100644
--- a/compiler/rodimpl.nim
+++ b/compiler/rodimpl.nim
@@ -52,7 +52,7 @@ proc needsRecompile(g: ModuleGraph; fileIdx: FileIndex; fullpath: AbsoluteFile;
       return true
   return false
 
-proc getModuleId*(g: ModuleGraph; fileIdx: FileIndex; fullpath: AbsoluteFile): int =
+proc getModuleId(g: ModuleGraph; fileIdx: FileIndex; fullpath: AbsoluteFile): int =
   ## Analyse the known dependency graph.
   if g.config.symbolFiles == disabledSf: return getID()
   when false:
@@ -82,8 +82,12 @@ proc getModuleId*(g: ModuleGraph; fileIdx: FileIndex; fullpath: AbsoluteFile): i
     db.exec(sql"delete from toplevelstmts where module = ?", module[0])
     db.exec(sql"delete from statics where module = ?", module[0])
 
+proc loadModuleSym*(g: ModuleGraph; fileIdx: FileIndex; fullpath: AbsoluteFile): (PSym, int) =
+  let id = getModuleId(g, fileIdx, fullpath)
+  result = (g.incr.r.syms.getOrDefault(abs id), id)
+
 proc pushType(w: var Writer, t: PType) =
-  if not containsOrIncl(w.tmarks, t.id):
+  if not containsOrIncl(w.tmarks, t.uniqueId):
     w.tstack.add(t)
 
 proc pushSym(w: var Writer, s: PSym) =
@@ -109,7 +113,8 @@ proc encodeNode(g: ModuleGraph; fInfo: TLineInfo, n: PNode,
     result.add(',')
     encodeVInt(int n.info.line, result)
     result.add(',')
-    encodeVInt(toDbFileId(g.incr, g.config, n.info.fileIndex), result)
+    #encodeVInt(toDbFileId(g.incr, g.config, n.info.fileIndex), result)
+    encodeVInt(n.info.fileIndex.int, result)
   elif fInfo.line != n.info.line:
     result.add('?')
     encodeVInt(n.info.col, result)
@@ -126,7 +131,7 @@ proc encodeNode(g: ModuleGraph; fInfo: TLineInfo, n: PNode,
     encodeVInt(cast[int32](f), result)
   if n.typ != nil:
     result.add('^')
-    encodeVInt(n.typ.id, result)
+    encodeVInt(n.typ.uniqueId, result)
     pushType(w, n.typ)
   case n.kind
   of nkCharLit..nkUInt64Lit:
@@ -187,7 +192,10 @@ proc encodeType(g: ModuleGraph, t: PType, result: var string) =
   add(result, '[')
   encodeVInt(ord(t.kind), result)
   add(result, '+')
-  encodeVInt(t.id, result)
+  encodeVInt(t.uniqueId, result)
+  if t.id != t.uniqueId:
+    add(result, '+')
+    encodeVInt(t.id, result)
   if t.n != nil:
     encodeNode(g, unknownLineInfo(), t.n, result)
   if t.flags != {}:
@@ -236,12 +244,16 @@ proc encodeType(g: ModuleGraph, t: PType, result: var string) =
     encodeVInt(s.id, result)
     pushSym(w, s)
   encodeLoc(g, t.loc, result)
+  if t.typeInst != nil:
+    add(result, '\21')
+    encodeVInt(t.typeInst.uniqueId, result)
+    pushType(w, t.typeInst)
   for i in countup(0, sonsLen(t) - 1):
     if t.sons[i] == nil:
       add(result, "^()")
     else:
       add(result, '^')
-      encodeVInt(t.sons[i].id, result)
+      encodeVInt(t.sons[i].uniqueId, result)
       pushType(w, t.sons[i])
 
 proc encodeLib(g: ModuleGraph, lib: PLib, info: TLineInfo, result: var string) =
@@ -260,7 +272,7 @@ proc encodeInstantiations(g: ModuleGraph; s: seq[PInstantiation];
     pushSym(w, t.sym)
     for tt in t.concreteTypes:
       result.add('\17')
-      encodeVInt(tt.id, result)
+      encodeVInt(tt.uniqueId, result)
       pushType(w, tt)
     result.add('\20')
     encodeVInt(t.compilesId, result)
@@ -278,14 +290,15 @@ proc encodeSym(g: ModuleGraph, s: PSym, result: var string) =
   encodeStr(s.name.s, result)
   if s.typ != nil:
     result.add('^')
-    encodeVInt(s.typ.id, result)
+    encodeVInt(s.typ.uniqueId, result)
     pushType(w, s.typ)
   result.add('?')
   if s.info.col != -1'i16: encodeVInt(s.info.col, result)
   result.add(',')
   encodeVInt(int s.info.line, result)
   result.add(',')
-  encodeVInt(toDbFileId(g.incr, g.config, s.info.fileIndex), result)
+  #encodeVInt(toDbFileId(g.incr, g.config, s.info.fileIndex), result)
+  encodeVInt(s.info.fileIndex.int, result)
   if s.owner != nil:
     result.add('*')
     encodeVInt(s.owner.id, result)
@@ -313,7 +326,7 @@ proc encodeSym(g: ModuleGraph, s: PSym, result: var string) =
   of skType, skGenericParam:
     for t in s.typeInstCache:
       result.add('\14')
-      encodeVInt(t.id, result)
+      encodeVInt(t.uniqueId, result)
       pushType(w, t)
   of routineKinds:
     encodeInstantiations(g, s.procInstCache, result)
@@ -321,6 +334,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:
@@ -361,18 +377,12 @@ proc storeType(g: ModuleGraph; t: PType) =
   let m = if t.owner != nil: getModule(t.owner) else: nil
   let mid = if m == nil: 0 else: abs(m.id)
   db.exec(sql"insert into types(nimid, module, data) values (?, ?, ?)",
-    t.id, mid, buf)
+    t.uniqueId, 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:
+    if i > 100_000:
       doAssert false, "loop never ends!"
     if w.sstack.len > 0:
       let s = w.sstack.pop()
@@ -383,14 +393,30 @@ proc storeNode*(g: ModuleGraph; module: PSym; n: PNode) =
       let t = w.tstack.pop()
       storeType(g, t)
       when false:
-        echo "popped type ", typeToString(t), " ", t.id
+        echo "popped type ", typeToString(t), " ", t.uniqueId
     else:
       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 +426,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 -----------------------------------
 
@@ -426,9 +459,11 @@ proc decodeLineInfo(g; b; info: var TLineInfo) =
       else: info.line = uint16(decodeVInt(b.s, b.pos))
       if b.s[b.pos] == ',':
         inc(b.pos)
-        info.fileIndex = fromDbFileId(g.incr, g.config, decodeVInt(b.s, b.pos))
+        #info.fileIndex = fromDbFileId(g.incr, g.config, decodeVInt(b.s, b.pos))
+        info.fileIndex = FileIndex decodeVInt(b.s, b.pos)
 
 proc skipNode(b) =
+  # ')' itself cannot be part of a string literal so that this is correct.
   assert b.s[b.pos] == '('
   var par = 0
   var pos = b.pos+1
@@ -563,13 +598,18 @@ proc loadType(g; id: int; info: TLineInfo): PType =
   result.kind = TTypeKind(decodeVInt(b.s, b.pos))
   if b.s[b.pos] == '+':
     inc(b.pos)
-    result.id = decodeVInt(b.s, b.pos)
-    setId(result.id)
+    result.uniqueId = decodeVInt(b.s, b.pos)
+    setId(result.uniqueId)
     #if debugIds: registerID(result)
   else:
     internalError(g.config, info, "decodeType: no id")
+  if b.s[b.pos] == '+':
+    inc(b.pos)
+    result.id = decodeVInt(b.s, b.pos)
+  else:
+    result.id = result.uniqueId
   # here this also avoids endless recursion for recursive type
-  g.incr.r.types.add(result.id, result)
+  g.incr.r.types.add(result.uniqueId, result)
   if b.s[b.pos] == '(': result.n = decodeNode(g, b, unknownLineInfo())
   if b.s[b.pos] == '$':
     inc(b.pos)
@@ -620,6 +660,10 @@ proc loadType(g; id: int; info: TLineInfo): PType =
     let y = loadSym(g, decodeVInt(b.s, b.pos), info)
     result.methods.add((x, y))
   decodeLoc(g, b, result.loc, info)
+  if b.s[b.pos] == '\21':
+    inc(b.pos)
+    let d = decodeVInt(b.s, b.pos)
+    result.typeInst = loadType(g, d, info)
   while b.s[b.pos] == '^':
     inc(b.pos)
     if b.s[b.pos] == '(':
@@ -725,6 +769,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:
@@ -874,20 +921,22 @@ proc setupModuleCache*(g: ModuleGraph) =
   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/sem.nim b/compiler/sem.nim
index 775c9f7c9..924e53b66 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -204,7 +204,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
   if n.kind == nkSym:
     # and sfGenSym in n.sym.flags:
     result = n.sym
-    if result.kind != kind:
+    if result.kind notin {kind, skTemp}:
       localError(c.config, n.info, "cannot use symbol of kind '" &
                  $result.kind & "' as a '" & $kind & "'")
     if sfGenSym in result.flags and result.kind notin {skTemplate, skMacro, skParam}:
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 9433a7327..08917cb29 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -1490,6 +1490,13 @@ proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
 template resultTypeIsInferrable(typ: PType): untyped =
   typ.isMetaType and typ.kind != tyTypeDesc
 
+
+proc goodLineInfo(arg: PNode): TLineinfo =
+  if arg.kind == nkStmtListExpr and arg.len > 0:
+    goodLineInfo(arg[^1])
+  else:
+    arg.info
+
 proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
   checkSonsLen(n, 2, c.config)
   var a = n.sons[0]
@@ -1571,7 +1578,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
         else:
           typeMismatch(c.config, n.info, lhs.typ, rhsTyp)
 
-    n.sons[1] = fitNode(c, le, rhs, n.info)
+    n.sons[1] = fitNode(c, le, rhs, goodLineInfo(n[1]))
     liftTypeBoundOps(c, lhs.typ, lhs.info)
     #liftTypeBoundOps(c, n.sons[0].typ, n.sons[0].info)
 
@@ -1968,6 +1975,22 @@ proc setMs(n: PNode, s: PSym): PNode =
   n.sons[0] = newSymNode(s)
   n.sons[0].info = n.info
 
+proc semSizeof(c: PContext, n: PNode): PNode =
+  if sonsLen(n) != 2:
+    localError(c.config, n.info, errXExpectsTypeOrValue % "sizeof")
+  else:
+    n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
+    #restoreOldStyleType(n.sons[1])
+  n.typ = getSysType(c.graph, n.info, tyInt)
+
+  let size = getSize(c.config, n[1].typ)
+  if size >= 0:
+    result = newIntNode(nkIntLit, size)
+    result.info = n.info
+    result.typ = n.typ
+  else:
+    result = n
+
 proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
   # this is a hotspot in the compiler!
   result = n
@@ -2039,6 +2062,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
   of mRunnableExamples:
     if c.config.cmd == cmdDoc and n.len >= 2 and n.lastSon.kind == nkStmtList:
       when false:
+        # some of this dead code was moved to `prepareExamples`
         if sfMainModule in c.module.flags:
           let inp = toFullPath(c.config, c.module.info)
           if c.runnableExamples == nil:
@@ -2052,6 +2076,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
       result = setMs(n, s)
     else:
       result = c.graph.emptyNode
+  of mSizeOf: result = semSizeof(c, setMs(n, s))
   of mOmpParFor:
     checkMinSonsLen(n, 3, c.config)
     result = semDirectOp(c, n, flags)
@@ -2346,7 +2371,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)
@@ -2354,6 +2378,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/seminst.nim b/compiler/seminst.nim
index de2e10a9b..17f61c7dd 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -118,7 +118,7 @@ proc freshGenSyms(n: PNode, owner, orig: PSym, symMap: var TIdTable) =
       n.sym = x
     elif s.owner.kind == skPackage:
       #echo "copied this ", s.name.s
-      x = copySym(s, false)
+      x = copySym(s)
       x.owner = owner
       idTablePut(symMap, s, x)
       n.sym = x
@@ -337,7 +337,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   c.matchedConcept = nil
   let oldScope = c.currentScope
   while not isTopLevel(c): c.currentScope = c.currentScope.parent
-  result = copySym(fn, false)
+  result = copySym(fn)
   incl(result.flags, sfFromGeneric)
   result.owner = fn
   result.ast = n
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 2aae562f9..df2c084a1 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -346,7 +346,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
       result.info = n.info
       result.typ = n.typ
     else:
-      localError(c.config, n.info, "cannot evaluate 'sizeof' because its type is not defined completely")
+      localError(c.config, n.info, "cannot evaluate 'sizeof' because its type is not defined completely, type: " & n[1].typ.typeToString)
       result = n
   of mAlignOf:
     result = newIntNode(nkIntLit, getAlign(c.config, n[1].typ))
@@ -381,7 +381,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
     if n[0].sym.name.s == "=":
       result = semAsgnOpr(c, n)
     else:
-      result = n
+      result = semShallowCopy(c, n, flags)
   of mIsPartOf: result = semIsPartOf(c, n, flags)
   of mTypeTrait: result = semTypeTraits(c, n)
   of mAstToStr:
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index 0317fd8ba..75dea069f 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -56,6 +56,7 @@ type
     guards: TModel # nested guards
     locked: seq[PNode] # locked locations
     gcUnsafe, isRecursive, isToplevel, hasSideEffect, inEnforcedGcSafe: bool
+    inEnforcedNoSideEffects: bool
     maxLockLevel, currLockLevel: TLockLevel
     config: ConfigRef
     graph: ModuleGraph
@@ -194,10 +195,10 @@ proc markGcUnsafe(a: PEffects; reason: PNode) =
 
 when true:
   template markSideEffect(a: PEffects; reason: typed) =
-    a.hasSideEffect = true
+    if not a.inEnforcedNoSideEffects: a.hasSideEffect = true
 else:
   template markSideEffect(a: PEffects; reason: typed) =
-    a.hasSideEffect = true
+    if not a.inEnforcedNoSideEffects: a.hasSideEffect = true
     markGcUnsafe(a, reason)
 
 proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet; conf: ConfigRef) =
@@ -846,15 +847,20 @@ proc track(tracked: PEffects, n: PNode) =
     let oldLocked = tracked.locked.len
     let oldLockLevel = tracked.currLockLevel
     var enforcedGcSafety = false
+    var enforceNoSideEffects = false
     for i in 0 ..< pragmaList.len:
       let pragma = whichPragma(pragmaList.sons[i])
       if pragma == wLocks:
         lockLocations(tracked, pragmaList.sons[i])
       elif pragma == wGcSafe:
         enforcedGcSafety = true
+      elif pragma == wNosideeffect:
+        enforceNoSideEffects = true
     if enforcedGcSafety: tracked.inEnforcedGcSafe = true
+    if enforceNoSideEffects: tracked.inEnforcedNoSideEffects = true
     track(tracked, n.lastSon)
     if enforcedGcSafety: tracked.inEnforcedGcSafe = false
+    if enforceNoSideEffects: tracked.inEnforcedNoSideEffects = false
     setLen(tracked.locked, oldLocked)
     tracked.currLockLevel = oldLockLevel
   of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 1f2b9f0b3..48aa75528 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1268,7 +1268,7 @@ proc semProcAnnotation(c: PContext, prc: PNode;
     x.add(prc)
 
     # recursion assures that this works for multiple macro annotations too:
-    var r = semOverloadedCall(c, x, x, {skMacro}, {efNoUndeclared})
+    var r = semOverloadedCall(c, x, x, {skMacro, skTemplate}, {efNoUndeclared})
     if r == nil:
       # Restore the old list of pragmas since we couldn't process this
       prc.sons[pragmasPos] = n
@@ -1860,7 +1860,7 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
   for i in 0 ..< pragmaList.len:
     case whichPragma(pragmaList.sons[i])
     of wLine: setLine(result, pragmaList.sons[i].info)
-    of wLocks, wGcSafe:
+    of wLocks, wGcSafe, wNosideeffect:
       result = n
       result.typ = n.sons[1].typ
     of wNoRewrite:
@@ -1963,7 +1963,8 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
         case n.sons[j].kind
         of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkBlockExpr,
             nkBlockStmt, nkState: discard
-        else: localError(c.config, n.sons[j].info, "unreachable statement after 'return'")
+        else: localError(c.config, n.sons[j].info,
+          "unreachable statement after 'return' statement or '{.noReturn.}' proc")
     else: discard
 
   if result.len == 1 and
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index f4a1b0302..a011a8fc8 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -392,7 +392,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
           localError(c.config, n.info, errTypeExpected)
           return errorSym(c, n)
         result = result.typ.sym.copySym
-        result.typ = copyType(result.typ, result.typ.owner, true)
+        result.typ = exactReplica(result.typ)
         result.typ.flags.incl tfUnresolved
 
       if result.kind == skGenericParam:
@@ -1728,7 +1728,7 @@ proc processMagicType(c: PContext, m: PSym) =
   of mBool: setMagicType(c.config, m, tyBool, 1)
   of mChar: setMagicType(c.config, m, tyChar, 1)
   of mString:
-    setMagicType(c.config, m, tyString, c.config.target.ptrSize)
+    setMagicType(c.config, m, tyString, szUncomputedSize)
     rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar))
     when false:
       if c.config.selectedGc == gcDestructors:
@@ -1758,28 +1758,28 @@ proc processMagicType(c: PContext, m: PSym) =
   of mVoidType:
     setMagicType(c.config, m, tyVoid, 0)
   of mArray:
-    setMagicType(c.config, m, tyArray, 0)
+    setMagicType(c.config, m, tyArray, szUncomputedSize)
   of mOpenArray:
-    setMagicType(c.config, m, tyOpenArray, 0)
+    setMagicType(c.config, m, tyOpenArray, szUncomputedSize)
   of mVarargs:
-    setMagicType(c.config, m, tyVarargs, 0)
+    setMagicType(c.config, m, tyVarargs, szUncomputedSize)
   of mRange:
-    setMagicType(c.config, m, tyRange, 0)
+    setMagicType(c.config, m, tyRange, szUncomputedSize)
     rawAddSon(m.typ, newTypeS(tyNone, c))
   of mSet:
-    setMagicType(c.config, m, tySet, 0)
+    setMagicType(c.config, m, tySet, szUncomputedSize)
   of mUncheckedArray:
-    setMagicType(c.config, m, tyUncheckedArray, 0)
+    setMagicType(c.config, m, tyUncheckedArray, szUncomputedSize)
   of mSeq:
-    setMagicType(c.config, m, tySequence, 0)
+    setMagicType(c.config, m, tySequence, szUncomputedSize)
     if c.config.selectedGc == gcDestructors:
       incl m.typ.flags, tfHasAsgn
     assert c.graph.sysTypes[tySequence] == nil
     c.graph.sysTypes[tySequence] = m.typ
   of mOpt:
-    setMagicType(c.config, m, tyOpt, 0)
+    setMagicType(c.config, m, tyOpt, szUncomputedSize)
   of mOrdinal:
-    setMagicType(c.config, m, tyOrdinal, 0)
+    setMagicType(c.config, m, tyOrdinal, szUncomputedSize)
     rawAddSon(m.typ, newTypeS(tyNone, c))
   of mPNimrodNode:
     incl m.typ.flags, tfTriggersCompileTime
@@ -1787,7 +1787,7 @@ proc processMagicType(c: PContext, m: PSym) =
   of mBuiltinType:
     case m.name.s
     of "lent": setMagicType(c.config, m, tyLent, c.config.target.ptrSize)
-    of "sink": setMagicType(c.config, m, tySink, 0)
+    of "sink": setMagicType(c.config, m, tySink, szUncomputedSize)
     else: localError(c.config, m.info, errTypeExpected)
   else: localError(c.config, m.info, errTypeExpected)
 
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index b05fb37ae..ffa913f1d 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -233,7 +233,7 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
 
   #result = PSym(idTableGet(cl.symMap, s))
   #if result == nil:
-  result = copySym(s, false)
+  result = copySym(s)
   incl(result.flags, sfFromGeneric)
   #idTablePut(cl.symMap, s, result)
   result.owner = s.owner
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 4adf0bed3..d66e8d121 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -432,7 +432,7 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
     else: result = isNone
 
 proc genericParamPut(c: var TCandidate; last, fGenericOrigin: PType) =
- if fGenericOrigin != nil and last.kind == tyGenericInst and
+  if fGenericOrigin != nil and last.kind == tyGenericInst and
      last.len-1 == fGenericOrigin.len:
    for i in countup(1, sonsLen(fGenericOrigin) - 1):
      let x = PType(idTableGet(c.bindings, fGenericOrigin.sons[i]))
@@ -1034,8 +1034,8 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
 
   template doBind: bool = trDontBind notin flags
 
-  # var and static arguments match regular modifier-free types
-  var a = maybeSkipDistinct(c, aOrig.skipTypes({tyStatic, tyVar, tyLent}), c.calleeSym)
+  # var, sink and static arguments match regular modifier-free types
+  var a = maybeSkipDistinct(c, aOrig.skipTypes({tyStatic, tyVar, tyLent, tySink}), c.calleeSym)
   # XXX: Theoretically, maybeSkipDistinct could be called before we even
   # start the param matching process. This could be done in `prepareOperand`
   # for example, but unfortunately `prepareOperand` is not called in certain
@@ -1045,7 +1045,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
     return typeRel(c, f, lastSon(aOrig))
 
   if a.kind == tyGenericInst and
-      skipTypes(f, {tyVar, tyLent}).kind notin {
+      skipTypes(f, {tyVar, tyLent, tySink}).kind notin {
         tyGenericBody, tyGenericInvocation,
         tyGenericInst, tyGenericParam} + tyTypeClasses:
     return typeRel(c, f, lastSon(a))
@@ -1835,7 +1835,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
     if destIsGeneric:
       dest = generateTypeInstance(c, m.bindings, arg, dest)
     let fdest = typeRel(m, f, dest)
-    if fdest in {isEqual, isGeneric}:
+    if fdest in {isEqual, isGeneric} and not (dest.kind == tyLent and f.kind == tyVar):
       markUsed(c.config, arg.info, c.converters[i], c.graph.usageSym)
       var s = newSymNode(c.converters[i])
       s.typ = c.converters[i].typ
@@ -2231,8 +2231,15 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
       else:
         m.state = csNoMatch
         return
+    
     if formal.typ.kind == tyVar:
-      if not n.isLValue:
+      let arg_converter = if arg.kind == nkHiddenDeref: arg[0] else: arg
+      if arg_converter.kind == nkHiddenCallConv:
+        if arg_converter.typ.kind != tyVar:
+          m.state = csNoMatch
+          m.mutabilityProblem = uint8(f-1)
+          return  
+      elif not n.isLValue:
         m.state = csNoMatch
         m.mutabilityProblem = uint8(f-1)
         return
@@ -2243,6 +2250,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
         else: 0
     # iterates over the actual given arguments
     a = 1
+    arg: PNode # current prepared argument
 
   m.state = csMatch # until proven otherwise
   m.call = newNodeI(n.kind, n.info)
@@ -2297,7 +2305,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
       m.typedescMatched = false
       n.sons[a].sons[1] = prepareOperand(c, formal.typ, n.sons[a].sons[1])
       n.sons[a].typ = n.sons[a].sons[1].typ
-      var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
+      arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
                                 n.sons[a].sons[1], n.sons[a].sons[1])
       if arg == nil:
         m.state = csNoMatch
@@ -2334,7 +2342,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           m.typedescMatched = false
           incl(marker, formal.position)
           n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
-          var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
+          arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
                                     n.sons[a], nOrig.sons[a])
           if arg != nil and m.baseTypeMatch and container != nil:
             addSon(container, arg)
@@ -2368,7 +2376,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
           m.baseTypeMatch = false
           m.typedescMatched = false
           n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
-          var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
+          arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
                                     n.sons[a], nOrig.sons[a])
           if arg == nil:
             m.state = csNoMatch
diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim
index 4791788fa..a34383d9f 100644
--- a/compiler/sizealignoffsetimpl.nim
+++ b/compiler/sizealignoffsetimpl.nim
@@ -52,6 +52,7 @@ proc computeSubObjectAlign(conf: ConfigRef; n: PNode): BiggestInt =
 proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, initialOffset: BiggestInt): tuple[offset, align: BiggestInt] =
   ## ``offset`` is the offset within the object, after the node has been written, no padding bytes added
   ## ``align`` maximum alignment from all sub nodes
+  assert n != nil
   if n.typ != nil and n.typ.size == szIllegalRecursion:
     result.offset = szIllegalRecursion
     result.align  = szIllegalRecursion
@@ -177,7 +178,7 @@ proc computePackedObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, initialOf
 
 proc computeSizeAlign(conf: ConfigRef; typ: PType) =
   ## computes and sets ``size`` and ``align`` members of ``typ``
-
+  assert typ != nil
   let hasSize = typ.size != szUncomputedSize
   let hasAlign = typ.align != szUncomputedSize
 
@@ -220,7 +221,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
     typ.align = int16(conf.target.ptrSize)
 
   of tyString:
-    if tfHasAsgn in typ.flags:
+    if conf.selectedGC == gcDestructors:
       typ.size = conf.target.ptrSize * 2
     else:
       typ.size = conf.target.ptrSize
@@ -237,13 +238,13 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
     # recursive tuplers are not allowed and should be detected in the frontend
     if base.kind == tyTuple:
       computeSizeAlign(conf, base)
-      if base.size == szIllegalRecursion:
-        typ.size = szIllegalRecursion
-        typ.align = szIllegalRecursion
+      if base.size < 0:
+        typ.size = base.size
+        typ.align = base.align
         return
 
     typ.align = int16(conf.target.ptrSize)
-    if typ.kind == tySequence and tfHasAsgn in typ.flags:
+    if typ.kind == tySequence and conf.selectedGC == gcDestructors:
       typ.size = conf.target.ptrSize * 2
     else:
       typ.size = conf.target.ptrSize
@@ -310,9 +311,9 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
     for i in countup(0, sonsLen(typ) - 1):
       let child = typ.sons[i]
       computeSizeAlign(conf, child)
-      if child.size == szIllegalRecursion:
-        typ.size = szIllegalRecursion
-        typ.align = szIllegalRecursion
+      if child.size < 0:
+        typ.size = child.size
+        typ.align = child.align
         return
       maxAlign = max(maxAlign, child.align)
       sizeAccum = align(sizeAccum, child.align) + child.size
@@ -379,7 +380,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
       typ.size = typ.lastSon.size
       typ.align = typ.lastSon.align
 
-  of tyGenericInst, tyDistinct, tyGenericBody, tyAlias:
+  of tyGenericInst, tyDistinct, tyGenericBody, tyAlias, tySink:
     computeSizeAlign(conf, typ.lastSon)
     typ.size = typ.lastSon.size
     typ.align = typ.lastSon.align
diff --git a/compiler/trees.nim b/compiler/trees.nim
index fb523de9d..ca2360e12 100644
--- a/compiler/trees.nim
+++ b/compiler/trees.nim
@@ -92,8 +92,7 @@ proc isCaseObj*(n: PNode): bool =
 
 proc isDeepConstExpr*(n: PNode): bool =
   case n.kind
-  of nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
-      nkFloatLit..nkFloat64Lit, nkNilLit:
+  of nkCharLit..nkNilLit:
     result = true
   of nkExprEqExpr, nkExprColonExpr, nkHiddenStdConv, nkHiddenSubConv:
     result = isDeepConstExpr(n.sons[1])
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 5b5b807bb..7e7ec8903 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -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:
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/vmgen.nim b/compiler/vmgen.nim
index c37ec7c6b..1f2a3e6d1 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -1148,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)
@@ -1238,8 +1239,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     if dest < 0: dest = c.getTemp(n.typ)
     c.gABC(n, opcCallSite, dest)
   of mNGenSym: genBinaryABC(c, n, dest, opcGenSym)
-  of mMinI, mMaxI, mAbsF64, mMinF64, mMaxF64, mAbsI,
-     mDotDot:
+  of mMinI, mMaxI, mAbsF64, mMinF64, mMaxF64, mAbsI, mDotDot:
     c.genCall(n, dest)
   of mExpandToAst:
     if n.len != 2:
@@ -1258,6 +1258,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     globalError(c.config, n.info, "cannot evaluate 'sizeof/alignof' because its type is not defined completely")
   of mRunnableExamples:
     discard "just ignore any call to runnableExamples"
+  of mDestroy: discard "ignore calls to the default destructor"
   else:
     # mGCref, mGCunref,
     globalError(c.config, n.info, "cannot generate code for: " & $m)
diff --git a/compiler/vmops.nim b/compiler/vmops.nim
index f87ab4508..75873bfe8 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, `mod`, fmod
+  floor, ceil, `mod`
 
 from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir
 
@@ -102,7 +102,6 @@ proc registerAdditionalOps*(c: PCtx) =
   wrap1f_math(trunc)
   wrap1f_math(floor)
   wrap1f_math(ceil)
-  wrap2f_math(fmod)
 
   proc `mod Wrapper`(a: VmArgs) {.nimcall.} =
     setResult(a, `mod`(getFloat(a, 0), getFloat(a, 1)))
diff --git a/doc/advopt.txt b/doc/advopt.txt
index 4fabdda9a..7cd72f6c3 100644
--- a/doc/advopt.txt
+++ b/doc/advopt.txt
@@ -101,6 +101,7 @@ Advanced options:
   --listCmd                 list the commands used to execute external programs
   --parallelBuild:0|1|...   perform a parallel build
                             value = number of processors (0 for auto-detect)
+  --incremental:on|off      only recompile the changed modules (experimental!)
   --verbosity:0|1|2|3       set Nim's verbosity level (1 is default)
   --experimental:$1
                             enable experimental language feature
diff --git a/doc/backends.rst b/doc/backends.rst
index ef30971c9..a85b39e5e 100644
--- a/doc/backends.rst
+++ b/doc/backends.rst
@@ -268,7 +268,7 @@ form the Nim code, then link them into a static binary along your main C
 program::
 
   $ nim c --noMain --noLinking --header:fib.h fib.nim
-  $ gcc -o m -Inimcache -Ipath/to/nim/lib nimcache/*.c maths.c
+  $ gcc -o m -I$HOME/.cache/nim/fib_d -Ipath/to/nim/lib $HOME/.cache/nim/fib_d/*.c maths.c
 
 The first command runs the Nim compiler with three special options to avoid
 generating a ``main()`` function in the generated files, avoid linking the
diff --git a/doc/manual.rst b/doc/manual.rst
index b39711dfb..a646b7963 100644
--- a/doc/manual.rst
+++ b/doc/manual.rst
@@ -6755,6 +6755,16 @@ routines marked as ``noSideEffect``.
   func `+` (x, y: int): int
 
 
+To override the compiler's side effect analysis a ``{.noSideEffect.}``
+pragma block can be used:
+
+.. code-block:: nim
+
+  func f() =
+    {.noSideEffect.}:
+      echo "test"
+
+
 compileTime pragma
 ------------------
 The ``compileTime`` pragma is used to mark a proc or variable to be used at
diff --git a/doc/tut2.rst b/doc/tut2.rst
index 39e3bd89a..d0c6e7247 100644
--- a/doc/tut2.rst
+++ b/doc/tut2.rst
@@ -13,7 +13,6 @@ Introduction
 
   "Repetition renders the ridiculous reasonable." -- Norman Wildberger
 
-
 This document is a tutorial for the advanced constructs of the *Nim*
 programming language. **Note that this document is somewhat obsolete as the**
 `manual <manual.html>`_ **contains many more examples of the advanced language
@@ -652,369 +651,8 @@ avoid a common bug: to forget to close the file. Note how the
 ``let fn = filename`` statement ensures that ``filename`` is evaluated only
 once.
 
-Macros
-======
-
-Macros enable advanced compile-time code transformations, but they cannot
-change Nim's syntax. However, this is no real restriction because Nim's
-syntax is flexible enough anyway. Macros have to be implemented in pure Nim
-code if the `foreign function interface (FFI)
-<manual.html#foreign-function-interface>`_ is not enabled in the compiler, but
-other than that restriction (which at some point in the future will go away)
-you can write any kind of Nim code and the compiler will run it at compile
-time.
-
-There are two ways to write a macro, either *generating* Nim source code and
-letting the compiler parse it, or creating manually an abstract syntax tree
-(AST) which you feed to the compiler. In order to build the AST one needs to
-know how the Nim concrete syntax is converted to an abstract syntax tree
-(AST). The AST is documented in the `macros <macros.html>`_ module.
-
-Once your macro is finished, there are two ways to invoke it:
-(1) invoking a macro like a procedure call (expression macros)
-(2) invoking a macro with the special ``macrostmt``
-    syntax (statement macros)
-
-
-Expression Macros
------------------
-
-The following example implements a powerful ``debug`` command that accepts a
-variable number of arguments:
-
-.. code-block:: nim
-    :test: "nim c $1"
-  # to work with Nim syntax trees, we need an API that is defined in the
-  # ``macros`` module:
-  import macros
-
-  macro debug(n: varargs[untyped]): typed =
-    # `n` is a Nim AST that contains a list of expressions;
-    # this macro returns a list of statements (n is passed for proper line
-    # information):
-    result = newNimNode(nnkStmtList, n)
-    # iterate over any argument that is passed to this macro:
-    for x in n:
-      # add a call to the statement list that writes the expression;
-      # `toStrLit` converts an AST to its string representation:
-      result.add(newCall("write", newIdentNode("stdout"), toStrLit(x)))
-      # add a call to the statement list that writes ": "
-      result.add(newCall("write", newIdentNode("stdout"), newStrLitNode(": ")))
-      # add a call to the statement list that writes the expressions value:
-      result.add(newCall("writeLine", newIdentNode("stdout"), x))
-
-  var
-    a: array[0..10, int]
-    x = "some string"
-  a[0] = 42
-  a[1] = 45
-
-  debug(a[0], a[1], x)
-
-The macro call expands to:
-
-.. code-block:: nim
-  write(stdout, "a[0]")
-  write(stdout, ": ")
-  writeLine(stdout, a[0])
-
-  write(stdout, "a[1]")
-  write(stdout, ": ")
-  writeLine(stdout, a[1])
-
-  write(stdout, "x")
-  write(stdout, ": ")
-  writeLine(stdout, x)
-
-
-
-Statement Macros
-----------------
-
-Statement macros are defined just as expression macros. However, they are
-invoked by an expression following a colon.
-
-The following example outlines a macro that generates a lexical analyzer from
-regular expressions:
-
-.. code-block:: nim
-
-  macro case_token(n: varargs[untyped]): typed =
-    # creates a lexical analyzer from regular expressions
-    # ... (implementation is an exercise for the reader :-)
-    discard
-
-  case_token: # this colon tells the parser it is a macro statement
-  of r"[A-Za-z_]+[A-Za-z_0-9]*":
-    return tkIdentifier
-  of r"0-9+":
-    return tkInteger
-  of r"[\+\-\*\?]+":
-    return tkOperator
-  else:
-    return tkUnknown
-
-
-Building your first macro
--------------------------
-
-To give a footstart to writing macros we will show now how to turn your typical
-dynamic code into something that compiles statically. For the exercise we will
-use the following snippet of code as the starting point:
-
-.. code-block:: nim
-    :test: "nim c $1"
-
-  import strutils, tables
-
-  proc readCfgAtRuntime(cfgFilename: string): Table[string, string] =
-    let
-      inputString = readFile(cfgFilename)
-    var
-      source = ""
-
-    result = initTable[string, string]()
-    for line in inputString.splitLines:
-      # Ignore empty lines
-      if line.len < 1: continue
-      var chunks = split(line, ',')
-      if chunks.len != 2:
-        quit("Input needs comma split values, got: " & line)
-      result[chunks[0]] = chunks[1]
-
-    if result.len < 1: quit("Input file empty!")
-
-  let info = readCfgAtRuntime("data.cfg")
-
-  when isMainModule:
-    echo info["licenseOwner"]
-    echo info["licenseKey"]
-    echo info["version"]
-
-Presumably this snippet of code could be used in a commercial software, reading
-a configuration file to display information about the person who bought the
-software. This external file would be generated by an online web shopping cart
-to be included along the program containing the license information::
-
-  version,1.1
-  licenseOwner,Hyori Lee
-  licenseKey,M1Tl3PjBWO2CC48m
-
-The ``readCfgAtRuntime`` proc will open the given filename and return a
-``Table`` from the `tables module <tables.html>`_. The parsing of the file is
-done (without much care for handling invalid data or corner cases) using the
-`splitLines proc from the strutils module <strutils.html#splitLines>`_. There
-are many things which can fail; mind the purpose is explaining how to make
-this run at compile time, not how to properly implement a DRM scheme.
-
-The reimplementation of this code as a compile time proc will allow us to get
-rid of the ``data.cfg`` file we would need to distribute along the binary, plus
-if the information is really constant, it doesn't make from a logical point of
-view to have it *mutable* in a global variable, it would be better if it was a
-constant. Finally, and likely the most valuable feature, we can implement some
-verification at compile time. You could think of this as a *better unit
-testing*, since it is impossible to obtain a binary unless everything is
-correct, preventing you to ship to users a broken program which won't start
-because a small critical file is missing or its contents changed by mistake to
-something invalid.
-
-
-Generating source code
-++++++++++++++++++++++
-
-Our first attempt will start by modifying the program to generate a compile
-time string with the *generated source code*, which we then pass to the
-``parseStmt`` proc from the `macros module <macros.html>`_. Here is the
-modified source code implementing the macro:
-
-.. code-block:: nim
-   :number-lines:
-
-  import macros, strutils
-
-  macro readCfgAndBuildSource(cfgFilename: string): typed =
-    let
-      inputString = slurp(cfgFilename.strVal)
-    var
-      source = ""
-
-    for line in inputString.splitLines:
-      # Ignore empty lines
-      if line.len < 1: continue
-      var chunks = split(line, ',')
-      if chunks.len != 2:
-        error("Input needs comma split values, got: " & line)
-      source &= "const cfg" & chunks[0] & "= \"" & chunks[1] & "\"\n"
-
-    if source.len < 1: error("Input file empty!")
-    result = parseStmt(source)
-
-  readCfgAndBuildSource("data.cfg")
-
-  when isMainModule:
-    echo cfglicenseOwner
-    echo cfglicenseKey
-    echo cfgversion
-
-The good news is not much has changed! First, we need to change the handling
-of the input parameter (line 3). In the dynamic version the
-``readCfgAtRuntime`` proc receives a string parameter. However, in the macro
-version it is also declared as string, but this is the *outside* interface of
-the macro.  When the macro is run, it actually gets a ``PNimNode`` object
-instead of a string, and we have to call the `strVal proc
-<macros.html#strVal>`_ (line 5) from the `macros module <macros.html>`_ to
-obtain the string being passed in to the macro.
-
-Second, we cannot use the `readFile proc <system.html#readFile>`_ from the
-`system module <system.html>`_ due to FFI restriction at compile time. If we
-try to use this proc, or any other which depends on FFI, the compiler will
-error with the message ``cannot evaluate`` and a dump of the macro's source
-code, along with a stack trace where the compiler reached before bailing out.
-We can get around this limitation by using the `slurp proc
-<system.html#slurp>`_ from the `system module <system.html>`_, which was
-precisely made for compilation time (just like `gorge <system.html#gorge>`_
-which executes an external program and captures its output).
-
-The interesting thing is that our macro does not return a runtime `Table
-<tables.html#Table>`_ object. Instead, it builds up Nim source code into
-the ``source`` variable.  For each line of the configuration file a ``const``
-variable will be generated (line 15).  To avoid conflicts we prefix these
-variables with ``cfg``. In essence, what the compiler is doing is replacing
-the line calling the macro with the following snippet of code:
-
-.. code-block:: nim
-  const cfgversion = "1.1"
-  const cfglicenseOwner = "Hyori Lee"
-  const cfglicenseKey = "M1Tl3PjBWO2CC48m"
-
-You can verify this yourself adding the line ``echo source`` somewhere at the
-end of the macro and compiling the program. Another difference is that instead
-of calling the usual `quit proc <system.html#quit>`_ to abort (which we could
-still call) this version calls the `error proc <macros.html#error>`_ (line
-14). The ``error`` proc has the same behavior as ``quit`` but will dump also
-the source and file line information where the error happened, making it
-easier for the programmer to find where compilation failed. In this situation
-it would point to the line invoking the macro, but **not** the line of
-``data.cfg`` we are processing, that's something the macro itself would need
-to control.
-
-
-Generating AST by hand
-++++++++++++++++++++++
-
-To generate an AST we would need to intimately know the structures used by the
-Nim compiler exposed in the `macros module <macros.html>`_, which at first
-look seems a daunting task. But we can use as helper shortcut the `dumpTree
-macro <macros.html#dumpTree>`_, which is used as a statement macro instead of
-an expression macro.  Since we know that we want to generate a bunch of
-``const`` symbols we can create the following source file and compile it to
-see what the compiler *expects* from us:
-
-.. code-block:: nim
-    :test: "nim c $1"
-  import macros
-
-  dumpTree:
-    const cfgversion: string = "1.1"
-    const cfglicenseOwner = "Hyori Lee"
-    const cfglicenseKey = "M1Tl3PjBWO2CC48m"
-
-During compilation of the source code we should see the following lines in the
-output (again, since this is a macro, compilation is enough, you don't have to
-run any binary)::
-
-  StmtList
-    ConstSection
-      ConstDef
-        Ident !"cfgversion"
-        Ident !"string"
-        StrLit 1.1
-    ConstSection
-      ConstDef
-        Ident !"cfglicenseOwner"
-        Empty
-        StrLit Hyori Lee
-    ConstSection
-      ConstDef
-        Ident !"cfglicenseKey"
-        Empty
-        StrLit M1Tl3PjBWO2CC48m
-
-With this output we have a better idea of what kind of input the compiler
-expects. We need to generate a list of statements. For each constant the source
-code generates a ``ConstSection`` and a ``ConstDef``. If we were to move all
-the constants to a single ``const`` block we would see only a single
-``ConstSection`` with three children.
-
-Maybe you didn't notice, but in the ``dumpTree`` example the first constant
-explicitly specifies the type of the constant.  That's why in the tree output
-the two last constants have their second child ``Empty`` but the first has a
-string identifier. So basically a ``const`` definition is made up from an
-identifier, optionally a type (can be an *empty* node) and the value. Armed
-with this knowledge, let's look at the finished version of the AST building
-macro:
-
-.. code-block:: nim
-   :number-lines:
-
-  import macros, strutils
-
-  macro readCfgAndBuildAST(cfgFilename: string): typed =
-    let
-      inputString = slurp(cfgFilename.strVal)
-
-    result = newNimNode(nnkStmtList)
-    for line in inputString.splitLines:
-      # Ignore empty lines
-      if line.len < 1: continue
-      var chunks = split(line, ',')
-      if chunks.len != 2:
-        error("Input needs comma split values, got: " & line)
-      var
-        section = newNimNode(nnkConstSection)
-        constDef = newNimNode(nnkConstDef)
-      constDef.add(newIdentNode("cfg" & chunks[0]))
-      constDef.add(newEmptyNode())
-      constDef.add(newStrLitNode(chunks[1]))
-      section.add(constDef)
-      result.add(section)
-
-    if result.len < 1: error("Input file empty!")
-
-  readCfgAndBuildAST("data.cfg")
-
-  when isMainModule:
-    echo cfglicenseOwner
-    echo cfglicenseKey
-    echo cfgversion
-
-Since we are building on the previous example generating source code, we will
-only mention the differences to it. Instead of creating a temporary ``string``
-variable and writing into it source code as if it were written *by hand*, we
-use the ``result`` variable directly and create a statement list node
-(``nnkStmtList``) which will hold our children (line 7).
-
-For each input line we have to create a constant definition (``nnkConstDef``)
-and wrap it inside a constant section (``nnkConstSection``). Once these
-variables are created, we fill them hierarchichally (line 17) like the
-previous AST dump tree showed: the constant definition is a child of the
-section definition, and the constant definition has an identifier node, an
-empty node (we let the compiler figure out the type), and a string literal
-with the value.
-
-A last tip when writing a macro: if you are not sure the AST you are building
-looks ok, you may be tempted to use the ``dumpTree`` macro. But you can't use
-it *inside* the macro you are writting/debugging. Instead ``echo`` the string
-generated by `treeRepr <macros.html#treeRepr>`_. If at the end of the this
-example you add ``echo treeRepr(result)`` you should get the same output as
-using the ``dumpTree`` macro, but of course you can call that at any point of
-the macro where you might be having troubles.
-
-Example Templates and Macros
-============================
-
-Lifting Procs
-+++++++++++++
+Example: Lifting Procs
+----------------------
 
 .. code-block:: nim
     :test: "nim c $1"
@@ -1039,36 +677,6 @@ Lifting Procs
   liftScalarProc(sqrt)   # make sqrt() work for sequences
   echo sqrt(@[4.0, 16.0, 25.0, 36.0])   # => @[2.0, 4.0, 5.0, 6.0]
 
-Identifier Mangling
-+++++++++++++++++++
-
-.. code-block:: nim
-  proc echoHW() =
-    echo "Hello world"
-  proc echoHW0() =
-    echo "Hello world 0"
-  proc echoHW1() =
-    echo "Hello world 1"
-
-  template joinSymbols(a, b: untyped): untyped =
-    `a b`()
-
-  joinSymbols(echo, HW)
-
-  macro str2Call(s1, s2): typed =
-    result = newNimNode(nnkStmtList)
-    for i in 0..1:
-      # combines s1, s2 and an integer into an proc identifier
-      # that is called in a statement list
-      result.add(newCall(!($s1 & $s2 & $i)))
-
-  str2Call("echo", "HW")
-
-  # Output:
-  #   Hello world
-  #   Hello world 0
-  #   Hello world 1
-
 Compilation to JavaScript
 =========================
 
@@ -1083,3 +691,9 @@ JavaScript-compatible code you should remember the following:
 - ``cstring`` in JavaScript means JavaScript string. It is a good practice to
   use ``cstring`` only when it is semantically appropriate. E.g. don't use
   ``cstring`` as a binary data buffer.
+
+
+Part 3
+======
+
+Next part will be entirely about metaprogramming via macros: `Part III <tut3.html>`_
diff --git a/doc/tut3.rst b/doc/tut3.rst
new file mode 100644
index 000000000..5590db8fe
--- /dev/null
+++ b/doc/tut3.rst
@@ -0,0 +1,354 @@
+=======================
+Nim Tutorial (Part III)
+=======================
+
+:Author: Arne Döring
+:Version: |nimversion|
+
+.. contents::
+
+
+Introduction
+============
+
+  "With Great Power Comes Great Responsibility." -- Spider Man's Uncle
+
+This document is a tutorial about Nim's macro system.
+A macro is a function that is executed at compile time and transforms
+a Nim syntax tree into a different tree.
+
+Examples of things that can be implemented in macros:
+
+ * An assert macro that prints both sides of a comparison operator, if
+the assertion fails. ``myAssert(a == b)`` is converted to
+``if a != b: quit($a " != " $b)``
+
+ * A debug macro that prints the value and the name of the symbol.
+``myDebugEcho(a)`` is converted to ``echo "a: ", a``
+
+ * Symbolic differentiation of an expression.
+``diff(a*pow(x,3) + b*pow(x,2) + c*x + d, x)``  is converted to
+``3*a*pow(x,2) + 2*a*x + c``
+
+
+Macro Arguments
+---------------
+
+The types of macro arguments have two faces. One face is used for
+the overload resolution, and the other face is used within the macro
+body. For example, if ``macro foo(arg: int)`` is called in an
+expression ``foo(x)``, ``x`` has to be of a type compatible to int, but
+*within* the macro's body ``arg`` has the type ``NimNode``, not ``int``!
+Why it is done this way will become obvious later, when we have seen
+concrete examples.
+
+There are two ways to pass arguments to a macro, an argument can be
+either ``typed`` or ``untyped``.
+
+
+Untyped Arguments
+-----------------
+
+Untyped macro arguments are passed to the macro before they are
+semantically checked. This means the syntax tree that is passed down
+to the macro does not need to make sense for Nim yet, the only
+limitation is that it needs to be parseable. Usually the macro does
+not check the argument either but uses it in the transformation's
+result somehow. The result of a macro expansion is always checked
+by the compiler, so apart from weird error messages nothing bad
+can happen.
+
+The downside for an ``untyped`` argument is that these do not play
+well with Nim's overloading resolution.
+
+The upside for untyped arguments is that the syntax tree is
+quite predictable and less complex compared to its ``typed``
+counterpart.
+
+
+Typed Arguments
+---------------
+
+For typed arguments, the semantic checker runs on the argument and
+does transformations on it, before it is passed to the macro. Here
+identifier nodes are resolved as symbols, implicit type
+conversions are visible in the tree as calls, templates are
+expanded and probably most importantly, nodes have type information.
+Typed arguments can have the type ``typed`` in the arguments list.
+But all other types, such as ``int``, ``float`` or ``MyObjectType``
+are typed arguments as well, and they are passed to the macro as a
+syntax tree.
+
+
+Static Arguments
+----------------
+
+Static arguments are a way to pass values as values and not as syntax
+tree nodes to a macro. For example for ``macro foo(arg: static[int])``
+in the expression ``foo(x)``, ``x`` needs to be an integer constant,
+but in the macro body ``arg`` is just like a normal parameter of type
+``int``.
+
+.. code-block:: nim
+
+  import macros
+
+  macro myMacro(arg: static[int]): untyped =
+    echo arg # just an int (7), not ``NimNode``
+
+  myMacro(1 + 2 * 3)
+
+
+Code blocks as arguments
+------------------------
+
+It is possible to pass the last argument of a call expression in a
+separate code block with indentation. For example the following code
+example is a valid (but not a recommended) way to call ``echo``:
+
+.. code-block:: nim
+
+  echo "Hello ":
+    let a = "Wor"
+    let b = "ld!"
+    a & b
+
+For macros this way of calling is very useful; syntax trees of arbitrary
+complexity can be passed to macros with this notation.
+
+
+The Syntax Tree
+---------------
+
+In order to build a Nim syntax tree one needs to know how Nim source
+code is represented as a syntax tree, and how such a tree needs to
+look like so that the Nim compiler will understand it. The nodes of the
+Nim syntax tree are documented in the `macros <macros.html>`_ module.
+But a more interactive way to explore the Nim
+syntax tree is with ``macros.treeRepr``, it converts a syntax tree
+into a multi line string for printing on the console. It can be used
+to explore how the argument expressions are represented in tree form
+and for debug printing of generated syntax tree. ``dumpTree`` is a
+predefined macro that just prints its argument in tree representation,
+but does nothing else. Here is an example of such a tree representation:
+
+.. code-block:: nim
+
+  dumpTree:
+    var mt: MyType = MyType(a:123.456, b:"abcdef")
+
+  # output:
+  #   StmtList
+  #     VarSection
+  #       IdentDefs
+  #         Ident "mt"
+  #         Ident "MyType"
+  #         ObjConstr
+  #           Ident "MyType"
+  #           ExprColonExpr
+  #             Ident "a"
+  #             FloatLit 123.456
+  #           ExprColonExpr
+  #             Ident "b"
+  #             StrLit "abcdef"
+
+
+Custom sematic checking
+-----------------------
+
+The first thing that a macro should do with its arguments is to check
+if the argument is in the correct form. Not every type of wrong input
+needs to be caught here, but anything that could cause a crash during
+macro evaluation should be caught and create a nice error message.
+``macros.expectKind`` and ``macros.expectLen`` are a good start. If
+the checks need to be more complex, arbitrary error messages can
+be created with the ``macros.error`` proc.
+
+.. code-block:: nim
+
+  macro myAssert(arg: untyped): untyped =
+    arg.expectKind nnkInfix
+
+
+Generating Code
+---------------
+
+There are two ways to generate the code. Either by creating the syntax
+tree with expressions that contain a lot of calls to ``newTree`` and
+``newLit``, or with ``quote do:`` expressions. The first option offers
+the best low level control for the syntax tree generation, but the
+second option is much less verbose. If you choose to create the syntax
+tree with calls to ``newTree`` and ``newLit`` the macro
+``marcos.dumpAstGen`` can help you with the verbosity. ``quote do:``
+allows you to write the code that you want to generate literally,
+backticks are used to insert code from ``NimNode`` symbols into the
+generated expression. This means that you can't use backticks within
+``quote do:`` for anything else than injecting symbols.  Make sure to
+inject only symbols of type ``NimNode`` into the generated syntax
+tree. You can use ``newLit`` to convert arbitrary values into
+expressions trees of type ``NimNode`` so that it is safe to inject
+them into the tree.
+
+
+.. code-block:: nim
+    :test: "nim c $1"
+
+  import macros
+
+  type
+    MyType = object
+      a: float
+      b: string
+
+  macro myMacro(arg: untyped): untyped =
+    var mt: MyType = MyType(a:123.456, b:"abcdef")
+
+    # ...
+
+    let mtLit = newLit(mt)
+
+    result = quote do:
+      echo `arg`
+      echo `mtLit`
+
+  myMacro("Hallo")
+
+The call to ``myMacro`` will generate the following code:
+
+.. code-block:: nim
+  echo "Hallo"
+  echo MyType(a: 123.456'f64, b: "abcdef")
+
+
+Building your first macro
+-------------------------
+
+To give a footstart to writing macros we will show now how to
+implement the ``myDebug`` macro mentioned earlier. The first thing to
+do is to build a simple example of the macro usage, and then just
+print the argument. This way it is possible to get an idea of a
+correct argument should be look like.
+
+.. code-block:: nim
+    :test: "nim c $1"
+
+  import macros
+
+  macro myAssert(arg: untyped): untyped =
+    echo arg.treeRepr
+
+  let a = 1
+  let b = 2
+
+  myAssert(a != b)
+
+.. code-block::
+
+  Infix
+    Ident "!="
+    Ident "a"
+    Ident "b"
+
+
+From the output it is possible to see that the information that the
+argument is an infix operator (node kind is "Infix"), as well as that the two
+operands are at index 1 and 2. With this information the actual
+macro can be written.
+
+.. code-block:: nim
+    :test: "nim c $1"
+
+  import macros
+
+  macro myAssert(arg: untyped): untyped =
+    # all node kind identifiers are prefixed with "nnk"
+    arg.expectKind nnkInfix
+    arg.expectLen 3
+    # operator as string literal
+    let op  = newLit(" " & arg[0].repr & " ")
+    let lhs = arg[1]
+    let rhs = arg[2]
+
+    result = quote do:
+      if not `arg`:
+        raise newException(AssertionError,$`lhs` & `op` & $`rhs`)
+
+  let a = 1
+  let b = 2
+
+  myAssert(a != b)
+  myAssert(a == b)
+
+
+This is the code that will be generated. To debug what the macro
+actually generated, the statement ``echo result.repr`` can be used, in
+the last line of the macro. It is also the statement that has been
+used to get this output.
+
+.. code-block:: nim
+  if not (a != b):
+    raise newException(AssertionError, $a & " != " & $b)
+
+With Power Comes Responsibility
+-------------------------------
+
+Macros are very powerful. A good advice is to use them as little as
+possible, but as much as necessary. Macros can change the semantics of
+expressions, making the code incomprehensible for anybody who does not
+know exactly what the macro does with it. So whenever a macro is not
+necessary and the same logic can be implemented using templates or
+generics, it is probably better not to use a macro. And when a macro
+is used for something, the macro should better have a well written
+documentation. For all the people who claim to write only perfectly
+self-explanatory code: when it comes to macros, the implementation is
+not enough for documentation.
+
+Limitations
+-----------
+
+Since macros are evaluated in the compiler in the NimVM, macros share
+all the limitations of the NimVM. They have to be implemented in pure Nim
+code. Macros can start external processes on the shell, but they
+cannot call C functions except from those that are built in the
+compiler.
+
+
+More Examples
+=============
+
+This tutorial can only cover the basics of the macro system. There are
+macros out there that could be an inspiration for you of what is
+possible with it.
+
+
+Strformat
+---------
+
+In the Nim standard library, the ``strformat`` library provides a
+macro that parses a string literal at compile time. Parsing a string
+in a macro like here is generally not recommended. The parsed AST
+cannot have type information, and parsing implemented on the VM is
+generally not very fast. Working on AST nodes is almost always the
+recommended way. But still ``strformat`` is a good example for a
+practical use case for a macro that is slightly more complex that the
+``assert`` macro.
+
+`Strformat <https://github.com/nim-lang/Nim/blob/5845716df8c96157a047c2bd6bcdd795a7a2b9b1/lib/pure/strformat.nim#L280>`_
+
+Ast Pattern Matching
+--------------------
+
+Ast Pattern Matching is a macro library to aid in writing complex
+macros. This can be seen as a good example of how to repurpose the
+Nim syntax tree with new semantics.
+
+`Ast Pattern Matching <https://github.com/krux02/ast-pattern-matching>`_
+
+OpenGL Sandbox
+--------------
+
+This project has a working Nim to GLSL compiler written entirely in
+macros. It scans recursively though all used function symbols to
+compile them so that cross library functions can be executed on the GPU.
+
+`OpenGL Sandbox <https://github.com/krux02/opengl-sandbox>`_
diff --git a/examples/tunit.nim b/examples/tunit.nim
index 785b9aa5e..bc447812d 100644
--- a/examples/tunit.nim
+++ b/examples/tunit.nim
@@ -1,3 +1,4 @@
+
 import
   unittest, macros
 
@@ -44,4 +45,3 @@ test "arithmetic failure":
 
   expect(ArithmeticError, CatchableError):
     discard foo()
-
diff --git a/lib/core/allocators.nim b/lib/core/allocators.nim
index f652f0d85..5189bb762 100644
--- a/lib/core/allocators.nim
+++ b/lib/core/allocators.nim
@@ -11,19 +11,36 @@ type
   AllocatorFlag* {.pure.} = enum  ## flags describing the properties of the allocator
     ThreadLocal ## the allocator is thread local only.
     ZerosMem    ## the allocator always zeros the memory on an allocation
-  Allocator* = ptr object {.inheritable.}
+  Allocator* = ptr AllocatorObj
+  AllocatorObj* {.inheritable.} = object
     alloc*: proc (a: Allocator; size: int; alignment: int = 8): pointer {.nimcall.}
     dealloc*: proc (a: Allocator; p: pointer; size: int) {.nimcall.}
     realloc*: proc (a: Allocator; p: pointer; oldSize, newSize: int): pointer {.nimcall.}
     deallocAll*: proc (a: Allocator) {.nimcall.}
     flags*: set[AllocatorFlag]
+    allocCount: int
+    deallocCount: int
 
 var
   localAllocator {.threadvar.}: Allocator
   sharedAllocator: Allocator
+  allocatorStorage {.threadvar.}: AllocatorObj
 
 proc getLocalAllocator*(): Allocator =
   result = localAllocator
+  if result == nil:
+    result = addr allocatorStorage
+    result.alloc = proc (a: Allocator; size: int; alignment: int = 8): pointer {.nimcall.} =
+      result = system.alloc(size)
+      inc a.allocCount
+    result.dealloc = proc (a: Allocator; p: pointer; size: int) {.nimcall.} =
+      system.dealloc(p)
+      inc a.deallocCount
+    result.realloc = proc (a: Allocator; p: pointer; oldSize, newSize: int): pointer {.nimcall.} =
+      result = system.realloc(p, newSize)
+    result.deallocAll = nil
+    result.flags = {ThreadLocal}
+    localAllocator = result
 
 proc setLocalAllocator*(a: Allocator) =
   localAllocator = a
@@ -34,15 +51,6 @@ proc getSharedAllocator*(): Allocator =
 proc setSharedAllocator*(a: Allocator) =
   sharedAllocator = a
 
-when false:
-  proc alloc*(size: int; alignment: int = 8): pointer =
-    let a = getCurrentAllocator()
-    result = a.alloc(a, size, alignment)
-
-  proc dealloc*(p: pointer; size: int) =
-    let a = getCurrentAllocator()
-    a.dealloc(a, p, size)
-
-  proc realloc*(p: pointer; oldSize, newSize: int): pointer =
-    let a = getCurrentAllocator()
-    result = a.realloc(a, p, oldSize, newSize)
+proc allocCounters*(): (int, int) =
+  let a = getLocalAllocator()
+  result = (a.allocCount, a.deallocCount)
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index d74d86bf6..f45ca3f82 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -274,6 +274,12 @@ when defined(nimHasSymOwnerInMacro):
     ## result is also mnde of kind nnkSym if owner exists otherwise
     ## nnkNilLit is returned
 
+when defined(nimHasInstantiationOfInMacro):
+  proc isInstantiationOf*(instanceProcSym, genProcSym: NimNode): bool {.magic: "SymIsInstantiationOf", noSideEffect.}
+    ## check if proc symbol is instance of the generic proc symbol
+    ## useful to check proc symbols against generic symbols 
+    ## returned by `bindSym`
+ 
 proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.}
   ## with 'getType' you can access the node's `type`:idx:. A Nim type is
   ## mapped to a Nim AST too, so it's slightly confusing but it means the same
diff --git a/lib/core/seqs.nim b/lib/core/seqs.nim
index fb81a30de..a41ef10ab 100644
--- a/lib/core/seqs.nim
+++ b/lib/core/seqs.nim
@@ -85,7 +85,7 @@ type
 proc newSeqPayload(cap, elemSize: int): pointer {.compilerRtl.} =
   # we have to use type erasure here as Nim does not support generic
   # compilerProcs. Oh well, this will all be inlined anyway.
-  if cap <= 0:
+  if cap > 0:
     let region = getLocalAllocator()
     var p = cast[ptr PayloadBase](region.alloc(region, cap * elemSize + sizeof(int) + sizeof(Allocator)))
     p.region = region
@@ -94,23 +94,25 @@ proc newSeqPayload(cap, elemSize: int): pointer {.compilerRtl.} =
   else:
     result = nil
 
-proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {.compilerRtl.} =
-  if len+addlen <= len:
-    result = p
-  elif p == nil:
-    result = newSeqPayload(len+addlen, elemSize)
-  else:
-    # Note: this means we cannot support things that have internal pointers as
-    # they get reallocated here. This needs to be documented clearly.
-    var p = cast[ptr PayloadBase](p)
-    let region = if p.region == nil: getLocalAllocator() else: p.region
-    let cap = max(resize(p.cap), len+addlen)
-    var q = cast[ptr PayloadBase](region.realloc(region, p,
-      sizeof(int) + sizeof(Allocator) + elemSize * p.cap,
-      sizeof(int) + sizeof(Allocator) + elemSize * cap))
-    q.region = region
-    q.cap = cap
-    result = q
+proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {.
+    compilerRtl, noSideEffect.} =
+  {.noSideEffect.}:
+    if len+addlen <= len:
+      result = p
+    elif p == nil:
+      result = newSeqPayload(len+addlen, elemSize)
+    else:
+      # Note: this means we cannot support things that have internal pointers as
+      # they get reallocated here. This needs to be documented clearly.
+      var p = cast[ptr PayloadBase](p)
+      let region = if p.region == nil: getLocalAllocator() else: p.region
+      let cap = max(resize(p.cap), len+addlen)
+      var q = cast[ptr PayloadBase](region.realloc(region, p,
+        sizeof(int) + sizeof(Allocator) + elemSize * p.cap,
+        sizeof(int) + sizeof(Allocator) + elemSize * cap))
+      q.region = region
+      q.cap = cap
+      result = q
 
 proc shrink*[T](x: var seq[T]; newLen: Natural) =
   sysAssert newLen <= x.len, "invalid newLen parameter for 'shrink'"
@@ -124,18 +126,19 @@ proc grow*[T](x: var seq[T]; newLen: Natural; value: T) =
   let oldLen = x.len
   if newLen <= oldLen: return
   var xu = cast[ptr NimSeqV2[T]](addr x)
-
-  xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newLen - oldLen, sizeof(T)))
+  if xu.p == nil or xu.p.cap < newLen:
+    xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, newLen - oldLen, sizeof(T)))
   xu.len = newLen
   for i in oldLen .. newLen-1:
-    x.data[i] = value
+    xu.p.data[i] = value
 
 proc setLen[T](s: var seq[T], newlen: Natural) =
-  if newlen < s.len:
-    shrink(s, newLen)
-  else:
-    var v: T # get the default value of 'v'
-    grow(s, newLen, v)
+  {.noSideEffect.}:
+    if newlen < s.len:
+      shrink(s, newLen)
+    else:
+      var v: T # get the default value of 'v'
+      grow(s, newLen, v)
 
 when false:
   proc resize[T](s: var NimSeqV2[T]) =
diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim
index 14613c50d..cfb8f8f5d 100644
--- a/lib/core/typeinfo.nim
+++ b/lib/core/typeinfo.nim
@@ -106,6 +106,7 @@ proc getDiscriminant(aa: pointer, n: ptr TNimNode): int =
   of 1: d = ze(cast[ptr int8](a +% n.offset)[])
   of 2: d = ze(cast[ptr int16](a +% n.offset)[])
   of 4: d = int(cast[ptr int32](a +% n.offset)[])
+  of 8: d = int(cast[ptr int64](a +% n.offset)[])
   else: assert(false)
   return d
 
diff --git a/lib/js/jsffi.nim b/lib/js/jsffi.nim
index 307fe2382..e1c59803d 100644
--- a/lib/js/jsffi.nim
+++ b/lib/js/jsffi.nim
@@ -69,10 +69,25 @@ template mangleJsName(name: cstring): cstring =
   inc nameCounter
   "mangledName" & $nameCounter
 
+# only values that can be mapped 1 to 1 with cstring should be keys: they have an injective function with cstring
+
+proc toJsKey*[T: SomeInteger](text: cstring, t: type T): T {.importcpp: "parseInt(#)".}
+
+proc toJsKey*[T: enum](text: cstring, t: type T): T =
+  T(text.toJsKey(int))
+
+proc toJsKey*(text: cstring, t: type cstring): cstring =
+  text
+
+proc toJsKey*[T: SomeFloat](text: cstring, t: type T): T {.importcpp: "parseFloat(#)".}
+
 type
+  JsKey* = concept a, type T
+    cstring.toJsKey(T) is type(a)
+
   JsObject* = ref object of JsRoot
     ## Dynamically typed wrapper around a JavaScript object.
-  JsAssoc*[K, V] = ref object of JsRoot
+  JsAssoc*[K: JsKey, V] = ref object of JsRoot
     ## Statically typed wrapper around a JavaScript object.
 
   js* = JsObject
@@ -104,7 +119,7 @@ type
 proc newJsObject*: JsObject {. importcpp: "{@}" .}
   ## Creates a new empty JsObject
 
-proc newJsAssoc*[K, V]: JsAssoc[K, V] {. importcpp: "{@}" .}
+proc newJsAssoc*[K: JsKey, V]: JsAssoc[K, V] {. importcpp: "{@}" .}
   ## Creates a new empty JsAssoc with key type `K` and value type `V`.
 
 # Checks
@@ -176,21 +191,19 @@ proc `[]=`*[T](obj: JsObject, field: cstring, val: T) {. importcpp: setImpl .}
 proc `[]=`*[T](obj: JsObject, field: int, val: T) {. importcpp: setImpl .}
   ## Set the value of a property of name `field` in a JsObject `obj` to `v`.
 
-proc `[]`*[K: not string, V](obj: JsAssoc[K, V], field: K): V
-  {. importcpp: getImpl .}
-  ## Return the value of a property of name `field` from a JsAssoc `obj`.
-
-proc `[]`*[V](obj: JsAssoc[string, V], field: cstring): V
+proc `[]`*[K: JsKey, V](obj: JsAssoc[K, V], field: K): V
   {. importcpp: getImpl .}
   ## Return the value of a property of name `field` from a JsAssoc `obj`.
 
-proc `[]=`*[K: not string, V](obj: JsAssoc[K, V], field: K, val: V)
+proc `[]=`*[K: JsKey, V](obj: JsAssoc[K, V], field: K, val: V)
   {. importcpp: setImpl .}
   ## Set the value of a property of name `field` in a JsAssoc `obj` to `v`.
 
-proc `[]=`*[V](obj: JsAssoc[string, V], field: cstring, val: V)
-  {. importcpp: setImpl .}
-  ## Set the value of a property of name `field` in a JsAssoc `obj` to `v`.
+proc `[]`*[V](obj: JsAssoc[cstring, V], field: string): V =
+  obj[cstring(field)]
+
+proc `[]=`*[V](obj: JsAssoc[cstring, V], field: string, val: V) =
+  obj[cstring(field)] = val
 
 proc `==`*(x, y: JsRoot): bool {. importcpp: "(# === #)" .}
   ## Compare two JsObjects or JsAssocs. Be careful though, as this is comparison
@@ -277,7 +290,7 @@ macro `.()`*(obj: JsObject,
     result[0][3].add newIdentDefs(paramName, newIdentNode(!"JsObject"))
     result[1].add args[idx].copyNimTree
 
-macro `.`*[K: string | cstring, V](obj: JsAssoc[K, V],
+macro `.`*[K: cstring, V](obj: JsAssoc[K, V],
                                    field: untyped): V =
   ## Experimental dot accessor (get) for type JsAssoc.
   ## Returns the value of a property of name `field` from a JsObject `x`.
@@ -293,7 +306,7 @@ macro `.`*[K: string | cstring, V](obj: JsAssoc[K, V],
       {. importcpp: `importString`, gensym .}
     helper(`obj`)
 
-macro `.=`*[K: string | cstring, V](obj: JsAssoc[K, V],
+macro `.=`*[K: cstring, V](obj: JsAssoc[K, V],
                                     field: untyped,
                                     value: V): untyped =
   ## Experimental dot accessor (set) for type JsAssoc.
@@ -310,7 +323,7 @@ macro `.=`*[K: string | cstring, V](obj: JsAssoc[K, V],
       {. importcpp: `importString`, gensym .}
     helper(`obj`, `value`)
 
-macro `.()`*[K: string | cstring, V: proc](obj: JsAssoc[K, V],
+macro `.()`*[K: cstring, V: proc](obj: JsAssoc[K, V],
                                            field: untyped,
                                            args: varargs[untyped]): auto =
   ## Experimental "method call" operator for type JsAssoc.
@@ -354,24 +367,18 @@ iterator keys*(obj: JsObject): cstring =
   yield k
   {.emit: "}".}
 
-iterator pairs*[K, V](assoc: JsAssoc[K, V]): (K,V) =
+iterator pairs*[K: JsKey, V](assoc: JsAssoc[K, V]): (K,V) =
   ## Yields tuples of type ``(K, V)``, with the first entry
   ## being a `key` in the JsAssoc and the second being its corresponding value.
-  when K is string:
-    var k: cstring
-  else:
-    var k: K
+  var k: cstring
   var v: V
   {.emit: "for (var `k` in `assoc`) {".}
   {.emit: "  if (!`assoc`.hasOwnProperty(`k`)) continue;".}
   {.emit: "  `v`=`assoc`[`k`];".}
-  when K is string:
-    yield ($k, v)
-  else:
-    yield (k, v)
+  yield (k.toJsKey(K), v)
   {.emit: "}".}
 
-iterator items*[K,V](assoc: JSAssoc[K,V]): V =
+iterator items*[K, V](assoc: JSAssoc[K, V]): V =
   ## Yields the `values` in a JsAssoc.
   var v: V
   {.emit: "for (var k in `assoc`) {".}
@@ -380,18 +387,12 @@ iterator items*[K,V](assoc: JSAssoc[K,V]): V =
   yield v
   {.emit: "}".}
 
-iterator keys*[K,V](assoc: JSAssoc[K,V]): K =
+iterator keys*[K: JsKey, V](assoc: JSAssoc[K, V]): K =
   ## Yields the `keys` in a JsAssoc.
-  when K is string:
-    var k: cstring
-  else:
-    var k: K
+  var k: cstring
   {.emit: "for (var `k` in `assoc`) {".}
   {.emit: "  if (!`assoc`.hasOwnProperty(`k`)) continue;".}
-  when K is string:
-    yield $k
-  else:
-    yield k
+  yield k.toJsKey(K)
   {.emit: "}".}
 
 # Literal generation
diff --git a/lib/nimrtl.nim b/lib/nimrtl.nim
index 4e4cf7e0e..335207f54 100644
--- a/lib/nimrtl.nim
+++ b/lib/nimrtl.nim
@@ -33,4 +33,3 @@ when not defined(createNimRtl):
 import
   parseutils, strutils, parseopt, parsecfg, strtabs, unicode, pegs, ropes,
   os, osproc, times
-
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim
index 0c66aa2b9..175f6a61d 100644
--- a/lib/posix/posix.nim
+++ b/lib/posix/posix.nim
@@ -823,6 +823,12 @@ proc CMSG_NXTHDR*(mhdr: ptr Tmsghdr, cmsg: ptr Tcmsghdr): ptr Tcmsghdr {.
 proc CMSG_FIRSTHDR*(mhdr: ptr Tmsghdr): ptr Tcmsghdr {.
   importc, header: "<sys/socket.h>".}
 
+proc CMSG_SPACE*(len: csize): csize {.
+  importc, header: "<sys/socket.h>".}
+
+proc CMSG_LEN*(len: csize): csize {.
+  importc, header: "<sys/socket.h>".}
+
 const
   INVALID_SOCKET* = SocketHandle(-1)
 
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index 59ef06459..e33ddeaf0 100644
--- a/lib/pure/asyncnet.nim
+++ b/lib/pure/asyncnet.nim
@@ -218,7 +218,7 @@ when defineSsl:
       var data = await recv(socket.fd.AsyncFD, BufferSize, flags)
       let length = len(data)
       if length > 0:
-        let ret = bioWrite(socket.bioIn, addr data[0], data.len.cint)
+        let ret = bioWrite(socket.bioIn, addr data[0], length.cint)
         if ret < 0:
           raiseSSLError()
       elif length == 0:
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index e8ea675f5..be10780ff 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -504,36 +504,76 @@ template anyIt*(s, pred: untyped): bool =
       break
   result
 
-template toSeq*(iter: untyped): untyped =
-  ## Transforms any iterator into a sequence.
-  ##
-  ## Example:
-  ##
-  ## .. code-block::
-  ##   let
-  ##     numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
-  ##     odd_numbers = toSeq(filter(numeric) do (x: int) -> bool:
-  ##       if x mod 2 == 1:
-  ##         result = true)
-  ##   assert odd_numbers == @[1, 3, 5, 7, 9]
-
-  # Note: see also `mapIt` for explanation of some of the implementation
-  # subtleties.
-  when compiles(iter.len):
+template toSeq1(s: not iterator): untyped =
+  # overload for typed but not iterator
+  type outType = type(items(s))
+  when compiles(s.len):
     block:
-      evalOnceAs(iter2, iter, true)
-      var result = newSeq[type(iter)](iter2.len)
+      evalOnceAs(s2, s, compiles((let _ = s)))
       var i = 0
-      for x in iter2:
-        result[i] = x
-        inc i
+      var result = newSeq[outType](s2.len)
+      for it in s2:
+        result[i] = it
+        i += 1
       result
   else:
-    var result: seq[type(iter)] = @[]
-    for x in iter:
-      result.add(x)
+    var result: seq[outType] = @[]
+    for it in s:
+      result.add(it)
+    result
+
+template toSeq2(iter: iterator): untyped =
+  # overload for iterator
+  evalOnceAs(iter2, iter(), false)
+  when compiles(iter2.len):
+    var i = 0
+    var result = newSeq[type(iter2)](iter2.len)
+    for x in iter2:
+      result[i] = x
+      inc i
+    result
+  else:
+    type outType = type(iter2())
+    var result: seq[outType] = @[]
+    when compiles(iter2()):
+      evalOnceAs(iter4, iter, false)
+      let iter3=iter4()
+      for x in iter3():
+        result.add(x)
+    else:
+      for x in iter2():
+        result.add(x)
     result
 
+template toSeq*(iter: untyped): untyped =
+  ## Transforms any iterable into a sequence.
+  runnableExamples:
+    let
+      numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
+      odd_numbers = toSeq(filter(numeric, proc(x: int): bool = x mod 2 == 1))
+    doAssert odd_numbers == @[1, 3, 5, 7, 9]
+
+  when compiles(toSeq1(iter)):
+    toSeq1(iter)
+  elif compiles(toSeq2(iter)):
+    toSeq2(iter)
+  else:
+    # overload for untyped, eg: `toSeq(myInlineIterator(3))`
+    when compiles(iter.len):
+      block:
+        evalOnceAs(iter2, iter, true)
+        var result = newSeq[type(iter)](iter2.len)
+        var i = 0
+        for x in iter2:
+          result[i] = x
+          inc i
+        result
+    else:
+      var result: seq[type(iter)] = @[]
+      for x in iter:
+        result.add(x)
+      result
+
 template foldl*(sequence, operation: untyped): untyped =
   ## Template to fold a sequence from left to right, returning the accumulation.
   ##
@@ -1033,12 +1073,72 @@ when isMainModule:
     assert anyIt(anumbers, it > 9) == false
 
   block: # toSeq test
-    let
-      numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
-      odd_numbers = toSeq(filter(numeric) do (x: int) -> bool:
-        if x mod 2 == 1:
-          result = true)
-    assert odd_numbers == @[1, 3, 5, 7, 9]
+    block:
+      let
+        numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
+        odd_numbers = toSeq(filter(numeric) do (x: int) -> bool:
+          if x mod 2 == 1:
+            result = true)
+      assert odd_numbers == @[1, 3, 5, 7, 9]
+
+    block:
+      doAssert [1,2].toSeq == @[1,2]
+      doAssert @[1,2].toSeq == @[1,2]
+
+      doAssert @[1,2].toSeq == @[1,2]
+      doAssert toSeq(@[1,2]) == @[1,2]
+
+    block:
+      iterator myIter(seed:int):auto=
+        for i in 0..<seed:
+          yield i
+      doAssert toSeq(myIter(2)) == @[0, 1]
+
+    block:
+      iterator myIter():auto{.inline.}=
+        yield 1
+        yield 2
+
+      doAssert myIter.toSeq == @[1,2]
+      doAssert toSeq(myIter) == @[1,2]
+
+    block:
+      iterator myIter():int {.closure.} =
+        yield 1
+        yield 2
+
+      doAssert myIter.toSeq == @[1,2]
+      doAssert toSeq(myIter) == @[1,2]
+
+    block:
+      proc myIter():auto=
+        iterator ret():int{.closure.}=
+          yield 1
+          yield 2
+        result = ret
+
+      doAssert myIter().toSeq == @[1,2]
+      doAssert toSeq(myIter()) == @[1,2]
+
+    block:
+      proc myIter(n:int):auto=
+        var counter = 0
+        iterator ret():int{.closure.}=
+          while counter<n:
+            yield counter
+            counter.inc
+        result = ret
+
+      block:
+        let myIter3 = myIter(3)
+        doAssert myIter3.toSeq == @[0,1,2]
+      block:
+        let myIter3 = myIter(3)
+        doAssert toSeq(myIter3) == @[0,1,2]
+      block:
+        # makes sure this does not hang forever
+        doAssert myIter(3).toSeq == @[0,1,2]
+        doAssert toSeq(myIter(3)) == @[0,1,2]
 
   block:
     # tests https://github.com/nim-lang/Nim/issues/7187
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 841985605..b7498b1c5 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -1208,7 +1208,9 @@ proc request*(client: HttpClient | AsyncHttpClient, url: string,
   for i in 1..client.maxRedirects:
     if result.status.redirection():
       let redirectTo = getNewLocation(lastURL, result.headers)
-      result = await client.requestAux(redirectTo, httpMethod, body, headers)
+      # Guarantee method for HTTP 307: see https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/307
+      var meth = if result.status == "307": httpMethod else: "GET"
+      result = await client.requestAux(redirectTo, meth, body, headers)
       lastURL = redirectTo
 
 
@@ -1227,36 +1229,49 @@ proc request*(client: HttpClient | AsyncHttpClient, url: string,
   ## be closed.
   result = await request(client, url, $httpMethod, body, headers)
 
+proc responseContent(resp: Response | AsyncResponse): Future[string] {.multisync.} =
+  ## Returns the content of a response as a string.
+  ##
+  ## A ``HttpRequestError`` will be raised if the server responds with a
+  ## client error (status code 4xx) or a server error (status code 5xx).
+  if resp.code.is4xx or resp.code.is5xx:
+    raise newException(HttpRequestError, resp.status)
+  else:
+    return await resp.bodyStream.readAll()
+
+proc head*(client: HttpClient | AsyncHttpClient,
+          url: string): Future[Response | AsyncResponse] {.multisync.} =
+  ## Connects to the hostname specified by the URL and performs a HEAD request.
+  ##
+  ## This procedure uses httpClient values such as ``client.maxRedirects``.
+  result = await client.request(url, HttpHEAD)
+
 proc get*(client: HttpClient | AsyncHttpClient,
           url: string): Future[Response | AsyncResponse] {.multisync.} =
   ## Connects to the hostname specified by the URL and performs a GET request.
   ##
-  ## This procedure will follow redirects up to a maximum number of redirects
-  ## specified in ``client.maxRedirects``.
+  ## This procedure uses httpClient values such as ``client.maxRedirects``.
   result = await client.request(url, HttpGET)
 
 proc getContent*(client: HttpClient | AsyncHttpClient,
                  url: string): Future[string] {.multisync.} =
-  ## Connects to the hostname specified by the URL and performs a GET request.
-  ##
-  ## This procedure will follow redirects up to a maximum number of redirects
-  ## specified in ``client.maxRedirects``.
-  ##
-  ## A ``HttpRequestError`` will be raised if the server responds with a
-  ## client error (status code 4xx) or a server error (status code 5xx).
+  ## Connects to the hostname specified by the URL and returns the content of a GET request.
   let resp = await get(client, url)
-  if resp.code.is4xx or resp.code.is5xx:
-    raise newException(HttpRequestError, resp.status)
-  else:
-    return await resp.bodyStream.readAll()
+  return await responseContent(resp)
 
-proc post*(client: HttpClient | AsyncHttpClient, url: string, body = "",
-           multipart: MultipartData = nil): Future[Response | AsyncResponse]
-           {.multisync.} =
-  ## Connects to the hostname specified by the URL and performs a POST request.
-  ##
-  ## This procedure will follow redirects up to a maximum number of redirects
-  ## specified in ``client.maxRedirects``.
+proc delete*(client: HttpClient | AsyncHttpClient,
+          url: string): Future[Response | AsyncResponse] {.multisync.} =
+  ## Connects to the hostname specified by the URL and performs a DELETE request.
+  ## This procedure uses httpClient values such as ``client.maxRedirects``.
+  result = await client.request(url, HttpDELETE)
+
+proc deleteContent*(client: HttpClient | AsyncHttpClient,
+                 url: string): Future[string] {.multisync.} =
+  ## Connects to the hostname specified by the URL and returns the content of a DELETE request.
+  let resp = await delete(client, url)
+  return await responseContent(resp)
+
+proc makeRequestContent(body = "", multipart: MultipartData = nil): (string, HttpHeaders) =
   let (mpContentType, mpBody) = format(multipart)
   # TODO: Support FutureStream for `body` parameter.
   template withNewLine(x): untyped =
@@ -1265,38 +1280,59 @@ proc post*(client: HttpClient | AsyncHttpClient, url: string, body = "",
     else:
       x
   var xb = mpBody.withNewLine() & body
-
   var headers = newHttpHeaders()
   if multipart != nil:
     headers["Content-Type"] = mpContentType
   headers["Content-Length"] = $len(xb)
+  return (xb, headers)
 
-  result = await client.requestAux(url, $HttpPOST, xb, headers)
-  # Handle redirects.
-  var lastURL = url
-  for i in 1..client.maxRedirects:
-    if result.status.redirection():
-      let redirectTo = getNewLocation(lastURL, result.headers)
-      var meth = if result.status != "307": HttpGet else: HttpPost
-      result = await client.requestAux(redirectTo, $meth, xb, headers)
-      lastURL = redirectTo
+proc post*(client: HttpClient | AsyncHttpClient, url: string, body = "",
+           multipart: MultipartData = nil): Future[Response | AsyncResponse]
+           {.multisync.} =
+  ## Connects to the hostname specified by the URL and performs a POST request.
+  ## This procedure uses httpClient values such as ``client.maxRedirects``.
+  var (xb, headers) = makeRequestContent(body, multipart)
+  result = await client.request(url, $HttpPOST, xb, headers)
 
 proc postContent*(client: HttpClient | AsyncHttpClient, url: string,
                   body = "",
                   multipart: MultipartData = nil): Future[string]
                   {.multisync.} =
-  ## Connects to the hostname specified by the URL and performs a POST request.
-  ##
-  ## This procedure will follow redirects up to a maximum number of redirects
-  ## specified in ``client.maxRedirects``.
-  ##
-  ## A ``HttpRequestError`` will be raised if the server responds with a
-  ## client error (status code 4xx) or a server error (status code 5xx).
+  ## Connects to the hostname specified by the URL and returns the content of a POST request.
   let resp = await post(client, url, body, multipart)
-  if resp.code.is4xx or resp.code.is5xx:
-    raise newException(HttpRequestError, resp.status)
-  else:
-    return await resp.bodyStream.readAll()
+  return await responseContent(resp)
+
+proc put*(client: HttpClient | AsyncHttpClient, url: string, body = "",
+           multipart: MultipartData = nil): Future[Response | AsyncResponse]
+           {.multisync.} =
+  ## Connects to the hostname specified by the URL and performs a PUT request.
+  ## This procedure uses httpClient values such as ``client.maxRedirects``.
+  var (xb, headers) = makeRequestContent(body, multipart)
+  result = await client.request(url, $HttpPUT, xb, headers)
+
+proc putContent*(client: HttpClient | AsyncHttpClient, url: string,
+                  body = "",
+                  multipart: MultipartData = nil): Future[string]
+                  {.multisync.} =
+  ## Connects to the hostname specified by the URL andreturns the content of a PUT request.
+  let resp = await put(client, url, body, multipart)
+  return await responseContent(resp)
+
+proc patch*(client: HttpClient | AsyncHttpClient, url: string, body = "",
+           multipart: MultipartData = nil): Future[Response | AsyncResponse]
+           {.multisync.} =
+  ## Connects to the hostname specified by the URL and performs a PATCH request.
+  ## This procedure uses httpClient values such as ``client.maxRedirects``.
+  var (xb, headers) = makeRequestContent(body, multipart)
+  result = await client.request(url, $HttpPATCH, xb, headers)
+
+proc patchContent*(client: HttpClient | AsyncHttpClient, url: string,
+                  body = "",
+                  multipart: MultipartData = nil): Future[string]
+                  {.multisync.} =
+  ## Connects to the hostname specified by the URL and returns the content of a PATCH request.
+  let resp = await patch(client, url, body, multipart)
+  return await responseContent(resp)
 
 proc downloadFile*(client: HttpClient, url: string, filename: string) =
   ## Downloads ``url`` and saves it to ``filename``.
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 0e43e18ca..31610a59e 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -2424,6 +2424,15 @@ proc isHidden*(path: string): bool {.noNimScript.} =
     let fileName = lastPathPart(path)
     result = len(fileName) >= 2 and fileName[0] == '.' and fileName != ".."
 
+proc getCurrentProcessId*(): int {.noNimScript.} =
+  ## return current process ID. See also ``osproc.processID(p: Process)``.
+  when defined(windows):
+    proc GetCurrentProcessId(): DWORD {.stdcall, dynlib: "kernel32",
+                                        importc: "GetCurrentProcessId".}
+    result = GetCurrentProcessId().int
+  else:
+    result = getpid()
+
 {.pop.}
 
 proc setLastModificationTime*(file: string, t: times.Time) {.noNimScript.} =
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index 0cf2171de..b2239b9c5 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -64,6 +64,7 @@ const poUseShell* {.deprecated.} = poUsePath
   ## Deprecated alias for poUsePath.
 
 proc execProcess*(command: string,
+                  workingDir: string = "",
                   args: openArray[string] = [],
                   env: StringTableRef = nil,
                   options: set[ProcessOption] = {poStdErrToStdOut,
@@ -154,7 +155,7 @@ proc running*(p: Process): bool {.rtl, extern: "nosp$1", tags: [].}
   ## Returns true iff the process `p` is still running. Returns immediately.
 
 proc processID*(p: Process): int {.rtl, extern: "nosp$1".} =
-  ## returns `p`'s process ID.
+  ## returns `p`'s process ID. See also ``os.getCurrentProcessId()``.
   return p.id
 
 proc waitForExit*(p: Process, timeout: int = -1): int {.rtl,
@@ -349,12 +350,13 @@ proc select*(readfds: var seq[Process], timeout = 500): int
 
 when not defined(useNimRtl):
   proc execProcess(command: string,
+                   workingDir: string = "",
                    args: openArray[string] = [],
                    env: StringTableRef = nil,
                    options: set[ProcessOption] = {poStdErrToStdOut,
                                                    poUsePath,
                                                    poEvalCommand}): TaintedString =
-    var p = startProcess(command, args=args, env=env, options=options)
+    var p = startProcess(command, workingDir=workingDir, args=args, env=env, options=options)
     var outp = outputStream(p)
     result = TaintedString""
     var line = newStringOfCap(120).TaintedString
@@ -1323,6 +1325,12 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = {
   ##  let (outp, errC) = execCmdEx("nim c -r mytestfile.nim")
   var p = startProcess(command, options=options + {poEvalCommand})
   var outp = outputStream(p)
+
+  # There is no way to provide input for the child process
+  # anymore. Closing it will create EOF on stdin instead of eternal
+  # blocking.
+  close inputStream(p)
+
   result = (TaintedString"", -1)
   var line = newStringOfCap(120).TaintedString
   while true:
@@ -1333,3 +1341,4 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = {
       result[1] = peekExitCode(p)
       if result[1] != -1: break
   close(p)
+
diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim
index f68baaf6b..fb4bc19af 100644
--- a/lib/pure/parseutils.nim
+++ b/lib/pure/parseutils.nim
@@ -129,8 +129,8 @@ proc parseIdent*(s: string, ident: var string, start = 0): int =
     result = i-start
 
 proc parseIdent*(s: string, start = 0): string =
-  ## parses an identifier and stores it in ``ident``.
-  ## Returns the parsed identifier or an empty string in case of an error.
+  ## parses an identifier and returns it or an empty string in
+  ## case of an error.
   result = ""
   var i = start
   if i < s.len and s[i] in IdentStartChars:
diff --git a/lib/pure/random.nim b/lib/pure/random.nim
index a2c2c1f88..c458d51eb 100644
--- a/lib/pure/random.nim
+++ b/lib/pure/random.nim
@@ -231,4 +231,8 @@ when isMainModule:
       except RangeError:
         discard
 
+
+    # don't use causes integer overflow
+    doAssert compiles(random[int](low(int) .. high(int)))
+
   main()
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index b8f76276a..010551b5a 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -22,7 +22,7 @@
     let time = cpuTime()
 
     sleep(100)   # replace this with something to be timed
-    echo "Time taken: ",cpuTime() - time
+    echo "Time taken: ", cpuTime() - time
 
     echo "My formatted time: ", format(now(), "d MMMM yyyy HH:mm")
     echo "Using predefined formats: ", getClockStr(), " ", getDateStr()
@@ -158,7 +158,9 @@ when defined(posix):
 
   type CTime = posix.Time
 
-  var CLOCK_REALTIME {.importc: "CLOCK_REALTIME", header: "<time.h>".}: Clockid
+  var
+    realTimeClockId {.importc: "CLOCK_REALTIME", header: "<time.h>".}: Clockid
+    cpuClockId {.importc: "CLOCK_THREAD_CPUTIME_ID", header: "<time.h>".}: Clockid
 
   proc gettimeofday(tp: var Timeval, unused: pointer = nil) {.
     importc: "gettimeofday", header: "<sys/time.h>".}
@@ -745,8 +747,7 @@ proc abs*(a: Duration): Duration =
   initDuration(seconds = abs(a.seconds), nanoseconds = -a.nanosecond)
 
 proc toTime*(dt: DateTime): Time {.tags: [], raises: [], benign.} =
-  ## Converts a broken-down time structure to
-  ## calendar time representation.
+  ## Converts a ``DateTime`` to a ``Time`` representing the same point in time.
   let epochDay = toEpochday(dt.monthday, dt.month, dt.year)
   var seconds = epochDay * secondsInDay
   seconds.inc dt.hour * secondsInHour
@@ -840,6 +841,11 @@ proc `$`*(zone: Timezone): string =
 
 proc `==`*(zone1, zone2: Timezone): bool =
   ## Two ``Timezone``'s are considered equal if their name is equal.
+  if system.`==`(zone1, zone2):
+    return true
+  if zone1.isNil or zone2.isNil:
+    return false
+
   runnableExamples:
     doAssert local() == local()
     doAssert local() != utc()
@@ -1047,7 +1053,7 @@ proc local*(t: Time): DateTime =
   t.inZone(local())
 
 proc getTime*(): Time {.tags: [TimeEffect], benign.} =
-  ## Gets the current time as a ``Time`` with nanosecond resolution.
+  ## Gets the current time as a ``Time`` with up to nanosecond resolution.
   when defined(JS):
     let millis = newDate().getTime()
     let seconds = convert(Milliseconds, Seconds, millis)
@@ -1061,7 +1067,7 @@ proc getTime*(): Time {.tags: [TimeEffect], benign.} =
     result = initTime(a.tv_sec.int64, convert(Microseconds, Nanoseconds, a.tv_usec.int))
   elif defined(posix):
     var ts: Timespec
-    discard clock_gettime(CLOCK_REALTIME, ts)
+    discard clock_gettime(realTimeClockId, ts)
     result = initTime(ts.tv_sec.int64, ts.tv_nsec.int)
   elif defined(windows):
     var f: FILETIME
@@ -1141,16 +1147,16 @@ proc `-`*(ti1, ti2: TimeInterval): TimeInterval =
   result = ti1 + (-ti2)
 
 proc getDateStr*(): string {.rtl, extern: "nt$1", tags: [TimeEffect].} =
-  ## Gets the current date as a string of the format ``YYYY-MM-DD``.
-  var ti = now()
-  result = $ti.year & '-' & intToStr(ord(ti.month), 2) &
-    '-' & intToStr(ti.monthday, 2)
+  ## Gets the current local date as a string of the format ``YYYY-MM-DD``.
+  var dt = now()
+  result = $dt.year & '-' & intToStr(ord(dt.month), 2) &
+    '-' & intToStr(dt.monthday, 2)
 
 proc getClockStr*(): string {.rtl, extern: "nt$1", tags: [TimeEffect].} =
-  ## Gets the current clock time as a string of the format ``HH:MM:SS``.
-  var ti = now()
-  result = intToStr(ti.hour, 2) & ':' & intToStr(ti.minute, 2) &
-    ':' & intToStr(ti.second, 2)
+  ## Gets the current local clock time as a string of the format ``HH:MM:SS``.
+  var dt = now()
+  result = intToStr(dt.hour, 2) & ':' & intToStr(dt.minute, 2) &
+    ':' & intToStr(dt.second, 2)
 
 proc toParts* (ti: TimeInterval): TimeIntervalParts =
   ## Converts a `TimeInterval` into an array consisting of its time units,
@@ -1382,7 +1388,6 @@ proc `==`*(a, b: DateTime): bool =
   ## Returns true if ``a == b``, that is if both dates represent the same point in time.
   return a.toTime == b.toTime
 
-
 proc isStaticInterval(interval: TimeInterval): bool =
   interval.years == 0 and interval.months == 0 and
     interval.days == 0 and interval.weeks == 0
@@ -1397,28 +1402,20 @@ proc evaluateStaticInterval(interval: TimeInterval): Duration =
     hours = interval.hours)
 
 proc between*(startDt, endDt: DateTime): TimeInterval =
-  ## Evaluate difference between two dates in ``TimeInterval`` format, so, it
-  ## will be relative.
+  ## Gives the difference between ``startDt`` and ``endDt`` as a
+  ## ``TimeInterval``.
   ##
-  ## **Warning:** It's not recommended to use ``between`` for ``DateTime's`` in
-  ## different ``TimeZone's``.
-  ## ``a + between(a, b) == b`` is only guaranteed when ``a`` and ``b`` are in UTC.
+  ## **Warning:** This proc currently gives very few guarantees about the
+  ## result. ``a + between(a, b) == b`` is **not** true in general
+  ## (it's always true when UTC is used however). Neither is it guaranteed that
+  ## all components in the result will have the same sign. The behavior of this
+  ## proc might change in the future.
   runnableExamples:
-    var a = initDateTime(year = 2018, month = Month(3), monthday = 25,
-                     hour = 0, minute = 59, second = 59, nanosecond = 1,
-                     zone = utc()).local
-    var b = initDateTime(year = 2018, month = Month(3), monthday = 25,
-                     hour = 1, minute =  1, second =  1, nanosecond = 0,
-                     zone = utc()).local
-    doAssert between(a, b) == initTimeInterval(
-      nanoseconds=999, milliseconds=999, microseconds=999, seconds=1, minutes=1)
-
-    a = parse("2018-01-09T00:00:00+00:00", "yyyy-MM-dd'T'HH:mm:sszzz", utc())
-    b = parse("2018-01-10T23:00:00-02:00", "yyyy-MM-dd'T'HH:mm:sszzz")
-    doAssert between(a, b) == initTimeInterval(hours=1, days=2)
-    ## Though, here correct answer should be 1 day 25 hours (cause this day in
-    ## this tz is actually 26 hours). That's why operating different TZ is
-    ## discouraged
+    var a = initDateTime(25, mMar, 2015, 12, 0, 0, utc())
+    var b = initDateTime(1, mApr, 2017, 15, 0, 15, utc())
+    var ti = initTimeInterval(years = 2, days = 7, hours = 3, seconds = 15)
+    doAssert between(a, b) == ti
+    doAssert between(a, b) == -between(b, a)
 
   var startDt = startDt.utc()
   var endDt = endDt.utc()
@@ -1546,7 +1543,6 @@ proc `*=`*[T: TimesMutableTypes, U](a: var T, b: U) =
     var dur = initDuration(seconds = 1)
     dur *= 5
     doAssert dur == initDuration(seconds = 5)
-
   a = a * b
 
 #
@@ -1810,7 +1806,7 @@ proc formatPattern(dt: DateTime, pattern: FormatPattern, result: var string) =
   of UUUU:
       result.add $dt.year
   of z, zz, zzz, zzzz:
-    if dt.timezone.name == "Etc/UTC":
+    if dt.timezone != nil and dt.timezone.name == "Etc/UTC":
       result.add 'Z'
     else:
       result.add  if -dt.utcOffset >= 0: '+' else: '-'
@@ -2343,7 +2339,15 @@ when not defined(JS):
           fib.add(fib[^1] + fib[^2])
         echo "CPU time [s] ", cpuTime() - t0
         echo "Fib is [s] ", fib
-      result = toFloat(int(getClock())) / toFloat(clocksPerSec)
+      when defined(posix):
+        # 'clocksPerSec' is a compile-time constant, possibly a
+        # rather awful one, so use clock_gettime instead
+        var ts: Timespec
+        discard clock_gettime(cpuClockId, ts)
+        result = toFloat(ts.tv_sec.int) +
+          toFloat(ts.tv_nsec.int) / 1_000_000_000
+      else:
+        result = toFloat(int(getClock())) / toFloat(clocksPerSec)
 
     proc epochTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].} =
       ## gets time after the UNIX epoch (1970) in seconds. It is a float
diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim
index 664765954..712cc46c8 100644
--- a/lib/pure/unicode.nim
+++ b/lib/pure/unicode.nim
@@ -1941,9 +1941,9 @@ proc strip*(s: string, leading = true, trailing = true,
         e_i = l_i - 1
         break
       dec(i)
-  let newLen = e_i - s_i
+  let newLen = e_i - s_i + 1
   result = newStringOfCap(newLen)
-  if e_i > s_i:
+  if newLen > 0:
     result.add s[s_i .. e_i]
 
 proc repeat*(c: Rune, count: Natural): string {.noSideEffect,
@@ -2161,6 +2161,9 @@ when isMainModule:
     doAssert s.split(' '.Rune, maxsplit = 1) == @["", "this is an example  "]
 
   block stripTests:
+    doAssert(strip("") == "")
+    doAssert(strip(" ") == "")
+    doAssert(strip("y") == "y")
     doAssert(strip("  foofoofoo  ") == "foofoofoo")
     doAssert(strip("sfoofoofoos", runes = ['s'.Rune]) == "foofoofoo")
 
diff --git a/lib/system.nim b/lib/system.nim
index ace3f5e38..ea767e27a 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -373,7 +373,7 @@ when defined(nimArrIdx):
     x: S) {.noSideEffect, magic: "ArrPut".}
 
   when defined(nimNewRuntime):
-    proc `=destroy`*[T](x: var T) {.inline, magic: "Asgn".} =
+    proc `=destroy`*[T](x: var T) {.inline, magic: "Destroy".} =
       ## generic `destructor`:idx: implementation that can be overriden.
       discard
     proc `=sink`*[T](x: var T; y: T) {.inline, magic: "Asgn".} =
@@ -2522,12 +2522,13 @@ proc `==`*[T](x, y: seq[T]): bool {.noSideEffect.} =
     when not defined(JS):
       proc seqToPtr[T](x: seq[T]): pointer {.inline, nosideeffect.} =
         result = cast[pointer](x)
-    else:
-      proc seqToPtr[T](x: seq[T]): pointer {.asmNoStackFrame, nosideeffect.} =
-        asm """return `x`"""
 
-    if seqToPtr(x) == seqToPtr(y):
-      return true
+      if seqToPtr(x) == seqToPtr(y):
+        return true
+    else:
+      var sameObject = false
+      asm """`sameObject` = `x` === `y`"""
+      if sameObject: return true
 
   when not defined(nimNoNil):
     if x.isNil or y.isNil:
@@ -3460,6 +3461,7 @@ when not defined(JS): #and not defined(nimscript):
       of 1: d = ze(cast[ptr int8](a +% n.offset)[])
       of 2: d = ze(cast[ptr int16](a +% n.offset)[])
       of 4: d = int(cast[ptr int32](a +% n.offset)[])
+      of 8: d = int(cast[ptr int64](a +% n.offset)[])
       else: sysAssert(false, "getDiscriminant: invalid n.typ.size")
       return d
 
@@ -4017,6 +4019,7 @@ proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
   ## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not
   ## perform deep copies of `s`. This is only useful for optimization
   ## purposes.
+  if s.len == 0: return
   when not defined(JS) and not defined(nimscript):
     var s = cast[PGenericSeq](s)
     s.reserved = s.reserved or seqShallowFlag
@@ -4027,6 +4030,8 @@ proc shallow*(s: var string) {.noSideEffect, inline.} =
   ## purposes.
   when not defined(JS) and not defined(nimscript) and not defined(gcDestructors):
     var s = cast[PGenericSeq](s)
+    if s == nil:
+      s = cast[PGenericSeq](newString(0))
     # string literals cannot become 'shallow':
     if (s.reserved and strlitFlag) == 0:
       s.reserved = s.reserved or seqShallowFlag
@@ -4206,6 +4211,10 @@ when hasAlloc and not defined(nimscript) and not defined(JS) and
     ## for the implementation of ``spawn``.
     discard
 
+  proc deepCopy*[T](y: T): T =
+    ## Convenience wrapper around `deepCopy` overload.
+    deepCopy(result, y)
+
   include "system/deepcopy"
 
 proc procCall*(x: untyped) {.magic: "ProcCall", compileTime.} =
diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim
index d6c361b2c..70bdc429b 100644
--- a/lib/system/dyncalls.nim
+++ b/lib/system/dyncalls.nim
@@ -17,13 +17,6 @@
 const
   NilLibHandle: LibHandle = nil
 
-proc c_fwrite(buf: pointer, size, n: csize, f: File): cint {.
-  importc: "fwrite", header: "<stdio.h>".}
-
-proc rawWrite(f: File, s: string|cstring) =
-  # we cannot throw an exception here!
-  discard c_fwrite(cstring(s), 1, s.len, f)
-
 proc nimLoadLibraryError(path: string) =
   # carefully written to avoid memory allocation:
   stderr.rawWrite("could not load: ")
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 778137668..a6da8f5a3 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -17,8 +17,15 @@ var
     ## instead of stdmsg.write when printing stacktrace.
     ## Unstable API.
 
+proc c_fwrite(buf: pointer, size, n: csize, f: File): cint {.
+  importc: "fwrite", header: "<stdio.h>".}
+
+proc rawWrite(f: File, s: string|cstring) =
+  # we cannot throw an exception here!
+  discard c_fwrite(cstring(s), 1, s.len, f)
+
 when not defined(windows) or not defined(guiapp):
-  proc writeToStdErr(msg: cstring) = write(stdmsg, msg)
+  proc writeToStdErr(msg: cstring) = rawWrite(stdmsg, msg)
 
 else:
   proc MessageBoxA(hWnd: cint, lpText, lpCaption: cstring, uType: int): int32 {.
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index 74ac68eea..fb20edbbb 100644
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -100,14 +100,6 @@ var
 when not defined(useNimRtl):
   instantiateForRegion(gch.region)
 
-template acquire(gch: GcHeap) =
-  when hasThreadSupport and hasSharedHeap:
-    acquireSys(HeapLock)
-
-template release(gch: GcHeap) =
-  when hasThreadSupport and hasSharedHeap:
-    releaseSys(HeapLock)
-
 template gcAssert(cond: bool, msg: string) =
   when defined(useGcAssert):
     if not cond:
@@ -177,15 +169,6 @@ proc doOperation(p: pointer, op: WalkOp) {.benign.}
 proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.}
 # we need the prototype here for debugging purposes
 
-when hasThreadSupport and hasSharedHeap:
-  template `--`(x: untyped): untyped = atomicDec(x, rcIncrement) <% rcIncrement
-  template `++`(x: untyped) = discard atomicInc(x, rcIncrement)
-else:
-  template `--`(x: untyped): untyped =
-    dec(x, rcIncrement)
-    x <% rcIncrement
-  template `++`(x: untyped) = inc(x, rcIncrement)
-
 proc incRef(c: PCell) {.inline.} =
   gcAssert(isAllocatedPtr(gch.region, c), "incRef: interiorPtr")
   c.refcount = c.refcount +% rcIncrement
@@ -194,28 +177,19 @@ proc incRef(c: PCell) {.inline.} =
 
 proc nimGCref(p: pointer) {.compilerProc.} =
   # we keep it from being collected by pretending it's not even allocated:
-  add(gch.additionalRoots, usrToCell(p))
-  incRef(usrToCell(p))
-
-proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
-  # we MUST access gch as a global here, because this crosses DLL boundaries!
-  when hasThreadSupport and hasSharedHeap:
-    acquireSys(HeapLock)
-  when hasThreadSupport and hasSharedHeap:
-    releaseSys(HeapLock)
+  let c = usrToCell(p)
+  add(gch.additionalRoots, c)
+  incRef(c)
 
 proc rtlAddZCT(c: PCell) {.rtl, inl.} =
   # we MUST access gch as a global here, because this crosses DLL boundaries!
-  when hasThreadSupport and hasSharedHeap:
-    acquireSys(HeapLock)
   addZCT(gch.zct, c)
-  when hasThreadSupport and hasSharedHeap:
-    releaseSys(HeapLock)
 
 proc decRef(c: PCell) {.inline.} =
   gcAssert(isAllocatedPtr(gch.region, c), "decRef: interiorPtr")
   gcAssert(c.refcount >=% rcIncrement, "decRef")
-  if --c.refcount:
+  c.refcount = c.refcount -% rcIncrement
+  if c.refcount <% rcIncrement:
     rtlAddZCT(c)
 
 proc nimGCunref(p: pointer) {.compilerProc.} =
@@ -239,19 +213,9 @@ template beforeDealloc(gch: var GcHeap; c: PCell; msg: typed) =
       if gch.decStack.d[i] == c:
         sysAssert(false, msg)
 
-proc GC_addCycleRoot*[T](p: ref T) {.inline.} =
-  ## adds 'p' to the cycle candidate set for the cycle collector. It is
-  ## necessary if you used the 'acyclic' pragma for optimization
-  ## purposes and need to break cycles manually.
-  rtlAddCycleRoot(usrToCell(cast[pointer](p)))
-
 proc nimGCunrefNoCycle(p: pointer) {.compilerProc, inline.} =
   sysAssert(allocInv(gch.region), "begin nimGCunrefNoCycle")
-  var c = usrToCell(p)
-  gcAssert(isAllocatedPtr(gch.region, c), "nimGCunrefNoCycle: isAllocatedPtr")
-  if --c.refcount:
-    rtlAddZCT(c)
-    sysAssert(allocInv(gch.region), "end nimGCunrefNoCycle 2")
+  decRef(usrToCell(p))
   sysAssert(allocInv(gch.region), "end nimGCunrefNoCycle 5")
 
 proc nimGCunrefRC1(p: pointer) {.compilerProc, inline.} =
@@ -265,17 +229,8 @@ proc asgnRef(dest: PPointer, src: pointer) {.compilerProc, inline.} =
   if dest[] != nil: decRef(usrToCell(dest[]))
   dest[] = src
 
-proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerProc, inline.} =
-  # the code generator calls this proc if it is known at compile time that no
-  # cycle is possible.
-  if src != nil:
-    var c = usrToCell(src)
-    ++c.refcount
-  if dest[] != nil:
-    var c = usrToCell(dest[])
-    if --c.refcount:
-      rtlAddZCT(c)
-  dest[] = src
+proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline,
+  deprecated: "old compiler compat".} = asgnRef(dest, src)
 
 proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerProc.} =
   # unsureAsgnRef updates the reference counters only if dest is not on the
@@ -440,7 +395,6 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
   # generates a new object and sets its reference counter to 0
   incTypeSize typ, size
   sysAssert(allocInv(gch.region), "rawNewObj begin")
-  acquire(gch)
   gcAssert(typ.kind in {tyRef, tyOptAsRef, tyString, tySequence}, "newObj: 1")
   collectCT(gch)
   var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
@@ -457,7 +411,6 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
   when logGC: writeCell("new cell", res)
   track("rawNewObj", res, size)
   gcTrace(res, csAllocated)
-  release(gch)
   when useCellIds:
     inc gch.idGenerator
     res.id = gch.idGenerator * 1000_000 + gch.gcThreadId
@@ -488,7 +441,6 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
   # generates a new object and sets its reference counter to 1
   incTypeSize typ, size
   sysAssert(allocInv(gch.region), "newObjRC1 begin")
-  acquire(gch)
   gcAssert(typ.kind in {tyRef, tyOptAsRef, tyString, tySequence}, "newObj: 1")
   collectCT(gch)
   sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
@@ -504,7 +456,6 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
   when logGC: writeCell("new cell", res)
   track("newObjRC1", res, size)
   gcTrace(res, csAllocated)
-  release(gch)
   when useCellIds:
     inc gch.idGenerator
     res.id = gch.idGenerator * 1000_000 + gch.gcThreadId
@@ -521,7 +472,6 @@ proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
   when defined(memProfiler): nimProfile(size)
 
 proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
-  acquire(gch)
   collectCT(gch)
   var ol = usrToCell(old)
   sysAssert(ol.typ != nil, "growObj: 1")
@@ -577,7 +527,6 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
   else:
     sysAssert(ol.typ != nil, "growObj: 5")
     zeroMem(ol, sizeof(Cell))
-  release(gch)
   when useCellIds:
     inc gch.idGenerator
     res.id = gch.idGenerator * 1000_000 + gch.gcThreadId
@@ -665,11 +614,9 @@ proc doOperation(p: pointer, op: WalkOp) =
     #  c_fprintf(stdout, "[GC] decref bug: %p", c)
     gcAssert(isAllocatedPtr(gch.region, c), "decRef: waZctDecRef")
     gcAssert(c.refcount >=% rcIncrement, "doOperation 2")
-    #c.refcount = c.refcount -% rcIncrement
     when logGC: writeCell("decref (from doOperation)", c)
     track("waZctDecref", p, 0)
     decRef(c)
-    #if c.refcount <% rcIncrement: addZCT(gch.zct, c)
   of waPush:
     add(gch.tempStack, c)
   of waMarkGlobal:
@@ -707,13 +654,13 @@ proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
     var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell))
     if objStart != nil:
       # mark the cell:
-      objStart.refcount = objStart.refcount +% rcIncrement
+      incRef(objStart)
       add(gch.decStack, objStart)
     when false:
       if isAllocatedPtr(gch.region, cell):
         sysAssert false, "allocated pointer but not interior?"
         # mark the cell:
-        cell.refcount = cell.refcount +% rcIncrement
+        incRef(cell)
         add(gch.decStack, cell)
   sysAssert(allocInv(gch.region), "gcMark end")
 
@@ -787,11 +734,6 @@ proc unmarkStackAndRegisters(gch: var GcHeap) =
   for i in 0..gch.decStack.len-1:
     sysAssert isAllocatedPtr(gch.region, d[i]), "unmarkStackAndRegisters"
     decRef(d[i])
-    #var c = d[i]
-    # XXX no need for an atomic dec here:
-    #if --c.refcount:
-    #  addZCT(gch.zct, c)
-    #sysAssert c.typ != nil, "unmarkStackAndRegisters 2"
   gch.decStack.len = 0
 
 proc collectCTBody(gch: var GcHeap) =
@@ -850,13 +792,11 @@ when withRealTime:
     gch.maxPause = MaxPauseInUs.toNano
 
   proc GC_step(gch: var GcHeap, us: int, strongAdvice: bool) =
-    acquire(gch)
     gch.maxPause = us.toNano
     if (gch.zct.len >= ZctThreshold or (cycleGC and
         getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) or
         strongAdvice:
       collectCTBody(gch)
-    release(gch)
 
   proc GC_step*(us: int, strongAdvice = false, stackSize = -1) {.noinline.} =
     if stackSize >= 0:
@@ -880,18 +820,12 @@ when withRealTime:
 
 when not defined(useNimRtl):
   proc GC_disable() =
-    when hasThreadSupport and hasSharedHeap:
-      discard atomicInc(gch.recGcLock, 1)
-    else:
-      inc(gch.recGcLock)
+    inc(gch.recGcLock)
   proc GC_enable() =
     if gch.recGcLock <= 0:
       raise newException(AssertionError,
           "API usage error: GC_enable called but GC is already enabled")
-    when hasThreadSupport and hasSharedHeap:
-      discard atomicDec(gch.recGcLock, 1)
-    else:
-      dec(gch.recGcLock)
+    dec(gch.recGcLock)
 
   proc GC_setStrategy(strategy: GC_Strategy) =
     discard
@@ -904,12 +838,10 @@ when not defined(useNimRtl):
     # set to the max value to suppress the cycle detector
 
   proc GC_fullCollect() =
-    acquire(gch)
     var oldThreshold = gch.cycleThreshold
     gch.cycleThreshold = 0 # forces cycle collection
     collectCT(gch)
     gch.cycleThreshold = oldThreshold
-    release(gch)
 
   proc GC_getStatistics(): string =
     result = "[GC] total memory: " & $(getTotalMem()) & "\n" &
diff --git a/lib/system/gc2.nim b/lib/system/gc2.nim
index 283919503..522b2742b 100644
--- a/lib/system/gc2.nim
+++ b/lib/system/gc2.nim
@@ -112,14 +112,6 @@ var
 when not defined(useNimRtl):
   instantiateForRegion(gch.region)
 
-template acquire(gch: GcHeap) =
-  when hasThreadSupport and hasSharedHeap:
-    acquireSys(HeapLock)
-
-template release(gch: GcHeap) =
-  when hasThreadSupport and hasSharedHeap:
-    releaseSys(HeapLock)
-
 # Which color to use for new objects is tricky: When we're marking,
 # they have to be *white* so that everything is marked that is only
 # reachable from them. However, when we are sweeping, they have to
@@ -204,10 +196,6 @@ proc doOperation(p: pointer, op: WalkOp) {.benign.}
 proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.}
 # we need the prototype here for debugging purposes
 
-proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
-  # we MUST access gch as a global here, because this crosses DLL boundaries!
-  discard
-
 proc nimGCref(p: pointer) {.compilerProc.} =
   let cell = usrToCell(p)
   markAsEscaped(cell)
@@ -240,13 +228,8 @@ template markGrey(x: PCell) =
     x.setColor(rcGrey)
     add(gch.greyStack, x)
 
-proc GC_addCycleRoot*[T](p: ref T) {.inline.} =
-  ## adds 'p' to the cycle candidate set for the cycle collector. It is
-  ## necessary if you used the 'acyclic' pragma for optimization
-  ## purposes and need to break cycles manually.
-  discard
-
-template asgnRefImpl =
+proc asgnRef(dest: PPointer, src: pointer) {.compilerProc, inline.} =
+  # the code generator calls this proc!
   gcAssert(not isOnStack(dest), "asgnRef")
   # BUGFIX: first incRef then decRef!
   if src != nil:
@@ -255,12 +238,8 @@ template asgnRefImpl =
     markGrey(s)
   dest[] = src
 
-proc asgnRef(dest: PPointer, src: pointer) {.compilerProc, inline.} =
-  # the code generator calls this proc!
-  asgnRefImpl()
-
-proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerProc, inline.} =
-  asgnRefImpl()
+proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline,
+  deprecated: "old compiler compat".} = asgnRef(dest, src)
 
 proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerProc.} =
   # unsureAsgnRef marks 'src' as grey only if dest is not on the
@@ -396,7 +375,6 @@ proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
   result = newSeq(typ, len)
 
 proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
-  acquire(gch)
   collectCT(gch)
   var ol = usrToCell(old)
   sysAssert(ol.typ != nil, "growObj: 1")
@@ -420,7 +398,6 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
   when useCellIds:
     inc gch.idGenerator
     res.id = gch.idGenerator
-  release(gch)
   result = cellToUsr(res)
   when defined(memProfiler): nimProfile(newsize-oldsize)
 
@@ -732,16 +709,10 @@ when withRealTime:
 
 when not defined(useNimRtl):
   proc GC_disable() =
-    when hasThreadSupport and hasSharedHeap:
-      discard atomicInc(gch.recGcLock, 1)
-    else:
-      inc(gch.recGcLock)
+    inc(gch.recGcLock)
   proc GC_enable() =
     if gch.recGcLock > 0:
-      when hasThreadSupport and hasSharedHeap:
-        discard atomicDec(gch.recGcLock, 1)
-      else:
-        dec(gch.recGcLock)
+      dec(gch.recGcLock)
 
   proc GC_setStrategy(strategy: GC_Strategy) =
     discard
diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim
index 96221b175..d8cb3e2d0 100644
--- a/lib/system/gc_ms.nim
+++ b/lib/system/gc_ms.nim
@@ -85,14 +85,6 @@ var
 when not defined(useNimRtl):
   instantiateForRegion(gch.region)
 
-template acquire(gch: GcHeap) =
-  when hasThreadSupport and hasSharedHeap:
-    acquireSys(HeapLock)
-
-template release(gch: GcHeap) =
-  when hasThreadSupport and hasSharedHeap:
-    releaseSys(HeapLock)
-
 template gcAssert(cond: bool, msg: string) =
   when defined(useGcAssert):
     if not cond:
@@ -276,7 +268,6 @@ proc forAllChildren(cell: PCell, op: WalkOp) =
 proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
   # generates a new object and sets its reference counter to 0
   incTypeSize typ, size
-  acquire(gch)
   gcAssert(typ.kind in {tyRef, tyOptAsRef, tyString, tySequence}, "newObj: 1")
   collectCT(gch, size + sizeof(Cell))
   var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
@@ -288,7 +279,6 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
       res.filename = framePtr.prev.filename
       res.line = framePtr.prev.line
   res.refcount = 0
-  release(gch)
   when withBitvectors: incl(gch.allocated, res)
   when useCellIds:
     inc gch.idGenerator
@@ -333,7 +323,6 @@ when not defined(gcDestructors):
     when defined(memProfiler): nimProfile(size)
 
   proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
-    acquire(gch)
     collectCT(gch, newsize + sizeof(Cell))
     var ol = usrToCell(old)
     sysAssert(ol.typ != nil, "growObj: 1")
@@ -353,7 +342,6 @@ when not defined(gcDestructors):
     when useCellIds:
       inc gch.idGenerator
       res.id = gch.idGenerator
-    release(gch)
     result = cellToUsr(res)
     when defined(memProfiler): nimProfile(newsize-oldsize)
 
@@ -503,18 +491,12 @@ proc collectCT(gch: var GcHeap; size: int) =
 
 when not defined(useNimRtl):
   proc GC_disable() =
-    when hasThreadSupport and hasSharedHeap:
-      atomicInc(gch.recGcLock, 1)
-    else:
-      inc(gch.recGcLock)
+    inc(gch.recGcLock)
   proc GC_enable() =
     if gch.recGcLock <= 0:
       raise newException(AssertionError,
           "API usage error: GC_enable called but GC is already enabled")
-    when hasThreadSupport and hasSharedHeap:
-      atomicDec(gch.recGcLock, 1)
-    else:
-      dec(gch.recGcLock)
+    dec(gch.recGcLock)
 
   proc GC_setStrategy(strategy: GC_Strategy) = discard
 
@@ -530,12 +512,10 @@ when not defined(useNimRtl):
       gch.tracing = true
 
   proc GC_fullCollect() =
-    acquire(gch)
     var oldThreshold = gch.cycleThreshold
     gch.cycleThreshold = 0 # forces cycle collection
     collectCT(gch, 0)
     gch.cycleThreshold = oldThreshold
-    release(gch)
 
   proc GC_getStatistics(): string =
     result = "[GC] total memory: " & $getTotalMem() & "\n" &
diff --git a/lib/system/gc_regions.nim b/lib/system/gc_regions.nim
index 06fded86b..8a1446944 100644
--- a/lib/system/gc_regions.nim
+++ b/lib/system/gc_regions.nim
@@ -339,8 +339,8 @@ proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
   dest[] = src
 proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
   dest[] = src
-proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline.} =
-  dest[] = src
+proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline,
+  deprecated: "old compiler compat".} = asgnRef(dest, src)
 
 proc alloc(size: Natural): pointer =
   result = c_malloc(size)
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
index 5ac0ca8b2..8be19e5b8 100644
--- a/lib/system/jssys.nim
+++ b/lib/system/jssys.nim
@@ -519,8 +519,11 @@ proc nimCopyAux(dest, src: JSRef, n: ptr TNimNode) {.compilerproc.} =
       `dest`[`n`.offset] = nimCopy(`dest`[`n`.offset], `src`[`n`.offset], `n`.typ);
     """
   of nkList:
-    for i in 0..n.len-1:
-      nimCopyAux(dest, src, n.sons[i])
+    asm """
+    for (var i = 0; i < `n`.sons.length; i++) {
+      nimCopyAux(`dest`, `src`, `n`.sons[i]);
+    }
+    """
   of nkCase:
     asm """
       `dest`[`n`.offset] = nimCopy(`dest`[`n`.offset], `src`[`n`.offset], `n`.typ);
diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim
index 683e84f7d..89bc11d2c 100644
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -170,8 +170,8 @@ when defined(boehmgc):
     dest[] = src
   proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
     dest[] = src
-  proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline.} =
-    dest[] = src
+  proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline,
+    deprecated: "old compiler compat".} = asgnRef(dest, src)
 
   type
     MemRegion = object
@@ -326,8 +326,8 @@ elif defined(gogc):
     writebarrierptr(dest, src)
   proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
     writebarrierptr(dest, src)
-  proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline.} =
-    writebarrierptr(dest, src)
+  proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline,
+    deprecated: "old compiler compat".} = asgnRef(dest, src)
 
   type
     MemRegion = object
@@ -416,8 +416,8 @@ elif defined(nogc) and defined(useMalloc):
     dest[] = src
   proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
     dest[] = src
-  proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline.} =
-    dest[] = src
+  proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline,
+    deprecated: "old compiler compat".} = asgnRef(dest, src)
 
   type
     MemRegion = object
@@ -473,8 +473,8 @@ elif defined(nogc):
     dest[] = src
   proc asgnRef(dest: PPointer, src: pointer) {.compilerproc, inline.} =
     dest[] = src
-  proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline.} =
-    dest[] = src
+  proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline,
+    deprecated: "old compiler compat".} = asgnRef(dest, src)
 
   var allocator {.rtlThreadVar.}: MemRegion
   instantiateForRegion(allocator)
diff --git a/lib/system/reprjs.nim b/lib/system/reprjs.nim
index 7cb25a252..fb231bbed 100644
--- a/lib/system/reprjs.nim
+++ b/lib/system/reprjs.nim
@@ -64,7 +64,9 @@ proc reprStrAux(result: var string, s: cstring, len: int) =
 
 proc reprStr(s: string): string {.compilerRtl.} =
   result = ""
-  if cast[pointer](s).isNil:
+  var sIsNil = false
+  asm """`sIsNil` = `s` === null"""
+  if sIsNil: # cast[pointer](s).isNil:
     # Handle nil strings here because they don't have a length field in js
     # TODO: check for null/undefined before generating call to length in js?
     # Also: c backend repr of a nil string is <pointer>"", but repr of an
diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim
index 34b1cc4f7..c8c6101d7 100644
--- a/nimsuggest/nimsuggest.nim
+++ b/nimsuggest/nimsuggest.nim
@@ -159,19 +159,13 @@ proc symFromInfo(graph: ModuleGraph; trackPos: TLineInfo): PSym =
   if m != nil and m.ast != nil:
     result = findNode(m.ast, trackPos)
 
-proc execute(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int;
+proc executeNoHooks(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int;
              graph: ModuleGraph) =
   let conf = graph.config
   myLog("cmd: " & $cmd & ", file: " & file.string &
         ", dirtyFile: " & dirtyfile.string &
         "[" & $line & ":" & $col & "]")
   conf.ideCmd = cmd
-  if cmd == ideChk:
-    conf.structuredErrorHook = errorHook
-    conf.writelnHook = myLog
-  else:
-    conf.structuredErrorHook = nil
-    conf.writelnHook = myLog
   if cmd == ideUse and conf.suggestVersion != 0:
     graph.resetAllModules()
   var isKnownFile = true
@@ -186,7 +180,7 @@ proc execute(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int;
   if conf.suggestVersion == 1:
     graph.usageSym = nil
   if not isKnownFile:
-    graph.compileProject()
+    graph.compileProject(dirtyIdx)
   if conf.suggestVersion == 0 and conf.ideCmd in {ideUse, ideDus} and
       dirtyfile.isEmpty:
     discard "no need to recompile anything"
@@ -195,7 +189,8 @@ proc execute(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int;
     graph.markDirty dirtyIdx
     graph.markClientsDirty dirtyIdx
     if conf.ideCmd != ideMod:
-      graph.compileProject(modIdx)
+      if isKnownFile:
+        graph.compileProject(modIdx)
   if conf.ideCmd in {ideUse, ideDus}:
     let u = if conf.suggestVersion != 1: graph.symFromInfo(conf.m.trackPos) else: graph.usageSym
     if u != nil:
@@ -203,6 +198,16 @@ proc execute(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int;
     else:
       localError(conf, conf.m.trackPos, "found no symbol at this position " & (conf $ conf.m.trackPos))
 
+proc execute(cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int;
+             graph: ModuleGraph) =
+  if cmd == ideChk:
+    graph.config.structuredErrorHook = errorHook
+    graph.config.writelnHook = myLog
+  else:
+    graph.config.structuredErrorHook = nil
+    graph.config.writelnHook = myLog
+  executeNoHooks(cmd, file, dirtyfile, line, col, graph)
+
 proc executeEpc(cmd: IdeCmd, args: SexpNode;
                 graph: ModuleGraph) =
   let
@@ -613,4 +618,113 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
 
   discard self.loadConfigsAndRunMainCommand(cache, conf)
 
-handleCmdline(newIdentCache(), newConfigRef())
+when isMainModule:
+  handleCmdline(newIdentCache(), newConfigRef())
+else:
+  export Suggest
+  export IdeCmd
+  export AbsoluteFile
+  type NimSuggest* = ref object
+    graph: ModuleGraph
+    idle: int
+    cachedMsgs: CachedMsgs
+
+  proc initNimSuggest*(project: string, nimPath: string = ""): NimSuggest =
+    var retval: ModuleGraph
+    proc mockCommand(graph: ModuleGraph) =
+      retval = graph
+      let conf = graph.config
+      clearPasses(graph)
+      registerPass graph, verbosePass
+      registerPass graph, semPass
+      conf.cmd = cmdIdeTools
+      wantMainModule(conf)
+
+      if not fileExists(conf.projectFull):
+        quit "cannot find file: " & conf.projectFull.string
+
+      add(conf.searchPaths, conf.libpath)
+
+      # do not stop after the first error:
+      conf.errorMax = high(int)
+      # do not print errors, but log them
+      conf.writelnHook = proc (s: string) = log(s)
+      conf.structuredErrorHook = nil
+
+      # compile the project before showing any input so that we already
+      # can answer questions right away:
+      compileProject(graph)
+
+
+    proc mockCmdLine(pass: TCmdLinePass, cmd: string; conf: ConfigRef) =
+      conf.suggestVersion = 0
+      let a = unixToNativePath(project)
+      if dirExists(a) and not fileExists(a.addFileExt("nim")):
+        conf.projectName = findProjectNimFile(conf, a)
+        # don't make it worse, report the error the old way:
+        if conf.projectName.len == 0: conf.projectName = a
+      else:
+        conf.projectName = a
+          # if processArgument(pass, p, argsCount): break
+    let
+      cache = newIdentCache()
+      conf = newConfigRef()
+      self = NimProg(
+        suggestMode: true,
+        processCmdLine: mockCmdLine,
+        mainCommand: mockCommand
+      )
+    self.initDefinesProg(conf, "nimsuggest")
+
+    self.processCmdLineAndProjectPath(conf)
+
+    if gMode != mstdin:
+      conf.writelnHook = proc (msg: string) = discard
+    # Find Nim's prefix dir.
+    if nimPath == "":
+      let binaryPath = findExe("nim")
+      if binaryPath == "":
+        raise newException(IOError,
+            "Cannot find Nim standard library: Nim compiler not in PATH")
+      conf.prefixDir = AbsoluteDir binaryPath.splitPath().head.parentDir()
+      if not dirExists(conf.prefixDir / RelativeDir"lib"):
+        conf.prefixDir = AbsoluteDir""
+    else:
+      conf.prefixDir = AbsoluteDir nimPath
+
+    #msgs.writelnHook = proc (line: string) = log(line)
+    myLog("START " & conf.projectFull.string)
+
+    discard self.loadConfigsAndRunMainCommand(cache, conf)
+    if gLogging:
+      for it in conf.searchPaths:
+        log(it.string)
+
+    retval.doStopCompile = proc (): bool = false
+    return NimSuggest(graph: retval, idle: 0, cachedMsgs: @[])
+
+  proc runCmd*(nimsuggest: NimSuggest, cmd: IdeCmd, file, dirtyfile: AbsoluteFile, line, col: int): seq[Suggest] =
+    var retval: seq[Suggest] = @[]
+    let conf = nimsuggest.graph.config
+    conf.ideCmd = cmd
+    conf.writelnHook = proc (line: string) =
+      retval.add(Suggest(section: ideMsg, doc: line))
+    conf.suggestionResultHook = proc (s: Suggest) =
+      retval.add(s)
+    conf.writelnHook = proc (s: string) =
+      stderr.write s & "\n"
+    if conf.ideCmd == ideKnown:
+      retval.add(Suggest(section: ideKnown, quality: ord(fileInfoKnown(conf, file))))
+    else:
+      if conf.ideCmd == ideChk:
+        for cm in nimsuggest.cachedMsgs: errorHook(conf, cm.info, cm.msg, cm.sev)
+      if conf.ideCmd == ideChk:
+        conf.structuredErrorHook = proc (conf: ConfigRef; info: TLineInfo; msg: string; sev: Severity) =
+          retval.add(Suggest(section: ideChk, filePath: toFullPath(conf, info),
+            line: toLinenumber(info), column: toColumn(info), doc: msg,
+            forth: $sev))
+
+      else:
+        conf.structuredErrorHook = nil
+      executeNoHooks(conf.ideCmd, file, dirtyfile, line, col, nimsuggest.graph)
+    return retval
diff --git a/testament/categories.nim b/testament/categories.nim
index 36f2a271a..e1f173c26 100644
--- a/testament/categories.nim
+++ b/testament/categories.nim
@@ -97,11 +97,10 @@ proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) =
     else:
       ""
 
-  testSpec c, makeTest("lib/nimrtl.nim",
-    options & " --app:lib -d:createNimRtl --threads:on", cat)
-  testSpec c, makeTest("tests/dll/server.nim",
-    options & " --app:lib -d:useNimRtl --threads:on" & rpath, cat)
-
+  testNoSpec c, makeTest("lib/nimrtl.nim",
+    options & " --app:lib -d:createNimRtl --threads:on", cat, actionCompile)
+  testNoSpec c, makeTest("tests/dll/server.nim",
+    options & " --app:lib -d:useNimRtl --threads:on" & rpath, cat, actionCompile)
 
   when defined(Windows):
     # windows looks in the dir of the exe (yay!):
@@ -298,25 +297,24 @@ proc testNimInAction(r: var TResults, cat: Category, options: string) =
   # whoever edits these hashes without dom96's permission, j/k. But please only
   # edit when making a conscious breaking change, also please try to make your
   # commit message clear and notify me so I can easily compile an errata later.
-  var testHashes: seq[string] = @[]
-
-  for test in tests:
-    testHashes.add(getMD5(readFile("tests" / test.addFileExt("nim")).string))
-
   const refHashes = @[
     "51afdfa84b3ca3d810809d6c4e5037ba", "30f07e4cd5eaec981f67868d4e91cfcf",
     "d14e7c032de36d219c9548066a97e846", "2e40bfd5daadb268268727da91bb4e81",
     "c5d3853ed0aba04bf6d35ba28a98dca0", "058603145ff92d46c009006b06e5b228",
     "7b94a029b94ddb7efafddd546c965ff6", "586d74514394e49f2370dfc01dd9e830",
-    "e1901837b757c9357dc8d259fd0ef0f6", "097670c7ae12e825debaf8ec3995227b",
-    "a8cb7b78cc78d28535ab467361db5d6e", "bfaec2816a1848991b530c1ad17a0184",
-    "47cb71bb4c1198d6d29cdbee05aa10b9", "87e4436809f9d73324cfc4f57f116770",
-    "7b7db5cddc8cf8fa9b6776eef1d0a31d", "e6e40219f0f2b877869b738737b7685e",
-    "6532ee87d819f2605a443d5e94f9422a", "9a8fe78c588d08018843b64b57409a02",
-    "03a801275b8b76b4170c870cd0da079d", "20bb7d3e2d38d43b0cb5fcff4909a4a8",
-    "af6844598f534fab6942abfa4dfe9ab2", "2a7a17f84f6503d9bc89a5ab8feea127"
+    "13febc363ed82585f2a60de40ddfefda", "c11a013db35e798f44077bc0763cc86d",
+    "3e32e2c5e9a24bd13375e1cd0467079c", "0b9fe7ba159623d49ae60db18a15037c",
+    "b2dd5293d7f784824bbf9792c6fb51ad", "4c19d8d9026bfe151b31d7007fa3c237",
+    "9415c6a568cfceed08da8378e95b5cd5", "da520038c153f4054cb8cc5faa617714",
+    "e6c6e061b6f77b2475db6fec7abfb7f4", "9a8fe78c588d08018843b64b57409a02",
+    "8b5d28e985c0542163927d253a3e4fc9", "783299b98179cc725f9c46b5e3b5381f",
+    "bc523f9a9921299090bac1af6c958e73", "80f9c3e594a798225046e8a42e990daf"
   ]
-  doAssert testHashes == refHashes, "Nim in Action tests were changed."
+
+  for i, test in tests:
+    let filename = "tests" / test.addFileExt("nim")
+    let testHash = getMD5(readFile(filename).string)
+    doAssert testHash == refHashes[i], "Nim in Action test " & filename & " was changed."
 
   # Run the tests.
   for testfile in tests:
@@ -329,8 +327,6 @@ proc testNimInAction(r: var TResults, cat: Category, options: string) =
   testCPP cppFile
 
 
-
-
 # ------------------------- manyloc -------------------------------------------
 #proc runSpecialTests(r: var TResults, options: string) =
 #  for t in ["lib/packages/docutils/highlite"]:
diff --git a/testament/specs.nim b/testament/specs.nim
index c51a3343e..86fc8bed4 100644
--- a/testament/specs.nim
+++ b/testament/specs.nim
@@ -10,20 +10,21 @@
 import parseutils, strutils, os, osproc, streams, parsecfg
 
 
-var compilerPrefix* = "compiler" / "nim "
+var compilerPrefix* = "compiler" / "nim"
 
 let isTravis* = existsEnv("TRAVIS")
 let isAppVeyor* = existsEnv("APPVEYOR")
 
 proc cmdTemplate*(): string =
-  compilerPrefix & "$target --lib:lib --hints:on -d:testing --nimblePath:tests/deps $options $file"
+  compilerPrefix & " $target --hints:on -d:testing --nimblePath:tests/deps $options $file"
 
 type
   TTestAction* = enum
-    actionCompile = "compile"
     actionRun = "run"
+    actionCompile = "compile"
     actionReject = "reject"
     actionRunNoSpec = "runNoSpec"
+
   TResultEnum* = enum
     reNimcCrash,     # nim compiler seems to have crashed
     reMsgsDiffer,       # error messages differ
@@ -39,6 +40,7 @@ type
     reBuildFailed       # package building failed
     reIgnored,          # test is ignored
     reSuccess           # test was successful
+
   TTarget* = enum
     targetC = "C"
     targetCpp = "C++"
@@ -48,6 +50,7 @@ type
   TSpec* = object
     action*: TTestAction
     file*, cmd*: string
+    input*: string
     outp*: string
     line*, column*: int
     tfile*: string
@@ -144,6 +147,8 @@ proc parseSpec*(filename: string): TSpec =
     of "output":
       result.action = actionRun
       result.outp = e.value
+    of "input":
+      result.input = e.value
     of "outputsub":
       result.action = actionRun
       result.outp = e.value
@@ -186,7 +191,7 @@ proc parseSpec*(filename: string): TSpec =
         raise newException(ValueError, "cannot interpret as a bool: " & e.value)
     of "cmd":
       if e.value.startsWith("nim "):
-        result.cmd = compilerPrefix & e.value[4..^1]
+        result.cmd = compilerPrefix & e.value[3..^1]
       else:
         result.cmd = e.value
     of "ccodecheck": result.ccodeCheck = e.value
diff --git a/testament/tester.nim b/testament/tester.nim
index 169210255..59c0171b4 100644
--- a/testament/tester.nim
+++ b/testament/tester.nim
@@ -14,6 +14,8 @@ import
   marshal, backend, parseopt, specs, htmlgen, browsers, terminal,
   algorithm, compiler/nodejs, times, sets, md5
 
+var useColors = true
+
 const
   resultsFile = "testresults.html"
   #jsonFile = "testresults.json" # not used
@@ -32,6 +34,8 @@ Options:
   --failing                 only show failing/ignored tests
   --targets:"c c++ js objc" run tests for specified targets (default: all)
   --nim:path                use a particular nim executable (default: compiler/nim)
+  --directory:dir           Change to directory dir before reading the tests or doing anything else.
+  --colors:on|off           turn messagescoloring on|off
 """ % resultsFile
 
 type
@@ -74,6 +78,33 @@ proc getFileDir(filename: string): string =
   if not result.isAbsolute():
     result = getCurrentDir() / result
 
+proc execCmdEx2(command: string, args: openarray[string], options: set[ProcessOption], input: string): tuple[
+                output: TaintedString,
+                exitCode: int] {.tags:
+                [ExecIOEffect, ReadIOEffect, RootEffect], gcsafe.} =
+  var p = startProcess(command, args=args, options=options)
+  var outp = outputStream(p)
+
+  # There is no way to provide input for the child process
+  # anymore. Closing it will create EOF on stdin instead of eternal
+  # blocking.
+  let instream = inputStream(p)
+  instream.write(input)
+  close instream
+
+  result = (TaintedString"", -1)
+  var line = newStringOfCap(120).TaintedString
+  while true:
+    if outp.readLine(line):
+      result[0].string.add(line.string)
+      result[0].string.add("\n")
+    else:
+      result[1] = peekExitCode(p)
+      if result[1] != -1: break
+  close(p)
+
+
+
 proc nimcacheDir(filename, options: string, target: TTarget): string =
   ## Give each test a private nimcache dir so they don't clobber each other's.
   let hashInput = options & $target
@@ -153,11 +184,30 @@ proc initResults: TResults =
   result.skipped = 0
   result.data = ""
 
-#proc readResults(filename: string): TResults = # not used
-#  result = marshal.to[TResults](readFile(filename).string)
+import macros
+
+macro ignoreStyleEcho(args: varargs[typed]): untyped =
+  let typForegroundColor = bindSym"ForegroundColor".getType
+  let typBackgroundColor = bindSym"BackgroundColor".getType
+  let typStyle = bindSym"Style".getType
+  let typTerminalCmd = bindSym"TerminalCmd".getType
+  result = newCall(bindSym"echo")
+  for arg in children(args):
+    if arg.kind == nnkNilLit: continue
+    let typ = arg.getType
+    if typ.kind != nnkEnumTy or
+       typ != typForegroundColor and
+       typ != typBackgroundColor and
+       typ != typStyle and
+       typ != typTerminalCmd:
+      result.add(arg)
+
+template maybeStyledEcho(args: varargs[untyped]): untyped =
+  if useColors:
+    styledEcho(args)
+  else:
+    ignoreStyleEcho(args)
 
-#proc writeResults(filename: string, r: TResults) = # not used
-#  writeFile(filename, $$r)
 
 proc `$`(x: TResults): string =
   result = ("Tests passed: $1 / $3 <br />\n" &
@@ -168,7 +218,7 @@ proc addResult(r: var TResults, test: TTest, target: TTarget,
                expected, given: string, success: TResultEnum) =
   let name = test.name.extractFilename & " " & $target & test.options
   let duration = epochTime() - test.startTime
-  let durationStr = duration.formatFloat(ffDecimal, precision = 8)
+  let durationStr = duration.formatFloat(ffDecimal, precision = 8).align(11)
   backend.writeTestResult(name = name,
                           category = test.cat.string,
                           target = $target,
@@ -178,17 +228,17 @@ proc addResult(r: var TResults, test: TTest, target: TTarget,
                           given = given)
   r.data.addf("$#\t$#\t$#\t$#", name, expected, given, $success)
   if success == reSuccess:
-    styledEcho fgGreen, "PASS: ", fgCyan, alignLeft(name, 60), fgBlue, " (", durationStr, " secs)"
+    maybeStyledEcho fgGreen, "PASS: ", fgCyan, alignLeft(name, 60), fgBlue, " (", durationStr, " secs)"
   elif success == reIgnored:
-    styledEcho styleDim, fgYellow, "SKIP: ", styleBright, fgCyan, name
+    maybeStyledEcho styleDim, fgYellow, "SKIP: ", styleBright, fgCyan, name
   else:
-    styledEcho styleBright, fgRed, "FAIL: ", fgCyan, name
-    styledEcho styleBright, fgCyan, "Test \"", test.name, "\"", " in category \"", test.cat.string, "\""
-    styledEcho styleBright, fgRed, "Failure: ", $success
-    styledEcho fgYellow, "Expected:"
-    styledEcho styleBright, expected, "\n"
-    styledEcho fgYellow, "Gotten:"
-    styledEcho styleBright, given, "\n"
+    maybeStyledEcho styleBright, fgRed, "FAIL: ", fgCyan, name
+    maybeStyledEcho styleBright, fgCyan, "Test \"", test.name, "\"", " in category \"", test.cat.string, "\""
+    maybeStyledEcho styleBright, fgRed, "Failure: ", $success
+    maybeStyledEcho fgYellow, "Expected:"
+    maybeStyledEcho styleBright, expected, "\n"
+    maybeStyledEcho fgYellow, "Gotten:"
+    maybeStyledEcho styleBright, given, "\n"
 
   if existsEnv("APPVEYOR"):
     let (outcome, msg) =
@@ -268,10 +318,15 @@ proc codegenCheck(test: TTest, target: TTarget, spec: TSpec, expectedMsg: var st
     echo getCurrentExceptionMsg()
 
 proc nimoutCheck(test: TTest; expectedNimout: string; given: var TSpec) =
-  let exp = expectedNimout.strip.replace("\C\L", "\L")
-  let giv = given.nimout.strip.replace("\C\L", "\L")
-  if exp notin giv:
-    given.err = reMsgsDiffer
+  let giv = given.nimout.strip
+  var currentPos = 0
+  # Only check that nimout contains all expected lines in that order.
+  # There may be more output in nimout. It is ignored here.
+  for line in expectedNimout.strip.splitLines:
+    currentPos = giv.find(line.strip, currentPos)
+    if currentPos < 0:
+      given.err = reMsgsDiffer
+      return
 
 proc makeDeterministic(s: string): string =
   var x = splitLines(s)
@@ -297,7 +352,6 @@ proc compilerOutputTests(test: TTest, target: TTarget, given: var TSpec,
 
 proc testSpec(r: var TResults, test: TTest, target = targetC) =
   let tname = test.name.addFileExt(".nim")
-  #echo "TESTING ", tname
   var expected: TSpec
   if test.action != actionRunNoSpec:
     expected = parseSpec(tname)
@@ -336,6 +390,12 @@ proc testSpec(r: var TResults, test: TTest, target = targetC) =
       var given = callCompiler(expected.cmd, test.name, test.options,
                                target)
 
+      # echo "expected.cmd: ", expected.cmd
+      # echo "nimout: ", given.nimout
+      # echo "outp:   ", given.outp
+      # echo "msg:    ", given.msg
+      # echo "err:    ", given.err
+
       if given.err != reSuccess:
         r.addResult(test, target, "", given.msg, given.err)
         continue
@@ -358,8 +418,16 @@ proc testSpec(r: var TResults, test: TTest, target = targetC) =
                     reExeNotFound)
         continue
 
-      let exeCmd = (if isJsTarget: nodejs & " " else: "") & exeFile
-      var (buf, exitCode) = execCmdEx(exeCmd, options = {poStdErrToStdOut})
+
+      var exeCmd: string
+      var args: seq[string]
+      if isJsTarget:
+        exeCmd = nodejs
+        args.add exeFile
+      else:
+        exeCmd = exeFile
+
+      var (buf, exitCode) = execCmdEx2(exeCmd, args, options = {poStdErrToStdOut}, input = expected.input)
 
       # Treat all failure codes from nodejs as 1. Older versions of nodejs used
       # to return other codes, but for us it is sufficient to know that it's not 0.
@@ -402,7 +470,7 @@ proc testC(r: var TResults, test: TTest) =
   # runs C code. Doesn't support any specs, just goes by exit code.
   let tname = test.name.addFileExt(".c")
   inc(r.total)
-  styledEcho "Processing ", fgCyan, extractFilename(tname)
+  maybeStyledEcho "Processing ", fgCyan, extractFilename(tname)
   var given = callCCompiler(cmdTemplate(), test.name & ".c", test.options, targetC)
   if given.err != reSuccess:
     r.addResult(test, targetC, "", given.msg, given.err)
@@ -459,6 +527,7 @@ proc main() =
 
   var targetsStr = ""
 
+
   var p = initOptParser()
   p.next()
   while p.kind == cmdLongoption:
@@ -469,8 +538,18 @@ proc main() =
     of "targets":
       targetsStr = p.val.string
       targets = parseTargets(targetsStr)
-    of "nim": compilerPrefix = p.val.string & " "
-    else: quit Usage
+    of "nim": compilerPrefix = p.val.string
+    of "directory":
+      setCurrentDir(p.val.string)
+    of "colors":
+      if p.val.string == "on":
+        useColors = true
+      elif p.val.string == "off":
+        useColors = false
+      else:
+        quit Usage
+    else:
+      quit Usage
     p.next()
   if p.kind != cmdArgument: quit Usage
   var action = p.key.string.normalize
diff --git a/testament/tests/shouldfail/tccodecheck.nim b/testament/tests/shouldfail/tccodecheck.nim
new file mode 100644
index 000000000..a8d216a5b
--- /dev/null
+++ b/testament/tests/shouldfail/tccodecheck.nim
@@ -0,0 +1,8 @@
+discard """
+ccodecheck: "baz"
+"""
+
+proc foo(): void {.exportc: "bar".}=
+  echo "Hello World"
+
+foo()
diff --git a/testament/tests/shouldfail/tcolumn.nim b/testament/tests/shouldfail/tcolumn.nim
new file mode 100644
index 000000000..f4046d58d
--- /dev/null
+++ b/testament/tests/shouldfail/tcolumn.nim
@@ -0,0 +1,8 @@
+discard """
+line: 8
+column: 7
+errormsg: "undeclared identifier: 'undeclared'"
+"""
+
+# test should fail because the line directive is wrong
+echo undeclared
diff --git a/testament/tests/shouldfail/terrormsg.nim b/testament/tests/shouldfail/terrormsg.nim
new file mode 100644
index 000000000..61c08d93d
--- /dev/null
+++ b/testament/tests/shouldfail/terrormsg.nim
@@ -0,0 +1,8 @@
+discard """
+line: 8
+column: 6
+errormsg: "wrong error message"
+"""
+
+# test should fail because the line directive is wrong
+echo undeclared
diff --git a/testament/tests/shouldfail/texitcode1.nim b/testament/tests/shouldfail/texitcode1.nim
new file mode 100644
index 000000000..1b38b4f2e
--- /dev/null
+++ b/testament/tests/shouldfail/texitcode1.nim
@@ -0,0 +1,3 @@
+discard """
+exitcode: 1
+"""
diff --git a/testament/tests/shouldfail/tfile.nim b/testament/tests/shouldfail/tfile.nim
new file mode 100644
index 000000000..07a526c68
--- /dev/null
+++ b/testament/tests/shouldfail/tfile.nim
@@ -0,0 +1,6 @@
+discard """
+file: "notthisfile.nim"
+errmsg: "undeclared identifier: 'undefined'"
+"""
+
+echo undefined
diff --git a/testament/tests/shouldfail/tline.nim b/testament/tests/shouldfail/tline.nim
new file mode 100644
index 000000000..963e44fc7
--- /dev/null
+++ b/testament/tests/shouldfail/tline.nim
@@ -0,0 +1,8 @@
+discard """
+line: 9
+column: 6
+errormsg: "undeclared identifier: 'undeclared'"
+"""
+
+# test should fail because the line directive is wrong
+echo undeclared
diff --git a/testament/tests/shouldfail/tmaxcodesize.nim b/testament/tests/shouldfail/tmaxcodesize.nim
new file mode 100644
index 000000000..9879e4181
--- /dev/null
+++ b/testament/tests/shouldfail/tmaxcodesize.nim
@@ -0,0 +1,5 @@
+discard """
+maxcodesize: 1
+"""
+
+echo "Hello World"
diff --git a/testament/tests/shouldfail/tmsg.nim b/testament/tests/shouldfail/tmsg.nim
new file mode 100644
index 000000000..4ad17fa95
--- /dev/null
+++ b/testament/tests/shouldfail/tmsg.nim
@@ -0,0 +1,6 @@
+discard """
+msg: "Hello World"
+"""
+
+static:
+  echo "something else"
diff --git a/testament/tests/shouldfail/tnimout.nim b/testament/tests/shouldfail/tnimout.nim
new file mode 100644
index 000000000..c0e332053
--- /dev/null
+++ b/testament/tests/shouldfail/tnimout.nim
@@ -0,0 +1,7 @@
+discard """
+nimout: "Hello World!"
+action: compile
+"""
+
+static:
+  echo "something else"
diff --git a/testament/tests/shouldfail/toutput.nim b/testament/tests/shouldfail/toutput.nim
new file mode 100644
index 000000000..ac0bc7a46
--- /dev/null
+++ b/testament/tests/shouldfail/toutput.nim
@@ -0,0 +1,7 @@
+discard """
+output: '''
+done
+'''
+"""
+
+echo "broken"
diff --git a/testament/tests/shouldfail/toutputsub.nim b/testament/tests/shouldfail/toutputsub.nim
new file mode 100644
index 000000000..7cc51ee8d
--- /dev/null
+++ b/testament/tests/shouldfail/toutputsub.nim
@@ -0,0 +1,5 @@
+discard """
+outputsub: "something else"
+"""
+
+echo "Hello World!"
diff --git a/testament/tests/shouldfail/tsortoutput.nim b/testament/tests/shouldfail/tsortoutput.nim
new file mode 100644
index 000000000..4ce9ce26d
--- /dev/null
+++ b/testament/tests/shouldfail/tsortoutput.nim
@@ -0,0 +1,11 @@
+discard """
+sortoutput: true
+output: '''
+2
+1
+'''
+"""
+
+# this test should ensure that the output is actually sorted
+echo "2"
+echo "1"
diff --git a/tests/async/tasyncall.nim b/tests/async/tasyncall.nim
index 775dd0c6f..3e30e8ba8 100644
--- a/tests/async/tasyncall.nim
+++ b/tests/async/tasyncall.nim
@@ -2,7 +2,7 @@ discard """
   file: "tasyncall.nim"
   exitcode: 0
 """
-import times, sequtils, unittest
+import times, sequtils
 import asyncdispatch
 
 const
diff --git a/tests/async/tasyncssl.nim b/tests/async/tasyncssl.nim
index 61f0b5661..212260922 100644
--- a/tests/async/tasyncssl.nim
+++ b/tests/async/tasyncssl.nim
@@ -3,7 +3,12 @@ discard """
   cmd: "nim $target --hints:on --define:ssl $options $file"
   output: "500"
   disabled: "windows"
+  target: c
+  action: compile
 """
+
+# XXX, deactivated
+
 import asyncdispatch, asyncnet, net, strutils, os
 
 when defined(ssl):
@@ -63,5 +68,3 @@ when defined(ssl):
 
   assert msgCount == swarmSize * messagesToSend
   echo msgCount
-
-
diff --git a/tests/async/tfuturevar.nim b/tests/async/tfuturevar.nim
index ea2c63e03..9e3134261 100644
--- a/tests/async/tfuturevar.nim
+++ b/tests/async/tfuturevar.nim
@@ -1,3 +1,8 @@
+discard """
+action: compile
+"""
+# XXX: action should be run!
+
 import asyncdispatch
 
 proc completeOnReturn(fut: FutureVar[string], x: bool) {.async.} =
@@ -44,4 +49,3 @@ proc main() {.async.} =
 
 
 waitFor main()
-
diff --git a/tests/casestmt/tlinearscanend.nim b/tests/casestmt/tlinearscanend.nim
index 9a984e039..96e3727d5 100644
--- a/tests/casestmt/tlinearscanend.nim
+++ b/tests/casestmt/tlinearscanend.nim
@@ -1,3 +1,6 @@
+discard """
+action: compile
+"""
 
 import strutils
 
@@ -21,4 +24,3 @@ of 21: echo "21"
 else:
   {.linearScanEnd.}
   echo "default"
-
diff --git a/tests/ccgbugs/t6756.nim b/tests/ccgbugs/t6756.nim
index 0f08557eb..5170a99f4 100644
--- a/tests/ccgbugs/t6756.nim
+++ b/tests/ccgbugs/t6756.nim
@@ -1,3 +1,9 @@
+discard """
+output: '''
+(v: 3)
+'''
+"""
+
 import typetraits
 type
   A[T] = ref object
diff --git a/tests/ccgbugs/t8964.nim b/tests/ccgbugs/t8964.nim
deleted file mode 100644
index 5b41e8bdb..000000000
--- a/tests/ccgbugs/t8964.nim
+++ /dev/null
@@ -1,10 +0,0 @@
-discard """
-  targets: "c cpp"
-"""
-
-from json import JsonParsingError
-import marshal
-
-const nothing = ""
-doAssertRaises(JsonParsingError):
-  var bar = marshal.to[int](nothing)
diff --git a/tests/ccgbugs/tcodegendecllambda.nim b/tests/ccgbugs/tcodegendecllambda.nim
index 6dce68db5..5c6608b77 100644
--- a/tests/ccgbugs/tcodegendecllambda.nim
+++ b/tests/ccgbugs/tcodegendecllambda.nim
@@ -1,6 +1,7 @@
 discard """
   targets: "c cpp js"
   ccodecheck: "'HELLO'"
+  action: compile
 """
 
 when defined(JS):
diff --git a/tests/ccgbugs/tgeneric_closure.nim b/tests/ccgbugs/tgeneric_closure.nim
index f9d5e7910..bb3b924b9 100644
--- a/tests/ccgbugs/tgeneric_closure.nim
+++ b/tests/ccgbugs/tgeneric_closure.nim
@@ -1,4 +1,10 @@
-
+discard """
+output: '''
+2
+2
+2
+'''
+"""
 
 # bug 2659
 
diff --git a/tests/ccgbugs/trecursive_closure.nim b/tests/ccgbugs/trecursive_closure.nim
index f64382a8c..4b6514b90 100644
--- a/tests/ccgbugs/trecursive_closure.nim
+++ b/tests/ccgbugs/trecursive_closure.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 # bug #2233
 type MalType = object
   fun: proc: MalType
diff --git a/tests/ccgbugs/tsighash_typename_regression.nim b/tests/ccgbugs/tsighash_typename_regression.nim
index 7122902d9..6e49bafc3 100644
--- a/tests/ccgbugs/tsighash_typename_regression.nim
+++ b/tests/ccgbugs/tsighash_typename_regression.nim
@@ -1,3 +1,10 @@
+discard """
+output: '''
+123
+baz
+'''
+"""
+
 # bug #5147
 
 proc foo[T](t: T) =
diff --git a/tests/ccgbugs/tuple_canon.nim b/tests/ccgbugs/tuple_canon.nim
index 7e9e91836..671986054 100644
--- a/tests/ccgbugs/tuple_canon.nim
+++ b/tests/ccgbugs/tuple_canon.nim
@@ -1,4 +1,9 @@
-
+discard """
+output: '''
+vidx 18
+0,0
+'''
+"""
 
 # bug #4626
 var foo: (int, array[1, int]) # Tuple must be of length > 1
diff --git a/tests/closure/tinfer_closure_for_nestedproc.nim b/tests/closure/tinfer_closure_for_nestedproc.nim
new file mode 100644
index 000000000..6450d1492
--- /dev/null
+++ b/tests/closure/tinfer_closure_for_nestedproc.nim
@@ -0,0 +1,42 @@
+discard """
+  action: compile
+"""
+
+# bug #9441
+import asyncdispatch, asyncfutures, strtabs
+
+type
+  Request = object
+  Context = object
+    position: int
+    accept: bool
+    headers: StringTableRef
+  Handler = proc (r: ref Request, c: Context): Future[Context]
+
+proc respond(req: Request): Future[void] = discard
+
+proc handle*(h: Handler): auto = # (proc (req: Request): Future[void]) =
+  proc server(req: Request): Future[void] {.async.} =
+    let emptyCtx = Context(
+      position: 0,
+      accept: true,
+      headers: newStringTable()
+    )
+    var reqHeap = new(Request)
+    reqHeap[] = req
+    var
+      f: Future[Context]
+      ctx: Context
+    try:
+      f = h(reqHeap, emptyCtx)
+      ctx = await f
+    except:
+      discard
+    if f.failed:
+      await req.respond()
+    else:
+      if not ctx.accept:
+        await req.respond()
+  return server
+
+waitFor handle(nil)(Request())
diff --git a/tests/closure/tmacrobust1512.nim b/tests/closure/tmacrobust1512.nim
index 5f13e8286..0f44c5e1a 100644
--- a/tests/closure/tmacrobust1512.nim
+++ b/tests/closure/tmacrobust1512.nim
@@ -1,8 +1,12 @@
+discard """
+output: ""
+"""
+
 import macros, strutils
 
 # https://github.com/nim-lang/Nim/issues/1512
 
-proc macrobust0(raw_input: string) =
+proc macrobust0(input: string): string =
   var output = ""
   proc p1(a:string) =
     output.add(a)
@@ -27,13 +31,9 @@ proc macrobust0(raw_input: string) =
   proc p19(a:string) = p18(a)
   proc p20(a:string) = p19(a)
 
-  let input = $raw_input
-
   for a in input.split():
     p20(a)
     p19(a)
-
-
     p18(a)
     p17(a)
     p16(a)
@@ -53,11 +53,9 @@ proc macrobust0(raw_input: string) =
     p2(a)
     p1(a)
 
+  result = output
 
-  echo output
-
-macro macrobust(raw_input: untyped): untyped =
-
+macro macrobust(input: static[string]): untyped =
   var output = ""
   proc p1(a:string) =
     output.add(a)
@@ -82,12 +80,9 @@ macro macrobust(raw_input: untyped): untyped =
   proc p19(a:string) = p18(a)
   proc p20(a:string) = p19(a)
 
-  let input = $raw_input
-
   for a in input.split():
     p20(a)
     p19(a)
-
     p18(a)
     p17(a)
     p16(a)
@@ -105,11 +100,11 @@ macro macrobust(raw_input: untyped): untyped =
     p4(a)
     p3(a)
     p2(a)
+    p1(a)
 
-  echo output
-  discard result
+  result = newLit(output)
 
-macrobust """
+const input = """
   fdsasadfsdfa sadfsdafsdaf
   dsfsdafdsfadsfa fsdaasdfasdf
   fsdafsadfsad asdfasdfasdf
@@ -122,16 +117,7 @@ macrobust """
   sdfasdafsadf sdfasdafsdaf sdfasdafsdaf
 """
 
+let str1 = macrobust(input)
+let str2 = macrobust0(input)
 
-macrobust0 """
-  fdsasadfsdfa sadfsdafsdaf
-  dsfsdafdsfadsfa fsdaasdfasdf
-  fsdafsadfsad asdfasdfasdf
-  fdsasdfasdfa sadfsadfsadf
-  sadfasdfsdaf sadfsdafsdaf dsfasdaf
-  sadfsdafsadf fdsasdafsadf fdsasadfsdaf
-  sdfasadfsdafdfsa sadfsadfsdaf
-  sdafsdaffsda sdfasadfsadf
-  fsdasdafsdfa sdfasdfafsda
-  sdfasdafsadf sdfasdafsdaf sdfasdafsdaf
-"""
+doAssert str1 == str2
diff --git a/tests/closure/ttimeinfo.nim b/tests/closure/ttimeinfo.nim
index 3096a5d65..7416c0d31 100644
--- a/tests/closure/ttimeinfo.nim
+++ b/tests/closure/ttimeinfo.nim
@@ -1,3 +1,10 @@
+discard """
+output: '''
+@[2000-01-01T00:00:00+00:00, 2001-01-01T00:00:00+00:00, 2002-01-01T00:00:00+00:00, 2003-01-01T00:00:00+00:00, 2004-01-01T00:00:00+00:00, 2005-01-01T00:00:00+00:00, 2006-01-01T00:00:00+00:00, 2007-01-01T00:00:00+00:00, 2008-01-01T00:00:00+00:00, 2009-01-01T00:00:00+00:00, 2010-01-01T00:00:00+00:00, 2011-01-01T00:00:00+00:00, 2012-01-01T00:00:00+00:00, 2013-01-01T00:00:00+00:00, 2014-01-01T00:00:00+00:00, 2015-01-01T00:00:00+00:00]
+@[2000-01-01T00:00:00+00:00, 2001-01-01T00:00:00+00:00, 2002-01-01T00:00:00+00:00, 2003-01-01T00:00:00+00:00, 2004-01-01T00:00:00+00:00, 2005-01-01T00:00:00+00:00, 2006-01-01T00:00:00+00:00, 2007-01-01T00:00:00+00:00, 2008-01-01T00:00:00+00:00, 2009-01-01T00:00:00+00:00, 2010-01-01T00:00:00+00:00, 2011-01-01T00:00:00+00:00, 2012-01-01T00:00:00+00:00, 2013-01-01T00:00:00+00:00, 2014-01-01T00:00:00+00:00, 2015-01-01T00:00:00+00:00]
+'''
+"""
+
 # bug #2073
 
 import sequtils
diff --git a/tests/compiles/trecursive_generic_in_compiles.nim b/tests/compiles/trecursive_generic_in_compiles.nim
index 9c7fd10b3..c435ebaac 100644
--- a/tests/compiles/trecursive_generic_in_compiles.nim
+++ b/tests/compiles/trecursive_generic_in_compiles.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 # bug #3313
 import unittest, sugar
 {.experimental: "notnil".}
diff --git a/tests/concepts/tconcepts_issues.nim b/tests/concepts/tconcepts_issues.nim
index e145b9f37..df4037ffb 100644
--- a/tests/concepts/tconcepts_issues.nim
+++ b/tests/concepts/tconcepts_issues.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tissues.nim"
   output: '''
 20.0 USD
 Printable
diff --git a/tests/concepts/tmapconcept.nim b/tests/concepts/tmapconcept.nim
index 5082fcb61..6b959eff2 100644
--- a/tests/concepts/tmapconcept.nim
+++ b/tests/concepts/tmapconcept.nim
@@ -3,7 +3,7 @@ output: '''10
 10
 
 1'''
-msg: '''
+nimout: '''
 K=string V=int
 K=int64 V=string
 K=int V=int
diff --git a/tests/concepts/tmatrixconcept.nim b/tests/concepts/tmatrixconcept.nim
index dd5a080b6..ca31f5942 100644
--- a/tests/concepts/tmatrixconcept.nim
+++ b/tests/concepts/tmatrixconcept.nim
@@ -1,6 +1,6 @@
 discard """
 output: "0\n0\n0"
-msg: '''
+nimout: '''
 R=3 C=3 TE=9 FF=14 FC=20 T=int
 R=3 C=3 T=int
 '''
diff --git a/tests/concepts/tstackconcept.nim b/tests/concepts/tstackconcept.nim
index cb8db566d..fb6032732 100644
--- a/tests/concepts/tstackconcept.nim
+++ b/tests/concepts/tstackconcept.nim
@@ -1,6 +1,6 @@
 discard """
 output: "20\n10"
-msg: '''
+nimout: '''
 INFERRED int
 VALUE TYPE int
 VALUE TYPE NAME INT
diff --git a/tests/controlflow/tstatret.nim b/tests/controlflow/tstatret.nim
index 04cac9966..8f43c5d8f 100644
--- a/tests/controlflow/tstatret.nim
+++ b/tests/controlflow/tstatret.nim
@@ -1,7 +1,7 @@
 discard """
   file: "tstatret.nim"
   line: 9
-  errormsg: "unreachable statement after 'return'"
+  errormsg: "unreachable statement after 'return' statement or '{.noReturn.}' proc"
 """
 # no statement after return
 proc main() =
diff --git a/tests/converter/t7098.nim b/tests/converter/t7098.nim
index 66e629fa8..8e7634882 100644
--- a/tests/converter/t7098.nim
+++ b/tests/converter/t7098.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 type
   Byte* = uint8
   Bytes* = seq[Byte]
diff --git a/tests/converter/tconvcolors.nim b/tests/converter/tconvcolors.nim
index 07e829550..7b440cabd 100644
--- a/tests/converter/tconvcolors.nim
+++ b/tests/converter/tconvcolors.nim
@@ -1,5 +1,7 @@
+discard """
+output: "16777215A"
+"""
 
 import colors
 
 echo int32(colWhite), 'A'
-
diff --git a/tests/converter/tconvert.nim b/tests/converter/tconvert.nim
index 8aa4e97a3..5eee2a92d 100644
--- a/tests/converter/tconvert.nim
+++ b/tests/converter/tconvert.nim
@@ -26,3 +26,19 @@ block:
   var x = "101"
   var y: int = x # instantiate withVar
   doAssert(y == ord('0'))
+
+
+######################
+# bug #3503
+type Foo = object
+  r: float
+
+converter toFoo(r: float): Foo =
+  result.r = r
+
+proc `+=`*(x: var Foo, r: float) =
+  x.r += r
+
+var a: Foo
+a.r += 3.0
+
diff --git a/tests/converter/tconverter_unique_ptr.nim b/tests/converter/tconverter_unique_ptr.nim
index 15ec609a3..25b001d52 100644
--- a/tests/converter/tconverter_unique_ptr.nim
+++ b/tests/converter/tconverter_unique_ptr.nim
@@ -2,9 +2,7 @@
 discard """
   file: "tconverter_unique_ptr.nim"
   targets: "c cpp"
-  output: '''5
-2.0 5
-'''
+  output: ""
 """
 
 ## Bugs 9698 and 9699
@@ -22,6 +20,8 @@ type
     data: ptr UncheckedArray[float]
 
 proc `$`(x: MyLen): string {.borrow.}
+proc `==`(x1, x2: MyLen): bool {.borrow.}
+
 
 proc `=destroy`*(m: var MySeq) {.inline.} =
   if m.data != nil:
@@ -50,10 +50,12 @@ proc len*(m: MySeq): MyLen {.inline.} = m.len
 
 proc lenx*(m: var MySeq): MyLen {.inline.} = m.len
 
-
 proc `[]`*(m: MySeq; i: MyLen): float {.inline.} =
   m.data[i.int]
 
+proc `[]`*(m: var MySeq; i: MyLen): var float {.inline.} =
+  m.data[i.int]
+
 proc `[]=`*(m: var MySeq; i: MyLen, val: float) {.inline.} =
   m.data[i.int] = val
 
@@ -97,11 +99,55 @@ proc newUniquePtr*[T](val: sink T): UniquePtr[T] =
 converter convertPtrToObj*[T](p: UniquePtr[T]): var T =
   result = p.val[]
 
-
 var pu = newUniquePtr(newMySeq(5, 1.0))
-echo pu.len
+let pu2 = newUniquePtr(newMySeq(5, 1.0))
+doAssert: pu.len == 5
+doAssert: pu2.len == 5
+doAssert: pu.lenx == 5
+doAssert: pu2.lenx == 5
 
 pu[0] = 2.0
-echo pu[0], " ", pu.lenx
+pu2[0] = 2.0
+doAssert pu[0] == 2.0
+doAssert: pu2[0] == 2.0
+
+##-----------------------------------------------------------------------------------------
+## Bugs #9735 and #9736 
+type
+  ConstPtr*[T] = object
+    ## This pointer makes it impossible to change underlying value
+    ## as it returns only `lent T`
+    val: ptr T
 
+proc `=destroy`*[T](p: var ConstPtr[T]) =
+  if p.val != nil:
+    `=destroy`(p.val[])
+    dealloc(p.val)
+    p.val = nil
+
+proc `=`*[T](dest: var ConstPtr[T], src: ConstPtr[T]) {.error.}
+
+proc `=sink`*[T](dest: var ConstPtr[T], src: ConstPtr[T]) {.inline.} =
+  if dest.val != nil and dest.val != src.val:
+    `=destroy`(dest)
+  dest.val = src.val
+
+proc newConstPtr*[T](val: sink T): ConstPtr[T] =
+  result.val = cast[type(result.val)](alloc(sizeof(result.val[])))
+  reset(result.val[])
+  result.val[] = val
+
+converter convertConstPtrToObj*[T](p: ConstPtr[T]): lent T =
+  result = p.val[]
 
+var pc = newConstPtr(newMySeq(3, 1.0))
+let pc2 = newConstPtr(newMySeq(3, 1.0))
+doAssert: pc.len == 3
+doAssert: pc.len == 3
+doAssert: compiles(pc.lenx == 2) == false
+doAssert: compiles(pc2.lenx == 2) == false
+doAssert: compiles(pc[0] = 2.0) == false
+doAssert: compiles(pc2[0] = 2.0) == false
+
+doAssert: pc[0] == 1.0
+doAssert: pc2[0] == 1.0
diff --git a/tests/converter/tgenericconverter2.nim b/tests/converter/tgenericconverter2.nim
index ae064d852..017651a6b 100644
--- a/tests/converter/tgenericconverter2.nim
+++ b/tests/converter/tgenericconverter2.nim
@@ -1,4 +1,36 @@
 # bug #3799
+discard """
+output: '''
+00000000000000000000000000000000000000000
+00000000000001111111111111110000000000000
+00000000001111111111111111111110000000000
+00000000111111111111111111111111100000000
+00000011111222222221111111111111111000000
+00000111122222222222221111111111111100000
+00001112222333333459432111111111111110000
+00011122355544344463533221111111111111000
+00111124676667556896443322211111111111100
+00111126545561919686543322221111111111100
+01111123333346967807554322222211111111110
+01111122233334455582015332222221111111110
+01111122222333344567275432222222111111110
+01111112222222334456075443222222211111110
+01111111222222233459965444332222221111110
+01111111122222223457486554433322222111110
+01111111112222222367899655543333322111110
+01111111111122222344573948465444332111110
+00111111111112222334467987727667762111100
+00111111111111122233474655557836432111100
+00011111111111112233 454433334 4321111000
+00001111111111111122354333322222211110000
+00000111111111111111222222222222111100000
+00000001111111111111111122222111110000000
+00000000111111111111111111111111100000000
+00000000000111111111111111111100000000000
+00000000000000111111111111100000000000000
+'''
+"""
+
 
 import macros
 
@@ -37,9 +69,9 @@ iterator stepIt[T](start, step: T, iterations: int): T =
 
 
 let c = (0.36237, 0.32)
-for y in stepIt(2.0, -0.0375, 107):
+for y in stepIt(2.0, -0.0375 * 4, 107 div 4):
   var row = ""
-  for x in stepIt(-2.0, 0.025, 160):
+  for x in stepIt(-2.0, 0.025 * 4, 160 div 4):
     #let n = julia((x, y), c, 4.0, nmax)         ### this works
     let n = dendriteFractal((x, y), 4.0, nmax)
     if n < nmax:
diff --git a/tests/coroutines/texceptions.nim b/tests/coroutines/texceptions.nim
index e67f954c3..323eb055d 100644
--- a/tests/coroutines/texceptions.nim
+++ b/tests/coroutines/texceptions.nim
@@ -14,6 +14,7 @@ proc testExceptions(id: int, sleep: float) =
     numbers.add(id)
     raise (ref ValueError)()
   except:
+    suspend(sleep)
     numbers.add(id)
     suspend(sleep)
     numbers.add(id)
@@ -22,6 +23,6 @@ proc testExceptions(id: int, sleep: float) =
 
 start(proc() = testExceptions(1, 0.01))
 start(proc() = testExceptions(2, 0.011))
-run()
+coro.run()
 doAssert(stackCheckValue == 1100220033, "Thread stack got corrupted")
 doAssert(numbers == @[1, 2, 1, 2, 1, 2, 1, 2, 1, 2], "Coroutines executed in incorrect order")
diff --git a/tests/coroutines/titerators.nim b/tests/coroutines/titerators.nim
index 610f2771a..abcfbde43 100644
--- a/tests/coroutines/titerators.nim
+++ b/tests/coroutines/titerators.nim
@@ -22,7 +22,7 @@ var start = getTicks()
 start(proc() = theCoroutine(1, 0.01))
 start(proc() = theCoroutine(2, 0.011))
 run()
+
 var executionTime = getTicks() - start
-doAssert(executionTime >= 55_000_000.Nanos and executionTime < 56_000_000.Nanos, "Coroutines executed too short")
 doAssert(stackCheckValue == 1100220033, "Thread stack got corrupted")
 doAssert(numbers == @[10, 20, 11, 21, 12, 22, 13, 23, 14, 24], "Coroutines executed in incorrect order")
diff --git a/tests/cpp/t8241.nim b/tests/cpp/t8241.nim
index cbee1d85a..9aed13fcb 100644
--- a/tests/cpp/t8241.nim
+++ b/tests/cpp/t8241.nim
@@ -20,4 +20,13 @@ proc findlib2: string =
 proc imported_func2*(a: cint): cstring {.importc, dynlib: findlib2().}
 
 echo imported_func(1)
-echo imported_func2(1)
\ No newline at end of file
+echo imported_func2(1)
+
+# issue #8946
+
+from json import JsonParsingError
+import marshal
+
+const nothing = ""
+doAssertRaises(JsonParsingError):
+  var bar = marshal.to[int](nothing)
diff --git a/tests/cpp/tnativesockets.nim b/tests/cpp/tnativesockets.nim
index c62008050..1284811b5 100644
--- a/tests/cpp/tnativesockets.nim
+++ b/tests/cpp/tnativesockets.nim
@@ -1,5 +1,6 @@
 discard """
   targets: "cpp"
+outputsub: ""
 """
 
 import nativesockets
diff --git a/tests/cpp/tsigbreak.nim b/tests/cpp/tsigbreak.nim
index 9a381d84f..14d29adf7 100644
--- a/tests/cpp/tsigbreak.nim
+++ b/tests/cpp/tsigbreak.nim
@@ -1,5 +1,6 @@
 discard """
   targets: "cpp"
+  action: compile
 """
 
 import tables, lists
diff --git a/tests/defaultprocparam/tdefaultprocparam.nim b/tests/defaultprocparam/tdefaultprocparam.nim
index 23ecf72e9..5f8c1adab 100644
--- a/tests/defaultprocparam/tdefaultprocparam.nim
+++ b/tests/defaultprocparam/tdefaultprocparam.nim
@@ -1,4 +1,8 @@
-
+discard """
+output: '''
+hi
+'''
+"""
 import mdefaultprocparam
 
 p()
diff --git a/tests/destructor/t6434.nim b/tests/destructor/t6434.nim
index 9c912f1f9..c9ad213c2 100644
--- a/tests/destructor/t6434.nim
+++ b/tests/destructor/t6434.nim
@@ -1,21 +1,26 @@
 discard """
   exitcode: 0
-  output: '''assingment
-assingment
-assingment
-assingment
-'''
+  output: ""
 """
 
 type
   Foo* = object
     boo: int
 
+var sink_counter = 0
+var assign_counter = 0
+
+proc `=sink`(dest: var Foo, src: Foo) =
+  sink_counter.inc
+
 proc `=`(dest: var Foo, src: Foo) =
-  debugEcho "assingment"
+  assign_counter.inc
 
 proc test(): auto =
   var a,b : Foo
-  return (a, b)
+  return (a, b, Foo(boo: 5))
+
+var (a, b, _) = test()
 
-var (a, b) = test()
\ No newline at end of file
+doAssert: assign_counter == 0
+doAssert: sink_counter == 9
\ No newline at end of file
diff --git a/tests/destructor/tatomicptrs.nim b/tests/destructor/tatomicptrs.nim
index d20596415..fd8fc34d9 100644
--- a/tests/destructor/tatomicptrs.nim
+++ b/tests/destructor/tatomicptrs.nim
@@ -8,6 +8,8 @@ allocating
 deallocating
 deallocating
 deallocating
+allocating
+deallocating
 '''
   cmd: '''nim c --newruntime $file'''
 """
@@ -23,8 +25,7 @@ template incRef(x) =
 
 template decRef(x): untyped = atomicDec(x.refcount)
 
-proc makeShared*[T](x: T): SharedPtr[T] =
-  # XXX could benefit from 'sink' parameter.
+proc makeShared*[T](x: sink T): SharedPtr[T] =
   # XXX could benefit from a macro that generates it.
   result = cast[SharedPtr[T]](allocShared(sizeof(x)))
   result.x[] = x
@@ -59,6 +60,9 @@ proc `=sink`*[T](dest: var SharedPtr[T]; src: SharedPtr[T]) =
       echo "deallocating"
     dest.x = src.x
 
+proc get*[T](s: SharedPtr[T]): lent T =
+  s.x[]
+
 template `.`*[T](s: SharedPtr[T]; field: untyped): untyped =
   s.x.field
 
@@ -99,3 +103,47 @@ proc main =
 
 main()
 
+
+
+#-------------------------------------------------------
+#bug #9781
+
+type
+  MySeq* [T] = object
+    refcount: int
+    len: int
+    data: ptr UncheckedArray[T]
+
+proc `=destroy`*[T](m: var MySeq[T]) {.inline.} =
+  if m.data != nil:
+    deallocShared(m.data)
+    m.data = nil
+
+proc `=`*[T](m: var MySeq[T], m2: MySeq[T]) =
+  if m.data == m2.data: return
+  if m.data != nil:
+    `=destroy`(m)
+
+  m.len = m2.len
+  let bytes = m.len.int * sizeof(float) 
+  if bytes > 0:
+    m.data = cast[ptr UncheckedArray[T]](allocShared(bytes))
+    copyMem(m.data, m2.data, bytes)
+
+proc `=sink`*[T](m: var MySeq[T], m2: MySeq[T]) {.inline.} =
+  if m.data != m2.data:
+    if m.data != nil:
+      `=destroy`(m)
+    m.len = m2.len
+    m.data = m2.data
+
+proc len*[T](m: MySeq[T]): int {.inline.} = m.len
+
+proc newMySeq*[T](size: int, initial_value: T): MySeq[T] =
+  result.len = size
+  if size > 0:
+    result.data = cast[ptr UncheckedArray[T]](allocShared(sizeof(T) * size))
+
+
+let x = makeShared(newMySeq(10, 1.0))
+doAssert: x.get().len == 10
diff --git a/tests/destructor/tmove_objconstr.nim b/tests/destructor/tmove_objconstr.nim
index 50aecf46d..26cc682b5 100644
--- a/tests/destructor/tmove_objconstr.nim
+++ b/tests/destructor/tmove_objconstr.nim
@@ -60,3 +60,66 @@ for x in getPony():
 # XXX this needs to be enabled once top level statements
 # produce destructor calls again.
 #echo "Pony is dying!"
+
+
+#------------------------------------------------------------
+#-- Move into tuple constructor and move on tuple unpacking
+#------------------------------------------------------------
+
+type
+  MySeqNonCopyable* = object
+    len: int 
+    data: ptr UncheckedArray[float]
+
+proc `=destroy`*(m: var MySeqNonCopyable) {.inline.} =
+  if m.data != nil:
+    deallocShared(m.data)
+    m.data = nil
+
+proc `=`*(m: var MySeqNonCopyable, m2: MySeqNonCopyable) {.error.}
+
+proc `=sink`*(m: var MySeqNonCopyable, m2: MySeqNonCopyable) {.inline.} =
+  if m.data != m2.data:
+    if m.data != nil:
+      `=destroy`(m)
+    m.len = m2.len
+    m.data = m2.data
+
+proc len*(m: MySeqNonCopyable): int {.inline.} = m.len
+
+proc `[]`*(m: MySeqNonCopyable; i: int): float {.inline.} =
+  m.data[i.int]
+
+proc `[]=`*(m: var MySeqNonCopyable; i, val: float) {.inline.} =
+  m.data[i.int] = val
+
+proc setTo(s: var MySeqNonCopyable, val: float) = 
+  for i in 0..<s.len.int:
+    s.data[i] = val
+
+proc newMySeq*(size: int, initial_value = 0.0): MySeqNonCopyable =#
+  result.len = size
+  if size > 0:
+    result.data = cast[ptr UncheckedArray[float]](createShared(float, size))
+
+  result.setTo(initial_value)
+
+proc myfunc(x, y: int): (MySeqNonCopyable, MySeqNonCopyable) =
+  result = (newMySeq(x, 1.0), newMySeq(y, 5.0))
+
+proc myfunc2(x, y: int): tuple[a: MySeqNonCopyable, b:int, c:MySeqNonCopyable] =
+  var cc = newMySeq(y, 5.0)
+  (a: newMySeq(x, 1.0), b:0, c: cc)
+
+let (seq1, seq2) = myfunc(2, 3)
+doAssert seq1.len == 2
+doAssert seq1[0] == 1.0
+doAssert seq2.len == 3
+doAssert seq2[0] == 5.0
+
+var (seq3, i, _) = myfunc2(2, 3)
+doAssert seq3.len == 2
+doAssert seq3[0] == 1.0
+
+var seq4, seq5: MySeqNonCopyable
+(seq4, i, seq5) = myfunc2(2, 3)
\ No newline at end of file
diff --git a/tests/dir with space/tspace.nim b/tests/dir with space/tspace.nim
index 2b74fa629..59237c9a1 100644
--- a/tests/dir with space/tspace.nim
+++ b/tests/dir with space/tspace.nim
@@ -1,3 +1,6 @@
-# Test for the compiler to be able to compile a Nim file with spaces in it.
+discard """
+output: "Successful"
+"""
+# Test for the compiler to be able to compile a Nim file with spaces in the directory name.
 
 echo("Successful")
diff --git a/tests/discard/tdiscardable.nim b/tests/discard/tdiscardable.nim
index 99144e324..a3dd966a0 100644
--- a/tests/discard/tdiscardable.nim
+++ b/tests/discard/tdiscardable.nim
@@ -1,3 +1,10 @@
+discard """
+output: '''
+1
+1
+'''
+"""
+
 # Test the discardable pragma
 
 proc p(x, y: int): int {.discardable.} =
diff --git a/tests/dll/server.nim b/tests/dll/server.nim
index e6b80df88..5ce1976ce 100644
--- a/tests/dll/server.nim
+++ b/tests/dll/server.nim
@@ -1,4 +1,5 @@
 discard """
+action: compile
   cmd: "nim $target --debuginfo --hints:on --define:useNimRtl --app:lib $options $file"
 """
 
@@ -25,10 +26,3 @@ proc newOp(k: TNodeKind, a, b: PNode): PNode {.exportc: "newOp", dynlib.} =
 
 proc buildTree(x: int): PNode {.exportc: "buildTree", dynlib.} =
   result = newOp(nkMul, newOp(nkAdd, newLit(x), newLit(x)), newLit(x))
-
-when false:
-  # Test the GC:
-  for i in 0..100_000:
-    discard buildTree(2)
-
-  echo "Done"
diff --git a/tests/effects/teffects6.nim b/tests/effects/teffects6.nim
index 3dd83786f..6a4eea155 100644
--- a/tests/effects/teffects6.nim
+++ b/tests/effects/teffects6.nim
@@ -1,3 +1,8 @@
+discard """
+action: compile
+"""
+
+# XXX: it is not actually tested if the effects are inferred
 
 type
   PMenu = ref object
diff --git a/tests/errmsgs/treportunused.nim b/tests/errmsgs/treportunused.nim
new file mode 100644
index 000000000..929da8843
--- /dev/null
+++ b/tests/errmsgs/treportunused.nim
@@ -0,0 +1,29 @@
+discard """
+  nimout: '''
+treportunused.nim(19, 10) Hint: 'treportunused.s1(a: string)[declared in treportunused.nim(19, 9)]' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(26, 5) Hint: 's8' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(22, 6) Hint: 'treportunused.s4()[declared in treportunused.nim(22, 5)]' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(25, 7) Hint: 's7' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(24, 7) Hint: 's6' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(23, 6) Hint: 'treportunused.s5(a: T)[declared in treportunused.nim(23, 5)]' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(20, 10) Hint: 'treportunused.s2()[declared in treportunused.nim(20, 9)]' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(29, 6) Hint: 's11' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(27, 5) Hint: 's9' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(21, 10) Hint: 's3' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(28, 6) Hint: 's10' is declared but not used [XDeclaredButNotUsed]
+'''
+"""
+
+# bug #9764
+
+iterator s1(a:string): int = discard
+iterator s2(): int = discard
+template s3(): untyped = 123
+proc s4(): int = 123
+proc s5[T](a: T): int = 123
+macro s6(a: int): untyped = discard
+const s7 = 0
+let s8 = 0
+var s9: int
+type s10 = object
+type s11 = type(1.2)
diff --git a/tests/errmsgs/tshow_asgn.nim b/tests/errmsgs/tshow_asgn.nim
index 1627c9b71..28a9acbeb 100644
--- a/tests/errmsgs/tshow_asgn.nim
+++ b/tests/errmsgs/tshow_asgn.nim
@@ -1,7 +1,7 @@
 discard """
   errormsg: "type mismatch: got <int> but expected 'cshort = int16'"
   line: 12
-  column: 10
+  column: 27
   file: "tshow_asgn.nim"
 """
 
diff --git a/tests/exception/t9657.nim b/tests/exception/t9657.nim
new file mode 100644
index 000000000..5d5164f4f
--- /dev/null
+++ b/tests/exception/t9657.nim
@@ -0,0 +1,6 @@
+discard """
+  action: run
+  exitcode: 1
+"""
+close stdmsg
+writeLine stdmsg, "exception!"
diff --git a/tests/exprs/tifexpr_typeinference.nim b/tests/exprs/tifexpr_typeinference.nim
index d02492a34..ccaea3e80 100644
--- a/tests/exprs/tifexpr_typeinference.nim
+++ b/tests/exprs/tifexpr_typeinference.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 #bug #712
 
 import tables
diff --git a/tests/flags/tgenscript.nim b/tests/flags/tgenscript.nim
index 45cfbfb84..989ca8bcb 100644
--- a/tests/flags/tgenscript.nim
+++ b/tests/flags/tgenscript.nim
@@ -1,6 +1,7 @@
 discard """
   file: "tgenscript.nim"
   target: "c"
+  action: compile
 """
 
 echo "--genscript"
diff --git a/tests/generics/t2tables.nim b/tests/generics/t2tables.nim
index 3ef5e621e..e4b1fb967 100644
--- a/tests/generics/t2tables.nim
+++ b/tests/generics/t2tables.nim
@@ -1,3 +1,6 @@
+discard """
+action: compile
+"""
 
 # bug #3669
 
@@ -10,4 +13,3 @@ type
 
 var g: G[string]
 echo g.rnodes["foo"]
-
diff --git a/tests/generics/tgeneric3.nim b/tests/generics/tgeneric3.nim
index 6897d9de2..34b415446 100644
--- a/tests/generics/tgeneric3.nim
+++ b/tests/generics/tgeneric3.nim
@@ -1,3 +1,13 @@
+discard """
+output: '''
+312
+1000000
+1000000
+500000
+0
+'''
+"""
+
 import strutils
 
 type
diff --git a/tests/generics/tgenericvariant.nim b/tests/generics/tgenericvariant.nim
index 348d3da6e..73c8af825 100644
--- a/tests/generics/tgenericvariant.nim
+++ b/tests/generics/tgenericvariant.nim
@@ -1,3 +1,13 @@
+discard """
+output: '''
+Test
+abcxyz123
+'''
+"""
+
+proc fakeReadLine(): string =
+  "abcxyz123"
+
 type
   TMaybe[T] = object
     case empty: bool
@@ -12,7 +22,7 @@ proc Nothing[T](): TMaybe[T] =
   result.empty = true
 
 proc safeReadLine(): TMaybe[string] =
-  var r = stdin.readLine()
+  var r = fakeReadLine()
   if r == "": return Nothing[string]()
   else: return Just(r)
 
@@ -21,3 +31,4 @@ when isMainModule:
   echo(Test.value)
   var mSomething = safeReadLine()
   echo(mSomething.value)
+  mSomething = safeReadLine()
diff --git a/tests/generics/tlateboundstatic.nim b/tests/generics/tlateboundstatic.nim
index f68f95f8d..90b44aa8e 100644
--- a/tests/generics/tlateboundstatic.nim
+++ b/tests/generics/tlateboundstatic.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: "array[0..3, int]"
+  nimout: "array[0..3, int]"
 """
 
 type
diff --git a/tests/generics/tthread_generic.nim b/tests/generics/tthread_generic.nim
index def1acfe1..f2e9cafa9 100644
--- a/tests/generics/tthread_generic.nim
+++ b/tests/generics/tthread_generic.nim
@@ -1,5 +1,6 @@
 discard """
   cmd: "nim $target --hints:on --threads:on $options $file"
+  action: compile
 """
 
 type
@@ -36,4 +37,3 @@ when isMainModule:
   echo("test")
   joinThread(thr)
   os.sleep(3000)
-
diff --git a/tests/global/tglobalforvar.nim b/tests/global/tglobalforvar.nim
index af75df5c8..bc18f33f2 100644
--- a/tests/global/tglobalforvar.nim
+++ b/tests/global/tglobalforvar.nim
@@ -1,7 +1,9 @@
+discard """
+output: 100
+"""
 
 var funcs: seq[proc (): int {.nimcall.}] = @[]
 for i in 0..10:
   funcs.add((proc (): int = return i * i))
 
 echo(funcs[3]())
-
diff --git a/tests/init/t8314.nim b/tests/init/t8314.nim
index 59d46eb33..47c8480c2 100644
--- a/tests/init/t8314.nim
+++ b/tests/init/t8314.nim
@@ -1,8 +1,14 @@
 discard """
   nimout: '''
-t8314.nim(8, 7) Hint: BEGIN [User]
-t8314.nim(19, 7) Hint: END [User]
+t8314.nim(14, 7) Hint: BEGIN [User]
+t8314.nim(25, 7) Hint: END [User]
   '''
+
+output: '''
+1
+1
+1
+'''
 """
 
 {.hint: "BEGIN".}
diff --git a/tests/init/tuninit1.nim b/tests/init/tuninit1.nim
index 891f1e96c..67c0c4d8b 100644
--- a/tests/init/tuninit1.nim
+++ b/tests/init/tuninit1.nim
@@ -1,6 +1,7 @@
 discard """
-  msg: "Warning: 'y' might not have been initialized [Uninit]"
+  nimout: "Warning: 'y' might not have been initialized [Uninit]"
   line:34
+  action: compile
 """
 
 import strutils
diff --git a/tests/iter/timplicit_auto.nim b/tests/iter/timplicit_auto.nim
index d5cb95eb8..1b9f06843 100644
--- a/tests/iter/timplicit_auto.nim
+++ b/tests/iter/timplicit_auto.nim
@@ -15,4 +15,4 @@ iterator fields(a = (0,0), b = (h-1,w-1)): auto =
       yield (y,x)
 
 for y,x in fields():
-  stdout.write disp[univ(x, y)]
+  doAssert disp[univ(x, y)] == disp[Tree]
diff --git a/tests/iter/titer.nim b/tests/iter/titer.nim
index c4143ae4f..22be1bad5 100644
--- a/tests/iter/titer.nim
+++ b/tests/iter/titer.nim
@@ -1,3 +1,16 @@
+discard """
+output: '''
+testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest2!test3?hi
+what's
+your
+name
+hi
+what's
+your
+name
+'''
+"""
+
 # Test the new iterators
 
 iterator xrange(fromm, to: int, step = 1): int =
diff --git a/tests/iter/titer_no_tuple_unpack.nim b/tests/iter/titer_no_tuple_unpack.nim
index 13ec11bd6..d8df10189 100644
--- a/tests/iter/titer_no_tuple_unpack.nim
+++ b/tests/iter/titer_no_tuple_unpack.nim
@@ -1,3 +1,18 @@
+discard """
+output: '''
+3 4
+4 5
+5 6
+6 7
+7 8
+(x: 3, y: 4)
+(x: 4, y: 5)
+(x: 5, y: 6)
+(x: 6, y: 7)
+(x: 7, y: 8)
+'''
+"""
+
 
 iterator xrange(fromm, to: int, step = 1): tuple[x, y: int] =
   var a = fromm
@@ -10,4 +25,3 @@ for a, b in xrange(3, 7):
 
 for tup in xrange(3, 7):
   echo tup
-
diff --git a/tests/iter/titervaropenarray.nim b/tests/iter/titervaropenarray.nim
index 1e70ce247..9eea085e3 100644
--- a/tests/iter/titervaropenarray.nim
+++ b/tests/iter/titervaropenarray.nim
@@ -11,6 +11,3 @@ iterator iterAndZero(a: var openArray[int]): int =
 var x = [[1, 2, 3], [4, 5, 6]]
 for y in iterAndZero(x[0]): write(stdout, $y)
 #OUT 123
-
-
-
diff --git a/tests/iter/tpermutations.nim b/tests/iter/tpermutations.nim
index 5149eb9c2..c5067ba31 100644
--- a/tests/iter/tpermutations.nim
+++ b/tests/iter/tpermutations.nim
@@ -1,3 +1,14 @@
+discard """
+output: '''
+@[@[1.0, 2.0], @[3.0, 4.0]]
+perm: 10.0 det: -2.0
+@[@[1.0, 2.0, 3.0, 4.0], @[4.0, 5.0, 6.0, 7.0], @[7.0, 8.0, 9.0, 10.0], @[10.0, 11.0, 12.0, 13.0]]
+perm: 29556.0 det: 0.0
+@[@[0.0, 1.0, 2.0, 3.0, 4.0], @[5.0, 6.0, 7.0, 8.0, 9.0], @[10.0, 11.0, 12.0, 13.0, 14.0], @[15.0, 16.0, 17.0, 18.0, 19.0], @[20.0, 21.0, 22.0, 23.0, 24.0]]
+perm: 6778800.0 det: 0.0
+'''
+"""
+
 
 import sequtils, sugar
 
diff --git a/tests/iter/tshallowcopy_closures.nim b/tests/iter/tshallowcopy_closures.nim
index 2f024ee7e..279e7d950 100644
--- a/tests/iter/tshallowcopy_closures.nim
+++ b/tests/iter/tshallowcopy_closures.nim
@@ -1,5 +1,9 @@
 discard """
   ccodecheck: "!@('{' \\s* 'NI HEX3Astate;' \\s* '}')"
+  output: '''
+a1 10
+a1 9
+'''
 """
 
 # bug #1803
@@ -26,6 +30,6 @@ var
   z: TaskFn
 
 discard x()
-z = x #shallowCopy(z, x)
-z = y #shallowCopy(z, y)
+shallowCopy(z, x)
+shallowCopy(z, y)
 discard x()
diff --git a/tests/iter/twrap_walkdir.nim b/tests/iter/twrap_walkdir.nim
index 4ac487d8e..1d52e9791 100644
--- a/tests/iter/twrap_walkdir.nim
+++ b/tests/iter/twrap_walkdir.nim
@@ -1,5 +1,6 @@
-
-
+discard """
+action: compile
+"""
 
 import os
 
diff --git a/tests/iter/tyieldintry.nim b/tests/iter/tyieldintry.nim
index ee2790e54..32eef494e 100644
--- a/tests/iter/tyieldintry.nim
+++ b/tests/iter/tyieldintry.nim
@@ -403,7 +403,7 @@ block: # yield in blockexpr
 
   test(it, 1, 2, 3)
 
-block: #8851 
+block: #8851
   type
     Foo = ref object of RootObj
   template someFoo(): Foo =
@@ -454,5 +454,18 @@ block: #9694 - yield in ObjConstr
 
   test(it, 1, 2)
 
+block: #9716
+  iterator it(): int {.closure.} =
+    var a = 0
+    for i in 1 .. 3:
+      var a: int # Make sure the "local" var is reset
+      var b: string # ditto
+      yield 1
+      a += 5
+      b &= "hello"
+      doAssert(a == 5)
+      doAssert(b == "hello")
+  test(it, 1, 1, 1)
+
 echo "ok"
 
diff --git a/tests/js/t9410.nim b/tests/js/t9410.nim
new file mode 100644
index 000000000..9aca6d45b
--- /dev/null
+++ b/tests/js/t9410.nim
@@ -0,0 +1,454 @@
+template doAssert(exp: untyped) =
+  when defined(echot9410):
+    let r = exp
+    echo $(instantiationInfo().line) & ":\n  " & astToStr(exp) & "\n  was " & repr(r)
+    when not defined(noassertt9410):
+      system.doAssert r
+  else:
+    when not defined(noassertt9410):
+      system.doAssert exp
+
+template tests =
+  block:
+    var i = 0
+    i = 2
+
+    var y: ptr int
+    doAssert y == nil
+    doAssert isNil(y)
+    y = i.addr
+    y[] = 3
+    doAssert i == 3
+    doAssert i == y[]
+
+    let z = i.addr
+    z[] = 4
+    doAssert i == 4
+    doAssert i == y[] and y[] == z[]
+
+    var hmm = (a: (b: z))
+    var hmmptr = hmm.a.b.addr
+    hmmptr[][] = 5
+
+    doAssert i == 5
+    doAssert y == z
+    doAssert z == hmmptr[]
+    doAssert 5 == y[] and 5 == z[] and 5 == hmmptr[][]
+
+  block:
+    var someint = 500
+
+    let p: ptr int = someint.addr
+    let tup = (f: p)
+    let tcopy = tup
+    var vtcopy = tcopy
+    p[] = 654
+    doAssert p[] == 654
+    doAssert tup.f[] == 654
+    doAssert tcopy.f[] == 654
+    doAssert vtcopy.f[] == 654
+
+  block:
+    var someint = 500
+
+    var p: ptr int = someint.addr
+    let arr = [p]
+    let arrc = arr
+    p[] = 256
+    doAssert someint == 256
+    doAssert p[] == 256
+    doAssert arr[0][] == 256
+    doAssert arrc[0][] == 256
+
+  block:
+    var someref: ref int
+    new(someref)
+    var someref2 = someref
+
+    var tup1 = (f: someref)
+    tup1.f = someref
+    let tup2 = tup1
+
+    someref[] = 543
+
+    proc passref(r: var ref int): var ref int = r
+    new(passref(someref))
+
+    doAssert someref[] == 0
+    doAssert tup1.f[] == 543
+    doAssert tup2.f[] == 543
+    doAssert someref2[] == 543
+
+  block:
+    type Whatever = object
+      i: ref int
+
+    var someref: ref int
+    new(someref)
+    someref[] = 10
+
+    let w = Whatever(i: someref)
+    var wcopy = w
+
+    someref[] = 20
+
+    doAssert w.i[] == 20
+    doAssert someref[] == 20
+    doAssert wcopy.i[] == 20
+    doAssert w.i == wcopy.i
+    #echo w.i[], " ", someref[], " ", wcopy.i[]
+
+  block:
+    var oneseq: ref seq[ref int]
+    new(oneseq)
+    var aref: ref int
+    new(aref)
+    aref[] = 123
+    let arefs = [aref]
+    oneseq[] &= arefs[0]
+    oneseq[] &= aref
+    aref[] = 222
+    new(aref)
+    doAssert oneseq[0] == oneseq[1]
+    doAssert oneseq[0][] == 222
+    doAssert oneseq[1][] == 222
+    doAssert aref[] == 0
+
+  block:
+    var seqs: ref seq[ref seq[ref int]]
+    new(seqs)
+    seqs[] = newSeq[ref seq[ref int]](1)
+    new(seqs[0])
+    seqs[0][] = newSeq[ref int](0)
+
+    var aref: ref int
+    new aref
+    aref[] = 654
+
+    let arefs = [aref]
+    doAssert arefs[0] == aref
+    seqs[0][] &= arefs[0]
+    seqs[0][] &= aref
+    seqs[0][1][] = 456
+    let seqs2 = seqs
+    let same = seqs2[0][0] == seqs2[0][1]
+    doAssert arefs[0] == aref
+    doAssert aref[] == 456
+    doAssert seqs[].len == 1
+    doAssert seqs[0][].len == 2
+    doAssert seqs[0][0][] == 456
+    doAssert seqs[0][1][] == 456
+    doAssert same
+
+  block:
+    type Obj = object
+      x, y: int
+
+    var objrefs: seq[ref Obj] = @[(ref Obj)(nil), nil, nil]
+    objrefs[2].new
+    objrefs[2][] = Obj(x: 123, y: 321)
+    objrefs[1] = objrefs[2]
+    doAssert objrefs[0] == nil
+    doAssert objrefs[1].y == 321
+    doAssert objrefs[2].y == 321
+    doAssert objrefs[1] == objrefs[2]
+
+  block:
+    var refs: seq[ref string] = @[(ref string)(nil), nil, nil]
+    refs[1].new
+    refs[1][] = "it's a ref!"
+    refs[0] = refs[1]
+    refs[2] = refs[1]
+    new(refs[0])
+    doAssert refs[0][] == ""
+    doAssert refs[1][] == "it's a ref!"
+    doAssert refs[2][] == "it's a ref!"
+    doAssert refs[1] == refs[2]
+
+  block:
+    var retaddr_calls = 0
+    proc retaddr(p: var int): var int =
+      retaddr_calls += 1
+      p
+
+    var tfoo_calls = 0
+    proc tfoo(x: var int) =
+      tfoo_calls += 1
+      x += 10
+      var y = x.addr
+      y[] += 20
+      retaddr(x) += 30
+      let z = retaddr(x).addr
+      z[] += 40
+
+    var ints = @[1, 2, 3]
+    tfoo(ints[1])
+    doAssert retaddr_calls == 2
+    doAssert tfoo_calls == 1
+    doAssert ints[1] == 102
+
+    var tbar_calls = 0
+    proc tbar(x: var int): var int =
+      tbar_calls += 1
+      x
+
+    tbar(ints[2]) += 10
+    tbar(ints[2]) *= 2
+    doAssert tbar_calls == 2
+
+    var tqux_calls = 0
+    proc tqux(x: var int): ptr int =
+      tqux_calls += 1
+      x.addr
+
+    discard tqux(ints[2]) == tqux(ints[2])
+    doAssert tqux_calls == 2
+    doAssert isNil(tqux(ints[2])) == false
+    doAssert tqux_calls == 3
+
+    var tseq_calls = 0
+    proc tseq(x: var seq[int]): var seq[int] =
+      tseq_calls += 1
+      x
+
+    tseq(ints) &= 999
+    doAssert tseq_calls == 1
+    doAssert ints == @[1, 102, 26, 999]
+
+    var rawints = @[555]
+    rawints &= 666
+    doAssert rawints == @[555, 666]
+
+    var resetints_calls = 0
+    proc resetInts(): int =
+      resetints_calls += 1
+      ints = @[0, 0, 0]
+      1
+
+    proc incr(x: var int; b: int): var int =
+      x = x + b
+      x
+
+    var q = 0
+    var qp = q.addr
+    qp[] += 123
+    doAssert q == 123
+    # check order of evaluation
+    doAssert (resetInts() + incr(q, tqux(ints[2])[])) == 124
+
+  block: # reset
+    var calls = 0
+    proc passsomething(x: var int): var int =
+      calls += 1
+      x
+
+    var
+      a = 123
+      b = 500
+      c = a.addr
+    reset(passsomething(a))
+    doAssert calls == 1
+    reset(b)
+    doAssert a == b
+    reset(c)
+    doAssert c == nil
+
+  block: # strings
+    var calls = 0
+    proc stringtest(s: var string): var string =
+      calls += 1
+      s
+
+    var somestr: string
+
+    stringtest(somestr) &= 'a'
+    stringtest(somestr) &= 'b'
+    doAssert calls == 2
+    doAssert somestr == "ab"
+    stringtest(somestr) &= "woot!"
+    doAssert somestr == "abwoot!"
+    doAssert calls == 3
+
+    doAssert stringtest(somestr).len == 7
+    doAssert calls == 4
+    doAssert high(stringtest(somestr)) == 6
+    doAssert calls == 5
+
+    var somestr2: string
+    stringtest(somestr2).setLen(stringtest(somestr).len)
+    doAssert calls == 7
+    doAssert somestr2.len == somestr.len
+
+    var somestr3: string
+    doAssert (somestr3 & "foo") == "foo"
+
+    block:
+      var a, b, c, d: string
+      d = a & b & c
+      doAssert d == ""
+      d = stringtest(a) & stringtest(b) & stringtest(c)
+      doAssert calls == 10
+      doAssert d == ""
+
+  block: # seqs
+    var calls = 0
+    proc seqtest(s: var seq[int]): var seq[int] =
+      calls += 1
+      s
+
+    var someseq: seq[int]
+
+    seqtest(someseq) &= 1
+    seqtest(someseq) &= 2
+    doAssert calls == 2
+    doAssert someseq == @[1, 2]
+    seqtest(someseq) &= @[3, 4, 5]
+    doAssert someseq == @[1, 2, 3, 4, 5]
+    doAssert calls == 3
+
+    doAssert seqtest(someseq).len == 5
+    doAssert calls == 4
+    doAssert high(seqtest(someseq)) == 4
+    doAssert calls == 5
+
+    # genArrayAddr
+    doAssert seqtest(someseq)[2] == 3
+    doAssert calls == 6
+
+    seqtest(someseq).setLen(seqtest(someseq).len)
+    doAssert calls == 8
+
+    var somenilseq: seq[int]
+    seqtest(somenilseq).setLen(3)
+    doAssert calls == 9
+    doAssert somenilseq[1] == 0
+
+    someseq = @[1, 2, 3]
+    doAssert (seqtest(someseq) & seqtest(someseq)) == @[1, 2, 3, 1, 2, 3]
+
+
+  block: # mInc, mDec
+    var calls = 0
+    proc someint(x: var int): var int =
+      calls += 1
+      x
+
+    var x = 10
+
+    inc(someint(x))
+    doAssert x == 11
+    doAssert calls == 1
+
+    dec(someint(x))
+    doAssert x == 10
+    doAssert calls == 2
+
+  block: # uints
+    var calls = 0
+    proc passuint(x: var uint32): var uint32 =
+      calls += 1
+      x
+
+    var u: uint32 = 5
+    passuint(u) += 1
+    doAssert u == 6
+    doAssert calls == 1
+
+    passuint(u) -= 1
+    doAssert u == 5
+    doAssert calls == 2
+
+    passuint(u) *= 2
+    doAssert u == 10
+    doAssert calls == 3
+
+  block: # objs
+    type Thing = ref object
+      x, y: int
+
+    var a, b: Thing
+    a = Thing()
+    b = a
+
+    doAssert a == b
+
+    var calls = 0
+    proc passobj(o: var Thing): var Thing =
+      calls += 1
+      o
+
+    passobj(b) = Thing(x: 123)
+    doAssert calls == 1
+    doAssert a != b
+    doAssert b.x == 123
+
+    var passobjptr_calls = 0
+    proc passobjptr(o: var Thing): ptr Thing =
+      passobjptr_calls += 1
+      o.addr
+
+    passobjptr(b)[] = Thing(x: 234)
+    doAssert passobjptr_calls == 1
+    doAssert a != b
+    doAssert b.x == 234
+    passobjptr(b)[].x = 500
+    doAssert b.x == 500
+
+    var pptr = passobjptr(b)
+    pptr.x += 100
+    doAssert b.x == 600
+
+    proc getuninitptr(): ptr int =
+      return
+
+    doAssert getuninitptr() == nil
+
+  block: # pointer casting
+    var obj = (x: 321, y: 543)
+    var x = 500
+
+    var objptr = obj.addr
+    var xptr = x.addr
+
+    var p1, p2: pointer
+    p1 = cast[pointer](objptr)
+    p2 = cast[pointer](xptr)
+    doAssert p1 != p2
+
+    p1 = cast[pointer](objptr)
+    p2 = cast[pointer](objptr)
+    doAssert p1 == p2
+
+    let objptr2 = cast[type(objptr)](p2)
+    doAssert objptr == objptr2
+
+    p1 = cast[pointer](xptr)
+    p2 = cast[pointer](xptr)
+    doAssert p1 == p2
+
+    let xptr2 = cast[type(xptr)](p2)
+    doAssert xptr == xptr2
+
+  when false:
+    block: # openarray
+          # Error: internal error: genAddr: nkStmtListExpr
+      var calls = 0
+      proc getvarint(x: var openarray[int]): var int =
+        calls += 1
+        if true:
+          x[1]
+        else:
+          x[0]
+
+      var arr = [1, 2, 3]
+      getvarint(arr) += 5
+      doAssert calls == 1
+      doAssert arr[1] == 7
+
+proc tests_in_proc =
+  tests
+
+# since pointers are handled differently in global/local contexts
+# let's just run all of them twice
+tests_in_proc()
+tests
diff --git a/tests/js/tcopying.nim b/tests/js/tcopying.nim
index 387df9cd3..c58a080e9 100644
--- a/tests/js/tcopying.nim
+++ b/tests/js/tcopying.nim
@@ -2,6 +2,10 @@ discard """
   output: '''123
 2 9
 2 9
+1 124
+true false
+100 300 100
+1
 '''
 """
 
@@ -35,3 +39,34 @@ block:
     obj.ary2[1] = 9
 
     echo ary1[1], " ", obj.ary2[1]
+
+block:
+    type TestObj = object
+        x, y: int
+
+    let obj = TestObj(x: 1, y: 2)
+    var s = @[obj]
+    s[0].x += 123
+    echo obj.x, " ", s[0].x
+
+block:
+    var nums = {1, 2, 3, 4}
+    let obj = (n: nums)
+    nums.incl 5
+    echo (5 in nums), " ", (5 in obj.n)
+
+block:
+    let tup1 = (a: 100)
+    var tup2 = (t: (t2: tup1))
+    var tup3 = tup1
+    tup2.t.t2.a = 300
+    echo tup1.a, " ", tup2.t.t2.a, " ", tup3.a
+
+block:
+    proc foo(arr: array[2, int]) =
+        var s = @arr
+        s[0] = 500
+
+    var nums = [1, 2]
+    foo(nums)
+    echo nums[0]
\ No newline at end of file
diff --git a/tests/js/tjsffi.nim b/tests/js/tjsffi.nim
index 213d05964..2420c60f6 100644
--- a/tests/js/tjsffi.nim
+++ b/tests/js/tjsffi.nim
@@ -154,7 +154,7 @@ block:
 # Test JsAssoc .= and .
 block:
   proc test(): bool =
-    let obj = newJsAssoc[string, int]()
+    let obj = newJsAssoc[cstring, int]()
     var working = true
     obj.a = 11
     obj.`$!&` = 42
@@ -168,7 +168,7 @@ block:
 # Test JsAssoc .()
 block:
   proc test(): bool =
-    let obj = newJsAssoc[string, proc(e: int): int]()
+    let obj = newJsAssoc[cstring, proc(e: int): int]()
     obj.a = proc(e: int): int = e * e
     obj.a(10) == 100
   echo test()
@@ -176,7 +176,7 @@ block:
 # Test JsAssoc []()
 block:
   proc test(): bool =
-    let obj = newJsAssoc[string, proc(e: int): int]()
+    let obj = newJsAssoc[cstring, proc(e: int): int]()
     obj.a = proc(e: int): int = e * e
     let call = obj["a"]
     call(10) == 100
@@ -185,7 +185,7 @@ block:
 # Test JsAssoc Iterators
 block:
   proc testPairs(): bool =
-    let obj = newJsAssoc[string, int]()
+    let obj = newJsAssoc[cstring, int]()
     var working = true
     obj.a = 10
     obj.b = 20
@@ -202,7 +202,7 @@ block:
         return false
     working
   proc testItems(): bool =
-    let obj = newJsAssoc[string, int]()
+    let obj = newJsAssoc[cstring, int]()
     var working = true
     obj.a = 10
     obj.b = 20
@@ -211,13 +211,13 @@ block:
       working = working and v in [10, 20, 30]
     working
   proc testKeys(): bool =
-    let obj = newJsAssoc[string, int]()
+    let obj = newJsAssoc[cstring, int]()
     var working = true
     obj.a = 10
     obj.b = 20
     obj.c = 30
     for v in obj.keys:
-      working = working and v in ["a", "b", "c"]
+      working = working and v in [cstring"a", cstring"b", cstring"c"]
     working
   proc test(): bool = testPairs() and testItems() and testKeys()
   echo test()
@@ -226,8 +226,8 @@ block:
 block:
   proc test(): bool =
     {. emit: "var comparison = {a: 22, b: 55};" .}
-    var comparison {. importcpp, nodecl .}: JsAssoc[string, int]
-    let obj = newJsAssoc[string, int]()
+    var comparison {. importcpp, nodecl .}: JsAssoc[cstring, int]
+    let obj = newJsAssoc[cstring, int]()
     obj.a = 22
     obj.b = 55
     obj.a == comparison.a and obj.b == comparison.b
@@ -237,15 +237,15 @@ block:
 block:
   proc test(): bool =
     {. emit: "var comparison = {a: 22, b: 55};" .}
-    var comparison {. importcpp, nodecl .}: JsAssoc[string, int]
-    let obj = JsAssoc[string, int]{ a: 22, b: 55 }
+    var comparison {. importcpp, nodecl .}: JsAssoc[cstring, int]
+    let obj = JsAssoc[cstring, int]{ a: 22, b: 55 }
     var working = true
     working = working and
       compiles(JsAssoc[int, int]{ 1: 22, 2: 55 })
     working = working and
       comparison.a == obj.a and comparison.b == obj.b
     working = working and
-      not compiles(JsAssoc[string, int]{ a: "test" })
+      not compiles(JsAssoc[cstring, int]{ a: "test" })
     working
   echo test()
 
diff --git a/tests/lexer/tident.nim b/tests/lexer/tident.nim
index 3327344a5..e5177436d 100644
--- a/tests/lexer/tident.nim
+++ b/tests/lexer/tident.nim
@@ -1,3 +1,16 @@
+discard """
+output: '''
+Length correct
+Correct
+Correct
+Correct
+Correct
+Correct
+Correct
+Correct
+Correct
+'''
+"""
 
 type
   TIdObj* = object of RootObj
@@ -19,4 +32,3 @@ proc myNewString(L: int): string {.inline.} =
       echo("Wrong")
 
 var s = myNewString(8)
-
diff --git a/tests/lookups/test.nim b/tests/lookups/test.nim
index a17d235a4..56f39a4d7 100644
--- a/tests/lookups/test.nim
+++ b/tests/lookups/test.nim
@@ -1,3 +1,10 @@
+discard """
+output: '''
+[Suite] memoization
+
+'''
+"""
+
 # This file needs to be called 'test' nim to provoke a clash
 # with the unittest.test name. Issue #
 
@@ -14,4 +21,3 @@ proc fib(n: int): int = 40
 suite "memoization":
   test "recursive function memoization":
     check fastFib(40) == fib(40)
-
diff --git a/tests/lookups/tprefer_proc.nim b/tests/lookups/tprefer_proc.nim
deleted file mode 100644
index 57ee8e539..000000000
--- a/tests/lookups/tprefer_proc.nim
+++ /dev/null
@@ -1,4 +0,0 @@
-
-# bug #4353
-import random
-echo random[int](low(int) .. high(int))
diff --git a/tests/macros/tbindsym.nim b/tests/macros/tbindsym.nim
index 2abcd98ce..a493d6a88 100644
--- a/tests/macros/tbindsym.nim
+++ b/tests/macros/tbindsym.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: '''initApple
+  nimout: '''initApple
 deinitApple
 Coral
 enum
diff --git a/tests/macros/tdumpastgen.nim b/tests/macros/tdumpastgen.nim
index 0a1836886..0e0581f6a 100644
--- a/tests/macros/tdumpastgen.nim
+++ b/tests/macros/tdumpastgen.nim
@@ -1,5 +1,5 @@
 discard """
-msg: '''nnkStmtList.newTree(
+nimout: '''nnkStmtList.newTree(
   nnkVarSection.newTree(
     nnkIdentDefs.newTree(
       newIdentNode("x"),
diff --git a/tests/macros/tdumptree.nim b/tests/macros/tdumptree.nim
index 58b011b45..f540306c4 100644
--- a/tests/macros/tdumptree.nim
+++ b/tests/macros/tdumptree.nim
@@ -1,13 +1,14 @@
 discard """
-msg: '''StmtList
+nimout: '''
+StmtList
   VarSection
     IdentDefs
-      Ident !"x"
+      Ident "x"
       Empty
       Call
         DotExpr
-          Ident !"foo"
-          Ident !"create"
+          Ident "foo"
+          Ident "create"
         IntLit 56'''
 """
 
diff --git a/tests/macros/tescape_var_into_quotedo_as_const.nim b/tests/macros/tescape_var_into_quotedo_as_const.nim
new file mode 100644
index 000000000..1ed93f012
--- /dev/null
+++ b/tests/macros/tescape_var_into_quotedo_as_const.nim
@@ -0,0 +1,36 @@
+discard """
+  output: '''ok'''
+"""
+# bug #9864
+import macros, tables
+
+proc bar(shOpt: Table[string, int]) = discard
+
+macro dispatchGen(): untyped =
+  var shOpt = initTable[string, int]()
+  shOpt["foo"] = 10
+  result = quote do:
+     bar(`shOpt`)
+
+dispatchGen()
+
+type
+  Foo = object
+    data: seq[int]
+
+proc barB(a: Foo) = discard
+
+proc shOptB(): auto =
+  var shOpt: Foo
+  shOpt.data.setLen 1 # fails
+  shOpt
+
+macro dispatchGenB(): untyped =
+  var shOpt = shOptB() # fails
+
+  result = quote do:
+     barB(`shOpt`)
+
+dispatchGenB()
+
+echo "ok"
diff --git a/tests/macros/tgetimpl.nim b/tests/macros/tgetimpl.nim
index a546271ff..d231a4336 100644
--- a/tests/macros/tgetimpl.nim
+++ b/tests/macros/tgetimpl.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: '''"muhaha"
+  nimout: '''"muhaha"
 proc poo(x, y: int) =
   let y = x
   echo ["poo"]'''
@@ -46,3 +46,22 @@ static:
   doAssert isSameOwner(foo, poo)
   doAssert isSameOwner(foo, echo) == false
   doAssert isSameOwner(poo, len) == false
+
+#---------------------------------------------------------------
+
+macro check_gen_proc(ex: typed): (bool, bool) =
+  let lenChoice = bindsym"len"
+  var is_equal = false 
+  var is_instance_of = false 
+  for child in lenChoice:
+    if not is_equal:
+      is_equal = ex[0] == child
+    if not is_instance_of:
+      is_instance_of = isInstantiationOf(ex[0], child)
+         
+  result = nnkTupleConstr.newTree(newLit(is_equal), newLit(is_instance_of))
+
+# check that len(seq[int]) is not equal to bindSym"len", but is instance of it
+let a = @[1,2,3]
+assert: check_gen_proc(len(a)) == (false, true)
+
diff --git a/tests/macros/tgettype.nim b/tests/macros/tgettype.nim
index fa02bce57..77a55471f 100644
--- a/tests/macros/tgettype.nim
+++ b/tests/macros/tgettype.nim
@@ -1,6 +1,8 @@
 discard """
-msg: '''ObjectTy(Sym(Model), RecList(Sym(name), Sym(password)))
-BracketExpr(Sym(typeDesc), Sym(User))'''
+output: '''
+(ObjectTy (Empty) (Sym "Model") (RecList (Sym "name") (Sym "password")))
+(BracketExpr (Sym "typeDesc") (Sym "User"))
+'''
 """
 import strutils, macros
 
diff --git a/tests/macros/tgettype2.nim b/tests/macros/tgettype2.nim
index f129e6e1b..c579cf6ff 100644
--- a/tests/macros/tgettype2.nim
+++ b/tests/macros/tgettype2.nim
@@ -1,3 +1,35 @@
+discard """
+output: '''
+############
+#### gt ####
+############
+gt(Foo):	typeDesc[Foo]
+gt(Bar):	typeDesc[Bar]
+gt(Baz):	typeDesc[int]
+gt(foo):	distinct[int]
+gt(bar):	distinct[int]
+gt(baz):	int, int
+gt(v):	seq[int]
+gt(vv):	seq[float]
+gt(t):	distinct[tuple[int, int]]
+gt(tt):	distinct[tuple[float, float]]
+gt(s):	distinct[tuple[int, int]]
+#############
+#### gt2 ####
+#############
+gt2(Foo): 	Foo
+gt2(Bar): 	Bar
+gt2(Baz): 	Baz
+gt2(foo): 	Foo
+gt2(bar): 	Bar
+gt2(baz): 	Baz
+gt2(v): 	seq[int]
+gt2(vv): 	seq[float]
+gt2(t): 	MyType[system.int]
+gt2(tt): 	MyType[system.float]
+gt2(s): 	MySimpleType
+'''
+"""
 
 import macros, typetraits
 
diff --git a/tests/macros/tmacrogenerics.nim b/tests/macros/tmacrogenerics.nim
index 919a15b46..e4acdc321 100644
--- a/tests/macros/tmacrogenerics.nim
+++ b/tests/macros/tmacrogenerics.nim
@@ -1,8 +1,10 @@
 discard """
   file: "tmacrogenerics.nim"
-  msg: '''
-instantiation 1 with typedesc and typedesc
-counter: 1
+  nimout: '''
+instantiation 1 with None and None
+instantiation 2 with None and None
+instantiation 3 with None and None
+counter: 3
 '''
   output: "int\nfloat\nint\nstring"
 """
diff --git a/tests/macros/tmacros_issues.nim b/tests/macros/tmacros_issues.nim
index ecdcd5da9..657f30fc4 100644
--- a/tests/macros/tmacros_issues.nim
+++ b/tests/macros/tmacros_issues.nim
@@ -1,13 +1,10 @@
 discard """
-  msg: '''
-proc init(foo129050: int; bar129052: typedesc[int]): int =
-  foo129050
-
+  nimout: '''
 IntLit 5
 proc (x: int): string => typeDesc[proc[string, int]]
 proc (x: int): void => typeDesc[proc[void, int]]
 proc (x: int) => typeDesc[proc[void, int]]
-x => uncheckedArray[int]
+x => UncheckedArray[int]
 a
 s
 d
@@ -43,8 +40,8 @@ block t7723:
       proc init(foo: int, bar: typedesc[int]): int =
         foo
 
-  expandMacros:
-    foo1()
+  #expandMacros:
+  foo1()
 
   doAssert init(1, int) == 1
 
@@ -144,11 +141,11 @@ block t1140:
       result.parse_template body[1].strVal
 
 
-  proc actual: string = tmpli html"""
+  proc actual: string {.used.} = tmpli html"""
       <p>Test!</p>
       """
 
-  proc another: string = tmpli html"""
+  proc another: string {.used.} = tmpli html"""
       <p>what</p>
       """
 
diff --git a/tests/macros/tmacros_various.nim b/tests/macros/tmacros_various.nim
index 15bd28a37..9eece00bd 100644
--- a/tests/macros/tmacros_various.nim
+++ b/tests/macros/tmacros_various.nim
@@ -1,9 +1,14 @@
 discard """
-  msg: '''
-range[0 .. 100]
-array[0 .. 100, int]
-10
-test
+  nimout: '''
+Infix
+  Ident "=>"
+  Call
+    Ident "name"
+    Ident "a"
+    ExprColonExpr
+      Ident "b"
+      Ident "cint"
+  NilLit
 '''
 
   output: '''
diff --git a/tests/macros/tmemit.nim b/tests/macros/tmemit.nim
index 3a3b8734b..06ab8a1e2 100644
--- a/tests/macros/tmemit.nim
+++ b/tests/macros/tmemit.nim
@@ -1,7 +1,9 @@
 discard """
-  output: '''HELLO WORLD
+  output: '''
+HELLO WORLD
 c_func
-12'''
+12
+'''
 """
 
 import macros, strutils
diff --git a/tests/macros/tquotedo.nim b/tests/macros/tquotedo.nim
index b663b81ba..cd1f69116 100644
--- a/tests/macros/tquotedo.nim
+++ b/tests/macros/tquotedo.nim
@@ -1,3 +1,11 @@
+discard """
+output: '''
+123
+Hallo Welt
+Hallo Welt
+'''
+"""
+
 import macros
 
 macro mac(): untyped =
diff --git a/tests/macros/tstaticparamsmacro.nim b/tests/macros/tstaticparamsmacro.nim
index ea59936e0..8bd653920 100644
--- a/tests/macros/tstaticparamsmacro.nim
+++ b/tests/macros/tstaticparamsmacro.nim
@@ -1,5 +1,6 @@
 discard """
-  msg: '''letters
+  nimout: '''
+letters
 aa
 bb
 numbers
@@ -8,7 +9,7 @@ numbers
 AST a
 [(11, 22), (33, 44)]
 AST b
-(e: [55, 66], f: [77, 88])
+([55, 66], [77, 88])
 55
 10
 20Test
@@ -44,10 +45,10 @@ const
   b : Tb = (@[55,66], @[77, 88])
 
 macro mA(data: static[Ta]): untyped =
-  echo "AST a \n", repr(data)
+  echo "AST a\n", repr(data)
 
 macro mB(data: static[Tb]): untyped =
-  echo "AST b \n", repr(data)
+  echo "AST b\n", repr(data)
   echo data.e[0]
 
 mA(a)
diff --git a/tests/metatype/tbindtypedesc.nim b/tests/metatype/tbindtypedesc.nim
index 039acfbe9..cfa80e581 100644
--- a/tests/metatype/tbindtypedesc.nim
+++ b/tests/metatype/tbindtypedesc.nim
@@ -1,10 +1,5 @@
 discard """
-  msg: '''int int
-float float
-int int
-TFoo TFoo
-int float
-TFoo TFoo'''
+  output: '''ok'''
 """
 
 import typetraits
@@ -86,3 +81,4 @@ reject bindArg(int, int, 10, 20, 30, "test")
 reject bindArg(int, string, 10.0, 20, "test", "nest")
 reject bindArg(int, string, "test", "nest", 10, 20)
 
+echo "ok"
diff --git a/tests/metatype/tmetatype_issues.nim b/tests/metatype/tmetatype_issues.nim
index 5c5380c9f..c5040f9ba 100644
--- a/tests/metatype/tmetatype_issues.nim
+++ b/tests/metatype/tmetatype_issues.nim
@@ -1,4 +1,15 @@
-
+discard """
+output:'''
+void
+(Field0: "string", Field1: "string")
+1 mod 7
+@[2, 2, 2, 2, 2]
+impl 2 called
+asd
+Foo
+Bar
+'''
+"""
 
 import typetraits, macros
 
@@ -145,6 +156,3 @@ block t3338:
   var t2 = Bar[int32]()
   t2.add()
   doAssert t2.x == 5
-
-
-
diff --git a/tests/metatype/tsemistatic.nim b/tests/metatype/tsemistatic.nim
index 3f36abde9..56b9a6218 100644
--- a/tests/metatype/tsemistatic.nim
+++ b/tests/metatype/tsemistatic.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: "static 10\ndynamic\nstatic 20\n"
+  nimout: "static 10\ndynamic\nstatic 20\n"
   output: "s\nd\nd\ns"
 """
 
diff --git a/tests/metatype/tstaticparammacro.nim b/tests/metatype/tstaticparammacro.nim
index 02021185f..16a6e56b8 100644
--- a/tests/metatype/tstaticparammacro.nim
+++ b/tests/metatype/tstaticparammacro.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: '''letters
+  nimout: '''letters
 aa
 bb
 numbers
@@ -8,7 +8,7 @@ numbers
 AST a
 [(11, 22), (33, 44)]
 AST b
-(e: [55, 66], f: [77, 88])
+([55, 66], [77, 88])
 55
 10
 20Test
@@ -44,10 +44,10 @@ const
   b : Tb = (@[55,66], @[77, 88])
 
 macro mA(data: static[Ta]): untyped =
-  echo "AST a \n", repr(data)
+  echo "AST a\n", repr(data)
 
 macro mB(data: static[Tb]): untyped =
-  echo "AST b \n", repr(data)
+  echo "AST b\n", repr(data)
   echo data.e[0]
 
 mA(a)
diff --git a/tests/metatype/ttypedesc3.nim b/tests/metatype/ttypedesc3.nim
index 3d1cf2ec9..bd973eed1 100644
--- a/tests/metatype/ttypedesc3.nim
+++ b/tests/metatype/ttypedesc3.nim
@@ -1,3 +1,13 @@
+discard """
+output: '''
+proc Base
+proc Child
+method Base
+yield Base
+yield Child
+'''
+"""
+
 import typetraits
 
 type
diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim
index 106257828..2765a4231 100644
--- a/tests/metatype/ttypetraits.nim
+++ b/tests/metatype/ttypetraits.nim
@@ -1,5 +1,5 @@
 discard """
-  msg:    "int\nstring\nTBar[int]"
+  nimout:    "int\nstring\nTBar[int]"
   output: "int\nstring\nTBar[int]\nint\nrange 0..2(int)\nstring"
   disabled: true
 """
diff --git a/tests/misc/tcmdline.nim b/tests/misc/tcmdline.nim
index cb8cb402c..2c4768716 100644
--- a/tests/misc/tcmdline.nim
+++ b/tests/misc/tcmdline.nim
@@ -1,3 +1,6 @@
+discard """
+outputsub: "Number of parameters: 0"
+"""
 # Test the command line
 
 import
diff --git a/tests/misc/tcolonisproc.nim b/tests/misc/tcolonisproc.nim
index 665e9e604..c10dabcf1 100644
--- a/tests/misc/tcolonisproc.nim
+++ b/tests/misc/tcolonisproc.nim
@@ -1,3 +1,9 @@
+discard """
+output: '''
+1
+2
+'''
+"""
 
 proc p(a, b: int, c: proc ()) =
   c()
diff --git a/tests/misc/tdllvar.nim b/tests/misc/tdllvar.nim
index 1c1238e8d..68029ddf4 100644
--- a/tests/misc/tdllvar.nim
+++ b/tests/misc/tdllvar.nim
@@ -1,3 +1,7 @@
+discard """
+disabled: true
+"""
+
 import os
 
 proc getDllName: string =
@@ -12,5 +16,3 @@ proc myImport2(s: int) {.cdecl, importc, dynlib: getDllName().}
 
 myImport("test2")
 myImport2(12)
-
-
diff --git a/tests/misc/tendian.nim b/tests/misc/tendian.nim
deleted file mode 100644
index 91044f4d5..000000000
--- a/tests/misc/tendian.nim
+++ /dev/null
@@ -1,3 +0,0 @@
-# test the new endian magic
-
-writeLine(stdout, repr(system.cpuEndian))
diff --git a/tests/misc/tgetstartmilsecs.nim b/tests/misc/tgetstartmilsecs.nim
deleted file mode 100644
index bf508dd54..000000000
--- a/tests/misc/tgetstartmilsecs.nim
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-import times, os
-
-var start = epochTime()
-os.sleep(1000)
-
-echo epochTime() - start #OUT 1000
diff --git a/tests/misc/thallo.nim b/tests/misc/thallo.nim
index 17e6089ed..6f9d49121 100644
--- a/tests/misc/thallo.nim
+++ b/tests/misc/thallo.nim
@@ -1,4 +1,8 @@
-# Hallo
+discard """
+action: compile
+"""
+
+# noted this seems to be an old test file designed for manual testing.
 
 import
   os, strutils, macros
diff --git a/tests/misc/theaproots.nim b/tests/misc/theaproots.nim
index 77d0207b0..1ea3c86b9 100644
--- a/tests/misc/theaproots.nim
+++ b/tests/misc/theaproots.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 type
   Bar = object
     x: int
diff --git a/tests/misc/tlastmod.nim b/tests/misc/tlastmod.nim
index c622ab518..1cc1d4bd9 100644
--- a/tests/misc/tlastmod.nim
+++ b/tests/misc/tlastmod.nim
@@ -1,18 +1,25 @@
+discard """
+outputsub: "is newer than"
+"""
 # test the new LastModificationTime() proc
 
+let
+  file1 = "tests/testdata/data.csv"
+  file2 = "tests/testdata/doc1.xml"
+
 import
   os, times, strutils
 
 proc main() =
   var
     a, b: Time
-  a = getLastModificationTime(paramStr(1))
-  b = getLastModificationTime(paramStr(2))
+  a = getLastModificationTime(file1)
+  b = getLastModificationTime(file2)
   writeLine(stdout, $a)
   writeLine(stdout, $b)
   if a < b:
-    write(stdout, "$2 is newer than $1\n" % [paramStr(1), paramStr(2)])
+    write(stdout, "$2 is newer than $1\n" % [file1, file2])
   else:
-    write(stdout, "$1 is newer than $2\n" % [paramStr(1), paramStr(2)])
+    write(stdout, "$1 is newer than $2\n" % [file1, file2])
 
 main()
diff --git a/tests/misc/tloops.nim b/tests/misc/tloops.nim
index b160500af..61e0baf10 100644
--- a/tests/misc/tloops.nim
+++ b/tests/misc/tloops.nim
@@ -1,3 +1,10 @@
+discard """
+output: '''
+Hello!(x: 1, y: 2, z: 3)
+(x: 1.0, y: 2.0)
+'''
+"""
+
 # Test nested loops and some other things
 
 proc andTest() =
@@ -84,4 +91,3 @@ proc main[T]() =
   echo myType2
 
 main[int]()
-
diff --git a/tests/misc/tmandelbrot.nim b/tests/misc/tmandelbrot.nim
deleted file mode 100644
index 504628313..000000000
--- a/tests/misc/tmandelbrot.nim
+++ /dev/null
@@ -1,57 +0,0 @@
-discard """
-  cmd: "nim $target --hints:on -d:release $options $file"
-"""
-
-# -*- nim -*-
-
-import math
-import os
-import strutils
-
-type TComplex = tuple[re, im: float]
-
-proc `+` (a, b: TComplex): TComplex =
-    return (a.re + b.re, a.im + b.im)
-
-proc `*` (a, b: TComplex): TComplex =
-    result.re = a.re * b.re - a.im * b.im
-    result.im = a.re * b.im + a.im * b.re
-
-proc abs2 (a: TComplex): float =
-    return a.re * a.re + a.im * a.im
-
-var size    = parseInt(paramStr(1))
-var bit     = 128
-var byteAcc = 0
-
-stdout.writeLine("P4")
-stdout.write($size)
-stdout.write(" ")
-stdout.writeLine($size)
-
-var fsize = float(size)
-for y in 0 .. size-1:
-    var fy = 2.0 * float(y) / fsize - 1.0
-    for x in 0 .. size-1:
-        var z = (0.0, 0.0)
-        var c = (float(2*x) / fsize - 1.5, fy)
-
-        block iter:
-            for i in 0 .. 49:
-                z = z*z + c
-                if abs2(z) >= 4.0:
-                    break iter
-            byteAcc = byteAcc + bit
-
-        if bit > 1:
-            bit = bit div 2
-        else:
-            stdout.write(chr(byteAcc))
-            bit     = 128
-            byteAcc = 0
-
-    if bit != 128:
-        stdout.write(chr(byteAcc))
-        bit     = 128
-        byteAcc = 0
-
diff --git a/tests/misc/tmemoization.nim b/tests/misc/tmemoization.nim
index 840eb3b0d..c65692608 100644
--- a/tests/misc/tmemoization.nim
+++ b/tests/misc/tmemoization.nim
@@ -1,5 +1,5 @@
 discard """
-  msg:    "test 1\ntest 2\ntest 3"
+  nimout:    "test 1\ntest 2\ntest 3"
   output: "TEST 1\nTEST 2\nTEST 3"
 """
 
diff --git a/tests/misc/tnew.nim b/tests/misc/tnew.nim
index 89f34a621..02282dd4a 100644
--- a/tests/misc/tnew.nim
+++ b/tests/misc/tnew.nim
@@ -1,3 +1,10 @@
+discard """
+outputsub: '''
+Simple tree node allocation worked!
+Simple cycle allocation worked!
+'''
+"""
+
 # Test the implementation of the new operator
 # and the code generation for gc walkers
 # (and the garbage collector):
diff --git a/tests/misc/tnewuns.nim b/tests/misc/tnewuns.nim
deleted file mode 100644
index d6bae4fb1..000000000
--- a/tests/misc/tnewuns.nim
+++ /dev/null
@@ -1,12 +0,0 @@
-# test the new unsigned operations:
-
-import
-  strutils
-
-var
-  x, y: int
-
-x = 1
-y = high(int)
-
-writeLine(stdout, $ ( x +% y ) )
diff --git a/tests/misc/tprep.nim b/tests/misc/tprep.nim
index 8f40300d6..45f25b790 100644
--- a/tests/misc/tprep.nim
+++ b/tests/misc/tprep.nim
@@ -1,3 +1,11 @@
+discard """
+nimout: '''
+tprep.nim(25, 9) Hint: Case 2 [User]
+tprep.nim(27, 11) Hint: Case 2.3 [User]
+'''
+outputsub: ""
+"""
+
 # Test the features that used to belong to the preprocessor
 
 import
diff --git a/tests/misc/tquicksort.nim b/tests/misc/tquicksort.nim
index 0867a3769..017c73fbc 100644
--- a/tests/misc/tquicksort.nim
+++ b/tests/misc/tquicksort.nim
@@ -17,10 +17,7 @@ proc echoSeq(a: seq[int]) =
     for i in low(a)..high(a):
         echo(a[i])
 
-var
-    list: seq[int]
-
-list = QuickSort(@[89,23,15,23,56,123,356,12,7,1,6,2,9,4,3])
-echoSeq(list)
-
+let list = QuickSort(@[89,23,15,23,56,123,356,12,7,1,6,2,9,4,3])
+let expected = @[1, 2, 3, 4, 6, 7, 9, 12, 15, 23, 56, 89, 123, 356]
 
+doAssert list == expected
diff --git a/tests/misc/tradix.nim b/tests/misc/tradix.nim
index 07674af18..5009dfcfb 100644
--- a/tests/misc/tradix.nim
+++ b/tests/misc/tradix.nim
@@ -1,3 +1,28 @@
+discard """
+output: '''
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+128
+1
+2
+3
+4
+255
+17
+45
+19000
+4294967288
+'''
+"""
+
 # implements and tests an efficient radix tree
 
 ## another method to store an efficient array of pointers:
diff --git a/tests/misc/treadln.nim b/tests/misc/treadln.nim
index 6e01097aa..b716c4711 100644
--- a/tests/misc/treadln.nim
+++ b/tests/misc/treadln.nim
@@ -1,3 +1,11 @@
+
+discard """
+output: '''
+test the improved readline handling that does not care whether its
+Macintosh, Unix or Windows text format.
+'''
+"""
+
 # test the improved readline handling that does not care whether its
 # Macintosh, Unix or Windows text format.
 
@@ -8,5 +16,6 @@ var
 if open(inp, "tests/misc/treadln.nim"):
   while not endOfFile(inp):
     line = readLine(inp)
-    echo("#" & line & "#")
+    if line.len >= 2 and line[0] == '#' and line[1] == ' ':
+      echo line[2..^1]
   close(inp)
diff --git a/tests/misc/treadx.nim b/tests/misc/treadx.nim
deleted file mode 100644
index e68b8933d..000000000
--- a/tests/misc/treadx.nim
+++ /dev/null
@@ -1,13 +0,0 @@
-
-when not defined(windows):
-  import posix
-
-  var inp = ""
-  var buf: array[0..10, char]
-  while true:
-    var r = read(0, addr(buf), sizeof(buf)-1)
-    add inp, $cstring(addr buf)
-    if r != sizeof(buf)-1: break
-
-  echo inp
-  #dafkladskölklödsaf ölksdakölfölksfklwe4iojr389wr 89uweokf sdlkf jweklr jweflksdj fioewjfsdlfsd
diff --git a/tests/misc/tshadow_magic_type.nim b/tests/misc/tshadow_magic_type.nim
index 03c83079e..6f9716bb9 100644
--- a/tests/misc/tshadow_magic_type.nim
+++ b/tests/misc/tshadow_magic_type.nim
@@ -1,3 +1,10 @@
+discard """
+output: '''
+mylist
+'''
+"""
+
+
 type
   TListItemType* = enum
     RedisNil, RedisString
@@ -15,7 +22,8 @@ proc seq*() =
 
 proc lrange*(key: string): TRedisList =
   var foo: TListItem
-  foo.kind = RedisNil
+  foo.kind = RedisString
+  foo.str = key
   result = @[foo]
 
 when isMainModule:
diff --git a/tests/misc/tsizeof2.nim b/tests/misc/tsizeof2.nim
index 67379871d..4252142d7 100644
--- a/tests/misc/tsizeof2.nim
+++ b/tests/misc/tsizeof2.nim
@@ -9,3 +9,7 @@ type
 const i = sizeof(MyStruct)
 
 echo i
+
+# bug #9868
+proc foo(a: SomeInteger): array[sizeof(a), byte] =
+  discard
diff --git a/tests/misc/tstrace.nim b/tests/misc/tstrace.nim
index 23590d958..00af0af69 100644
--- a/tests/misc/tstrace.nim
+++ b/tests/misc/tstrace.nim
@@ -1,3 +1,23 @@
+discard """
+exitcode: 1
+output: '''
+Traceback (most recent call last)
+tstrace.nim(36)          tstrace
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(31)          recTest
+SIGSEGV: Illegal storage access. (Attempt to read from nil?)
+'''
+"""
+
 # Test the new stacktraces (great for debugging!)
 
 {.push stack_trace: on.}
diff --git a/tests/misc/tstrdist.nim b/tests/misc/tstrdist.nim
index 3e1939e73..53ace2fae 100644
--- a/tests/misc/tstrdist.nim
+++ b/tests/misc/tstrdist.nim
@@ -23,4 +23,4 @@ proc editDistance(a, b: string): int =
       c[(i-1)*n + (j-1)] = min(x,min(y,z))
   return c[n*m]
 
-write(stdout, editDistance("abc", "abd"))
+doAssert editDistance("abc", "abd") == 3
diff --git a/tests/misc/tunsigned64mod.nim b/tests/misc/tunsigned64mod.nim
index 9c9e01c45..ca3286df3 100644
--- a/tests/misc/tunsigned64mod.nim
+++ b/tests/misc/tunsigned64mod.nim
@@ -12,13 +12,13 @@ let t4 = (v2 mod 2'u64).uint64 # works
 # bug #2550
 
 var x: uint # doesn't work
-echo x mod 2 == 0
+doAssert x mod 2 == 0
 
 var y: uint64 # doesn't work
-echo y mod 2 == 0
+doAssert y mod 2 == 0
 
 var z: uint32 # works
-echo z mod 2 == 0
+doAssert z mod 2 == 0
 
 var a: int # works
-echo a mod 2 == 0
+doAssert a mod 2 == 0
diff --git a/tests/misc/tvarious.nim b/tests/misc/tvarious.nim
index 8124b3fc7..191107a87 100644
--- a/tests/misc/tvarious.nim
+++ b/tests/misc/tvarious.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 # Test various aspects
 
 # bug #572
diff --git a/tests/modules/t8665.nim b/tests/modules/t8665.nim
index 51538df79..74d31452f 100644
--- a/tests/modules/t8665.nim
+++ b/tests/modules/t8665.nim
@@ -1 +1,5 @@
+discard """
+  action: compile
+"""
+
 import treorder
diff --git a/tests/modules/texport2.nim b/tests/modules/texport2.nim
index 6e55873c5..e90c58673 100644
--- a/tests/modules/texport2.nim
+++ b/tests/modules/texport2.nim
@@ -1,9 +1,16 @@
+discard """
+output: '''
+abc
+xyz
+B.foo
+'''
+"""
+
 # bug #1595, #1612
 
 import mexport2a
 
 proc main() =
-  echo "Import Test, two lines should follow. One with abc and one with xyz."
   printAbc()
   printXyz()
 
diff --git a/tests/newconfig/tfoo.nim b/tests/newconfig/tfoo.nim
index 52ea841ee..f332cd6d4 100644
--- a/tests/newconfig/tfoo.nim
+++ b/tests/newconfig/tfoo.nim
@@ -1,7 +1,7 @@
 discard """
   cmd: "nim default $file"
   output: '''hello world! 0.5'''
-  msg: '''[NimScript] exec: gcc -v'''
+  nimout: '''[NimScript] exec: gcc -v'''
 """
 
 when not defined(definedefine):
diff --git a/tests/niminaction/Chapter3/ChatApp/src/client.nim b/tests/niminaction/Chapter3/ChatApp/src/client.nim
index 4d139655c..d479ebf43 100644
--- a/tests/niminaction/Chapter3/ChatApp/src/client.nim
+++ b/tests/niminaction/Chapter3/ChatApp/src/client.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 import os, threadpool, asyncdispatch, asyncnet
 import protocol
 
diff --git a/tests/niminaction/Chapter3/ChatApp/src/server.nim b/tests/niminaction/Chapter3/ChatApp/src/server.nim
index 8c572aeb0..31da74d16 100644
--- a/tests/niminaction/Chapter3/ChatApp/src/server.nim
+++ b/tests/niminaction/Chapter3/ChatApp/src/server.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 import asyncdispatch, asyncnet
 
 type
@@ -81,4 +85,4 @@ when isMainModule:
   echo("Server initialised!")
   # Execute the ``loop`` procedure. The ``waitFor`` procedure will run the
   # asyncdispatch event loop until the ``loop`` procedure finishes executing.
-  waitFor loop(server)
\ No newline at end of file
+  waitFor loop(server)
diff --git a/tests/niminaction/Chapter3/various3.nim b/tests/niminaction/Chapter3/various3.nim
index 478229b00..7b2776d70 100644
--- a/tests/niminaction/Chapter3/various3.nim
+++ b/tests/niminaction/Chapter3/various3.nim
@@ -1,3 +1,9 @@
+discard """
+output: '''
+Future is no longer empty, 42
+'''
+"""
+
 import threadpool
 proc foo: string = "Dog"
 var x: FlowVar[string] = spawn foo()
@@ -33,9 +39,9 @@ let data = """
   {"username": "Dominik"}
 """
 
-let obj = parseJson(data) 
-assert obj.kind == JObject 
-assert obj["username"].kind == JString 
+let obj = parseJson(data)
+assert obj.kind == JObject
+assert obj["username"].kind == JString
 assert obj["username"].str == "Dominik"
 
 block:
@@ -60,12 +66,12 @@ var amy = Human(name: "Amy", age: 20)
 
 import asyncdispatch
 
-var future = newFuture[int]() 
-doAssert(not future.finished) 
+var future = newFuture[int]()
+doAssert(not future.finished)
 
-future.callback = 
-  proc (future: Future[int]) = 
-    echo("Future is no longer empty, ", future.read) 
+future.callback =
+  proc (future: Future[int]) =
+    echo("Future is no longer empty, ", future.read)
 
 future.complete(42)
 
@@ -85,9 +91,8 @@ import asyncdispatch, asyncfile, os
 proc readFiles() {.async.} =
   # --- Changed to getTempDir here.
   var file = openAsync(getTempDir() / "test.txt", fmReadWrite)
-  let data = await file.readAll() 
-  echo(data) 
-  await file.write("Hello!\n") 
+  let data = await file.readAll()
+  echo(data)
+  await file.write("Hello!\n")
 
 waitFor readFiles()
-
diff --git a/tests/niminaction/Chapter6/WikipediaStats/concurrency.nim b/tests/niminaction/Chapter6/WikipediaStats/concurrency.nim
index 478f533d9..f20e21f4d 100644
--- a/tests/niminaction/Chapter6/WikipediaStats/concurrency.nim
+++ b/tests/niminaction/Chapter6/WikipediaStats/concurrency.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 # See this page for info about the format https://wikitech.wikimedia.org/wiki/Analytics/Data/Pagecounts-all-sites
 import tables, parseutils, strutils, threadpool
 
diff --git a/tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim b/tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim
index 8df3b6aeb..dbd635634 100644
--- a/tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim
+++ b/tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 # See this page for info about the format https://wikitech.wikimedia.org/wiki/Analytics/Data/Pagecounts-all-sites
 import tables, parseutils, strutils, threadpool, re
 
diff --git a/tests/niminaction/Chapter6/WikipediaStats/naive.nim b/tests/niminaction/Chapter6/WikipediaStats/naive.nim
index ed4fba8e2..ce995efaf 100644
--- a/tests/niminaction/Chapter6/WikipediaStats/naive.nim
+++ b/tests/niminaction/Chapter6/WikipediaStats/naive.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 # See this page for info about the format https://wikitech.wikimedia.org/wiki/Analytics/Data/Pagecounts-all-sites
 import tables, parseutils, strutils
 
diff --git a/tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim b/tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim
index 7181145e9..74857367a 100644
--- a/tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim
+++ b/tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 import os, parseutils, threadpool, strutils
 
 type
@@ -69,4 +73,4 @@ proc readPageCounts(filename: string, chunkSize = 1_000_000) =
 when isMainModule:
   const file = "pagecounts-20160101-050000"
   let filename = getCurrentDir() / file
-  readPageCounts(filename)
\ No newline at end of file
+  readPageCounts(filename)
diff --git a/tests/niminaction/Chapter6/WikipediaStats/race_condition.nim b/tests/niminaction/Chapter6/WikipediaStats/race_condition.nim
index c62b2f93e..db68aeb5c 100644
--- a/tests/niminaction/Chapter6/WikipediaStats/race_condition.nim
+++ b/tests/niminaction/Chapter6/WikipediaStats/race_condition.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 import threadpool
 
 var counter = 0
@@ -10,4 +14,4 @@ proc increment(x: int) =
 spawn increment(10_000)
 spawn increment(10_000)
 sync()
-echo(counter)
\ No newline at end of file
+echo(counter)
diff --git a/tests/niminaction/Chapter6/WikipediaStats/sequential_counts.nim b/tests/niminaction/Chapter6/WikipediaStats/sequential_counts.nim
index 25ad7d5f4..102dd15d3 100644
--- a/tests/niminaction/Chapter6/WikipediaStats/sequential_counts.nim
+++ b/tests/niminaction/Chapter6/WikipediaStats/sequential_counts.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 import os, parseutils
 
 proc parse(line: string, domainCode, pageTitle: var string,
@@ -31,4 +35,4 @@ proc readPageCounts(filename: string) =
 when isMainModule:
   const file = "pagecounts-20160101-050000"
   let filename = getCurrentDir() / file
-  readPageCounts(filename)
\ No newline at end of file
+  readPageCounts(filename)
diff --git a/tests/niminaction/Chapter7/Tweeter/src/createDatabase.nim b/tests/niminaction/Chapter7/Tweeter/src/createDatabase.nim
index c7aee1b44..a7d4ebe00 100644
--- a/tests/niminaction/Chapter7/Tweeter/src/createDatabase.nim
+++ b/tests/niminaction/Chapter7/Tweeter/src/createDatabase.nim
@@ -1,6 +1,10 @@
+discard """
+output: "Database created successfully!"
+"""
+
 import database
 
 var db = newDatabase()
 db.setup()
 echo("Database created successfully!")
-db.close()
\ No newline at end of file
+db.close()
diff --git a/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim b/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim
index b8a36306e..12aaf49b8 100644
--- a/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim
+++ b/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 import asyncdispatch, times
 
 import jester
diff --git a/tests/niminaction/Chapter7/Tweeter/tests/database_test.nim b/tests/niminaction/Chapter7/Tweeter/tests/database_test.nim
index 926ca452c..da69a004c 100644
--- a/tests/niminaction/Chapter7/Tweeter/tests/database_test.nim
+++ b/tests/niminaction/Chapter7/Tweeter/tests/database_test.nim
@@ -1,3 +1,7 @@
+discard """
+outputsub: "All tests finished successfully!"
+"""
+
 import database, os, times
 
 when isMainModule:
diff --git a/tests/niminaction/Chapter8/canvas/canvas.nim b/tests/niminaction/Chapter8/canvas/canvas.nim
index 713d1e9e2..ae2765630 100644
--- a/tests/niminaction/Chapter8/canvas/canvas.nim
+++ b/tests/niminaction/Chapter8/canvas/canvas.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 import dom
 
 type
diff --git a/tests/niminaction/Chapter8/sdl/sdl_test.nim b/tests/niminaction/Chapter8/sdl/sdl_test.nim
index a572d5231..a49e08911 100644
--- a/tests/niminaction/Chapter8/sdl/sdl_test.nim
+++ b/tests/niminaction/Chapter8/sdl/sdl_test.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 import os
 import sdl
 
diff --git a/tests/niminaction/Chapter8/sfml/sfml_test.nim b/tests/niminaction/Chapter8/sfml/sfml_test.nim
index 7d56d0903..e71060cb4 100644
--- a/tests/niminaction/Chapter8/sfml/sfml_test.nim
+++ b/tests/niminaction/Chapter8/sfml/sfml_test.nim
@@ -1,5 +1,6 @@
 discard """
-  disabled: "windows"
+action: compile
+disabled: "windows"
 """
 
 import sfml, os
diff --git a/tests/objects/tobjcov.nim b/tests/objects/tobjcov.nim
index c766adde0..817c1fcda 100644
--- a/tests/objects/tobjcov.nim
+++ b/tests/objects/tobjcov.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 # Covariance is not type safe:
 
 type
@@ -14,4 +18,3 @@ proc bp(x: var TB) = x.b[high(x.b)] = -1
 var f = cast[proc (x: var TA) {.nimcall.}](bp)
 var a: TA
 f(a) # bp expects a TB, but gets a TA
-
diff --git a/tests/objects/tobject.nim b/tests/objects/tobject.nim
index cdb8f80db..61ef7442e 100644
--- a/tests/objects/tobject.nim
+++ b/tests/objects/tobject.nim
@@ -1,3 +1,7 @@
+discard """
+output: "[Suite] object basic methods"
+"""
+
 import unittest
 
 type Obj = object
diff --git a/tests/objects/tobjects.nim b/tests/objects/tobjects.nim
deleted file mode 100644
index 66a38960e..000000000
--- a/tests/objects/tobjects.nim
+++ /dev/null
@@ -1,52 +0,0 @@
-type
-  TBase = object of RootObj
-    x, y: int
-
-  TSubclassKind = enum ka, kb, kc, kd, ke, kf
-  TSubclass = object of TBase
-    case c: TSubclassKind
-    of ka, kb, kc, kd:
-      a, b: int
-    of ke:
-      d, e, f: char
-    else: nil
-    n: bool
-
-type
-  TMyObject = object of RootObj
-    case disp: range[0..4]
-      of 0: arg: char
-      of 1: s: string
-      else: wtf: bool
-
-var
-  x: TMyObject
-
-var
-  global: int
-
-var
-  s: string
-  r: float = 0.0
-  i: int = 500 + 400
-
-case i
-of 500..999: write(stdout, "ha!\n")
-of 1000..3000, 12: write(stdout, "ganz schön groß\n")
-of 1, 2, 3: write(stdout, "1 2 oder 3\n")
-else: write(stdout, "sollte nicht passieren\n")
-
-case readLine(stdin)
-of "Rumpf": write(stdout, "Hallo Meister!\n")
-of "Andreas": write(stdout, "Hallo Meister!\n")
-else: write(stdout, "Nicht mein Meister!\n")
-
-global = global + 1
-write(stdout, "Hallo wie heißt du? \n")
-s = readLine(stdin)
-i = 0
-while i < len(s):
-  if s[i] == 'c': write(stdout, "'c' in deinem Namen gefunden\n")
-  i = i + 1
-
-write(stdout, "Du heißt " & s)
diff --git a/tests/objvariant/tcheckedfield1.nim b/tests/objvariant/tcheckedfield1.nim
index a7f232c5b..69b099f24 100644
--- a/tests/objvariant/tcheckedfield1.nim
+++ b/tests/objvariant/tcheckedfield1.nim
@@ -1,6 +1,8 @@
 discard """
-  msg: "Warning: cannot prove that field 'x.s' is accessible [ProveField]"
+  nimout: "Warning: cannot prove that field 'x.s' is accessible [ProveField]"
   line:51
+  action: run
+  output: "abc abc"
 """
 
 import strutils
diff --git a/tests/osproc/ta_in.nim b/tests/osproc/ta_in.nim
index b46890f6e..fb294ec14 100644
--- a/tests/osproc/ta_in.nim
+++ b/tests/osproc/ta_in.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 # This file is prefixed with an "a", because other tests
 # depend on it and it must be compiled first.
 import strutils
diff --git a/tests/osproc/ta_out.nim b/tests/osproc/ta_out.nim
index f7091a7f6..318a27d59 100644
--- a/tests/osproc/ta_out.nim
+++ b/tests/osproc/ta_out.nim
@@ -1,3 +1,14 @@
+discard """
+output: '''
+to stdout
+to stdout
+to stderr
+to stderr
+to stdout
+to stdout
+'''
+"""
+
 # This file is prefixed with an "a", because other tests
 # depend on it and it must be compiled first.
 stdout.writeLine("to stdout")
diff --git a/tests/osproc/tafalse.nim b/tests/osproc/tafalse.nim
index 24fd4fb2e..05a0bfce9 100644
--- a/tests/osproc/tafalse.nim
+++ b/tests/osproc/tafalse.nim
@@ -1,3 +1,7 @@
+discard """
+exitcode: 1
+"""
+
 # 'tafalse.nim' to ensure it is compiled before texitcode.nim
 import system
 quit(QuitFailure)
diff --git a/tests/osproc/texitcode.nim b/tests/osproc/texitcode.nim
index 4eaab6da2..6dc5508b5 100644
--- a/tests/osproc/texitcode.nim
+++ b/tests/osproc/texitcode.nim
@@ -2,6 +2,7 @@ discard """
   file: "texitcode.nim"
   output: ""
 """
+
 import osproc, os
 
 const filename = when defined(Windows): "tafalse.exe" else: "tafalse"
diff --git a/tests/overload/tselfderef.nim b/tests/overload/tselfderef.nim
index 708e4043b..96f1da42a 100644
--- a/tests/overload/tselfderef.nim
+++ b/tests/overload/tselfderef.nim
@@ -1,7 +1,10 @@
+discard """
+action: compile
+"""
+
 # bug #4671
 {.experimental.}
 {.this: self.}
-
 type
   SomeObj = object
     f: int
diff --git a/tests/parallel/tarray_of_channels.nim b/tests/parallel/tarray_of_channels.nim
index 90ae8369c..e2a682bd5 100644
--- a/tests/parallel/tarray_of_channels.nim
+++ b/tests/parallel/tarray_of_channels.nim
@@ -1,3 +1,15 @@
+discard """
+sortoutput: true
+output: '''
+(x: 0.0)
+(x: 0.0)
+(x: 0.0)
+test
+test
+test
+'''
+"""
+
 # bug #2257
 import threadpool
 
diff --git a/tests/parallel/tdont_be_stupid.nim b/tests/parallel/tdont_be_stupid.nim
index a7e82466a..d765c11a9 100644
--- a/tests/parallel/tdont_be_stupid.nim
+++ b/tests/parallel/tdont_be_stupid.nim
@@ -1,3 +1,11 @@
+discard """
+output: '''
+100
+200
+300
+400
+'''
+"""
 
 import threadpool, os
 
@@ -12,4 +20,4 @@ proc sleepsort(nums: openArray[int]) =
       spawn single(nums[i])
       i += 1
 
-sleepsort([50,3,40,25])
+sleepsort([400,100,300,200])
diff --git a/tests/parallel/tguard1.nim b/tests/parallel/tguard1.nim
index c7972d225..b1eb7e7c5 100644
--- a/tests/parallel/tguard1.nim
+++ b/tests/parallel/tguard1.nim
@@ -1,3 +1,7 @@
+discard """
+output: "90"
+"""
+
 
 when false:
   template lock(a, b: ptr Lock; body: stmt) =
diff --git a/tests/parallel/tlet_spawn.nim b/tests/parallel/tlet_spawn.nim
index 463ee1a47..62341d8f0 100644
--- a/tests/parallel/tlet_spawn.nim
+++ b/tests/parallel/tlet_spawn.nim
@@ -1,3 +1,8 @@
+discard """
+output: '''
+done999 999
+'''
+"""
 
 import threadpool
 
diff --git a/tests/parallel/tmissing_deepcopy.nim b/tests/parallel/tmissing_deepcopy.nim
index 53481e4df..45fdf0f8f 100644
--- a/tests/parallel/tmissing_deepcopy.nim
+++ b/tests/parallel/tmissing_deepcopy.nim
@@ -1,5 +1,6 @@
 discard """
-  ccodeCheck: "\\i @'deepCopy(' .*"
+  ccodeCheck: "@'genericDeepCopy(' .*"
+  action: compile
 """
 
 # bug #2286
diff --git a/tests/parallel/tsimple_array_checks.nim b/tests/parallel/tsimple_array_checks.nim
index 9874d3299..ee9508074 100644
--- a/tests/parallel/tsimple_array_checks.nim
+++ b/tests/parallel/tsimple_array_checks.nim
@@ -1,3 +1,25 @@
+discard """
+sortoutput: true
+output: '''
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+Hello 1
+Hello 2
+Hello 3
+Hello 4
+Hello 5
+Hello 6
+'''
+"""
+
 # bug #2287
 
 import threadPool
diff --git a/tests/pragmas/tnoreturn.nim b/tests/pragmas/tnoreturn.nim
index 50b427d71..6d0466df3 100644
--- a/tests/pragmas/tnoreturn.nim
+++ b/tests/pragmas/tnoreturn.nim
@@ -1,5 +1,6 @@
 discard """
 ccodeCheck: "\\i @'__attribute__((noreturn))' .*"
+action: compile
 """
 
 proc noret1*(i: int) {.noreturn.} =
diff --git a/tests/seq/tseq.nim b/tests/seq/tseq.nim
index 6528d518e..1cb94b308 100644
--- a/tests/seq/tseq.nim
+++ b/tests/seq/tseq.nim
@@ -170,6 +170,30 @@ block tshallowseq:
   xxx()
 
 
+block tshallowemptyseq:
+  proc test() =
+    var nilSeq: seq[int] = @[]
+    var emptySeq: seq[int] = newSeq[int]()
+    block:
+      var t = @[1,2,3]
+      shallow(nilSeq)
+      t = nilSeq
+      doAssert t == @[]
+    block:
+      var t = @[1,2,3]
+      shallow(emptySeq)
+      t = emptySeq
+      doAssert t == @[]
+    block:
+      var t = @[1,2,3]
+      shallowCopy(t, nilSeq)
+      doAssert t == @[]
+    block:
+      var t = @[1,2,3]
+      shallowCopy(t, emptySeq)
+      doAssert t == @[]
+  test()
+
 
 import strutils
 block ttoseq:
diff --git a/tests/stdlib/osproctest.nim b/tests/stdlib/osproctest.nim
new file mode 100644
index 000000000..8c4fba9ba
--- /dev/null
+++ b/tests/stdlib/osproctest.nim
@@ -0,0 +1,8 @@
+# This is test program for the osproc module.
+
+import os
+
+echo getCurrentDir()
+
+for i in 1..paramCount():
+  echo paramStr(i)
diff --git a/tests/stdlib/tcgi.nim b/tests/stdlib/tcgi.nim
new file mode 100644
index 000000000..23b8b82ca
--- /dev/null
+++ b/tests/stdlib/tcgi.nim
@@ -0,0 +1,23 @@
+discard """

+  action: run

+  file: tcgi.nim

+  output: "[Suite] Test cgi module"

+"""

+

+import unittest

+import cgi, strtabs

+

+suite "Test cgi module":

+  const queryString = "foo=bar&фу=бар&checked=✓&list=1,2,3&with_space=text%20with%20space"

+

+  test "test query parsing with readData":

+    let parsedQuery = readData(queryString)

+

+    check parsedQuery["foo"] == "bar"

+    check parsedQuery["фу"] == "бар"

+    check parsedQuery["checked"] == "✓"

+    check parsedQuery["list"] == "1,2,3"

+    check parsedQuery["with_space"] == "text with space"

+

+    expect KeyError:

+      discard parsedQuery["not_existing_key"]

diff --git a/tests/stdlib/tcputime.nim b/tests/stdlib/tcputime.nim
deleted file mode 100644
index b0cc19c6c..000000000
--- a/tests/stdlib/tcputime.nim
+++ /dev/null
@@ -1,11 +0,0 @@
-import times, os
-
-var e = epochTime()
-var c = cpuTime()
-
-os.sleep(1000)
-
-e = epochTime() - e
-c = cpuTime() - c
-
-echo "epochTime: ", e, " cpuTime: ", c
diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim
index c442b43fb..2cd1e4e47 100644
--- a/tests/stdlib/thashes.nim
+++ b/tests/stdlib/thashes.nim
@@ -1,5 +1,14 @@
-import unittest
-import hashes
+
+discard """
+output: '''
+[Suite] hashes
+
+[Suite] hashing
+
+'''
+"""
+
+import unittest, hashes
 
 suite "hashes":
   suite "hashing":
diff --git a/tests/stdlib/thttpcore.nim b/tests/stdlib/thttpcore.nim
index 9f99df93a..889c734c5 100644
--- a/tests/stdlib/thttpcore.nim
+++ b/tests/stdlib/thttpcore.nim
@@ -1,3 +1,6 @@
+discard """
+output: "[Suite] httpcore"
+"""
 
 import unittest
 
diff --git a/tests/stdlib/tjsonexternproc.nim b/tests/stdlib/tjsonexternproc.nim
index ec90e580d..1091d72cd 100644
--- a/tests/stdlib/tjsonexternproc.nim
+++ b/tests/stdlib/tjsonexternproc.nim
@@ -1,5 +1,11 @@
+discard """
+output: '''
+{"data":[1]}
+'''
+"""
+
 # Test case for https://github.com/nim-lang/Nim/issues/6385
 
 import mjsonexternproc
 # import json
-foo(1)
\ No newline at end of file
+foo(1)
diff --git a/tests/stdlib/tjsontestsuite.nim b/tests/stdlib/tjsontestsuite.nim
index 06f783a73..db31963fd 100644
--- a/tests/stdlib/tjsontestsuite.nim
+++ b/tests/stdlib/tjsontestsuite.nim
@@ -1,3 +1,7 @@
+discard """
+disabled: true
+"""
+
 ## JSON tests based on https://github.com/nst/JSONTestSuite
 
 import unittest,
diff --git a/tests/stdlib/tmath2.nim b/tests/stdlib/tmath2.nim
deleted file mode 100644
index eb0506f5f..000000000
--- a/tests/stdlib/tmath2.nim
+++ /dev/null
@@ -1,85 +0,0 @@
-# tests for the interpreter
-
-proc loops(a: var int) =
-  discard
-  #var
-  #  b: int
-  #b = glob
-  #while b != 0:
-  #  b = b + 1
-  #a = b
-
-proc mymax(a, b: int): int =
-  #loops(result)
-  result = a
-  if b > a: result = b
-
-proc test(a, b: int) =
-  var
-    x, y: int
-  x = 0
-  y = 7
-  if x == a + b * 3 - 7 or
-      x == 8 or
-      x == y and y > -56 and y < 699:
-    y = 0
-  elif y == 78 and x == 0:
-    y = 1
-  elif y == 0 and x == 0:
-    y = 2
-  else:
-    y = 3
-
-type
-  TTokType = enum
-    tkNil, tkType, tkConst, tkVar, tkSymbol, tkIf,
-    tkWhile, tkFor, tkLoop, tkCase, tkLabel, tkGoto
-
-proc testCase(t: TTokType): int =
-  case t
-  of tkNil, tkType, tkConst: result = 0
-  of tkVar: result = 1
-  of tkSymbol: result = 2
-  of tkIf..tkFor: result = 3
-  of tkLoop: result = 56
-  else: result = -1
-  test(0, 9) # test the call
-
-proc TestLoops() =
-  var
-    i, j: int
-
-  while i >= 0:
-    if i mod 3 == 0:
-      break
-    i = i + 1
-    while j == 13:
-      j = 13
-      break
-    break
-
-  while true:
-    break
-
-
-var
-  glob: int
-  a: array[0..5, int]
-
-proc main() =
-  #glob = 0
-  #loops( glob )
-  var
-    res: int
-    s: string
-  #write(stdout, mymax(23, 45))
-  write(stdout, "Hallo! Wie heisst du? ")
-  s = readLine(stdin)
-  # test the case statement
-  case s
-  of "Andreas": write(stdout, "Du bist mein Meister!\n")
-  of "Rumpf": write(stdout, "Du bist in der Familie meines Meisters!\n")
-  else: write(stdout, "ich kenne dich nicht!\n")
-  write(stdout, "Du heisst " & s & "\n")
-
-main()
diff --git a/tests/stdlib/tmemfiles1.nim b/tests/stdlib/tmemfiles1.nim
index 8b66dfcc1..a18fba083 100644
--- a/tests/stdlib/tmemfiles1.nim
+++ b/tests/stdlib/tmemfiles1.nim
@@ -1,5 +1,6 @@
 discard """
   file: "tmemfiles1.nim"
+  outputsub: ""
 """
 import memfiles, os
 var
@@ -8,5 +9,5 @@ var
 # Create a new file
 mm = memfiles.open(fn, mode = fmReadWrite, newFileSize = 20)
 mm.close()
-mm.close()
+# mm.close()
 if fileExists(fn): removeFile(fn)
diff --git a/tests/stdlib/tmemlines.nim b/tests/stdlib/tmemlines.nim
index c850b5493..98e03b5bb 100644
--- a/tests/stdlib/tmemlines.nim
+++ b/tests/stdlib/tmemlines.nim
@@ -1,3 +1,7 @@
+discard """
+outputsub: ""
+"""
+
 import memfiles
 var inp = memfiles.open("tests/stdlib/tmemlines.nim")
 for line in lines(inp):
diff --git a/tests/stdlib/tmemlinesBuf.nim b/tests/stdlib/tmemlinesBuf.nim
index 9fa68cf02..97ad751ee 100644
--- a/tests/stdlib/tmemlinesBuf.nim
+++ b/tests/stdlib/tmemlinesBuf.nim
@@ -1,6 +1,15 @@
+discard """
+output: "15"
+disabled: "appveyor"
+"""
+
 import memfiles
 var inp = memfiles.open("tests/stdlib/tmemlinesBuf.nim")
 var buffer: TaintedString = ""
+var lineCount = 0
 for line in lines(inp, buffer):
-  echo("#" & line & "#")
+  lineCount += 1
+
 close(inp)
+
+echo lineCount
diff --git a/tests/stdlib/tmemslices.nim b/tests/stdlib/tmemslices.nim
index d724254a2..c0d6d3960 100644
--- a/tests/stdlib/tmemslices.nim
+++ b/tests/stdlib/tmemslices.nim
@@ -1,3 +1,9 @@
+discard """
+outputsub: "rlwuiadtrnzb"
+"""
+
+# chatever the sub pattern it will find itself
+
 import memfiles
 var inp = memfiles.open("tests/stdlib/tmemslices.nim")
 for mem in memSlices(inp):
diff --git a/tests/stdlib/tnativesockets.nim b/tests/stdlib/tnativesockets.nim
index c683647bc..c2738b8a5 100644
--- a/tests/stdlib/tnativesockets.nim
+++ b/tests/stdlib/tnativesockets.nim
@@ -1,3 +1,7 @@
+discard """
+outputsub: ""
+"""
+
 import nativesockets, unittest
 
 suite "nativesockets":
@@ -5,4 +9,3 @@ suite "nativesockets":
     let hostname = getHostname()
     check hostname.len > 0
     check hostname.len < 64
-
diff --git a/tests/stdlib/tnet.nim b/tests/stdlib/tnet.nim
index 009561272..2dd22796c 100644
--- a/tests/stdlib/tnet.nim
+++ b/tests/stdlib/tnet.nim
@@ -1,3 +1,7 @@
+discard """
+outputsub: ""
+"""
+
 import net, nativesockets
 import unittest
 
diff --git a/tests/stdlib/tosproc.nim b/tests/stdlib/tosproc.nim
new file mode 100644
index 000000000..ac129e709
--- /dev/null
+++ b/tests/stdlib/tosproc.nim
@@ -0,0 +1,24 @@
+discard """
+  file: "tospaths.nim"
+  output: ""
+"""
+# test the osproc module
+
+import os, osproc
+
+block execProcessTest:
+  let dir = parentDir(currentSourcePath())
+  let (outp, err) = execCmdEx("nim c " & quoteShell(dir / "osproctest.nim"))
+  doAssert err == 0
+  let exePath = dir / addFileExt("osproctest", ExeExt)
+  let outStr1 = execProcess(exePath, workingDir=dir, args=["foo", "b A r"], options={})
+  doAssert outStr1 == dir & "\nfoo\nb A r\n"
+
+  const testDir = "t e st"
+  createDir(testDir)
+  doAssert dirExists(testDir)
+  let outStr2 = execProcess(exePath, workingDir=testDir, args=["x yz"], options={})
+  doAssert outStr2 == absolutePath(testDir) & "\nx yz\n"
+
+  removeDir(testDir)
+  removeFile(exePath)
diff --git a/tests/stdlib/tosprocterminate.nim b/tests/stdlib/tosprocterminate.nim
index 7fc6c5d85..a46d91d68 100644
--- a/tests/stdlib/tosprocterminate.nim
+++ b/tests/stdlib/tosprocterminate.nim
@@ -1,3 +1,7 @@
+discard """
+outputsub: "SUCCESS"
+"""
+
 import os, osproc
 
 when defined(Windows):
diff --git a/tests/stdlib/tparsopt.nim b/tests/stdlib/tparsopt.nim
index 848fba2da..948bc8d5f 100644
--- a/tests/stdlib/tparsopt.nim
+++ b/tests/stdlib/tparsopt.nim
@@ -1,4 +1,10 @@
-# Test the new parseopt module
+discard """
+disabled: true
+"""
+
+# this file has a type in the name, and it does not really test
+# parseopt module, because tester has no support to set arguments. Test the
+# new parseopt module. Therefore it is disabled.
 
 import
   parseopt
diff --git a/tests/stdlib/tposix.nim b/tests/stdlib/tposix.nim
index 57a43f99e..14f1fd6e2 100644
--- a/tests/stdlib/tposix.nim
+++ b/tests/stdlib/tposix.nim
@@ -1,3 +1,7 @@
+discard """
+outputsub: ""
+"""
+
 # Test Posix interface
 
 when not defined(windows):
@@ -13,4 +17,3 @@ when not defined(windows):
   writeLine(stdout, u.nodename)
   writeLine(stdout, u.release)
   writeLine(stdout, u.machine)
-
diff --git a/tests/stdlib/tquit.nim b/tests/stdlib/tquit.nim
index d18b468c8..4f8d5fb20 100644
--- a/tests/stdlib/tquit.nim
+++ b/tests/stdlib/tquit.nim
@@ -1,3 +1,9 @@
+discard """
+output: '''
+just exiting...
+'''
+"""
+
 # Test the new beforeQuit variable:
 
 proc myExit() {.noconv.} =
diff --git a/tests/stdlib/trepr2.nim b/tests/stdlib/trepr2.nim
index 300df565d..89379da96 100644
--- a/tests/stdlib/trepr2.nim
+++ b/tests/stdlib/trepr2.nim
@@ -1,3 +1,8 @@
+discard """
+outputsub: ""
+"""
+
+# output not testable because repr prints pointer adresses
 # test the new "repr" built-in proc
 
 type
diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim
index c702ccc2a..fd89f68af 100644
--- a/tests/stdlib/trstgen.nim
+++ b/tests/stdlib/trstgen.nim
@@ -1,3 +1,7 @@
+discard """
+outputsub: ""
+"""
+
 # tests for rstgen module.
 
 import ../../lib/packages/docutils/rstgen
@@ -27,7 +31,7 @@ suite "YAML syntax highlighting":
 <span class="Punctuation">?</span> <span class="StringLit">key</span>
 <span class="Punctuation">:</span> <span class="StringLit">value</span>
 <span class="Keyword">...</span></pre>"""
-  
+
   test "Block scalars":
     let input = """.. code-block:: yaml
     a literal block scalar: |
@@ -55,7 +59,7 @@ suite "YAML syntax highlighting":
 <span class="StringLit">another literal block scalar</span><span class="Punctuation">:</span>
   <span class="Command">|+</span> <span class="Comment"># comment after header</span><span class="LongStringLit">
  allowed, since more indented than parent</span></pre>"""
- 
+
   test "Directives":
     let input = """.. code-block:: yaml
     %YAML 1.2
@@ -97,7 +101,7 @@ suite "YAML syntax highlighting":
   <span class="StringLit">more numbers</span><span class="Punctuation">:</span> <span class="Punctuation">[</span><span class="DecNumber">-783</span><span class="Punctuation">,</span> <span class="FloatNumber">11e78</span><span class="Punctuation">]</span><span class="Punctuation">,</span>
   <span class="StringLit">not numbers</span><span class="Punctuation">:</span> <span class="Punctuation">[</span> <span class="StringLit">42e</span><span class="Punctuation">,</span> <span class="StringLit">0023</span><span class="Punctuation">,</span> <span class="StringLit">+32.37</span><span class="Punctuation">,</span> <span class="StringLit">8 ball</span><span class="Punctuation">]</span>
 <span class="Punctuation">}</span></pre>"""
-  
+
   test "Anchors, Aliases, Tags":
     let input = """.. code-block:: yaml
     --- !!map
@@ -136,4 +140,4 @@ suite "YAML syntax highlighting":
   <span class="DecNumber">-3</span>
   <span class="DecNumber">-4</span>
 <span class="StringLit">example.com/not/a#comment</span><span class="Punctuation">:</span>
-  <span class="StringLit">?not a map key</span></pre>"""
\ No newline at end of file
+  <span class="StringLit">?not a map key</span></pre>"""
diff --git a/tests/stdlib/tsortcall.nim b/tests/stdlib/tsortcall.nim
index 45b98805f..242e3fe4c 100644
--- a/tests/stdlib/tsortcall.nim
+++ b/tests/stdlib/tsortcall.nim
@@ -1,3 +1,7 @@
+discard """
+outputsub: ""
+"""
+
 import algorithm
 import unittest
 
@@ -40,7 +44,7 @@ suite "test sort, sorted, and isSorted procs":
   test "test the shortcut versions with descending sort order":
     check(not unSortedIntSeq.isSorted(SortOrder.Descending))
     check sorted(unSortedIntSeq, SortOrder.Descending) == reversed sortedIntSeq
-    check sorted(unSortedIntSeq).isSorted(SortOrder.Descending)
+    check sorted(unSortedIntSeq).isSorted(SortOrder.Ascending)
 
     unSortedIntSeq.sort(SortOrder.Descending)
     check unSortedIntSeq == reversed sortedIntSeq
diff --git a/tests/stdlib/tstreams.nim b/tests/stdlib/tstreams.nim
index 16dbc0e1b..559824d85 100644
--- a/tests/stdlib/tstreams.nim
+++ b/tests/stdlib/tstreams.nim
@@ -1,12 +1,25 @@
+discard """
+input: "Arne"
+output: '''
+Hello! What is your name?
+Nice name: Arne
+fs is: nil
+
+threw exception
+'''
+disabled: "windows"
+"""
+
+
 import streams
 
 
 block tstreams:
   var outp = newFileStream(stdout)
   var inp = newFileStream(stdin)
-  write(outp, "Hello! What is your name?")
+  writeLine(outp, "Hello! What is your name?")
   var line = readLine(inp)
-  write(outp, "Nice name: " & line)
+  writeLine(outp, "Nice name: " & line)
 
 
 block tstreams2:
diff --git a/tests/stdlib/tstrtabs.nim b/tests/stdlib/tstrtabs.nim
index a248cc3b2..18ed57167 100644
--- a/tests/stdlib/tstrtabs.nim
+++ b/tests/stdlib/tstrtabs.nim
@@ -1,3 +1,92 @@
+discard """
+sortoutput: true
+output: '''
+key1: value1
+key2: value2
+key_0: value0
+key_10: value10
+key_11: value11
+key_12: value12
+key_13: value13
+key_14: value14
+key_15: value15
+key_16: value16
+key_17: value17
+key_18: value18
+key_19: value19
+key_20: value20
+key_21: value21
+key_22: value22
+key_23: value23
+key_24: value24
+key_25: value25
+key_26: value26
+key_27: value27
+key_28: value28
+key_29: value29
+key_30: value30
+key_31: value31
+key_32: value32
+key_33: value33
+key_34: value34
+key_35: value35
+key_36: value36
+key_37: value37
+key_38: value38
+key_39: value39
+key_3: value3
+key_40: value40
+key_41: value41
+key_42: value42
+key_43: value43
+key_44: value44
+key_45: value45
+key_46: value46
+key_47: value47
+key_48: value48
+key_49: value49
+key_4: value4
+key_50: value50
+key_51: value51
+key_52: value52
+key_53: value53
+key_54: value54
+key_55: value55
+key_56: value56
+key_57: value57
+key_58: value58
+key_59: value59
+key_5: value5
+key_60: value60
+key_61: value61
+key_62: value62
+key_63: value63
+key_64: value64
+key_65: value65
+key_66: value66
+key_67: value67
+key_68: value68
+key_69: value69
+key_6: value6
+key_70: value70
+key_71: value71
+key_72: value72
+key_73: value73
+key_74: value74
+key_75: value75
+key_76: value76
+key_77: value77
+key_78: value78
+key_79: value79
+key_7: value7
+key_80: value80
+key_8: value8
+key_9: value9
+length of table 81
+value1 = value2
+'''
+"""
+
 import strtabs
 
 var tab = newStringTable({"key1": "val1", "key2": "val2"},
@@ -9,4 +98,4 @@ for key, val in pairs(tab):
   writeLine(stdout, key, ": ", val)
 writeLine(stdout, "length of table ", $tab.len)
 
-writeLine(stdout, `%`("$key1 = $key2; ${PATH}", tab, {useEnvironment}))
+writeLine(stdout, `%`("$key1 = $key2", tab, {useEnvironment}))
diff --git a/tests/stdlib/twalker.nim b/tests/stdlib/twalker.nim
deleted file mode 100644
index 91c97df01..000000000
--- a/tests/stdlib/twalker.nim
+++ /dev/null
@@ -1,13 +0,0 @@
-# iterate over all files with a given filter:
-
-import
-  "../../lib/pure/os.nim", ../../ lib / pure / times
-
-proc main(filter: string) =
-  for filename in walkFiles(filter):
-    writeLine(stdout, filename)
-
-  for key, val in envPairs():
-    writeLine(stdout, key & '=' & val)
-
-main("*.nim")
diff --git a/tests/system/t7894.nim b/tests/system/t7894.nim
index 2808e5020..27ee3f220 100644
--- a/tests/system/t7894.nim
+++ b/tests/system/t7894.nim
@@ -1,18 +1,24 @@
 discard """
+disabled: "travis"
+disabled: "appveyor"
 """
 
-import os
+# CI integration servers are out of memory for this test
 
 const size = 250000000
-var saved = newSeq[seq[int8]]()
 
-for i in 0..22:
-  # one of these is 0.25GB.
-  #echo i
-  var x = newSeq[int8](size)
-  sleep(10)
-  saved.add(x)
+proc main() =
 
-for x in saved:
-  #echo x.len
-  doAssert x.len == size
+  var saved = newSeq[seq[int8]]()
+
+  for i in 0..22:
+    # one of these is 0.25GB.
+    #echo i
+    var x = newSeq[int8](size)
+    saved.add(x)
+
+  for x in saved:
+    #echo x.len
+    doAssert x.len == size
+
+main()
diff --git a/tests/system/talloc.nim b/tests/system/talloc.nim
index bf2cd97a8..9b970fda0 100644
--- a/tests/system/talloc.nim
+++ b/tests/system/talloc.nim
@@ -1,6 +1,9 @@
 discard """
+disabled: "appveyor"
 """
 
+# appveyor is "out of memory"
+
 var x: ptr int
 
 x = cast[ptr int](alloc(7))
diff --git a/tests/system/talloc2.nim b/tests/system/talloc2.nim
index 0757c0724..e40c3f93c 100644
--- a/tests/system/talloc2.nim
+++ b/tests/system/talloc2.nim
@@ -1,6 +1,9 @@
 discard """
+disabled: "windows"
 """
 
+# appveyor is "out of memory"
+
 const
   nmax = 2*1024*1024*1024
 
diff --git a/tests/system/tio.nim b/tests/system/tio.nim
index 7e9e18950..c4d041560 100644
--- a/tests/system/tio.nim
+++ b/tests/system/tio.nim
@@ -1,14 +1,19 @@
 discard """
+outputsub: ""
+disabled: true
 """
 
 import
-  unittest, osproc, streams, os, strformat
+  unittest, osproc, streams, os, strformat, strutils
 const STRING_DATA = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
+
 const TEST_FILE = "tests/testdata/string.txt"
 
 proc echoLoop(str: string): string =
   result = ""
-  var process = startProcess(findExe("tests/system/helpers/readall_echo"))
+  let exe = findExe("tests/system/helpers/readall_echo")
+  echo "exe: ", exe
+  var process = startProcess(exe)
   var input = process.inputStream
   input.write(str)
   input.close()
@@ -22,10 +27,9 @@ suite "io":
     test "stdin":
       check:
         echoLoop(STRING_DATA) == STRING_DATA
-        echoLoop(STRING_DATA[0..3999]) == STRING_DATA[0..3999]
     test "file":
       check:
-        readFile(TEST_FILE) == STRING_DATA
+        readFile(TEST_FILE).strip == STRING_DATA
 
 
 proc verifyFileSize(sz: int64) =
diff --git a/tests/system/tnilconcats.nim b/tests/system/tnilconcats.nim
index 5e4a1b317..c1126405c 100644
--- a/tests/system/tnilconcats.nim
+++ b/tests/system/tnilconcats.nim
@@ -23,3 +23,10 @@ when true:
   doAssert s == "fooabc"
 
   echo x
+
+  # casting an empty string as sequence with shallow() should not segfault
+  var s2: string
+  shallow(s2)
+  s2 &= "foo"
+  doAssert s2 == "foo"
+
diff --git a/tests/system/tparams.nim b/tests/system/tparams.nim
index dd5511b8f..015530043 100644
--- a/tests/system/tparams.nim
+++ b/tests/system/tparams.nim
@@ -1,6 +1,3 @@
-discard """
-"""
-
 import os
 import osproc
 import parseopt2
@@ -13,7 +10,6 @@ if argv == @[]:
   doAssert execShellCmd(getAppFilename() & " \"foo bar\" --aa:bar=a --a=c:d --ab -c --a[baz]:doo") == 0
 else:
   let f = toSeq(getopt())
-  echo f.repr
   doAssert f[0].kind == cmdArgument and f[0].key == "foo bar" and f[0].val == ""
   doAssert f[1].kind == cmdLongOption and f[1].key == "aa" and f[1].val == "bar=a"
   doAssert f[2].kind == cmdLongOption and f[2].key == "a=c" and f[2].val == "d"
diff --git a/tests/template/tconfusinglocal.nim b/tests/template/tconfusinglocal.nim
index 50bf8f4b2..9f641e2bf 100644
--- a/tests/template/tconfusinglocal.nim
+++ b/tests/template/tconfusinglocal.nim
@@ -1,3 +1,7 @@
+discard """
+output: "0"
+"""
+
 
 # bug #5135
 proc fail*[E](e: E): void =
diff --git a/tests/template/texponential_eval.nim b/tests/template/texponential_eval.nim
index 32af9e8f7..b4e3faefb 100644
--- a/tests/template/texponential_eval.nim
+++ b/tests/template/texponential_eval.nim
@@ -1,13 +1,17 @@
 # bug #1940
 
 discard """
-  nimout: '''===
+nimout: '''
+===
 merge (A) with (B)
 merge (A B) with (C)
 merge (A B C) with (D)
 merge (A B C D) with (E)
 merge (A B C D E) with (F)
-==='''
+===
+'''
+
+output: "A B C D E F"
 """
 
 type SqlStmt = tuple
diff --git a/tests/template/thygienictempl.nim b/tests/template/thygienictempl.nim
index de40450aa..506f57148 100644
--- a/tests/template/thygienictempl.nim
+++ b/tests/template/thygienictempl.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 
 var
   e = "abc"
diff --git a/tests/template/tparams_gensymed.nim b/tests/template/tparams_gensymed.nim
index 3fb0dd4a5..da86d63dc 100644
--- a/tests/template/tparams_gensymed.nim
+++ b/tests/template/tparams_gensymed.nim
@@ -1,4 +1,15 @@
-
+discard """
+output: '''
+0
+1
+2
+3
+0
+1
+2
+3
+'''
+"""
 # bug #1915
 
 import macros
diff --git a/tests/template/tsighash_regression.nim b/tests/template/tsighash_regression.nim
index bf1f4dfe4..f3a6b4833 100644
--- a/tests/template/tsighash_regression.nim
+++ b/tests/template/tsighash_regression.nim
@@ -1,5 +1,8 @@
+discard """
+exitcode: 1
+outputsub: "0"
+"""
 
 import tconfusinglocal
 
-
 fail "foo"
diff --git a/tests/template/ttempl3.nim b/tests/template/ttempl3.nim
index d6a369d32..943cdae05 100644
--- a/tests/template/ttempl3.nim
+++ b/tests/template/ttempl3.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 
 template withOpenFile(f: untyped, filename: string, mode: FileMode,
                       actions: untyped): untyped =
diff --git a/tests/testament/tshouldfail.nim b/tests/testament/tshouldfail.nim
new file mode 100644
index 000000000..02e4bfd80
--- /dev/null
+++ b/tests/testament/tshouldfail.nim
@@ -0,0 +1,17 @@
+discard """
+cmd: "testament/tester --directory:testament --colors:off --nim:../compiler/nim category shouldfail"
+action: compile
+nimout: '''
+FAIL: tccodecheck.nim C
+FAIL: tcolumn.nim C
+FAIL: terrormsg.nim C
+FAIL: texitcode1.nim C
+FAIL: tfile.nim C
+FAIL: tline.nim C
+FAIL: tmaxcodesize.nim C
+FAIL: tnimout.nim C
+FAIL: toutput.nim C
+FAIL: toutputsub.nim C
+FAIL: tsortoutput.nim C
+'''
+"""
diff --git a/tests/typerel/tnoargopenarray.nim b/tests/typerel/tnoargopenarray.nim
index 20ebe5ecc..9e2b2fb86 100644
--- a/tests/typerel/tnoargopenarray.nim
+++ b/tests/typerel/tnoargopenarray.nim
@@ -1,7 +1,8 @@
+discard """
+action: compile
+"""
 
 import db_sqlite
 
 var db: DbConn
 exec(db, sql"create table blabla()")
-
-
diff --git a/tests/typerel/trettypeinference.nim b/tests/typerel/trettypeinference.nim
index fa4e89cc8..aa0d66e5b 100644
--- a/tests/typerel/trettypeinference.nim
+++ b/tests/typerel/trettypeinference.nim
@@ -1,5 +1,5 @@
 discard """
-  msg:    "instantiated for string\ninstantiated for int\ninstantiated for bool"
+  nimout:    "instantiated for string\ninstantiated for int\ninstantiated for bool"
   output: "int\nseq[string]\nA\nB\n100\ntrue"
 """
 
diff --git a/tests/typerel/tsecondarrayproperty.nim b/tests/typerel/tsecondarrayproperty.nim
index 3a6879b16..315ad06bf 100644
--- a/tests/typerel/tsecondarrayproperty.nim
+++ b/tests/typerel/tsecondarrayproperty.nim
@@ -1,3 +1,7 @@
+discard """
+output: "4"
+"""
+
 
 type
   TFoo = object
@@ -25,4 +29,3 @@ echo f.second[1]
 
 #echo `second[]`(f,1)
 # this is the only way I could use it, but not what I expected
-
diff --git a/tests/typerel/ttuple1.nim b/tests/typerel/ttuple1.nim
index d5c80800c..a03cc510e 100644
--- a/tests/typerel/ttuple1.nim
+++ b/tests/typerel/ttuple1.nim
@@ -1,3 +1,9 @@
+discard """
+output: '''
+M=1000, D=500, C=100, L=50, X=10, V=5, I=1
+'''
+"""
+
 const romanNumbers = [
     ("M", 1000), ("D", 500), ("C", 100),
     ("L", 50), ("X", 10), ("V", 5), ("I", 1) ]
@@ -12,5 +18,3 @@ for key, val in items(romanNumbers):
 proc PrintBiTuple(t: tuple[k: string, v: int]): int =
   stdout.write(t.k & "=" & $t.v & ", ")
   return 0
-
-
diff --git a/tests/types/taliasbugs.nim b/tests/types/taliasbugs.nim
index bdb2a7a32..f1b35edf6 100644
--- a/tests/types/taliasbugs.nim
+++ b/tests/types/taliasbugs.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: '''true
+  nimout: '''true
 true
 true
 true
diff --git a/tests/types/tauto_canbe_void.nim b/tests/types/tauto_canbe_void.nim
index b071c08e1..c43215d1e 100644
--- a/tests/types/tauto_canbe_void.nim
+++ b/tests/types/tauto_canbe_void.nim
@@ -1,3 +1,10 @@
+discard """
+output: '''
+arg
+arg
+'''
+"""
+
 
 import sugar
 
@@ -6,4 +13,3 @@ template tempo(s) =
 
 tempo((s: string)->auto => echo(s))
 tempo((s: string) => echo(s))
-
diff --git a/tests/types/tfinalobj.nim b/tests/types/tfinalobj.nim
index 2fda73363..6a1c8c2ce 100644
--- a/tests/types/tfinalobj.nim
+++ b/tests/types/tfinalobj.nim
@@ -1,5 +1,6 @@
 discard """
-  output: "abc"
+  output: '''abc
+16 == 16'''
 """
 
 type
@@ -14,3 +15,19 @@ doAssert TA.sizeof == string.sizeof
 
 echo a.x
 
+##########################################
+# bug #9794
+##########################################
+type
+  imported_double {.importc: "double".} = object
+
+  Pod = object
+    v* : imported_double
+    seed*: int32
+
+  Pod2 = tuple[v: imported_double, seed: int32]
+
+proc test() =
+  echo sizeof(Pod), " == ",sizeof(Pod2)
+
+test()
\ No newline at end of file
diff --git a/tests/vm/tconsteval.nim b/tests/vm/tconsteval.nim
index f4260495a..2e0fcb888 100644
--- a/tests/vm/tconsteval.nim
+++ b/tests/vm/tconsteval.nim
@@ -1,4 +1,5 @@
 discard """
+action: compile
 """
 
 import strutils
@@ -28,4 +29,3 @@ Possible Commands:
        CompileDate, CompileTime]
 
 echo HelpText
-
diff --git a/tests/vm/tconsttable2.nim b/tests/vm/tconsttable2.nim
index e07734eb5..5a392fb66 100644
--- a/tests/vm/tconsttable2.nim
+++ b/tests/vm/tconsttable2.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: '''61'''
+  nimout: '''61'''
 """
 
 # bug #2297
diff --git a/tests/vm/teval1.nim b/tests/vm/teval1.nim
index 0eaa050da..5c323f0e7 100644
--- a/tests/vm/teval1.nim
+++ b/tests/vm/teval1.nim
@@ -1,3 +1,8 @@
+
+discard """
+nimout: "##"
+"""
+
 import macros
 
 proc testProc: string {.compileTime.} =
@@ -14,9 +19,9 @@ when true:
 const
   x = testProc()
 
-echo "##", x, "##"
+doAssert x == ""
 
 # bug #1310
 static:
-    var i, j: set[int8] = {}
-    var k = i + j
+  var i, j: set[int8] = {}
+  var k = i + j
diff --git a/tests/vm/tgorge.nim b/tests/vm/tgorge.nim
index 694754f41..11c49a4cc 100644
--- a/tests/vm/tgorge.nim
+++ b/tests/vm/tgorge.nim
@@ -1,3 +1,10 @@
+discard """
+disabled: "windows"
+"""
+
+# If your os is windows and this test fails for you locally, please
+# check what is going wrong.
+
 import os
 
 template getScriptDir(): string =
diff --git a/tests/vm/tgorge.sh b/tests/vm/tgorge.sh
index ba47afeae..ba47afeae 100644..100755
--- a/tests/vm/tgorge.sh
+++ b/tests/vm/tgorge.sh
diff --git a/tests/vm/tgorgeex.sh b/tests/vm/tgorgeex.sh
index 36ba0a02f..36ba0a02f 100644..100755
--- a/tests/vm/tgorgeex.sh
+++ b/tests/vm/tgorgeex.sh
diff --git a/tests/vm/tinheritance.nim b/tests/vm/tinheritance.nim
index 2c224abcb..a94ccafcd 100644
--- a/tests/vm/tinheritance.nim
+++ b/tests/vm/tinheritance.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: '''Hello fred , managed by sally
+  nimout: '''Hello fred , managed by sally
 Hello sally , managed by bob'''
 """
 # bug #3973
diff --git a/tests/vm/tmitems.nim b/tests/vm/tmitems.nim
index a0e64d6aa..87835d1cd 100644
--- a/tests/vm/tmitems.nim
+++ b/tests/vm/tmitems.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: '''13'''
+  nimout: '''13'''
   output: '''3
 3
 3'''
diff --git a/tests/vm/tsimpleglobals.nim b/tests/vm/tsimpleglobals.nim
index 27bfdce50..7ab665070 100644
--- a/tests/vm/tsimpleglobals.nim
+++ b/tests/vm/tsimpleglobals.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: "abc xyz bb"
+  nimout: "abc xyz bb"
 """
 
 # bug #2473
diff --git a/tests/vm/tslurp.nim b/tests/vm/tslurp.nim
index d0041eaad..d762eb079 100644
--- a/tests/vm/tslurp.nim
+++ b/tests/vm/tslurp.nim
@@ -7,6 +7,6 @@ const
   relRes = slurp"./tslurp.nim"
   absRes = slurp(getScriptDir() / "tslurp.nim")
 
-echo relRes
-echo absRes
-
+doAssert relRes.len > 200
+doAssert absRes.len > 200
+doAssert relRes == absRes
diff --git a/tests/vm/tstaticprintseq.nim b/tests/vm/tstaticprintseq.nim
index 246a0211b..37bf62246 100644
--- a/tests/vm/tstaticprintseq.nim
+++ b/tests/vm/tstaticprintseq.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: '''1
+  nimout: '''1
 2
 3
 1
diff --git a/tests/vm/tswap.nim b/tests/vm/tswap.nim
index 2219be9ca..4243b5a71 100644
--- a/tests/vm/tswap.nim
+++ b/tests/vm/tswap.nim
@@ -1,5 +1,5 @@
 discard """
-msg: '''
+nimout: '''
 x.data = @[10]
 y = @[11]
 x.data = @[11]
diff --git a/tests/vm/ttouintconv.nim b/tests/vm/ttouintconv.nim
index 5f8884e80..dd4c597ba 100644
--- a/tests/vm/ttouintconv.nim
+++ b/tests/vm/ttouintconv.nim
@@ -1,7 +1,7 @@
 import macros
 
 discard """
-msg: '''
+nimout: '''
 8 9 17
 239 255
 61439 65534 65535
diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim
index 69275548f..7cd13b2ac 100644
--- a/tools/kochdocs.nim
+++ b/tools/kochdocs.nim
@@ -70,6 +70,7 @@ doc/manual.rst
 doc/lib.rst
 doc/tut1.rst
 doc/tut2.rst
+doc/tut3.rst
 doc/nimc.rst
 doc/niminst.rst
 doc/gc.rst
@@ -82,6 +83,7 @@ doc/lib.rst
 doc/manual.rst
 doc/tut1.rst
 doc/tut2.rst
+doc/tut3.rst
 doc/nimc.rst
 doc/overview.rst
 doc/filters.rst