summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--.gitlab-ci.yml3
-rw-r--r--.travis.yml4
-rw-r--r--appveyor.yml4
-rwxr-xr-x[-rw-r--r--]bin/nim-gdb0
-rw-r--r--changelog.md95
-rw-r--r--changelogs/changelog_0_19_0.md2
-rw-r--r--compiler/ast.nim39
-rw-r--r--compiler/astalgo.nim35
-rw-r--r--compiler/ccgcalls.nim20
-rw-r--r--compiler/ccgexprs.nim158
-rw-r--r--compiler/ccgliterals.nim4
-rw-r--r--compiler/ccgstmts.nim113
-rw-r--r--compiler/ccgtypes.nim11
-rw-r--r--compiler/cgen.nim130
-rw-r--r--compiler/cgendata.nim11
-rw-r--r--compiler/cgmeth.nim6
-rw-r--r--compiler/closureiters.nim41
-rw-r--r--compiler/commands.nim31
-rw-r--r--compiler/condsyms.nim4
-rw-r--r--compiler/destroyer.nim221
-rw-r--r--compiler/dfa.nim16
-rw-r--r--compiler/docgen.nim48
-rw-r--r--compiler/evaltempl.nim36
-rw-r--r--compiler/extccomp.nim37
-rw-r--r--compiler/importer.nim2
-rw-r--r--compiler/incremental.nim5
-rw-r--r--compiler/installer.ini16
-rw-r--r--compiler/jsgen.nim318
-rw-r--r--compiler/lambdalifting.nim43
-rw-r--r--compiler/layouter.nim35
-rw-r--r--compiler/lexer.nim29
-rw-r--r--compiler/lineinfos.nim5
-rw-r--r--compiler/linter.nim26
-rw-r--r--compiler/lookups.nim4
-rw-r--r--compiler/lowerings.nim2
-rw-r--r--compiler/main.nim157
-rw-r--r--compiler/modulegraphs.nim31
-rw-r--r--compiler/modules.nim49
-rw-r--r--compiler/msgs.nim9
-rw-r--r--compiler/nim.nim11
-rw-r--r--compiler/options.nim9
-rw-r--r--compiler/parser.nim59
-rw-r--r--compiler/pathutils.nim35
-rw-r--r--compiler/pragmas.nim37
-rw-r--r--compiler/reorder.nim2
-rw-r--r--compiler/rod.nim4
-rw-r--r--compiler/rodimpl.nim117
-rw-r--r--compiler/scriptconfig.nim4
-rw-r--r--compiler/sem.nim22
-rw-r--r--compiler/semasgn.nim31
-rw-r--r--compiler/semcall.nim31
-rw-r--r--compiler/semdata.nim6
-rw-r--r--compiler/semexprs.nim104
-rw-r--r--compiler/semfold.nim40
-rw-r--r--compiler/semgnrc.nim32
-rw-r--r--compiler/seminst.nim6
-rw-r--r--compiler/semmagic.nim54
-rw-r--r--compiler/sempass2.nim17
-rw-r--r--compiler/semstmts.nim93
-rw-r--r--compiler/semtempl.nim40
-rw-r--r--compiler/semtypes.nim68
-rw-r--r--compiler/semtypinst.nim7
-rw-r--r--compiler/sigmatch.nim49
-rw-r--r--compiler/sizealignoffsetimpl.nim71
-rw-r--r--compiler/suggest.nim4
-rw-r--r--compiler/syntaxes.nim30
-rw-r--r--compiler/transf.nim29
-rw-r--r--compiler/trees.nim3
-rw-r--r--compiler/types.nim6
-rw-r--r--compiler/vm.nim57
-rw-r--r--compiler/vmdef.nim7
-rw-r--r--compiler/vmdeps.nim19
-rw-r--r--compiler/vmgen.nim60
-rw-r--r--compiler/vmops.nim16
-rw-r--r--compiler/wordrecg.nim12
-rw-r--r--config/nim.cfg13
-rw-r--r--doc/advopt.txt12
-rw-r--r--doc/backends.rst2
-rw-r--r--doc/codeowners.rst2
-rw-r--r--doc/contributing.rst36
-rw-r--r--doc/filters.rst9
-rw-r--r--doc/grammar.txt9
-rw-r--r--doc/intern.rst2
-rw-r--r--doc/lib.rst9
-rw-r--r--doc/manual.rst81
-rw-r--r--doc/nimc.rst15
-rw-r--r--doc/nims.rst2
-rw-r--r--doc/tut2.rst402
-rw-r--r--doc/tut3.rst354
-rw-r--r--examples/tunit.nim2
-rw-r--r--install.txt88
-rw-r--r--issue_template.md14
-rw-r--r--koch.nim72
-rw-r--r--lib/core/allocators.nim34
-rw-r--r--lib/core/locks.nim2
-rw-r--r--lib/core/macros.nim200
-rw-r--r--lib/core/seqs.nim59
-rw-r--r--lib/core/typeinfo.nim3
-rw-r--r--lib/deprecated/pure/actors.nim1
-rw-r--r--lib/deprecated/pure/asyncio.nim11
-rw-r--r--lib/deprecated/pure/ftpclient.nim5
-rw-r--r--lib/deprecated/pure/ospaths.nim21
-rw-r--r--lib/deprecated/pure/parseurl.nim2
-rw-r--r--lib/deprecated/pure/sockets.nim41
-rw-r--r--lib/impure/db_mysql.nim1
-rw-r--r--lib/impure/db_odbc.nim2
-rw-r--r--lib/impure/db_postgres.nim1
-rw-r--r--lib/impure/db_sqlite.nim1
-rw-r--r--lib/impure/nre.nim153
-rw-r--r--lib/impure/nre/private/util.nim16
-rw-r--r--lib/impure/re.nim9
-rw-r--r--lib/impure/ssl.nim1
-rw-r--r--lib/js/jsffi.nim67
-rw-r--r--lib/nimrtl.nim1
-rw-r--r--lib/packages/fsmonitor.nim229
-rw-r--r--lib/posix/inotify.nim1
-rw-r--r--lib/posix/posix.nim7
-rw-r--r--lib/posix/posix_linux_amd64.nim33
-rw-r--r--lib/posix/posix_other.nim36
-rw-r--r--lib/posix/termios.nim1
-rw-r--r--lib/pure/asyncdispatch.nim227
-rw-r--r--lib/pure/asyncfutures.nim24
-rw-r--r--lib/pure/asyncnet.nim4
-rw-r--r--lib/pure/cgi.nim6
-rw-r--r--lib/pure/collections/LockFreeHash.nim4
-rw-r--r--lib/pure/collections/critbits.nim2
-rw-r--r--lib/pure/collections/intsets.nim2
-rw-r--r--lib/pure/collections/lists.nim24
-rw-r--r--lib/pure/collections/queues.nim2
-rw-r--r--lib/pure/collections/rtarrays.nim1
-rw-r--r--lib/pure/collections/sequtils.nim206
-rw-r--r--lib/pure/collections/sets.nim4
-rw-r--r--lib/pure/collections/sharedstrings.nim6
-rw-r--r--lib/pure/collections/tables.nim8
-rw-r--r--lib/pure/colors.nim2
-rw-r--r--lib/pure/complex.nim646
-rw-r--r--lib/pure/coro.nim24
-rw-r--r--lib/pure/encodings.nim3
-rw-r--r--lib/pure/htmlparser.nim3
-rw-r--r--lib/pure/httpclient.nim125
-rw-r--r--lib/pure/includes/asynccommon.nim211
-rw-r--r--lib/pure/includes/osenv.nim11
-rw-r--r--lib/pure/includes/oserr.nim7
-rw-r--r--lib/pure/ioselects/ioselectors_epoll.nim8
-rw-r--r--lib/pure/logging.nim11
-rw-r--r--lib/pure/marshal.nim4
-rw-r--r--lib/pure/math.nim57
-rw-r--r--lib/pure/memfiles.nim44
-rw-r--r--lib/pure/nativesockets.nim4
-rw-r--r--lib/pure/net.nim28
-rw-r--r--lib/pure/options.nim34
-rw-r--r--lib/pure/os.nim931
-rw-r--r--lib/pure/ospaths.nim713
-rw-r--r--lib/pure/osproc.nim16
-rw-r--r--lib/pure/parseopt.nim21
-rw-r--r--lib/pure/parsesql.nim28
-rw-r--r--lib/pure/parseutils.nim10
-rw-r--r--lib/pure/parsexml.nim28
-rw-r--r--lib/pure/pegs.nim18
-rw-r--r--lib/pure/random.nim4
-rw-r--r--lib/pure/smtp.nim22
-rw-r--r--lib/pure/streams.nim56
-rw-r--r--lib/pure/strscans.nim7
-rw-r--r--lib/pure/strutils.nim77
-rw-r--r--lib/pure/subexes.nim6
-rw-r--r--lib/pure/sugar.nim5
-rw-r--r--lib/pure/terminal.nim6
-rw-r--r--lib/pure/times.nim89
-rw-r--r--lib/pure/unicode.nim36
-rw-r--r--lib/pure/unittest.nim2
-rw-r--r--lib/std/diff.nim387
-rw-r--r--lib/std/editdistance.nim (renamed from lib/pure/editdistance.nim)0
-rw-r--r--lib/std/wordwrap.nim90
-rw-r--r--lib/system.nim152
-rw-r--r--lib/system/ansi_c.nim3
-rw-r--r--lib/system/atomics.nim1
-rw-r--r--lib/system/cellsets.nim3
-rw-r--r--lib/system/chcks.nim9
-rw-r--r--lib/system/debugger.nim2
-rw-r--r--lib/system/dyncalls.nim7
-rw-r--r--lib/system/endb.nim2
-rw-r--r--lib/system/excpt.nim44
-rw-r--r--lib/system/gc.nim92
-rw-r--r--lib/system/gc2.nim41
-rw-r--r--lib/system/gc_common.nim80
-rw-r--r--lib/system/gc_ms.nim24
-rw-r--r--lib/system/gc_regions.nim4
-rw-r--r--lib/system/helpers2.nim5
-rw-r--r--lib/system/jssys.nim10
-rw-r--r--lib/system/mmdisp.nim17
-rw-r--r--lib/system/nimscript.nim2
-rw-r--r--lib/system/profiler.nim1
-rw-r--r--lib/system/repr.nim1
-rw-r--r--lib/system/reprjs.nim4
-rw-r--r--lib/system/sets.nim1
-rw-r--r--lib/system/syslocks.nim2
-rw-r--r--lib/system/threads.nim6
-rw-r--r--lib/system/timers.nim5
-rw-r--r--lib/windows/winlean.nim17
-rw-r--r--lib/wrappers/odbcsql.nim11
-rw-r--r--lib/wrappers/openssl.nim4
-rw-r--r--lib/wrappers/pcre.nim8
-rw-r--r--lib/wrappers/postgres.nim4
-rw-r--r--lib/wrappers/sqlite3.nim6
-rw-r--r--lib/wrappers/tinyc.nim1
-rw-r--r--nimdoc/testproject/expected/subdir/subdir_b/utils.html31
-rw-r--r--nimdoc/testproject/expected/testproject.html62
-rw-r--r--nimdoc/testproject/expected/theindex.html26
-rw-r--r--nimdoc/testproject/subdir/subdir_b/utils.nim16
-rw-r--r--nimdoc/testproject/testproject.nim6
-rw-r--r--nimpretty/nimpretty.nim20
-rw-r--r--nimpretty/tester.nim22
-rw-r--r--nimpretty/tests/exhaustive.nim31
-rw-r--r--nimpretty/tests/expected/exhaustive.nim31
-rw-r--r--nimpretty/tests/expected/simple.nim11
-rw-r--r--nimpretty/tests/expected/simple2.nim19
-rw-r--r--nimpretty/tests/expected/simple3.nim16
-rw-r--r--nimpretty/tests/simple.nim8
-rw-r--r--nimpretty/tests/simple2.nim19
-rw-r--r--nimpretty/tests/simple3.nim14
-rw-r--r--nimsuggest/nimsuggest.nim134
-rw-r--r--nimsuggest/nimsuggest.nim.cfg2
-rw-r--r--readme.txt18
-rw-r--r--testament/backend.nim16
-rw-r--r--testament/categories.nim280
-rw-r--r--testament/specs.nim262
-rw-r--r--testament/tester.nim310
-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/ambsym/tambsym.nim4
-rw-r--r--tests/ambsym/tambsym2.nim3
-rw-r--r--tests/ambsym/tambsym3.nim4
-rw-r--r--tests/ambsym/tambsys.nim3
-rw-r--r--tests/array/tarray.nim9
-rw-r--r--tests/array/tarraycons.nim5
-rw-r--r--tests/array/tarraycons_ptr_generic2.nim2
-rw-r--r--tests/assert/tassert.nim3
-rw-r--r--tests/assert/testhelper.nim2
-rw-r--r--tests/assign/tassign.nim1
-rw-r--r--tests/assign/tvariantasgn.nim4
-rw-r--r--tests/async/t7192.nim14
-rw-r--r--tests/async/t7758.nim6
-rw-r--r--tests/async/t8982.nim33
-rw-r--r--tests/async/tasyncRecvLine.nim3
-rw-r--r--tests/async/tasync_gcunsafe.nim2
-rw-r--r--tests/async/tasyncall.nim3
-rw-r--r--tests/async/tasyncawait.nim1
-rw-r--r--tests/async/tasyncconnect.nim3
-rw-r--r--tests/async/tasyncdial.nim1
-rw-r--r--tests/async/tasyncexceptions.nim5
-rw-r--r--tests/async/tasyncfile.nim8
-rw-r--r--tests/async/tasyncrecursion.nim5
-rw-r--r--tests/async/tasyncsend4757.nim3
-rw-r--r--tests/async/tasyncssl.nim9
-rw-r--r--tests/async/tasynctry.nim4
-rw-r--r--tests/async/tawaitsemantics.nim4
-rw-r--r--tests/async/tcallbacks.nim5
-rw-r--r--tests/async/tfuturestream.nim6
-rw-r--r--tests/async/tfuturevar.nim6
-rw-r--r--tests/async/tioselectors.nim1
-rw-r--r--tests/async/tnewasyncudp.nim1
-rw-r--r--tests/async/tpendingcheck.nim3
-rw-r--r--tests/async/twinasyncrw.nim1
-rw-r--r--tests/benchmark.nim47
-rw-r--r--tests/benchmarks/fannkuch.nim69
-rw-r--r--tests/benchmarks/quicksort.nim54
-rw-r--r--tests/bind/tbind.nim4
-rw-r--r--tests/bind/tbind2.nim5
-rw-r--r--tests/bind/tdatabind.nim2
-rw-r--r--tests/bind/tinvalidbindtypedesc.nim3
-rw-r--r--tests/bind/tnicerrorforsymchoice.nim2
-rw-r--r--tests/borrow/tinvalidborrow.nim3
-rw-r--r--tests/caas/absurd_nesting.nim29
-rw-r--r--tests/caas/absurd_nesting.txt29
-rw-r--r--tests/caas/basic-recompile.txt10
-rw-r--r--tests/caas/compile-suggest.txt7
-rw-r--r--tests/caas/compile-then-def.txt11
-rw-r--r--tests/caas/completion_dot_syntax.txt9
-rw-r--r--tests/caas/completion_dot_syntax_dirty.nim25
-rw-r--r--tests/caas/completion_dot_syntax_main.nim24
-rw-r--r--tests/caas/def-def-compile.txt12
-rw-r--r--tests/caas/def-then-compile.txt8
-rw-r--r--tests/caas/forward_declarations.nim15
-rw-r--r--tests/caas/forward_declarations.txt9
-rw-r--r--tests/caas/forward_usages.txt17
-rw-r--r--tests/caas/idetools_api.nim84
-rw-r--r--tests/caas/idetools_api.txt59
-rw-r--r--tests/caas/imported.nim3
-rw-r--r--tests/caas/issue_416_template_shift.nim17
-rw-r--r--tests/caas/issue_416_template_shift.txt14
-rw-r--r--tests/caas/issue_452_export_shift.nim8
-rw-r--r--tests/caas/issue_452_export_shift.txt11
-rw-r--r--tests/caas/issue_477_dynamic_dispatch.nim19
-rw-r--r--tests/caas/issue_477_dynamic_dispatch.txt5
-rw-r--r--tests/caas/its_full_of_procs.nim29
-rw-r--r--tests/caas/its_full_of_procs.txt20
-rw-r--r--tests/caas/main.nim7
-rw-r--r--tests/caas/main_dirty.nim14
-rw-r--r--tests/caas/suggest-compile.txt13
-rw-r--r--tests/caas/suggest-invalid-source.txt26
-rw-r--r--tests/casestmt/t7699.nim2
-rw-r--r--tests/casestmt/tcaseexpr1.nim13
-rw-r--r--tests/casestmt/tcaseoverlaprange.nim2
-rw-r--r--tests/casestmt/tcaseoverlaprange2.nim2
-rw-r--r--tests/casestmt/tcasestmt.nim5
-rw-r--r--tests/casestmt/tcomputedgoto.nim9
-rw-r--r--tests/casestmt/tlinearscanend.nim4
-rw-r--r--tests/ccgbugs/t6756.nim6
-rw-r--r--tests/ccgbugs/t8616.nim2
-rw-r--r--tests/ccgbugs/t8781.nim2
-rw-r--r--tests/ccgbugs/t8964.nim10
-rw-r--r--tests/ccgbugs/tcgbug.nim8
-rw-r--r--tests/ccgbugs/tcodegendecllambda.nim1
-rw-r--r--tests/ccgbugs/tconstobj.nim16
-rw-r--r--tests/ccgbugs/tcvarargs.nim1
-rw-r--r--tests/ccgbugs/tgeneric_closure.nim10
-rw-r--r--tests/ccgbugs/tgeneric_smallobj_asgn_opt.nim5
-rw-r--r--tests/ccgbugs/tinefficient_const_table.nim2
-rw-r--r--tests/ccgbugs/tmarkerproc_regression.nim4
-rw-r--r--tests/ccgbugs/tmissingbracket.nim9
-rw-r--r--tests/ccgbugs/tmissinginit.nim2
-rw-r--r--tests/ccgbugs/tmissingvolatile.nim1
-rw-r--r--tests/ccgbugs/tobjconstr_bad_aliasing.nim3
-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/clearmsg/tconsttypemismatch.nim3
-rw-r--r--tests/clearmsg/tmacroerrorproc.nim2
-rw-r--r--tests/closure/tclosure.nim3
-rw-r--r--tests/closure/tclosure_issues.nim (renamed from tests/closure/tissues.nim)1
-rw-r--r--tests/closure/texplicit_dummy_closure.nim10
-rw-r--r--tests/closure/tinfer_closure_for_nestedproc.nim42
-rw-r--r--tests/closure/tinvalidclosure.nim2
-rw-r--r--tests/closure/tinvalidclosure2.nim2
-rw-r--r--tests/closure/tinvalidclosure3.nim4
-rw-r--r--tests/closure/tmacrobust1512.nim40
-rw-r--r--tests/closure/tnested.nim3
-rw-r--r--tests/closure/ttimeinfo.nim15
-rw-r--r--tests/cnstseq/tcnstseq.nim3
-rw-r--r--tests/collections/tcollections.nim4
-rw-r--r--tests/collections/thashsets.nim (renamed from tests/collections/tsets.nim)0
-rw-r--r--tests/collections/ttables.nim12
-rw-r--r--tests/compilerapi/tcompilerapi.nim3
-rw-r--r--tests/compiles/trecursive_generic_in_compiles.nim4
-rw-r--r--tests/concepts/t3330.nim1
-rw-r--r--tests/concepts/tconcepts.nim29
-rw-r--r--tests/concepts/tconcepts_issues.nim (renamed from tests/concepts/tissues.nim)1
-rw-r--r--tests/concepts/texplain.nim3
-rw-r--r--tests/concepts/tmapconcept.nim2
-rw-r--r--tests/concepts/tmatrixconcept.nim2
-rw-r--r--tests/concepts/trandomvars.nim4
-rw-r--r--tests/concepts/trandomvars2.nim (renamed from tests/concepts/trandom_vars.nim)0
-rw-r--r--tests/concepts/tstackconcept.nim2
-rw-r--r--tests/constr/tconstr1.nim4
-rw-r--r--tests/constr/tconstr2.nim6
-rw-r--r--tests/constraints/tconstraints.nim4
-rw-r--r--tests/constructors/t5965_1.nim2
-rw-r--r--tests/constructors/t5965_2.nim2
-rw-r--r--tests/controlflow/tblock1.nim4
-rw-r--r--tests/controlflow/tcontrolflow.nim10
-rw-r--r--tests/controlflow/tstatret.nim5
-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.nim152
-rw-r--r--tests/converter/tconverter_with_constraint.nim8
-rw-r--r--tests/converter/tgenericconverter2.nim36
-rw-r--r--tests/coroutines/texceptions.nim7
-rw-r--r--tests/coroutines/tgc.nim4
-rw-r--r--tests/coroutines/titerators.nim6
-rw-r--r--tests/coroutines/twait.nim1
-rw-r--r--tests/cpp/t6986.nim16
-rw-r--r--tests/cpp/t8241.nim11
-rw-r--r--tests/cpp/tcasts.nim12
-rw-r--r--tests/cpp/tcppraise.nim10
-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/deprecated/tnoannot.nim2
-rw-r--r--tests/deps/jester-#head/jester/patterns.nim2
-rw-r--r--tests/deps/jester-#head/jester/private/utils.nim2
-rw-r--r--tests/deps/zip-0.2.1/zip/zipfiles.nim2
-rw-r--r--tests/destructor/t6434.nim21
-rw-r--r--tests/destructor/tatomicptrs.nim52
-rw-r--r--tests/destructor/texplicit_move.nim12
-rw-r--r--tests/destructor/tmatrix.nim22
-rw-r--r--tests/destructor/tmove_objconstr.nim108
-rw-r--r--tests/destructor/turn_destroy_into_finalizer.nim8
-rw-r--r--tests/destructor/tuse_result_prevents_sinks.nim31
-rw-r--r--tests/dir with space/tspace.nim5
-rw-r--r--tests/discard/tdiscardable.nim18
-rw-r--r--tests/discard/tillegaldiscard.nim9
-rw-r--r--tests/discard/tneedsdiscard.nim2
-rw-r--r--tests/discard/tneedsdiscard_in_for.nim2
-rw-r--r--tests/distinct/tdistinct.nim6
-rw-r--r--tests/distinct/tdistinct_issues.nim (renamed from tests/distinct/tissues.nim)0
-rw-r--r--tests/distinct/tnil.nim4
-rw-r--r--tests/dll/server.nim8
-rw-r--r--tests/dummy.txt1
-rw-r--r--tests/effects/teffects1.nim3
-rw-r--r--tests/effects/teffects2.nim3
-rw-r--r--tests/effects/teffects3.nim3
-rw-r--r--tests/effects/teffects4.nim3
-rw-r--r--tests/effects/teffects6.nim5
-rw-r--r--tests/effects/tgcsafe.nim2
-rw-r--r--tests/effects/tsidee1.nim5
-rw-r--r--tests/effects/tsidee2.nim4
-rw-r--r--tests/effects/tsidee3.nim4
-rw-r--r--tests/effects/tsidee4.nim4
-rw-r--r--tests/enum/tenumitems.nim4
-rw-r--r--tests/errmsgs/t6483.nim2
-rw-r--r--tests/errmsgs/t8339.nim2
-rw-r--r--tests/errmsgs/t9908_01.nim10
-rw-r--r--tests/errmsgs/t9908_02.nim10
-rw-r--r--tests/errmsgs/tproper_stacktrace.nim2
-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/exception/tcontinuexc.nim4
-rw-r--r--tests/exception/texceptionbreak.nim1
-rw-r--r--tests/exception/texcsub.nim4
-rw-r--r--tests/exception/tfinally.nim6
-rw-r--r--tests/exception/tfinally2.nim12
-rw-r--r--tests/exception/tfinally3.nim7
-rw-r--r--tests/exception/tfinally4.nim1
-rw-r--r--tests/exception/tnestedreturn.nim1
-rw-r--r--tests/exception/tnestedreturn2.nim1
-rw-r--r--tests/exception/tonraise.nim34
-rw-r--r--tests/exception/treraise.nim4
-rw-r--r--tests/exception/tunhandledexc.nim5
-rw-r--r--tests/exception/twrongexc.nim5
-rw-r--r--tests/exprs/texprstmt.nim2
-rw-r--r--tests/exprs/tifexpr_typeinference.nim8
-rw-r--r--tests/exprs/tstmtexp.nim3
-rw-r--r--tests/flags/tgenscript.nim3
-rw-r--r--tests/float/tfloat1.nim3
-rw-r--r--tests/float/tfloat2.nim3
-rw-r--r--tests/float/tfloat3.nim15
-rw-r--r--tests/float/tfloat4.nim3
-rw-r--r--tests/float/tfloat5.nim7
-rw-r--r--tests/float/tfloat6.nim7
-rw-r--r--tests/float/tfloat7.nim7
-rw-r--r--tests/float/tfloatmod.nim130
-rw-r--r--tests/float/tfloatnan.nim4
-rw-r--r--tests/float/tissue5821.nim8
-rw-r--r--tests/generics/t2tables.nim4
-rw-r--r--tests/generics/t5707.nim6
-rw-r--r--tests/generics/t6137.nim3
-rw-r--r--tests/generics/t7141.nim3
-rw-r--r--tests/generics/t8270.nim2
-rw-r--r--tests/generics/tbintre2.nim31
-rw-r--r--tests/generics/tbintree.nim19
-rw-r--r--tests/generics/texplicitgeneric1.nim4
-rw-r--r--tests/generics/texplicitgeneric2.nim1
-rw-r--r--tests/generics/tgeneric0.nim5
-rw-r--r--tests/generics/tgeneric3.nim105
-rw-r--r--tests/generics/tgenericprocvar.nim1
-rw-r--r--tests/generics/tgenerics_issues.nim (renamed from tests/generics/tissues.nim)11
-rw-r--r--tests/generics/tgenerics_various.nim (renamed from tests/generics/tvarious.nim)3
-rw-r--r--tests/generics/tgenerictmpl2.nim2
-rw-r--r--tests/generics/tgenericvariant.nim17
-rw-r--r--tests/generics/tlateboundstatic.nim2
-rw-r--r--tests/generics/toverloading_typedesc.nim2
-rw-r--r--tests/generics/tparser_generator.nim32
-rw-r--r--tests/generics/trtree.nim152
-rw-r--r--tests/generics/tthread_generic.nim4
-rw-r--r--tests/generics/twrong_floatlit_type.nim2
-rw-r--r--tests/global/t5958.nim2
-rw-r--r--tests/global/tglobalforvar.nim4
-rw-r--r--tests/implicit/timplicit.nim5
-rw-r--r--tests/init/t8314.nim10
-rw-r--r--tests/init/tuninit1.nim3
-rw-r--r--tests/iter/tcountup.nim11
-rw-r--r--tests/iter/timplicit_auto.nim2
-rw-r--r--tests/iter/titer.nim13
-rw-r--r--tests/iter/titer10.nim2
-rw-r--r--tests/iter/titer11.nim4
-rw-r--r--tests/iter/titer3.nim1
-rw-r--r--tests/iter/titer4.nim4
-rw-r--r--tests/iter/titer5.nim5
-rw-r--r--tests/iter/titer6.nim4
-rw-r--r--tests/iter/titer7.nim4
-rw-r--r--tests/iter/titer_issues.nim (renamed from tests/iter/tissues.nim)0
-rw-r--r--tests/iter/titer_no_tuple_unpack.nim16
-rw-r--r--tests/iter/titerconcat.nim (renamed from tests/iter/tconcat.nim)0
-rw-r--r--tests/iter/titervaropenarray.nim4
-rw-r--r--tests/iter/tpermutations.nim11
-rw-r--r--tests/iter/treciter.nim4
-rw-r--r--tests/iter/tshallowcopy_closures.nim8
-rw-r--r--tests/iter/twrap_walkdir.nim5
-rw-r--r--tests/iter/twrongiter.nim2
-rw-r--r--tests/iter/tyieldintry.nim30
-rw-r--r--tests/js/t7224.nim3
-rw-r--r--tests/js/t9410.nim454
-rw-r--r--tests/js/taddnilstr.nim4
-rw-r--r--tests/js/tcopying.nim35
-rw-r--r--tests/js/tjsffi.nim24
-rw-r--r--tests/js/tnilstrs.nim17
-rw-r--r--tests/js/tstrconcat.nim5
-rw-r--r--tests/js/tvarargs.nim2
-rw-r--r--tests/let/tlet.nim3
-rw-r--r--tests/let/tlet2.nim3
-rw-r--r--tests/lexer/tident.nim14
-rw-r--r--tests/lexer/tind1.nim2
-rw-r--r--tests/lexer/tinvalidintegerliteral1.nim2
-rw-r--r--tests/lexer/tinvalidintegerliteral2.nim2
-rw-r--r--tests/lexer/tinvalidintegerliteral3.nim2
-rw-r--r--tests/lexer/tmissingnl.nim3
-rw-r--r--tests/lexer/tstrlits.nim7
-rw-r--r--tests/lexer/tunderscores.nim5
-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.nim36
-rw-r--r--tests/macros/tgettype.nim6
-rw-r--r--tests/macros/tgettype2.nim32
-rw-r--r--tests/macros/tgettypeinst.nim29
-rw-r--r--tests/macros/tmacro4.nim2
-rw-r--r--tests/macros/tmacrogenerics.nim9
-rw-r--r--tests/macros/tmacrogensym.nim (renamed from tests/macros/tgensym.nim)0
-rw-r--r--tests/macros/tmacros_issues.nim (renamed from tests/macros/tissues.nim)15
-rw-r--r--tests/macros/tmacros_various.nim (renamed from tests/macros/tvarious.nim)15
-rw-r--r--tests/macros/tmemit.nim6
-rw-r--r--tests/macros/tnewlit.nim20
-rw-r--r--tests/macros/tquotedo.nim25
-rw-r--r--tests/macros/tquotewords.nim1
-rw-r--r--tests/macros/trecmacro.nim2
-rw-r--r--tests/macros/tsametype.nim1
-rw-r--r--tests/macros/tslice.nim38
-rw-r--r--tests/macros/tstaticparamsmacro.nim9
-rw-r--r--tests/macros/tstringinterp.nim2
-rw-r--r--tests/magics/tmagics.nim18
-rw-r--r--tests/manyloc/argument_parser/argument_parser.nim2
-rw-r--r--tests/manyloc/argument_parser/ex_wget.nim2
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim2
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim22
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim2
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim2
-rw-r--r--tests/manyloc/keineschweine/dependencies/nake/nake.nim2
-rw-r--r--tests/manyloc/keineschweine/enet_server/enet_client.nim2
-rw-r--r--tests/manyloc/keineschweine/enet_server/enet_server.nim2
-rw-r--r--tests/manyloc/keineschweine/keineschweine.nim10
-rw-r--r--tests/manyloc/keineschweine/lib/client_helpers.nim2
-rw-r--r--tests/manyloc/keineschweine/lib/estreams.nim2
-rw-r--r--tests/manyloc/keineschweine/lib/map_filter.nim2
-rw-r--r--tests/manyloc/keineschweine/lib/sg_assets.nim14
-rw-r--r--tests/manyloc/keineschweine/lib/sg_gui.nim2
-rw-r--r--tests/manyloc/keineschweine/lib/sg_packets.nim2
-rw-r--r--tests/manyloc/keineschweine/lib/vehicles.nim2
-rw-r--r--tests/manyloc/keineschweine/lib/zlib_helpers.nim2
-rw-r--r--tests/manyloc/keineschweine/server/old_dirserver.nim2
-rw-r--r--tests/manyloc/keineschweine/server/old_sg_server.nim2
-rw-r--r--tests/manyloc/nake/nake.nim2
-rw-r--r--tests/metatype/tbindtypedesc.nim8
-rw-r--r--tests/metatype/tmatrix1.nim4
-rw-r--r--tests/metatype/tmeta_typeclasses.nim (renamed from tests/metatype/ttypeclasses.nim)0
-rw-r--r--tests/metatype/tmetatype_issues.nim (renamed from tests/metatype/tissues.nim)16
-rw-r--r--tests/metatype/tmetatype_various.nim (renamed from tests/metatype/tvarious.nim)0
-rw-r--r--tests/metatype/tmetatypematrix.nim (renamed from tests/metatype/tmatrix.nim)4
-rw-r--r--tests/metatype/tsemistatic.nim2
-rw-r--r--tests/metatype/tstaticparammacro.nim8
-rw-r--r--tests/metatype/tstaticparams.nim4
-rw-r--r--tests/metatype/ttypedesc3.nim10
-rw-r--r--tests/metatype/ttypetraits.nim2
-rw-r--r--tests/method/tmethod.nim2
-rw-r--r--tests/method/tmethod_issues.nim (renamed from tests/method/tissues.nim)0
-rw-r--r--tests/method/tmethod_various.nim (renamed from tests/method/tvarious.nim)0
-rw-r--r--tests/method/tmultim.nim10
-rw-r--r--tests/misc/t99bott.nim8
-rw-r--r--tests/misc/tack.nim4
-rw-r--r--tests/misc/tbug511622.nim4
-rw-r--r--tests/misc/tcmdline.nim4
-rw-r--r--tests/misc/tcolonisproc.nim6
-rw-r--r--tests/misc/tdllvar.nim6
-rw-r--r--tests/misc/temit.nim5
-rw-r--r--tests/misc/tendian.nim3
-rw-r--r--tests/misc/tevents.nim8
-rw-r--r--tests/misc/tgenconstraints.nim3
-rw-r--r--tests/misc/tgetstartmilsecs.nim7
-rw-r--r--tests/misc/thallo.nim10
-rw-r--r--tests/misc/theaproots.nim4
-rw-r--r--tests/misc/thintoff.nim12
-rw-r--r--tests/misc/tinc.nim6
-rw-r--r--tests/misc/tinit.nim3
-rw-r--r--tests/misc/tinout.nim4
-rw-r--r--tests/misc/tinvalidarrayaccess.nim25
-rw-r--r--tests/misc/tinvalidarrayaccess2.nim16
-rw-r--r--tests/misc/tinvalidnewseq.nim5
-rw-r--r--tests/misc/tissue710.nim2
-rw-r--r--tests/misc/tlastmod.nim17
-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.nim8
-rw-r--r--tests/misc/tnewuns.nim12
-rw-r--r--tests/misc/tnoinst.nim3
-rw-r--r--tests/misc/tnolen.nim3
-rw-r--r--tests/misc/tnoop.nim5
-rw-r--r--tests/misc/tnot.nim2
-rw-r--r--tests/misc/tparseopt.nim78
-rw-r--r--tests/misc/tpos.nim4
-rw-r--r--tests/misc/tprep.nim8
-rw-r--r--tests/misc/tquicksort.nim9
-rw-r--r--tests/misc/tradix.nim128
-rw-r--r--tests/misc/trawstr.nim4
-rw-r--r--tests/misc/treadln.nim13
-rw-r--r--tests/misc/treadx.nim13
-rw-r--r--tests/misc/treservedcidentsasfields.nim39
-rw-r--r--tests/misc/tshadow_magic_type.nim17
-rw-r--r--tests/misc/tsimtych.nim4
-rw-r--r--tests/misc/tsizeof.nim114
-rw-r--r--tests/misc/tsizeof2.nim6
-rw-r--r--tests/misc/tslices.nim5
-rw-r--r--tests/misc/tsortdev.nim5
-rw-r--r--tests/misc/tstrace.nim20
-rw-r--r--tests/misc/tstrange.nim8
-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/misc/tvarious1.nim4
-rw-r--r--tests/misc/tvarnums.nim3
-rw-r--r--tests/modules/m9627/a.nim1
-rw-r--r--tests/modules/m9627/b.nim1
-rw-r--r--tests/modules/t8665.nim4
-rw-r--r--tests/modules/t9627.nim7
-rw-r--r--tests/modules/texport2.nim9
-rw-r--r--tests/modules/timportas.nim8
-rw-r--r--tests/modules/timportexcept.nim3
-rw-r--r--tests/modules/tmismatchedvisibility.nim2
-rw-r--r--tests/modules/tnamspc.nim4
-rw-r--r--tests/modules/tnotuniquename.nim2
-rw-r--r--tests/modules/tnotuniquename2.nim2
-rw-r--r--tests/modules/topaque.nim4
-rw-r--r--tests/modules/trecinca.nim4
-rw-r--r--tests/modules/trecincb.nim4
-rw-r--r--tests/modules/trecmod.nim2
-rw-r--r--tests/modules/tselfimport.nim3
-rw-r--r--tests/namedparams/tnamedparams.nim5
-rw-r--r--tests/newconfig/tfoo.nim2
-rw-r--r--tests/newconfig/tfoo.nims3
-rw-r--r--tests/niminaction/Chapter2/explicit_discard.nim4
-rw-r--r--tests/niminaction/Chapter2/no_def_eq.nim4
-rw-r--r--tests/niminaction/Chapter2/no_iterator.nim4
-rw-r--r--tests/niminaction/Chapter2/no_seq_type.nim4
-rw-r--r--tests/niminaction/Chapter2/resultreject.nim8
-rw-r--r--tests/niminaction/Chapter3/ChatApp/src/client.nim4
-rw-r--r--tests/niminaction/Chapter3/ChatApp/src/protocol.nim2
-rw-r--r--tests/niminaction/Chapter3/ChatApp/src/server.nim8
-rw-r--r--tests/niminaction/Chapter3/various3.nim29
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/concurrency.nim6
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim6
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/naive.nim6
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim8
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/race_condition.nim6
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/sequential_counts.nim8
-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/src/views/user.nim2
-rw-r--r--tests/niminaction/Chapter7/Tweeter/tests/database_test.nim6
-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/notnil/tnotnil.nim2
-rw-r--r--tests/objects/tobjconstr.nim31
-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/objects/tobjects_issues.nim (renamed from tests/objects/tissues.nim)0
-rw-r--r--tests/objects/tobjects_various.nim (renamed from tests/objects/tvarious.nim)0
-rw-r--r--tests/objects/tobjpragma.nim9
-rw-r--r--tests/objects/toop1.nim1
-rw-r--r--tests/objvariant/tadrdisc.nim2
-rw-r--r--tests/objvariant/tcheckedfield1.nim4
-rw-r--r--tests/objvariant/temptycaseobj.nim4
-rw-r--r--tests/objvariant/tvariantstack.nim3
-rw-r--r--tests/openarray/t8259.nim2
-rw-r--r--tests/openarray/topena1.nim5
-rw-r--r--tests/openarray/topenarrayrepr.nim4
-rw-r--r--tests/openarray/topenlen.nim3
-rw-r--r--tests/openarray/tptrarrayderef.nim9
-rw-r--r--tests/osproc/ta_in.nim4
-rw-r--r--tests/osproc/ta_out.nim17
-rw-r--r--tests/osproc/tafalse.nim4
-rw-r--r--tests/osproc/texecps.nim8
-rw-r--r--tests/osproc/texitcode.nim2
-rw-r--r--tests/osproc/tstderr.nim7
-rw-r--r--tests/osproc/tstdin.nim1
-rw-r--r--tests/osproc/tstdout.nim2
-rw-r--r--tests/osproc/tworkingdir.nim1
-rw-r--r--tests/overflw/toverflw.nim2
-rw-r--r--tests/overflw/toverflw2.nim3
-rw-r--r--tests/overflw/tovfint.nim3
-rw-r--r--tests/overload/toverl.nim4
-rw-r--r--tests/overload/toverload_issues.nim (renamed from tests/overload/tissues.nim)34
-rw-r--r--tests/overload/toverload_various.nim (renamed from tests/overload/tvarious.nim)0
-rw-r--r--tests/overload/tselfderef.nim5
-rw-r--r--tests/parallel/tarray_of_channels.nim14
-rw-r--r--tests/parallel/tdont_be_stupid.nim10
-rw-r--r--tests/parallel/tgc_unsafe.nim2
-rw-r--r--tests/parallel/tgc_unsafe2.nim4
-rw-r--r--tests/parallel/tguard1.nim4
-rw-r--r--tests/parallel/tlet_spawn.nim5
-rw-r--r--tests/parallel/tmissing_deepcopy.nim5
-rw-r--r--tests/parallel/tsimple_array_checks.nim24
-rw-r--r--tests/parallel/tsysspawnbadarg.nim2
-rw-r--r--tests/parallel/twrong_refcounts.nim2
-rw-r--r--tests/parser/tdomulttest.nim4
-rw-r--r--tests/parser/tinvcolonlocation1.nim2
-rw-r--r--tests/parser/tinvcolonlocation2.nim2
-rw-r--r--tests/parser/tinvcolonlocation3.nim2
-rw-r--r--tests/parser/tinvwhen.nim4
-rw-r--r--tests/parser/toprprec.nim1
-rw-r--r--tests/parser/tprecedence.nim23
-rw-r--r--tests/parser/tstrongspaces.nim83
-rw-r--r--tests/parser/ttupleunpack.nim6
-rw-r--r--tests/pragmas/t6448.nim4
-rw-r--r--tests/pragmas/t8741.nim2
-rw-r--r--tests/pragmas/tcustom_pragma.nim22
-rw-r--r--tests/pragmas/tnoreturn.nim1
-rw-r--r--tests/pragmas/tused.nim10
-rw-r--r--tests/pragmas/tuserpragma2.nim2
-rw-r--r--tests/proc/tprocredef.nim3
-rw-r--r--tests/range/tsubrange.nim3
-rw-r--r--tests/range/tsubrange2.nim2
-rw-r--r--tests/range/tsubrange3.nim1
-rw-r--r--tests/rational/trat_float.nim2
-rw-r--r--tests/realtimeGC/shared.nim3
-rw-r--r--tests/seq/tseq.nim25
-rw-r--r--tests/sets/t2669.nim2
-rw-r--r--tests/sets/tsets.nim7
-rw-r--r--tests/sets/tsets_various.nim (renamed from tests/sets/tvarious.nim)6
-rw-r--r--tests/statictypes/t9255.nim2
-rw-r--r--tests/stdlib/nre/captures.nim31
-rw-r--r--tests/stdlib/nre/match.nim6
-rw-r--r--tests/stdlib/nre/replace.nim6
-rw-r--r--tests/stdlib/osproctest.nim8
-rw-r--r--tests/stdlib/somesql.sql2
-rw-r--r--tests/stdlib/t8925.nim2
-rw-r--r--tests/stdlib/tbitops.nim1
-rw-r--r--tests/stdlib/tbitops2.nim1
-rw-r--r--tests/stdlib/tcgi.nim17
-rw-r--r--tests/stdlib/tcputime.nim11
-rw-r--r--tests/stdlib/thashes.nim13
-rw-r--r--tests/stdlib/thtmlparser.nim58
-rw-r--r--tests/stdlib/thttpcore.nim3
-rw-r--r--tests/stdlib/tjsonexternproc.nim8
-rw-r--r--tests/stdlib/tjsonmacro.nim3
-rw-r--r--tests/stdlib/tjsonmacro_reject.nim4
-rw-r--r--tests/stdlib/tjsonmacro_reject2.nim4
-rw-r--r--tests/stdlib/tjsontestsuite.nim4
-rw-r--r--tests/stdlib/tlists.nim13
-rw-r--r--tests/stdlib/tmath2.nim85
-rw-r--r--tests/stdlib/tmemfiles1.nim5
-rw-r--r--tests/stdlib/tmemlines.nim6
-rw-r--r--tests/stdlib/tmemlinesBuf.nim13
-rw-r--r--tests/stdlib/tmemmapstreams.nim4
-rw-r--r--tests/stdlib/tmemslices.nim8
-rw-r--r--tests/stdlib/tnativesockets.nim8
-rw-r--r--tests/stdlib/tnet.nim4
-rw-r--r--tests/stdlib/tos.nim19
-rw-r--r--tests/stdlib/tospaths.nim1
-rw-r--r--tests/stdlib/tosproc.nim23
-rw-r--r--tests/stdlib/tosprocterminate.nim4
-rw-r--r--tests/stdlib/tparsesql.nim4
-rw-r--r--tests/stdlib/tparsopt.nim8
-rw-r--r--tests/stdlib/tposix.nim7
-rw-r--r--tests/stdlib/tquit.nim7
-rw-r--r--tests/stdlib/tregex.nim3
-rw-r--r--tests/stdlib/trepr.nim2
-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/tsqlparser.nim2
-rw-r--r--tests/stdlib/tstdlib_issues.nim (renamed from tests/stdlib/tissues.nim)0
-rw-r--r--tests/stdlib/tstdlib_various.nim (renamed from tests/stdlib/tvarious.nim)2
-rw-r--r--tests/stdlib/tstreams.nim17
-rw-r--r--tests/stdlib/tstreams2.nim1
-rw-r--r--tests/stdlib/tstreams3.nim1
-rw-r--r--tests/stdlib/tstring.nim1
-rw-r--r--tests/stdlib/tstrscans.nim86
-rw-r--r--tests/stdlib/tstrtabs.nim91
-rw-r--r--tests/stdlib/tstrutil.nim1
-rw-r--r--tests/stdlib/tsugar.nim1
-rw-r--r--tests/stdlib/ttimes.nim20
-rw-r--r--tests/stdlib/twalker.nim13
-rw-r--r--tests/system/helpers/readall_echo.nim2
-rw-r--r--tests/system/t7894.nim29
-rw-r--r--tests/system/talloc.nim3
-rw-r--r--tests/system/talloc2.nim4
-rw-r--r--tests/system/tio.nim12
-rw-r--r--tests/system/tnilconcats.nim7
-rw-r--r--tests/system/tostring.nim5
-rw-r--r--tests/system/tparams.nim3
-rw-r--r--tests/system/trealloc.nim1
-rw-r--r--tests/template/sunset.nimf (renamed from tests/template/sunset.tmpl)0
-rw-r--r--tests/template/t2416.nim2
-rw-r--r--tests/template/t2do.nim23
-rw-r--r--tests/template/t_otemplates.nim2
-rw-r--r--tests/template/tcan_access_hidden_field.nim9
-rw-r--r--tests/template/tconfusinglocal.nim4
-rw-r--r--tests/template/tdefault_nil.nim14
-rw-r--r--tests/template/template_issues.nim209
-rw-r--r--tests/template/template_various.nim251
-rw-r--r--tests/template/texponential_eval.nim8
-rw-r--r--tests/template/tgenerictemplates.nim37
-rw-r--r--tests/template/tgensym_generic_cross_module.nim14
-rw-r--r--tests/template/tgensym_label.nim18
-rw-r--r--tests/template/tgensymregression.nim2
-rw-r--r--tests/template/tgetast_typeliar.nim23
-rw-r--r--tests/template/thygienictempl.nim6
-rw-r--r--tests/template/tissue909.nim16
-rw-r--r--tests/template/tissue993.nim20
-rw-r--r--tests/template/tit.nim11
-rw-r--r--tests/template/tlt.nim7
-rw-r--r--tests/template/tnested_template.nim23
-rw-r--r--tests/template/tparams_gensymed.nim53
-rw-r--r--tests/template/tpattern_with_converter.nim27
-rw-r--r--tests/template/tprefer_immediate.nim15
-rw-r--r--tests/template/tprocparshadow.nim30
-rw-r--r--tests/template/tsighash_regression.nim5
-rw-r--r--tests/template/tstmt_semchecked_twice.nim30
-rw-r--r--tests/template/tsymchoicefield.nim11
-rw-r--r--tests/template/ttemp_in_varargs.nim9
-rw-r--r--tests/template/ttempl.nim27
-rw-r--r--tests/template/ttempl2.nim3
-rw-r--r--tests/template/ttempl3.nim4
-rw-r--r--tests/template/ttempl4.nim7
-rw-r--r--tests/template/ttempl5.nim28
-rw-r--r--tests/template/ttemplreturntype.nim4
-rw-r--r--tests/template/twhen_gensym.nim13
-rw-r--r--tests/template/twrongopensymchoice.nim2
-rw-r--r--tests/template/typedescids.nim17
-rw-r--r--tests/test_nimscript.nims2
-rw-r--r--tests/testament/tshouldfail.nim31
-rw-r--r--tests/threads/t8535.nim2
-rw-r--r--tests/threads/tactors2.nim2
-rw-r--r--tests/threads/threadex.nim4
-rw-r--r--tests/threads/tthreadanalysis2.nim3
-rw-r--r--tests/threads/tthreadheapviolation1.nim4
-rw-r--r--tests/trmacros/targlist.nim9
-rw-r--r--tests/trmacros/tcse.nim13
-rw-r--r--tests/trmacros/tdisallowif.nim2
-rw-r--r--tests/trmacros/thoist.nim13
-rw-r--r--tests/trmacros/tmatrix.nim29
-rw-r--r--tests/trmacros/tnoalias.nim16
-rw-r--r--tests/trmacros/tnoalias2.nim19
-rw-r--r--tests/trmacros/tnoendlessrec.nim10
-rw-r--r--tests/trmacros/tpartial.nim11
-rw-r--r--tests/trmacros/tpatterns.nim23
-rw-r--r--tests/trmacros/trmacros_various.nim110
-rw-r--r--tests/trmacros/trmacros_various2.nim79
-rw-r--r--tests/trmacros/tstar.nim19
-rw-r--r--tests/trmacros/tstatic_t_bug.nim24
-rw-r--r--tests/tuples/tanontuples.nim26
-rw-r--r--tests/tuples/tconver_tuple.nim23
-rw-r--r--tests/tuples/tdifferent_instantiations.nim9
-rw-r--r--tests/tuples/tgeneric_tuple.nim9
-rw-r--r--tests/tuples/tgeneric_tuple2.nim17
-rw-r--r--tests/tuples/ttuples_issues.nim77
-rw-r--r--tests/tuples/ttuples_various.nim136
-rw-r--r--tests/tuples/tuint_tuple.nim10
-rw-r--r--tests/tuples/tunpack_asgn.nim34
-rw-r--r--tests/tuples/tuple_subscript.nim40
-rw-r--r--tests/tuples/tuple_with_seq.nim46
-rw-r--r--tests/tuples/twrongtupleaccess.nim3
-rw-r--r--tests/typerel/t2plus.nim2
-rw-r--r--tests/typerel/t8172.nim2
-rw-r--r--tests/typerel/temptynode.nim2
-rw-r--r--tests/typerel/texplicitcmp.nim11
-rw-r--r--tests/typerel/tno_int_in_bool_context.nim3
-rw-r--r--tests/typerel/tnoargopenarray.nim5
-rw-r--r--tests/typerel/tnocontains.nim2
-rw-r--r--tests/typerel/trefs.nim5
-rw-r--r--tests/typerel/tregionptrs.nim2
-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/typerel/ttypedesc_as_genericparam1.nim2
-rw-r--r--tests/typerel/ttypedesc_as_genericparam2.nim2
-rw-r--r--tests/typerel/ttypenoval.nim4
-rw-r--r--tests/typerel/typredef.nim3
-rw-r--r--tests/types/t1252.nim12
-rw-r--r--tests/types/t5640.nim6
-rw-r--r--tests/types/t5648.nim21
-rw-r--r--tests/types/t6456.nim2
-rw-r--r--tests/types/t7581.nim1
-rw-r--r--tests/types/t7905.nim33
-rw-r--r--tests/types/taliasbugs.nim2
-rw-r--r--tests/types/tassignemptytuple.nim2
-rw-r--r--tests/types/tauto_canbe_void.nim8
-rw-r--r--tests/types/tfinalobj.nim19
-rw-r--r--tests/types/tillegaltyperecursion.nim2
-rw-r--r--tests/types/tillrec.nim3
-rw-r--r--tests/types/tissues_types.nim73
-rw-r--r--tests/types/tparameterizedparent0.nim2
-rw-r--r--tests/types/tparameterizedparent1.nim2
-rw-r--r--tests/types/tparameterizedparent3.nim2
-rw-r--r--tests/types/tparameterizedparent4.nim2
-rw-r--r--tests/untestable/tssl.nim2
-rw-r--r--tests/usingstmt/tusingstatement.nim3
-rw-r--r--tests/varres/tnewseq_on_result_vart.nim2
-rw-r--r--tests/varres/tprevent_forloopvar_mutations.nim2
-rw-r--r--tests/varres/tvarres1.nim3
-rw-r--r--tests/varres/tvarres2.nim3
-rw-r--r--tests/varres/tvarres_via_forwarding.nim2
-rw-r--r--tests/varres/tvartup.nim3
-rw-r--r--tests/varres/twrong_parameter.nim2
-rw-r--r--tests/varstmt/tvardecl.nim5
-rw-r--r--tests/vm/t2574.nim2
-rw-r--r--tests/vm/t4952.nim17
-rw-r--r--tests/vm/t9043.nim10
-rw-r--r--tests/vm/tcastint.nim48
-rw-r--r--tests/vm/tconsteval.nim2
-rw-r--r--tests/vm/tconstobj.nim22
-rw-r--r--tests/vm/tconsttable2.nim2
-rw-r--r--tests/vm/teval1.nim11
-rw-r--r--tests/vm/tforwardproc.nim2
-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.nim53
-rw-r--r--tests/vm/tissues.nim30
-rw-r--r--tests/vm/tmitems_vm.nim (renamed from tests/vm/tmitems.nim)2
-rw-r--r--tests/vm/tnimnode.nim14
-rw-r--r--tests/vm/tsetlen.nim30
-rw-r--r--tests/vm/tsimpleglobals.nim2
-rw-r--r--tests/vm/tslurp.nim10
-rw-r--r--tests/vm/tstaticprintseq.nim2
-rw-r--r--tests/vm/tswap.nim2
-rw-r--r--tests/vm/ttouintconv.nim2
-rw-r--r--tests/vm/tvmmisc.nim5
-rw-r--r--tools/kochdocs.nim18
-rw-r--r--tools/nim-gdb.py19
-rw-r--r--tools/nimfind.nim237
-rw-r--r--tools/nimfind.nims2
-rw-r--r--tools/niminst/buildbat.nimf (renamed from tools/niminst/buildbat.tmpl)0
-rw-r--r--tools/niminst/buildsh.nimf (renamed from tools/niminst/buildsh.tmpl)2
-rw-r--r--tools/niminst/debcreation.nim2
-rw-r--r--tools/niminst/deinstall.nimf (renamed from tools/niminst/deinstall.tmpl)0
-rw-r--r--tools/niminst/inno.nimf (renamed from tools/niminst/inno.tmpl)0
-rw-r--r--tools/niminst/install.nimf (renamed from tools/niminst/install.tmpl)0
-rw-r--r--tools/niminst/makefile.nimf (renamed from tools/niminst/makefile.tmpl)2
-rw-r--r--tools/niminst/niminst.nim14
-rw-r--r--tools/niminst/nsis.nimf (renamed from tools/niminst/nsis.tmpl)0
-rw-r--r--tools/nimweb.nim2
-rw-r--r--tools/vccenv/vccenv.nim1
-rw-r--r--tools/website.nimf (renamed from tools/website.tmpl)0
961 files changed, 11895 insertions, 8276 deletions
diff --git a/.gitignore b/.gitignore
index 8cd092639..d736cdf8d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -66,3 +66,6 @@ testresults/
 test.txt
 /test.ini
 
+tweeter.db
+tweeter_test.db
+megatest.nim
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 70ff59136..9f536e6c9 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -53,9 +53,8 @@ test-windows:
   <<: *win_set_path_def
   script:
     - call ci\deps.bat
-    - nim c --taintMode:on testament\tester
+    - nim c testament\tester
     - testament\tester.exe --pedantic all
   tags:
     - windows
     - fast
-
diff --git a/.travis.yml b/.travis.yml
index 6fb19648e..abd115701 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -42,7 +42,7 @@ before_script:
   - export PATH=$(pwd)/bin${PATH:+:$PATH}
 script:
   - nim c koch
-  - ./koch boot
+  - env NIM_COMPILE_TO_CPP=false ./koch boot
   - ./koch boot -d:release
   - ./koch nimble
   - nim e tests/test_nimscript.nims
@@ -51,7 +51,7 @@ script:
   #- nimble install sdl1
   #- nimble install jester@#head -y
   #- nimble install niminst
-  - nim c --taintMode:on -d:nimCoroutines testament/tester
+  - nim c -d:nimCoroutines testament/tester
   - testament/tester --pedantic all -d:nimCoroutines
   - nim c -o:bin/nimpretty nimpretty/nimpretty.nim
   - nim c -r nimpretty/tester.nim
diff --git a/appveyor.yml b/appveyor.yml
index a60831f9d..9c8525d72 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -53,8 +53,8 @@ build_script:
 #  - nimble install opengl -y
 #  - nimble install sdl1 -y
 #  - nimble install jester@#head -y
-  - nim c --taintMode:on -d:nimCoroutines --os:genode -d:posix --compileOnly testament/tester
-  - nim c --taintMode:on -d:nimCoroutines testament/tester
+  - nim c -d:nimCoroutines --os:genode -d:posix --compileOnly testament/tester
+  - nim c -d:nimCoroutines testament/tester
 
 test_script:
   - testament\tester --pedantic all -d:nimCoroutines
diff --git a/bin/nim-gdb b/bin/nim-gdb
index e7b41094d..e7b41094d 100644..100755
--- a/bin/nim-gdb
+++ b/bin/nim-gdb
diff --git a/changelog.md b/changelog.md
index 9a5671757..1772652d6 100644
--- a/changelog.md
+++ b/changelog.md
@@ -11,30 +11,122 @@
   use `editdistance.editDistance` or `editdistance.editDistanceAscii`
   instead.
 
+- The OpenMP parallel iterator \``||`\` now supports any `#pragma omp directives`
+  and not just `#pragma omp parallel for`. See
+  [OpenMP documentation](https://www.openmp.org/wp-content/uploads/OpenMP-4.5-1115-CPP-web.pdf).
+
+  The default annotation is `parallel for`, if you used OpenMP without annotation
+  the change is transparent, if you used annotations you will have to prefix
+  your previous annotations with `parallel for`.
+
+- The `unchecked` pragma was removed, instead use `system.UncheckedArray`.
+- The undocumented ``#? strongSpaces`` parsing mode has been removed.
+- The `not` operator is now always a unary operator, this means that code like
+  ``assert not isFalse(3)`` compiles.
+
 
 #### Breaking changes in the standard library
 
+- `osproc.execProcess` now also takes a `workingDir` parameter.
+
+- `options.UnpackError` is no longer a ref type and inherits from `System.Defect` instead of `System.ValueError`.
+
+- nre's `RegexMatch.{captureBounds,captures}[]`  no longer return `Option` or
+  `nil`/`""`, respectivly. Use the newly added `n in p.captures` method to
+  check if a group is captured, otherwise you'll recieve an exception.
+
+- nre's `RegexMatch.{captureBounds,captures}.toTable` no longer accept a
+  default parameter. Instead uncaptured entries are left empty. Use
+  `Table.getOrDefault()` if you need defaults.
+
+- nre's `RegexMatch.captures.{items,toSeq}` now returns an `Option[string]`
+  instead of a `string`. With the removal of `nil` strings, this is the only
+  way to indicate a missing match. Inside your loops, instead of `capture ==
+  ""` or `capture == nil`, use `capture.isSome` to check if a capture is
+  present, and `capture.get` to get its value.
+
+- nre's `replace()` no longer throws `ValueError` when the replacement string
+  has missing captures. It instead throws `KeyError` for named captures, and
+  `IndexError` for un-named captures. This is consistant with
+  `RegexMatch.{captureBounds,captures}[]`.
 
 #### Breaking changes in the compiler
 
+- The compiler now implements the "generic symbol prepass" for `when` statements
+  in generics, see bug #8603. This means that code like this does not compile
+  anymore:
+
+```nim
+proc enumToString*(enums: openArray[enum]): string =
+  # typo: 'e' instead 'enums'
+  when e.low.ord >= 0 and e.high.ord < 256:
+    result = newString(enums.len)
+  else:
+    result = newString(enums.len * 2)
+```
+
+- ``discard x`` is now illegal when `x` is a function symbol.
+
 ### Library additions
 
-- There is a new stdlib module `editdistance` as a replacement for the
+- There is a new stdlib module `std/editdistance` as a replacement for the
   deprecated `strutils.editDistance`.
 
+- There is a new stdlib module `std/wordwrap` as a replacement for the
+  deprecated `strutils.wordwrap`.
+
 - Added `split`, `splitWhitespace`, `size`, `alignLeft`, `align`,
   `strip`, `repeat` procs and iterators to `unicode.nim`.
 
 - Added `or` for `NimNode` in `macros`.
 
+- 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.
+
+- Added the parameter ``isSorted`` for the ``sequtils.deduplicate`` proc.
+- There is a new stdlib mdoule `std/diff` to compute the famous "diff"
+  of two texts by line.
+
 ### Library changes
 
+- The string output of `macros.lispRepr` proc has been tweaked
+  slightly. The `dumpLisp` macro in this module now outputs an
+  indented proper Lisp, devoid of commas.
+
+- In `strutils` empty strings now no longer matched as substrings
+  anymore.
+
+- Complex type is now generic and not a tuple anymore.
+
+- The `ospaths` module is now deprecated, use `os` instead. Note that
+  `os` is available in a NimScript environment but unsupported
+  operations produce a compile-time error.
+
+- The `parseopt` module now supports a new flag `allowWhitespaceAfterColon`
+  (default value: true) that can be set to `false` for better Posix
+  interoperability. (Bug #9619.)
+
 
 ### 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()
+- User defined pragmas are now allowed in the pragma blocks
+- Pragma blocks are now longer eliminated from the typed AST tree to preserve
+  pragmas for further analysis by macros
 
 ### Language changes
 
+- The standard extension for SCF (source code filters) files was changed from
+  ``.tmpl`` to ``.nimf``,
+  it's more recognizable and allows tools like github to recognize it as Nim,
+  see [#9647](https://github.com/nim-lang/Nim/issues/9647).
+  The previous extension will continue to work.
 
 ### Tool changes
 - `jsondoc` now include a `moduleDescription` field with the module
@@ -42,5 +134,6 @@
   documentation.
 
 ### Compiler changes
+- The deprecated `fmod` proc is now unavailable on the VM'.
 
 ### Bugfixes
diff --git a/changelogs/changelog_0_19_0.md b/changelogs/changelog_0_19_0.md
index 7464f50b6..18d3ca2b3 100644
--- a/changelogs/changelog_0_19_0.md
+++ b/changelogs/changelog_0_19_0.md
@@ -223,7 +223,7 @@
   into the namespace "Nim" in order to avoid naming conflicts with existing
   C++ code. This is done for all Nim code - internal and exported.
 
-- Added ``macros.getProjectPath`` and ``ospaths.putEnv`` procs to Nim's virtual
+- Added ``macros.getProjectPath`` and ``os.putEnv`` procs to Nim's virtual
   machine.
 
 - The ``deadCodeElim`` option is now always turned on and the switch has no
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 68c8e7dd2..5f5f296cb 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -565,13 +565,9 @@ const
   routineKinds* = {skProc, skFunc, skMethod, skIterator,
                    skConverter, skMacro, skTemplate}
   tfIncompleteStruct* = tfVarargs
-  tfUncheckedArray* = tfVarargs
   tfUnion* = tfNoSideEffect
   tfGcSafe* = tfThread
   tfObjHasKids* = tfEnumHasHoles
-  tfOldSchoolExprStmt* = tfVarargs # for now used to distinguish \
-    # 'varargs[expr]' from 'varargs[untyped]'. Eventually 'expr' will be
-    # deprecated and this mess can be cleaned up.
   tfReturnsNew* = tfInheritable
   skError* = skUnknown
 
@@ -631,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,
@@ -660,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,
@@ -726,10 +723,9 @@ type
       sons*: TNodeSeq
     comment*: string
 
-  TSymSeq* = seq[PSym]
   TStrTable* = object         # a table[PIdent] of PSym
     counter*: int
-    data*: TSymSeq
+    data*: seq[PSym]
 
   # -------------- backend information -------------------------------
   TLocKind* = enum
@@ -760,8 +756,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]
@@ -771,7 +765,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 ------------------------------
 
@@ -811,7 +804,7 @@ type
     of routineKinds:
       procInstCache*: seq[PInstantiation]
       gcUnsafetyReason*: PSym  # for better error messages wrt gcsafe
-      transformedBody*: PNode  # cached body after transf pass   
+      transformedBody*: PNode  # cached body after transf pass
     of skModule, skPackage:
       # modules keep track of the generic symbols they use from other modules.
       # this is because in incremental compilation, when a module is about to
@@ -902,6 +895,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
@@ -1091,9 +1086,6 @@ proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
   result.id = getID()
   when debugIds:
     registerId(result)
-  #if result.id == 77131:
-  #  writeStacktrace()
-  #  echo name.s
 
 proc isMetaType*(t: PType): bool =
   return t.kind in tyMetaTypes or
@@ -1265,6 +1257,9 @@ proc `$`*(x: TLockLevel): string =
   elif x.ord == UnknownLockLevel.ord: result = "<unknown>"
   else: result = $int16(x)
 
+proc `$`*(s: PSym): string =
+  result = s.name.s & "@" & $s.id
+
 proc newType*(kind: TTypeKind, owner: PSym): PType =
   new(result)
   result.kind = kind
@@ -1272,6 +1267,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)
@@ -1345,15 +1341,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:
@@ -1734,7 +1727,7 @@ proc isException*(t: PType): bool =
     return false
 
   var base = t
-  while base != nil:
+  while base != nil and base.kind in {tyRef, tyObject, tyGenericInst}:
     if base.sym != nil and base.sym.magic == mException:
       return true
     base = base.lastSon
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim
index b716882dc..60eecbdc5 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:
@@ -496,7 +507,7 @@ proc strTableContains*(t: TStrTable, n: PSym): bool =
     h = nextTry(h, high(t.data))
   result = false
 
-proc strTableRawInsert(data: var TSymSeq, n: PSym) =
+proc strTableRawInsert(data: var seq[PSym], n: PSym) =
   var h: Hash = n.name.h and high(data)
   if sfImmediate notin n.flags:
     # fast path:
@@ -524,7 +535,7 @@ proc strTableRawInsert(data: var TSymSeq, n: PSym) =
     data[h] = n
     if favPos >= 0: swap data[h], data[favPos]
 
-proc symTabReplaceRaw(data: var TSymSeq, prevSym: PSym, newSym: PSym) =
+proc symTabReplaceRaw(data: var seq[PSym], prevSym: PSym, newSym: PSym) =
   assert prevSym.name.h == newSym.name.h
   var h: Hash = prevSym.name.h and high(data)
   while data[h] != nil:
@@ -538,7 +549,7 @@ proc symTabReplace*(t: var TStrTable, prevSym: PSym, newSym: PSym) =
   symTabReplaceRaw(t.data, prevSym, newSym)
 
 proc strTableEnlarge(t: var TStrTable) =
-  var n: TSymSeq
+  var n: seq[PSym]
   newSeq(n, len(t.data) * GrowthFactor)
   for i in countup(0, high(t.data)):
     if t.data[i] != nil: strTableRawInsert(n, t.data[i])
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index b23cd598e..d177e1f88 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -63,26 +63,6 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
     add(pl, ~");$n")
     line(p, cpsStmts, pl)
 
-proc isInCurrentFrame(p: BProc, n: PNode): bool =
-  # checks if `n` is an expression that refers to the current frame;
-  # this does not work reliably because of forwarding + inlining can break it
-  case n.kind
-  of nkSym:
-    if n.sym.kind in {skVar, skResult, skTemp, skLet} and p.prc != nil:
-      result = p.prc.id == n.sym.owner.id
-  of nkDotExpr, nkBracketExpr:
-    if skipTypes(n.sons[0].typ, abstractInst).kind notin {tyVar,tyLent,tyPtr,tyRef}:
-      result = isInCurrentFrame(p, n.sons[0])
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv:
-    result = isInCurrentFrame(p, n.sons[1])
-  of nkHiddenDeref, nkDerefExpr:
-    # what about: var x = addr(y); callAsOpenArray(x[])?
-    # *shrug* ``addr`` is unsafe anyway.
-    result = false
-  of nkObjUpConv, nkObjDownConv, nkCheckedFieldExpr:
-    result = isInCurrentFrame(p, n.sons[0])
-  else: discard
-
 proc genBoundsCheck(p: BProc; arr, a, b: TLoc)
 
 proc openArrayLoc(p: BProc, n: PNode): Rope =
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index d73dac82f..d00371dd8 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),
@@ -741,7 +731,7 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) =
     initLocExpr(p, e.sons[0], a)
     putIntoDest(p, d, e, "&" & a.r, a.storage)
     #Message(e.info, warnUser, "HERE NEW &")
-  elif mapType(p.config, e.sons[0].typ) == ctArray or isCppRef(p, e.sons[0].typ):
+  elif mapType(p.config, e.sons[0].typ) == ctArray or isCppRef(p, e.typ):
     expr(p, e.sons[0], d)
   else:
     var a: TLoc
@@ -860,7 +850,6 @@ proc genUncheckedArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
   var a, b: TLoc
   initLocExpr(p, x, a)
   initLocExpr(p, y, b)
-  var ty = skipTypes(a.t, abstractVarRange + abstractPtrs + tyUserTypeClasses)
   d.inheritLocation(a)
   putIntoDest(p, d, n, ropecg(p.module, "$1[$2]", rdLoc(a), rdCharLoc(b)),
               a.storage)
@@ -872,20 +861,20 @@ proc genArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
   var ty = skipTypes(a.t, abstractVarRange + abstractPtrs + tyUserTypeClasses)
   var first = intLiteral(firstOrd(p.config, ty))
   # emit range check:
-  if optBoundsCheck in p.options and tfUncheckedArray notin ty.flags:
+  if optBoundsCheck in p.options and ty.kind != tyUncheckedArray:
     if not isConstExpr(y):
       # semantic pass has already checked for const index expressions
       if firstOrd(p.config, ty) == 0:
         if (firstOrd(p.config, b.t) < firstOrd(p.config, ty)) or (lastOrd(p.config, b.t) > lastOrd(p.config, ty)):
-          linefmt(p, cpsStmts, "if ((NU)($1) > (NU)($2)) #raiseIndexError();$n",
+          linefmt(p, cpsStmts, "if ((NU)($1) > (NU)($2)) #raiseIndexError2($1, $2);$n",
                   rdCharLoc(b), intLiteral(lastOrd(p.config, ty)))
       else:
-        linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n",
+        linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError3($1, $2, $3);$n",
                 rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty)))
     else:
       let idx = getOrdValue(y)
       if idx < firstOrd(p.config, ty) or idx > lastOrd(p.config, ty):
-        localError(p.config, x.info, "index out of bounds")
+        localError(p.config, x.info, formatErrorIndexBound(idx, firstOrd(p.config, ty), lastOrd(p.config, ty)))
   d.inheritLocation(a)
   putIntoDest(p, d, n,
               ropecg(p.module, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first), a.storage)
@@ -894,7 +883,6 @@ proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) =
   var a, b: TLoc
   initLocExpr(p, x, a)
   initLocExpr(p, y, b)
-  var ty = skipTypes(a.t, abstractVarRange)
   inheritLocation(d, a)
   putIntoDest(p, d, n,
               ropecg(p.module, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
@@ -909,11 +897,10 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
       rdLoc(a), rdLoc(b), rdLoc(arr))
   of tyArray:
     let first = intLiteral(firstOrd(p.config, ty))
-    if tfUncheckedArray notin ty.flags:
-      linefmt(p, cpsStmts,
-        "if ($2-$1 != -1 && " &
-        "($2-$1 < -1 || $1 < $3 || $1 > $4 || $2 < $3 || $2 > $4)) #raiseIndexError();$n",
-        rdCharLoc(a), rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty)))
+    linefmt(p, cpsStmts,
+      "if ($2-$1 != -1 && " &
+      "($2-$1 < -1 || $1 < $3 || $1 > $4 || $2 < $3 || $2 > $4)) #raiseIndexError();$n",
+      rdCharLoc(a), rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty)))
   of tySequence, tyString:
     linefmt(p, cpsStmts,
       "if ($2-$1 != -1 && " &
@@ -926,7 +913,7 @@ proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
   initLocExpr(p, x, a)
   initLocExpr(p, y, b) # emit range check:
   if optBoundsCheck in p.options:
-    linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)) #raiseIndexError();$n",
+    linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)) #raiseIndexError2($1,$2Len_0-1);$n",
             rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``!
   inheritLocation(d, a)
   putIntoDest(p, d, n,
@@ -942,11 +929,11 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
   if optBoundsCheck in p.options:
     if ty.kind == tyString and (not defined(nimNoZeroTerminator) or optLaxStrings in p.options):
       linefmt(p, cpsStmts,
-              "if ((NU)($1) > (NU)$2) #raiseIndexError();$n",
+              "if ((NU)($1) > (NU)$2) #raiseIndexError2($1,$2);$n",
               rdLoc(b), lenExpr(p, a))
     else:
       linefmt(p, cpsStmts,
-              "if ((NU)($1) >= (NU)$2) #raiseIndexError();$n",
+              "if ((NU)($1) >= (NU)$2) #raiseIndexError2($1,$2-1);$n",
               rdLoc(b), lenExpr(p, a))
   if d.k == locNone: d.storage = OnHeap
   if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
@@ -1149,14 +1136,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) =
@@ -1360,9 +1347,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))
@@ -1385,7 +1380,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:
@@ -1395,18 +1396,17 @@ 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)
-    let oldCode = p.s(cpsStmts)
     linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",  i.r, L.rope)
     initLoc(elem, locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap)
     elem.r = ropecg(p.module, "$1$3[$2]", rdLoc(d), rdLoc(i), dataField(p))
     elem.storage = OnHeap # we know that sequences are on the heap
     initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.sons[1].typ, abstractInst)), a.storage)
     arr.r = ropecg(p.module, "$1[$2]", rdLoc(a), rdLoc(i))
-    genAssignment(p, elem, arr, {afDestIsNil, needToCopy})
+    genAssignment(p, elem, arr, {needToCopy})
     lineF(p, cpsStmts, "}$n", [])
 
 
@@ -1581,8 +1581,17 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     else: putIntoDest(p, d, e, rope(lengthOrd(p.config, typ)))
   else: internalError(p.config, e.info, "genArrayLen()")
 
+proc makePtrType(baseType: PType): PType =
+  result = newType(tyPtr, baseType.owner)
+  addSonSkipIntLit(result, baseType)
+
+proc makeAddr(n: PNode): PNode =
+  result = newTree(nkHiddenAddr, n)
+  result.typ = makePtrType(n.typ)
+
 proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
   if p.config.selectedGc == gcDestructors:
+    e.sons[1] = makeAddr(e[1])
     genCall(p, e, d)
     return
   var a, b, call: TLoc
@@ -1964,6 +1973,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   of mAppendStrStr: genStrAppend(p, e, d)
   of mAppendSeqElem:
     if p.config.selectedGc == gcDestructors:
+      e.sons[1] = makeAddr(e[1])
       genCall(p, e, d)
     else:
       genSeqElemAppend(p, e, d)
@@ -2008,8 +2018,8 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       frmt = "$1 = $2->len;$n"
     lineCg(p, cpsStmts, frmt, tmp.r, rdLoc(a))
     putIntoDest(p, d, e, tmp.r)
-  of mGCref: unaryStmt(p, e, d, "#nimGCref($1);$n")
-  of mGCunref: unaryStmt(p, e, d, "#nimGCunref($1);$n")
+  of mGCref: unaryStmt(p, e, d, "if ($1) { #nimGCref($1); }$n")
+  of mGCunref: unaryStmt(p, e, d, "if ($1) { #nimGCunref($1); }$n")
   of mSetLengthStr: genSetLengthStr(p, e, d)
   of mSetLengthSeq: genSetLengthSeq(p, e, d)
   of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet,
@@ -2031,8 +2041,11 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     let n = lowerings.wrapProcForSpawn(p.module.g.graph, p.module.module, e, e.typ, nil, nil)
     expr(p, n, d)
   of mParallel:
-    let n = semparallel.liftParallel(p.module.g.graph, p.module.module, e)
-    expr(p, n, d)
+    when defined(leanCompiler):
+      quit "compiler built without support for the 'parallel' statement"
+    else:
+      let n = semparallel.liftParallel(p.module.g.graph, p.module.module, e)
+      expr(p, n, d)
   of mDeepCopy:
     var a, b: TLoc
     let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1]
@@ -2042,6 +2055,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")
@@ -2429,15 +2443,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
     if ex.kind != nkEmpty:
       genLineDir(p, n)
       var a: TLoc
-      if ex.kind in nkCallKinds and (ex[0].kind != nkSym or
-                                     ex[0].sym.magic == mNone):
-        # bug #6037: do not assign to a temp in C++ mode:
-        incl a.flags, lfSingleUse
-        genCall(p, ex, a)
-        if lfSingleUse notin a.flags:
-          line(p, cpsStmts, a.r & ";\L")
-      else:
-        initLocExpr(p, ex, a)
+      initLocExprSingleUse(p, ex, a)
+      line(p, cpsStmts, "(void)(" & a.r & ");\L")
   of nkAsmStmt: genAsmStmt(p, n)
   of nkTryStmt:
     if p.module.compileToCpp and optNoCppExceptions notin p.config.globalOptions:
@@ -2566,7 +2573,6 @@ proc genConstObjConstr(p: BProc; n: PNode): Rope =
 proc genConstSimpleList(p: BProc, n: PNode): Rope =
   var length = sonsLen(n)
   result = rope("{")
-  let t = n.typ.skipTypes(abstractInst)
   for i in countup(0, length - 2):
     addf(result, "$1,$n", [genNamedConstExpr(p, n.sons[i])])
   if length > 0:
diff --git a/compiler/ccgliterals.nim b/compiler/ccgliterals.nim
index 34677ec06..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)])
 
@@ -69,7 +69,7 @@ proc genStringLiteralV2(m: BModule; n: PNode): Rope =
     addf(m.s[cfsData], "static const NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
           [result, rope(len(n.strVal)), pureLit])
   else:
-    result = m.tmpBase & rope(id)
+    result = m.tmpBase & rope(id+1)
 
 proc genStringLiteralV2Const(m: BModule; n: PNode): Rope =
   let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 6c2e8ebc8..6c33b302d 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:
@@ -400,6 +402,16 @@ proc genGotoForCase(p: BProc; caseStmt: PNode) =
     genStmts(p, it.lastSon)
     endBlock(p)
 
+
+iterator fieldValuePairs(n: PNode): tuple[memberSym, valueSym: PNode] =
+  assert(n.kind in {nkLetSection, nkVarSection})
+  for identDefs in n:
+    if identDefs.kind == nkIdentDefs:
+      let valueSym = identDefs[^1]
+      for i in 0 ..< identDefs.len-2:
+        let memberSym = identDefs[i]
+        yield((memberSym: memberSym, valueSym: valueSym))
+
 proc genComputedGoto(p: BProc; n: PNode) =
   # first pass: Generate array of computed labels:
   var casePos = -1
@@ -429,22 +441,12 @@ proc genComputedGoto(p: BProc; n: PNode) =
   let tmp = "TMP$1_" % [id.rope]
   var gotoArray = "static void* $#[$#] = {" % [tmp, arraySize.rope]
   for i in 1..arraySize-1:
-    gotoArray.addf("&&TMP$#_, ", [(id+i).rope])
-  gotoArray.addf("&&TMP$#_};$n", [(id+arraySize).rope])
+    gotoArray.addf("&&TMP$#_, ", [rope(id+i)])
+  gotoArray.addf("&&TMP$#_};$n", [rope(id+arraySize)])
   line(p, cpsLocals, gotoArray)
 
-  let topBlock = p.blocks.len-1
-  let oldBody = p.blocks[topBlock].sections[cpsStmts]
-  p.blocks[topBlock].sections[cpsStmts] = nil
-
-  for j in casePos+1 ..< n.len: genStmts(p, n.sons[j])
-  let tailB = p.blocks[topBlock].sections[cpsStmts]
-
-  p.blocks[topBlock].sections[cpsStmts] = nil
-  for j in 0 .. casePos-1: genStmts(p, n.sons[j])
-  let tailA = p.blocks[topBlock].sections[cpsStmts]
-
-  p.blocks[topBlock].sections[cpsStmts] = oldBody & tailA
+  for j in 0 ..< casePos:
+    genStmts(p, n.sons[j])
 
   let caseStmt = n.sons[casePos]
   var a: TLoc
@@ -459,19 +461,40 @@ proc genComputedGoto(p: BProc; n: PNode) =
       if it.sons[j].kind == nkRange:
         localError(p.config, it.info, "range notation not available for computed goto")
         return
+
       let val = getOrdValue(it.sons[j])
       lineF(p, cpsStmts, "TMP$#_:$n", [intLiteral(val+id+1)])
+
     genStmts(p, it.lastSon)
-    #for j in casePos+1 ..< n.len: genStmts(p, n.sons[j]) # tailB
-    #for j in 0 .. casePos-1: genStmts(p, n.sons[j])  # tailA
-    add(p.s(cpsStmts), tailB)
-    add(p.s(cpsStmts), tailA)
+
+    for j in casePos+1 ..< n.sons.len:
+      genStmts(p, n.sons[j])
+
+    for j in 0 ..< casePos:
+      # prevent new local declarations
+      # compile declarations as assignments
+      let it = n.sons[j]
+      if it.kind in {nkLetSection, nkVarSection}:
+        let asgn = copyNode(it)
+        asgn.kind = nkAsgn
+        asgn.sons.setLen 2
+        for sym, value in it.fieldValuePairs:
+          if value.kind != nkEmpty:
+            asgn.sons[0] = sym
+            asgn.sons[1] = value
+            genStmts(p, asgn)
+      else:
+        genStmts(p, it)
 
     var a: TLoc
     initLocExpr(p, caseStmt.sons[0], a)
     lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
     endBlock(p)
 
+  for j in casePos+1 ..< n.sons.len:
+    genStmts(p, n.sons[j])
+
+
 proc genWhileStmt(p: BProc, t: PNode) =
   # we don't generate labels here as for example GCC would produce
   # significantly worse code
@@ -482,26 +505,26 @@ proc genWhileStmt(p: BProc, t: PNode) =
   genLineDir(p, t)
 
   preserveBreakIdx:
-    p.breakIdx = startBlock(p, "while (1) {$n")
-    p.blocks[p.breakIdx].isLoop = true
-    initLocExpr(p, t.sons[0], a)
-    if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
-      let label = assignLabel(p.blocks[p.breakIdx])
-      lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), label])
     var loopBody = t.sons[1]
     if loopBody.stmtsContainPragma(wComputedGoto) and
-        hasComputedGoto in CC[p.config.cCompiler].props:
-      # for closure support weird loop bodies are generated:
+       hasComputedGoto in CC[p.config.cCompiler].props:
+         # for closure support weird loop bodies are generated:
       if loopBody.len == 2 and loopBody.sons[0].kind == nkEmpty:
         loopBody = loopBody.sons[1]
       genComputedGoto(p, loopBody)
     else:
+      p.breakIdx = startBlock(p, "while (1) {$n")
+      p.blocks[p.breakIdx].isLoop = true
+      initLocExpr(p, t.sons[0], a)
+      if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0):
+        let label = assignLabel(p.blocks[p.breakIdx])
+        lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), label])
       genStmts(p, loopBody)
 
-    if optProfiler in p.options:
-      # invoke at loop body exit:
-      linefmt(p, cpsStmts, "#nimProfile();$n")
-    endBlock(p)
+      if optProfiler in p.options:
+        # invoke at loop body exit:
+        linefmt(p, cpsStmts, "#nimProfile();$n")
+      endBlock(p)
 
   dec(p.withinLoop)
 
@@ -536,7 +559,8 @@ proc genParForStmt(p: BProc, t: PNode) =
     initLocExpr(p, call.sons[1], rangeA)
     initLocExpr(p, call.sons[2], rangeB)
 
-    lineF(p, cpsStmts, "#pragma omp parallel for $4$n" &
+    # $n at the beginning because of #9710
+    lineF(p, cpsStmts, "$n#pragma omp $4$n" &
                         "for ($1 = $2; $1 <= $3; ++$1)",
                         [forLoopVar.loc.rdLoc,
                         rangeA.rdLoc, rangeB.rdLoc,
@@ -587,8 +611,10 @@ proc genRaiseStmt(p: BProc, t: PNode) =
     if isImportedException(typ, p.config):
       lineF(p, cpsStmts, "throw $1;$n", [e])
     else:
-      lineCg(p, cpsStmts, "#raiseException((#Exception*)$1, $2);$n",
-          [e, makeCString(typ.sym.name.s)])
+      lineCg(p, cpsStmts, "#raiseExceptionEx((#Exception*)$1, $2, $3, $4, $5);$n",
+          [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:
     genLineDir(p, t)
     # reraise the last exception:
@@ -851,14 +877,15 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
 
   discard pop(p.nestedTryStmts)
 
-  if not catchAllPresent and t[^1].kind == nkFinally:
-    # finally requires catch all presence
-    startBlock(p, "catch (...) {$n")
-    genSimpleBlock(p, t[^1][0])
-    line(p, cpsStmts, ~"throw;$n")
-    endBlock(p)
-
   if t[^1].kind == nkFinally:
+    # c++ does not have finally, therefore code needs to be generated twice
+    if not catchAllPresent:
+      # finally requires catch all presence
+      startBlock(p, "catch (...) {$n")
+      genStmts(p, t[^1][0])
+      line(p, cpsStmts, ~"throw;$n")
+      endBlock(p)
+
     genSimpleBlock(p, t[^1][0])
 
 proc genTry(p: BProc, t: PNode, d: var TLoc) =
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 985178f90..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
 
@@ -492,7 +490,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
     # with heavily templatized C++ code:
     if not isImportedCppType(rectype):
       let fieldType = field.loc.lode.typ.skipTypes(abstractInst)
-      if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
+      if fieldType.kind == tyUncheckedArray:
         addf(result, "$1 $2[SEQ_DECL_SIZE];$n",
             [getTypeDescAux(m, fieldType.elemType, check), sname])
       elif fieldType.kind == tySequence and m.config.selectedGC != gcDestructors:
@@ -546,7 +544,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
         appcg(m, result, "virtual void raise() {throw *this;}$n") # required for polymorphic exceptions
         if typ.sym.magic == mException:
           # Add cleanup destructor to Exception base class
-          appcg(m, result, "~$1() {if(this->raise_id) popCurrentExceptionEx(this->raise_id);}$n", [name])
+          appcg(m, result, "~$1() {if(this->raiseId) popCurrentExceptionEx(this->raiseId);}$n", [name])
           # hack: forward declare popCurrentExceptionEx() on top of type description,
           # proper request to generate popCurrentExceptionEx not possible for 2 reasons:
           # generated function will be below declared Exception type and circular dependency
@@ -1188,6 +1186,7 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
   let owner = t.skipTypes(typedescPtrs).owner.getModule
   if owner != m.module:
     # make sure the type info is created in the owner module
+    assert m.g.modules[owner.position] != nil
     discard genTypeInfo(m.g.modules[owner.position], origType, info)
     # reference the type info as extern here
     discard cgsym(m, "TNimType")
@@ -1213,8 +1212,8 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
       let x = fakeClosureType(m, t.owner)
       genTupleInfo(m, x, x, result, info)
   of tySequence:
+    genTypeInfoAux(m, t, t, result, info)
     if m.config.selectedGC != gcDestructors:
-      genTypeInfoAux(m, t, t, result, info)
       if m.config.selectedGC >= gcMarkAndSweep:
         let markerProc = genTraverseProc(m, origType, sig)
         addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 26d66a0f5..457a6e176 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -14,7 +14,12 @@ import
   nversion, nimsets, msgs, std / sha1, bitsets, idents, types,
   ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth,
   condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
-  lowerings, semparallel, tables, sets, ndi, lineinfos, pathutils, transf
+  lowerings, tables, sets, ndi, lineinfos, pathutils, transf
+
+import system/helpers2
+
+when not defined(leanCompiler):
+  import semparallel
 
 import strutils except `%` # collides with ropes.`%`
 
@@ -42,8 +47,7 @@ when options.hasTinyCBackend:
 # implementation
 
 proc addForwardedProc(m: BModule, prc: PSym) =
-  m.forwardedProcs.add(prc)
-  inc(m.g.forwardedProcsCounter)
+  m.g.forwardedProcs.add(prc)
 
 proc findPendingModule(m: BModule, s: PSym): BModule =
   var ms = getModule(s)
@@ -292,10 +296,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)
@@ -311,7 +315,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:
@@ -444,20 +448,21 @@ proc assignGlobalVar(p: BProc, n: PNode) =
     return
   useHeader(p.module, s)
   if lfNoDecl in s.loc.flags: return
-  if sfThread in s.flags:
-    declareThreadVar(p.module, s, sfImportc in s.flags)
-  else:
-    var decl: Rope = nil
-    var td = getTypeDesc(p.module, s.loc.t)
-    if s.constraint.isNil:
-      if sfImportc in s.flags: add(decl, "extern ")
-      add(decl, td)
-      if sfRegister in s.flags: add(decl, " register")
-      if sfVolatile in s.flags: add(decl, " volatile")
-      addf(decl, " $1;$n", [s.loc.r])
+  if not containsOrIncl(p.module.declaredThings, s.id):
+    if sfThread in s.flags:
+      declareThreadVar(p.module, s, sfImportc in s.flags)
     else:
-      decl = (s.cgDeclFrmt & ";$n") % [td, s.loc.r]
-    add(p.module.s[cfsVars], decl)
+      var decl: Rope = nil
+      var td = getTypeDesc(p.module, s.loc.t)
+      if s.constraint.isNil:
+        if sfImportc in s.flags: add(decl, "extern ")
+        add(decl, td)
+        if sfRegister in s.flags: add(decl, " register")
+        if sfVolatile in s.flags: add(decl, " volatile")
+        addf(decl, " $1;$n", [s.loc.r])
+      else:
+        decl = (s.cgDeclFrmt & ";$n") % [td, s.loc.r]
+      add(p.module.s[cfsVars], decl)
   if p.withinLoop > 0:
     # fixes tests/run/tzeroarray:
     resetLoc(p, s.loc)
@@ -1036,7 +1041,7 @@ proc genVarPrototype(m: BModule, n: PNode) =
   let sym = n.sym
   useHeader(m, sym)
   fillLoc(sym.loc, locGlobalVar, n, mangleName(m, sym), OnHeap)
-  if (lfNoDecl in sym.loc.flags) or containsOrIncl(m.declaredThings, sym.id):
+  if (lfNoDecl in sym.loc.flags) or contains(m.declaredThings, sym.id):
     return
   if sym.owner.id != m.module.id:
     # else we already have the symbol generated!
@@ -1055,7 +1060,7 @@ proc addIntTypes(result: var Rope; conf: ConfigRef) {.inline.} =
   addf(result, "#define NIM_NEW_MANGLING_RULES\L" &
                "#define NIM_INTBITS $1\L", [
     platform.CPU[conf.target.targetCPU].intSize.rope])
-  if conf.cppCustomNamespace.len > 0: 
+  if conf.cppCustomNamespace.len > 0:
     result.add("#define USE_NIM_NAMESPACE ")
     result.add(conf.cppCustomNamespace)
     result.add("\L")
@@ -1390,7 +1395,6 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule
   result.preInitProc = newPreInitProc(result)
   initNodeTable(result.dataCache)
   result.typeStack = @[]
-  result.forwardedProcs = @[]
   result.typeNodesName = getTempName(result)
   result.nimTypesName = getTempName(result)
   # no line tracing for the init sections of the system module so that we
@@ -1406,49 +1410,6 @@ proc nullify[T](arr: var T) =
   for i in low(arr)..high(arr):
     arr[i] = Rope(nil)
 
-proc resetModule*(m: BModule) =
-  # between two compilations in CAAS mode, we can throw
-  # away all the data that was written to disk
-  m.headerFiles = @[]
-  m.declaredProtos = initIntSet()
-  m.forwTypeCache = initTable[SigHash, Rope]()
-  m.initProc = newProc(nil, m)
-  m.initProc.options = initProcOptions(m)
-  m.preInitProc = newPreInitProc(m)
-  initNodeTable(m.dataCache)
-  m.typeStack = @[]
-  m.forwardedProcs = @[]
-  m.typeNodesName = getTempName(m)
-  m.nimTypesName = getTempName(m)
-  if sfSystemModule in m.module.flags:
-    incl m.flags, preventStackTrace
-  else:
-    excl m.flags, preventStackTrace
-  nullify m.s
-  m.typeNodes = 0
-  m.nimTypes = 0
-  nullify m.extensionLoaders
-
-  # indicate that this is now cached module
-  # the cache will be invalidated by nullifying gModules
-  #m.fromCache = true
-  m.g = nil
-
-  # we keep only the "merge info" information for the module
-  # and the properties that can't change:
-  # m.filename
-  # m.cfilename
-  # m.isHeaderFile
-  # m.module ?
-  # m.typeCache
-  # m.declaredThings
-  # m.typeInfoMarker
-  # m.labels
-  # m.FrameDeclared
-
-proc resetCgenModules*(g: BModuleList) =
-  for m in cgenModules(g): resetModule(m)
-
 proc rawNewModule(g: BModuleList; module: PSym; conf: ConfigRef): BModule =
   result = rawNewModule(g, module, AbsoluteFile toFullPath(conf, module.position.FileIndex))
 
@@ -1527,25 +1488,11 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
   let tranformed_n = transformStmt(m.g.graph, m.module, n)
   genStmts(m.initProc, tranformed_n)
 
-proc finishModule(m: BModule) =
-  var i = 0
-  while i <= high(m.forwardedProcs):
-    # Note: ``genProc`` may add to ``m.forwardedProcs``, so we cannot use
-    # a ``for`` loop here
-    var prc = m.forwardedProcs[i]
-    if sfForward in prc.flags:
-      internalError(m.config, prc.info, "still forwarded: " & prc.name.s)
-    genProcNoForward(m, prc)
-    inc(i)
-  assert(m.g.forwardedProcsCounter >= i)
-  dec(m.g.forwardedProcsCounter, i)
-  setLen(m.forwardedProcs, 0)
-
 proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool =
   result = true
   if optForceFullMake notin m.config.globalOptions:
     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
@@ -1636,12 +1583,26 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
   registerModuleToMain(m.g, m.module)
 
   if sfMainModule in m.module.flags:
-    if m.g.forwardedProcsCounter == 0:
+    if m.g.forwardedProcs.len == 0:
       incl m.flags, objHasKidsValid
     let disp = generateMethodDispatchers(graph)
     for x in disp: genProcAux(m, x.sym)
     genMainProc(m)
 
+proc genForwardedProcs(g: BModuleList) =
+  # Forward declared proc:s lack bodies when first encountered, so they're given
+  # a second pass here
+  # Note: ``genProcNoForward`` may add to ``forwardedProcs``
+  while g.forwardedProcs.len > 0:
+    let
+      prc = g.forwardedProcs.pop()
+      ms = getModule(prc)
+      m = g.modules[ms.position]
+    if sfForward in prc.flags:
+      internalError(m.config, prc.info, "still forwarded: " & prc.name.s)
+
+    genProcNoForward(m, prc)
+
 proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
   let g = BModuleList(backend)
   # we need to process the transitive closure because recursive module
@@ -1651,10 +1612,9 @@ proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
   let (outDir, _, _) = splitFile(config.outfile)
   if not outDir.isEmpty:
     createDir(outDir)
-  if g.generatedHeader != nil: finishModule(g.generatedHeader)
-  while g.forwardedProcsCounter > 0:
-    for m in cgenModules(g):
-      finishModule(m)
+
+  genForwardedProcs(g)
+
   for m in cgenModules(g):
     m.writeModule(pending=true)
   writeMapping(config, g.mapping)
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index 0c6097fbe..28e36364e 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -112,7 +112,7 @@ type
     mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope
     mapping*: Rope             # the generated mapping file (if requested)
     modules*: seq[BModule]     # list of all compiled modules
-    forwardedProcsCounter*: int
+    forwardedProcs*: seq[PSym] # proc:s that did not yet have a body
     generatedHeader*: BModule
     breakPointId*: int
     breakpoints*: Rope # later the breakpoints are inserted into the main proc
@@ -150,7 +150,6 @@ type
     preInitProc*: BProc       # code executed before the init proc
     typeStack*: TTypeSeq      # used for type generation
     dataCache*: TNodeTable
-    forwardedProcs*: TSymSeq  # keep forwarded procs here
     typeNodes*, nimTypes*: int # used for type info generation
     typeNodesName*, nimTypesName*: Rope # used for type info generation
     labels*: Natural          # for generating unique module-scope names
@@ -188,12 +187,12 @@ proc newProc*(prc: PSym, module: BModule): BProc =
   result.sigConflicts = initCountTable[string]()
 
 proc newModuleList*(g: ModuleGraph): BModuleList =
-  BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope](), config: g.config,
-    graph: g, nimtvDeps: @[], nimtvDeclared: initIntSet())
+  BModuleList(typeInfoMarker: initTable[SigHash, Rope](), config: g.config,
+    graph: g, nimtvDeclared: initIntSet())
 
 iterator cgenModules*(g: BModuleList): BModule =
-  for i in 0..high(g.modules):
+  for m in g.modules:
     # ultimately, we are iterating over the file ids here.
     # some "files" won't have an associated cgen module (like stdin)
     # and we must skip over them.
-    if g.modules[i] != nil: yield g.modules[i]
+    if m != nil: yield m
diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim
index cba07446f..f5014fa8c 100644
--- a/compiler/cgmeth.nim
+++ b/compiler/cgmeth.nim
@@ -188,7 +188,7 @@ proc methodDef*(g: ModuleGraph; s: PSym, fromCache: bool) =
   elif sfBase notin s.flags:
     message(g.config, s.info, warnUseBase)
 
-proc relevantCol(methods: TSymSeq, col: int): bool =
+proc relevantCol(methods: seq[PSym], col: int): bool =
   # returns true iff the position is relevant
   var t = methods[0].typ.sons[col].skipTypes(skipPtrs)
   if t.kind == tyObject:
@@ -206,7 +206,7 @@ proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
       if (d != high(int)) and d != 0:
         return d
 
-proc sortBucket(a: var TSymSeq, relevantCols: IntSet) =
+proc sortBucket(a: var seq[PSym], relevantCols: IntSet) =
   # we use shellsort here; fast and simple
   var n = len(a)
   var h = 1
@@ -225,7 +225,7 @@ proc sortBucket(a: var TSymSeq, relevantCols: IntSet) =
       a[j] = v
     if h == 1: break
 
-proc genDispatcher(g: ModuleGraph; methods: TSymSeq, relevantCols: IntSet): PSym =
+proc genDispatcher(g: ModuleGraph; methods: seq[PSym], relevantCols: IntSet): PSym =
   var base = lastSon(methods[0].ast).sym
   result = base
   var paramLen = sonsLen(base.typ)
diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim
index 258372d76..5ded6d054 100644
--- a/compiler/closureiters.nim
+++ b/compiler/closureiters.nim
@@ -462,10 +462,17 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
       result.typ = n.typ
 
       for i in 0 ..< n.len:
-        if n[i].kind == nkStmtListExpr:
+        case n[i].kind
+        of nkExprColonExpr:
+          if n[i][1].kind == nkStmtListExpr:
+            let (st, ex) = exprToStmtList(n[i][1])
+            result.add(st)
+            n[i][1] = ex
+        of nkStmtListExpr:
           let (st, ex) = exprToStmtList(n[i])
           result.add(st)
           n[i] = ex
+        else: discard
       result.add(n)
 
   of nkIfStmt, nkIfExpr:
@@ -852,15 +859,8 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
       discard
 
     of nkStmtList, nkStmtListExpr:
-      assert(isEmptyType(n.typ), "nkStmtListExpr not lowered")
-
       result = addGotoOut(result, gotoOut)
       for i in 0 ..< n.len:
-        if n[i].hasYieldsInExpressions:
-          # Lower nkStmtListExpr nodes inside `n[i]` first
-          var ns = false
-          n[i] = ctx.lowerStmtListExprs(n[i], ns)
-
         if n[i].hasYields:
           # Create a new split
           let go = newNodeI(nkGotoState, n[i].info)
@@ -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,13 +1294,18 @@ 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)
-  let n = n.toStmtList
+  var n = n.toStmtList
 
   discard ctx.newState(n, nil)
   let gotoOut = newTree(nkGotoState, g.newIntLit(n.info, -1))
 
+  var ns = false
+  n = ctx.lowerStmtListExprs(n, ns)
+
+  if n.hasYieldsInExpressions():
+    internalError(ctx.g.config, "yield in expr not lowered")
+
   # Splitting transformation
   discard ctx.transformClosureIteratorBody(n, gotoOut)
 
@@ -1314,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 39967c4bc..b090a09a5 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -115,6 +115,7 @@ const
   errInvalidCmdLineOption = "invalid command line option: '$1'"
   errOnOrOffExpectedButXFound = "'on' or 'off' expected, but '$1' found"
   errOnOffOrListExpectedButXFound = "'on', 'off' or 'list' expected, but '$1' found"
+  errOffHintsError = "'off', 'hint' or 'error' expected, but '$1' found"
 
 proc invalidCmdLineOption(conf: ConfigRef; pass: TCmdLinePass, switch: string, info: TLineInfo) =
   if switch == " ": localError(conf, info, errInvalidCmdLineOption % "-")
@@ -479,7 +480,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
     of "native", "gdb":
       incl(conf.globalOptions, optCDebug)
       conf.options = conf.options + {optLineDir} - {optEndb}
-      defineSymbol(conf.symbols, "nimTypeNames") # type names are used in gdb pretty printing
+      #defineSymbol(conf.symbols, "nimTypeNames") # type names are used in gdb pretty printing
       undefSymbol(conf.symbols, "endb")
     else:
       localError(conf, info, "expected endb|gdb but found " & arg)
@@ -616,6 +617,14 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
   of "run", "r":
     expectNoArg(conf, switch, arg, pass, info)
     incl(conf.globalOptions, optRun)
+  of "errormax":
+    expectArg(conf, switch, arg, pass, info)
+    # Note: `nim check` (etc) can overwrite this.
+    # `0` is meaningless, give it a useful meaning as in clang's -ferror-limit
+    # If user doesn't set this flag and the code doesn't either, it'd
+    # have the same effect as errorMax = 1
+    let ret = parseInt(arg)
+    conf.errorMax = if ret == 0: high(int) else: ret
   of "verbosity":
     expectArg(conf, switch, arg, pass, info)
     let verbosity = parseInt(arg)
@@ -641,14 +650,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)
@@ -732,8 +746,14 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
     doAssert(conf != nil)
     incl(conf.features, destructor)
     defineSymbol(conf.symbols, "nimNewRuntime")
-  of "nep1":
-    processOnOffSwitchG(conf, {optCheckNep1}, arg, pass, info)
+  of "stylecheck":
+    case arg.normalize
+    of "off": conf.globalOptions = conf.globalOptions - {optStyleHint, optStyleError}
+    of "hint": conf.globalOptions = conf.globalOptions + {optStyleHint}
+    of "error": conf.globalOptions = conf.globalOptions + {optStyleError}
+    else: localError(conf, info, errOffHintsError % arg)
+  of "showallmismatches":
+    processOnOffSwitchG(conf, {optShowAllMismatches}, arg, pass, info)
   of "cppcompiletonamespace":
     if arg.len > 0:
       conf.cppCustomNamespace = arg
@@ -769,6 +789,7 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser;
     # nim filename.nims  is the same as "nim e filename.nims":
     if p.key.endswith(".nims"):
       config.command = "e"
+      incl(config.globalOptions, optWasNimscript)
       config.projectName = unixToNativePath(p.key)
       config.arguments = cmdLineRest(p)
       result = true
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index 13e0d0d11..9a4c1701c 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -84,7 +84,9 @@ proc initDefines*(symbols: StringTableRef) =
   defineSymbol("nimNoNilSeqs2")
   defineSymbol("nimHasUserErrors")
   defineSymbol("nimUncheckedArrayTyp")
-
+  defineSymbol("nimHasTypeof")
+  defineSymbol("nimErrorProcCanHaveBody")
+  defineSymbol("nimHasInstantiationOfInMacro")
   defineSymbol("nimHasNilSeqs")
   for f in low(Feature)..high(Feature):
     defineSymbol("nimHas" & $f)
diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim
index 2a82b6f3b..40af11e70 100644
--- a/compiler/destroyer.nim
+++ b/compiler/destroyer.nim
@@ -116,8 +116,8 @@ 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
+  strutils, options, dfa, lowerings, tables, modulegraphs, msgs,
+  lineinfos, parampatterns
 
 const
   InterestingSyms = {skVar, skResult, skLet}
@@ -127,20 +127,11 @@ type
     owner: PSym
     g: ControlFlowGraph
     jumpTargets: IntSet
-    tmpObj: PType
-    tmp: PSym
     destroys, topLevelVars: PNode
-    toDropBit: Table[int, PSym]
     graph: ModuleGraph
     emptyNode: PNode
     otherRead: PNode
 
-proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode =
-  # XXX why are temps fields in an object here?
-  let f = newSym(skField, getIdent(c.graph.cache, ":d" & $c.tmpObj.n.len), c.owner, info)
-  f.typ = typ
-  rawAddField c.tmpObj, f
-  result = rawDirectAccess(c.tmp, f)
 
 proc isHarmlessVar*(s: PSym; c: Con): bool =
   # 's' is harmless if it used only once and its
@@ -261,6 +252,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
@@ -268,9 +264,6 @@ proc patchHead(n: PNode) =
       if sfFromGeneric in s.flags:
         excl(s.flags, sfFromGeneric)
         patchHead(s.getBody)
-      if n[1].typ.isNil:
-        # XXX toptree crashes without this workaround. Figure out why.
-        return
       let t = n[1].typ.skipTypes({tyVar, tyLent, tyGenericInst, tyAlias, tySink, tyInferred})
       template patch(op, field) =
         if s.name.s == op and field != nil and field != s:
@@ -296,6 +289,10 @@ proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) =
       m.add c.graph.config $ c.otherRead.info
   localError(c.graph.config, ri.info, errGenerated, m)
 
+proc makePtrType(c: Con, baseType: PType): PType =
+  result = newType(tyPtr, c.owner)
+  addSonSkipIntLit(result, baseType)
+
 template genOp(opr, opname, ri) =
   let op = opr
   if op == nil:
@@ -304,7 +301,9 @@ template genOp(opr, opname, ri) =
     globalError(c.graph.config, dest.info, "internal error: '" & opname & "' operator is generic")
   patchHead op
   if sfError in op.flags: checkForErrorPragma(c, t, ri, opname)
-  result = newTree(nkCall, newSymNode(op), newTree(nkHiddenAddr, dest))
+  let addrExp = newNodeIT(nkHiddenAddr, dest.info, makePtrType(c, dest.typ))
+  addrExp.add(dest)
+  result = newTree(nkCall, newSymNode(op), addrExp)
 
 proc genSink(c: Con; t: PType; dest, ri: PNode): PNode =
   let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
@@ -321,22 +320,11 @@ proc genDestroy(c: Con; t: PType; dest: PNode): PNode =
 proc addTopVar(c: var Con; v: PNode) =
   c.topLevelVars.add newTree(nkIdentDefs, v, c.emptyNode, c.emptyNode)
 
-proc dropBit(c: var Con; s: PSym): PSym =
-  result = c.toDropBit.getOrDefault(s.id)
-  assert result != nil
-
-proc registerDropBit(c: var Con; s: PSym) =
-  let result = newSym(skTemp, getIdent(c.graph.cache, s.name.s & "_AliveBit"), c.owner, s.info)
-  result.typ = getSysType(c.graph, s.info, tyBool)
-  let trueVal = newIntTypeNode(nkIntLit, 1, result.typ)
-  c.topLevelVars.add newTree(nkIdentDefs, newSymNode result, c.emptyNode, trueVal)
-  c.toDropBit[s.id] = result
-  # generate:
-  #  if not sinkParam_AliveBit: `=destroy`(sinkParam)
-  let t = s.typ.skipTypes({tyGenericInst, tyAlias, tySink})
-  if t.destructor != nil:
-    c.destroys.add newTree(nkIfStmt,
-      newTree(nkElifBranch, newSymNode result, genDestroy(c, t, newSymNode s)))
+proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode =
+  let sym = newSym(skTemp, getIdent(c.graph.cache, ":tmpD"), c.owner, info)
+  sym.typ = typ
+  result = newSymNode(sym)
+  c.addTopVar(result)
 
 proc p(n: PNode; c: var Con): PNode
 
@@ -347,16 +335,6 @@ template recurse(n, dest) =
 proc isSinkParam(s: PSym): bool {.inline.} =
   result = s.kind == skParam and s.typ.kind == tySink
 
-proc destructiveMoveSink(n: PNode; c: var Con): PNode =
-  # generate:  (chckMove(sinkParam_AliveBit); sinkParam_AliveBit = false; sinkParam)
-  result = newNodeIT(nkStmtListExpr, n.info, n.typ)
-  let bit = newSymNode dropBit(c, n.sym)
-  if optMoveCheck in c.owner.options:
-    result.add callCodegenProc(c.graph, "chckMove", bit.info, bit)
-  result.add newTree(nkAsgn, bit,
-    newIntTypeNode(nkIntLit, 0, getSysType(c.graph, n.info, tyBool)))
-  result.add n
-
 proc genMagicCall(n: PNode; c: var Con; magicname: string; m: TMagic): PNode =
   result = newNodeI(nkCall, n.info)
   result.add(newSymNode(createMagic(c.graph, magicname, m)))
@@ -387,6 +365,12 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode =
   result.add genWasMoved(n, c)
   result.add tempAsNode
 
+proc sinkParamIsLastReadCheck(c: var Con, s: PNode) = 
+  assert s.kind == nkSym and s.sym.kind == skParam
+  if not isLastRead(s, c):
+     localError(c.graph.config, c.otherRead.info, "sink parameter `" & $s.sym.name.s &
+         "` is already consumed at " & toFileLineCol(c. graph.config, s.info))
+
 proc passCopyToSink(n: PNode; c: var Con): PNode =
   result = newNodeIT(nkStmtListExpr, n.info, n.typ)
   let tmp = getTemp(c, n.typ, n.info)
@@ -394,14 +378,20 @@ 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
 
 proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
+  template pArgIfTyped(arg_part: PNode): PNode =
+    # typ is nil if we are in if/case expr branch with noreturn
+    if arg_part.typ == nil: p(arg_part, c)
+    else: pArg(arg_part, c, isSink)
+
   if isSink:
     if arg.kind in nkCallKinds:
       # recurse but skip the call expression in order to prevent
@@ -412,17 +402,53 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
       result.add arg[0]
       for i in 1..<arg.len:
         result.add pArg(arg[i], c, i < L and parameters[i].kind == tySink)
-    elif arg.kind in {nkObjConstr, nkCharLit..nkFloat128Lit}:
+    elif arg.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkBracket, nkCharLit..nkFloat128Lit}:
       discard "object construction to sink parameter: nothing to do"
       result = arg
+    elif arg.kind == nkSym and isSinkParam(arg.sym):
+      # Sinked params can be consumed only once. We need to reset the memory
+      # to disable the destructor which we have not elided
+      sinkParamIsLastReadCheck(c, arg)
+      result = destructiveMoveVar(arg, c)
     elif arg.kind == nkSym and arg.sym.kind in InterestingSyms and isLastRead(arg, c):
-      # if x is a variable and it its last read we eliminate its
-      # destructor invokation, but don't. We need to reset its memory
-      # to disable its destructor which we have not elided:
+      # it is the last read, can be sinked. We need to reset the memory
+      # to disable the destructor which we have not elided
       result = destructiveMoveVar(arg, c)
-    elif arg.kind == nkSym and isSinkParam(arg.sym):
-      # mark the sink parameter as used:
-      result = destructiveMoveSink(arg, c)
+    elif arg.kind in {nkBlockExpr, nkBlockStmt}:
+      result = copyNode(arg)
+      result.add arg[0]
+      result.add pArg(arg[1], c, isSink)
+    elif arg.kind == nkStmtListExpr:
+      result = copyNode(arg)
+      for i in 0..arg.len-2:
+        result.add p(arg[i], c)
+      result.add pArg(arg[^1], c, isSink)
+    elif arg.kind in {nkIfExpr, nkIfStmt}:
+      result = copyNode(arg)
+      for i in 0..<arg.len:
+        var branch = copyNode(arg[i])
+        if arg[i].kind in {nkElifBranch, nkElifExpr}:   
+          branch.add p(arg[i][0], c)
+          branch.add pArgIfTyped(arg[i][1])
+        else:
+          branch.add pArgIfTyped(arg[i][0])
+        result.add branch
+    elif arg.kind == nkCaseStmt:
+      result = copyNode(arg)
+      result.add p(arg[0], c)
+      for i in 1..<arg.len:
+        var branch: PNode
+        if arg[i].kind == nkOfbranch:
+          branch = arg[i] # of branch conditions are constants
+          branch[^1] = pArgIfTyped(arg[i][^1])
+        elif arg[i].kind in {nkElifBranch, nkElifExpr}:
+          branch = copyNode(arg[i])   
+          branch.add p(arg[i][0], c)
+          branch.add pArgIfTyped(arg[i][1])
+        else:
+          branch = copyNode(arg[i]) 
+          branch.add pArgIfTyped(arg[i][0])
+        result.add branch     
     else:
       # an object that is not temporary but passed to a 'sink' parameter
       # results in a copy.
@@ -431,6 +457,11 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
     result = p(arg, c)
 
 proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
+  template moveOrCopyIfTyped(ri_part: PNode): PNode =
+    # typ is nil if we are in if/case expr branch with noreturn
+    if ri_part.typ == nil: p(ri_part, c)
+    else: moveOrCopy(dest, ri_part, c)
+
   case ri.kind
   of nkCallKinds:
     result = genSink(c, dest.typ, dest, ri)
@@ -443,6 +474,57 @@ 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 nkBlockExpr, nkBlockStmt:
+    result = newNodeI(nkBlockStmt, ri.info)
+    result.add ri[0] ## add label
+    result.add moveOrCopy(dest, ri[1], c)
+  of nkIfExpr, nkIfStmt:
+    result = newNodeI(nkIfStmt, ri.info)
+    for i in 0..<ri.len:
+      var branch = copyNode(ri[i])
+      if ri[i].kind in {nkElifBranch, nkElifExpr}:
+        branch.add p(ri[i][0], c)
+        branch.add moveOrCopyIfTyped(ri[i][1])
+      else:
+        branch.add moveOrCopyIfTyped(ri[i][0])
+      result.add branch
+  of nkCaseStmt:
+    result = newNodeI(nkCaseStmt, ri.info)
+    result.add p(ri[0], c)
+    for i in 1..<ri.len:
+      var branch: PNode
+      if ri[i].kind == nkOfbranch:
+        branch = ri[i] # of branch conditions are constants
+        branch[^1] = moveOrCopyIfTyped(ri[i][^1])
+      elif ri[i].kind in {nkElifBranch, nkElifExpr}:
+        branch = copyNode(ri[i])   
+        branch.add p(ri[i][0], c)
+        branch.add moveOrCopyIfTyped(ri[i][1])
+      else:
+        branch = copyNode(ri[i]) 
+        branch.add moveOrCopyIfTyped(ri[i][0])
+      result.add branch
+  of nkBracket:
+    # array constructor
+    result = genSink(c, dest.typ, dest, ri)
+    let ri2 = copyTree(ri)
+    for i in 0..<ri.len:
+      # everything that is passed to an array constructor is consumed,
+      # so these all act like 'sink' parameters:
+      ri2[i] = pArg(ri[i], c, isSink = true)
+    result.add ri2
   of nkObjConstr:
     result = genSink(c, dest.typ, dest, ri)
     let ri2 = copyTree(ri)
@@ -451,15 +533,29 @@ 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):
+    if isSinkParam(ri.sym):
+      # Rule 3: `=sink`(x, z); wasMoved(z)
+      sinkParamIsLastReadCheck(c, ri)
+      var snk = genSink(c, dest.typ, dest, ri)
+      snk.add ri
+      result = newTree(nkStmtList, snk, genMagicCall(ri, c, "wasMoved", mWasMoved))   
+    elif ri.sym.kind != skParam and isLastRead(ri, c):
       # Rule 3: `=sink`(x, z); wasMoved(z)
       var snk = genSink(c, dest.typ, dest, ri)
-      snk.add p(ri, c)
+      snk.add ri
       result = newTree(nkStmtList, snk, genMagicCall(ri, c, "wasMoved", mWasMoved))
-    elif isSinkParam(ri.sym):
-      result = genSink(c, dest.typ, dest, ri)
-      result.add destructiveMoveSink(ri, c)
     else:
       result = genCopy(c, dest.typ, dest, ri)
       result.add p(ri, c)
@@ -487,7 +583,8 @@ proc p(n: PNode; c: var Con): PNode =
           # move the variable declaration to the top of the frame:
           c.addTopVar v
           # make sure it's destroyed at the end of the proc:
-          c.destroys.add genDestroy(c, v.typ, v)
+          if not isUnpackedTuple(it[0].sym):
+            c.destroys.add genDestroy(c, v.typ, v)
           if ri.kind != nkEmpty:
             let r = moveOrCopy(v, ri, c)
             result.add r
@@ -534,12 +631,8 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
     echo "injecting into ", n
   var c: Con
   c.owner = owner
-  c.tmp = newSym(skTemp, getIdent(g.cache, ":d"), owner, n.info)
-  c.tmpObj = createObj(g, owner, n.info)
-  c.tmp.typ = c.tmpObj
   c.destroys = newNodeI(nkStmtList, n.info)
   c.topLevelVars = newNodeI(nkVarSection, n.info)
-  c.toDropBit = initTable[int, PSym]()
   c.graph = g
   c.emptyNode = newNodeI(nkEmpty, n.info)
   let cfg = constructCfg(owner, n)
@@ -554,10 +647,10 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
     let params = owner.typ.n
     for i in 1 ..< params.len:
       let param = params[i].sym
-      if param.typ.kind == tySink: registerDropBit(c, param)
+      if param.typ.kind == tySink and hasDestructor(param.typ): 
+        c.destroys.add genDestroy(c, param.typ.skipTypes({tyGenericInst, tyAlias, tySink}), params[i])
+
   let body = p(n, c)
-  if c.tmp.typ.n.len > 0:
-    c.addTopVar(newSymNode c.tmp)
   result = newNodeI(nkStmtList, n.info)
   if c.topLevelVars.len > 0:
     result.add c.topLevelVars
diff --git a/compiler/dfa.nim b/compiler/dfa.nim
index 4b624e93b..cd32d95d5 100644
--- a/compiler/dfa.nim
+++ b/compiler/dfa.nim
@@ -56,6 +56,7 @@ type
     inCall, inTryStmt: int
     blocks: seq[TBlock]
     tryStmtFixups: seq[TPosition]
+    owner: PSym
 
 proc debugInfo(info: TLineInfo): string =
   result = $info.line #info.toFilename & ":" & $info.line
@@ -259,12 +260,19 @@ proc genRaise(c: var Con; n: PNode) =
   else:
     c.code.add Instr(n: n, kind: goto, dest: high(int) - c.code.len)
 
+proc genImplicitReturn(c: var Con) =
+  if c.owner.kind in {skProc, skFunc, skMethod, skIterator, skConverter} and resultPos < c.owner.ast.len:
+    gen(c, c.owner.ast.sons[resultPos])
+
 proc genReturn(c: var Con; n: PNode) =
-  if n.sons[0].kind != nkEmpty: gen(c, n.sons[0])
+  if n.sons[0].kind != nkEmpty:
+    gen(c, n.sons[0])
+  else:
+    genImplicitReturn(c)
   c.code.add Instr(n: n, kind: goto, dest: high(int) - c.code.len)
 
 const
-  InterestingSyms = {skVar, skResult, skLet}
+  InterestingSyms = {skVar, skResult, skLet, skParam}
 
 proc genUse(c: var Con; n: PNode) =
   var n = n
@@ -461,11 +469,13 @@ proc dfa(code: seq[Instr]; conf: ConfigRef) =
 proc dataflowAnalysis*(s: PSym; body: PNode; conf: ConfigRef) =
   var c = Con(code: @[], blocks: @[])
   gen(c, body)
+  genImplicitReturn(c)
   when defined(useDfa) and defined(debugDfa): echoCfg(c.code)
   dfa(c.code, conf)
 
 proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph =
   ## constructs a control flow graph for ``body``.
-  var c = Con(code: @[], blocks: @[])
+  var c = Con(code: @[], blocks: @[], owner: s)
   gen(c, body)
+  genImplicitReturn(c)
   shallowCopy(result, c.code)
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index de2a9831d..67f4108e1 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -247,18 +247,30 @@ proc genComment(d: PDoc, n: PNode): string =
                                toLinenumber(n.info), toColumn(n.info),
                                dummyHasToc, d.options, d.conf), result)
 
-proc genRecComment(d: PDoc, n: PNode): Rope =
+proc genRecCommentAux(d: PDoc, n: PNode): Rope =
   if n == nil: return nil
   result = genComment(d, n).rope
   if result == nil:
-    if n.kind notin {nkEmpty..nkNilLit, nkEnumTy, nkTupleTy}:
+    if n.kind in {nkStmtList, nkStmtListExpr, nkTypeDef, nkConstDef,
+                  nkObjectTy, nkRefTy, nkPtrTy, nkAsgn, nkFastAsgn}:
+      # notin {nkEmpty..nkNilLit, nkEnumTy, nkTupleTy}:
       for i in countup(0, len(n)-1):
-        result = genRecComment(d, n.sons[i])
+        result = genRecCommentAux(d, n.sons[i])
         if result != nil: return
   else:
     when defined(nimNoNilSeqs): n.comment = ""
     else: n.comment = nil
 
+proc genRecComment(d: PDoc, n: PNode): Rope =
+  if n == nil: return nil
+  result = genComment(d, n).rope
+  if result == nil:
+    if n.kind in {nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef,
+                  nkMacroDef, nkTemplateDef, nkConverterDef}:
+      result = genRecCommentAux(d, n[bodyPos])
+    else:
+      result = genRecCommentAux(d, n)
+
 proc getPlainDocstring(n: PNode): string =
   ## Gets the plain text docstring of a node non destructively.
   ##
@@ -388,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)
@@ -429,27 +447,6 @@ proc getAllRunnableExamplesRec(d: PDoc; n, orig: PNode; dest: var Rope) =
 proc getAllRunnableExamples(d: PDoc; n: PNode; dest: var Rope) =
   getAllRunnableExamplesRec(d, n, n, dest)
 
-when false:
-  proc findDocComment(n: PNode): PNode =
-    if n == nil: return nil
-    if not isNil(n.comment) and startsWith(n.comment, "##"): return n
-    for i in countup(0, safeLen(n)-1):
-      result = findDocComment(n.sons[i])
-      if result != nil: return
-
-  proc extractDocComment*(s: PSym, d: PDoc): string =
-    let n = findDocComment(s.ast)
-    result = ""
-    if not n.isNil:
-      if not d.isNil:
-        var dummyHasToc: bool
-        renderRstToOut(d[], parseRst(n.comment, toFilename(d.conf, n.info),
-                                     toLinenumber(n.info), toColumn(n.info),
-                                     dummyHasToc, d.options + {roSkipPounds}),
-                       result)
-      else:
-        result = n.comment.substr(2).replace("\n##", "\n").strip
-
 proc isVisible(d: PDoc; n: PNode): bool =
   result = false
   if n.kind == nkPostfix:
@@ -739,7 +736,6 @@ proc exportSym(d: PDoc; s: PSym) =
             rope changeFileExt(external, "html")])
 
 proc generateDoc*(d: PDoc, n, orig: PNode) =
-  if orig.info.fileIndex != n.info.fileIndex: return
   case n.kind
   of nkCommentStmt: add(d.modDesc, genComment(d, n))
   of nkProcDef:
@@ -907,7 +903,7 @@ proc genOutFile(d: PDoc): Rope =
     setIndexTerm(d[], external, "", title)
   else:
     # Modules get an automatic title for the HTML, but no entry in the index.
-    title = "Module " & extractFilename(changeFileExt(d.filename, ""))
+    title = extractFilename(changeFileExt(d.filename, ""))
 
   let bodyname = if d.hasToc and not d.isPureRst: "doc.body_toc_group"
                  elif d.hasToc: "doc.body_toc"
diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim
index d6c630e79..0f9220102 100644
--- a/compiler/evaltempl.nim
+++ b/compiler/evaltempl.nim
@@ -17,6 +17,7 @@ type
   TemplCtx = object
     owner, genSymOwner: PSym
     instLines: bool   # use the instantiation lines numbers
+    isDeclarative: bool
     mapping: TIdTable # every gensym'ed symbol needs to be mapped to some
                       # new symbol
     config: ConfigRef
@@ -36,29 +37,51 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
   case templ.kind
   of nkSym:
     var s = templ.sym
-    if s.owner.id == c.owner.id:
+    if s.owner == nil or s.owner.id == c.owner.id:
       if s.kind == skParam and sfGenSym notin s.flags:
         handleParam actual.sons[s.position]
-      elif s.kind == skGenericParam or
-           s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam:
+      elif (s.owner != nil) and (s.kind == skGenericParam or
+           s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam):
         handleParam actual.sons[s.owner.typ.len + s.position - 1]
       else:
         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.owner = c.genSymOwner
+          x = copySym(s)
+          # sem'check needs to set the owner properly later, see bug #9476
+          x.owner = nil # c.genSymOwner
+          #if x.kind == skParam and x.owner.kind == skModule:
+          #  internalAssert c.config, false
           idTablePut(c.mapping, s, x)
         result.add newSymNode(x, if c.instLines: actual.info else: templ.info)
     else:
       result.add copyNode(c, templ, actual)
   of nkNone..nkIdent, nkType..nkNilLit: # atom
     result.add copyNode(c, templ, actual)
+  of nkCommentStmt:
+    # for the documentation generator we don't keep documentation comments
+    # in the AST that would confuse it (bug #9432), but only if we are not in a
+    # "declarative" context (bug #9235).
+    if c.isDeclarative:
+      var res = copyNode(c, templ, actual)
+      for i in countup(0, sonsLen(templ) - 1):
+        evalTemplateAux(templ.sons[i], actual, c, res)
+      result.add res
+    else:
+      result.add newNodeI(nkEmpty, templ.info)
   else:
+    var isDeclarative = false
+    if templ.kind in {nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef,
+                      nkMacroDef, nkTemplateDef, nkConverterDef, nkTypeSection,
+                      nkVarSection, nkLetSection, nkConstSection} and
+        not c.isDeclarative:
+      c.isDeclarative = true
+      isDeclarative = true
     var res = copyNode(c, templ, actual)
     for i in countup(0, sonsLen(templ) - 1):
       evalTemplateAux(templ.sons[i], actual, c, res)
     result.add res
+    if isDeclarative: c.isDeclarative = false
 
 const
   errWrongNumberOfArguments = "wrong number of arguments"
@@ -153,6 +176,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
   initIdTable(ctx.mapping)
 
   let body = tmpl.getBody
+  #echo "instantion of ", renderTree(body, {renderIds})
   if isAtom(body):
     result = newNodeI(nkPar, body.info)
     evalTemplateAux(body, args, ctx, result)
@@ -169,5 +193,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
       evalTemplateAux(body.sons[i], args, ctx, result)
   result.flags.incl nfFromTemplate
   result = wrapInComesFrom(n.info, tmpl, result)
+  #if ctx.debugActive:
+  #  echo "instantion of ", renderTree(result, {renderIds})
   dec(conf.evalTemplateCounter)
 
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index 69698ae09..2fe151a1c 100644
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -627,7 +627,8 @@ proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool =
       close(f)
 
 proc addExternalFileToCompile*(conf: ConfigRef; c: var Cfile) =
-  if optForceFullMake notin conf.globalOptions and not externalFileChanged(conf, c):
+  if optForceFullMake notin conf.globalOptions and fileExists(c.obj) and
+      not externalFileChanged(conf, c):
     c.flags.incl CfileFlag.Cached
   conf.toCompile.add(c)
 
@@ -762,6 +763,32 @@ proc execCmdsInParallel(conf: ConfigRef; cmds: seq[string]; prettyCb: proc (idx:
       rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" %
         cmds.join())
 
+proc linkViaResponseFile(conf: ConfigRef; cmd: string) =
+  # Extracting the linker.exe here is a bit hacky but the best solution
+  # given ``buildLib``'s design.
+  var i = 0
+  var last = 0
+  if cmd.len > 0 and cmd[0] == '"':
+    inc i
+    while i < cmd.len and cmd[i] != '"': inc i
+    last = i
+    inc i
+  else:
+    while i < cmd.len and cmd[i] != ' ': inc i
+    last = i
+  while i < cmd.len and cmd[i] == ' ': inc i
+  let linkerArgs = conf.projectName & "_" & "linkerArgs.txt"
+  let args = cmd.substr(i)
+  # GCC's response files don't support backslashes. Junk.
+  if conf.cCompiler == ccGcc:
+    writeFile(linkerArgs, args.replace('\\', '/'))
+  else:
+    writeFile(linkerArgs, args)
+  try:
+    execLinkCmd(conf, cmd.substr(0, last) & " @" & linkerArgs)
+  finally:
+    removeFile(linkerArgs)
+
 proc callCCompiler*(conf: ConfigRef; projectfile: AbsoluteFile) =
   var
     linkCmd: string
@@ -794,7 +821,13 @@ proc callCCompiler*(conf: ConfigRef; projectfile: AbsoluteFile) =
 
     linkCmd = getLinkCmd(conf, projectfile, objfiles)
     if optCompileOnly notin conf.globalOptions:
-      execLinkCmd(conf, linkCmd)
+      if defined(windows) and linkCmd.len > 8_000:
+        # Windows's command line limit is about 8K (don't laugh...) so C compilers on
+        # Windows support a feature where the command line can be passed via ``@linkcmd``
+        # to them.
+        linkViaResponseFile(conf, linkCmd)
+      else:
+        execLinkCmd(conf, linkCmd)
   else:
     linkCmd = ""
   if optGenScript in conf.globalOptions:
diff --git a/compiler/importer.nim b/compiler/importer.nim
index 60b7872fe..131b1ad8a 100644
--- a/compiler/importer.nim
+++ b/compiler/importer.nim
@@ -100,7 +100,7 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
     if s.kind != skModule:
       if s.kind != skEnumField:
         if s.kind notin ExportableSymKinds:
-          internalError(c.config, s.info, "importAllSymbols: " & $s.kind)
+          internalError(c.config, s.info, "importAllSymbols: " & $s.kind & " " & s.name.s)
         if exceptSet.isNil or s.name.id notin exceptSet:
           rawImportSymbol(c, s)
     s = nextIter(i, fromMod.tab)
diff --git a/compiler/incremental.nim b/compiler/incremental.nim
index 47637b3c1..f66a75efd 100644
--- a/compiler/incremental.nim
+++ b/compiler/incremental.nim
@@ -59,8 +59,8 @@ when nimIncremental:
     let id = row[0]
     let fullhash = hashFileCached(conf, fileIdx, AbsoluteFile fullpath)
     if id.len == 0:
-      result = int incr.db.insertID(sql"insert into filenames(fullpath, fullhash) values (?, ?)",
-        fullpath, fullhash)
+      result = int incr.db.insertID(sql"insert into filenames(nimid, fullpath, fullhash) values (?, ?, ?)",
+        int(fileIdx), fullpath, fullhash)
     else:
       if row[1] != fullhash:
         incr.db.exec(sql"update filenames set fullhash = ? where fullpath = ?", fullhash, fullpath)
@@ -102,6 +102,7 @@ when nimIncremental:
     db.exec(sql"""
       create table if not exists filenames(
         id integer primary key,
+        nimid integer not null,
         fullpath varchar(8000) not null,
         fullHash varchar(256) not null
       );
diff --git a/compiler/installer.ini b/compiler/installer.ini
index 212ec438b..63790d90f 100644
--- a/compiler/installer.ini
+++ b/compiler/installer.ini
@@ -49,11 +49,8 @@ Start: "doc/html/overview.html"
 
 
 [Other]
-Files: "readme.txt;copying.txt;install.txt"
-Files: "makefile"
+Files: "copying.txt"
 Files: "koch.nim"
-Files: "install_nimble.nims"
-Files: "install_tools.nims"
 
 Files: "icons/nim.ico"
 Files: "icons/nim.rc"
@@ -69,16 +66,9 @@ Files: "doc"
 Files: "doc/html"
 Files: "tools"
 Files: "nimpretty"
+Files: "testament"
 Files: "nimsuggest"
 Files: "nimsuggest/tests/*.nim"
-Files: "web/website.ini"
-Files: "web/ticker.html"
-Files: "web/*.nim"
-Files: "web/*.rst"
-Files: "web/*.csv"
-Files: "web/news/*.rst"
-Files: "bin/nimblepkg/*.nim"
-Files: "bin/nimblepkg/*.cfg"
 
 [Lib]
 Files: "lib"
@@ -86,13 +76,11 @@ Files: "lib"
 [Other]
 Files: "examples"
 Files: "dist/nimble"
-Files: "dist/nimsuggest"
 
 Files: "tests"
 
 [Windows]
 Files: "bin/nim.exe"
-Files: "bin/c2nim.exe"
 Files: "bin/nimgrep.exe"
 Files: "bin/nimsuggest.exe"
 Files: "bin/nimble.exe"
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 19bbde777..4d22c4224 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, tyProc} + 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..ddde1be31 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
@@ -407,11 +407,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
               obj.n[0].sym.id = -s.id
             else:
               addField(obj, s, c.graph.cache)
-      # but always return because the rest of the proc is only relevant when
-      # ow != owner:
-      return
     # direct or indirect dependency:
-    if (innerProc and s.typ.callConv == ccClosure) or interestingVar(s):
+    elif (innerProc and s.typ.callConv == ccClosure) or interestingVar(s):
       discard """
         proc outer() =
           var x: int
@@ -454,11 +451,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 +668,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 +680,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 +715,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/layouter.nim b/compiler/layouter.nim
index 9ddfbeabc..8605ade45 100644
--- a/compiler/layouter.nim
+++ b/compiler/layouter.nim
@@ -28,9 +28,9 @@ type
     config: ConfigRef
     fid: FileIndex
     lastTok: TTokType
-    inquote: bool
+    inquote, lastTokWasTerse: bool
     semicolons: SemicolonKind
-    col, lastLineNumber, lineSpan, indentLevel, indWidth: int
+    col, lastLineNumber, lineSpan, indentLevel, indWidth*: int
     keepIndents*: int
     doIndentMore*: int
     content: string
@@ -41,9 +41,10 @@ type
 proc openEmitter*(em: var Emitter, cache: IdentCache;
                   config: ConfigRef, fileIdx: FileIndex) =
   let fullPath = Absolutefile config.toFullPath(fileIdx)
-  em.indWidth = getIndentWidth(fileIdx, llStreamOpen(fullPath, fmRead),
-                               cache, config)
-  if em.indWidth == 0: em.indWidth = 2
+  if em.indWidth == 0:
+    em.indWidth = getIndentWidth(fileIdx, llStreamOpen(fullPath, fmRead),
+                                cache, config)
+    if em.indWidth == 0: em.indWidth = 2
   em.config = config
   em.fid = fileIdx
   em.lastTok = tkInvalid
@@ -55,9 +56,13 @@ proc openEmitter*(em: var Emitter, cache: IdentCache;
   em.lastLineNumber = 1
 
 proc closeEmitter*(em: var Emitter) =
+  if fileExists(em.config.outFile) and readFile(em.config.outFile.string) == em.content:
+    discard "do nothing, see #9499"
+    return
   var f = llStreamOpen(em.config.outFile, fmWrite)
   if f == nil:
     rawMessage(em.config, errGenerated, "cannot open file: " & em.config.outFile.string)
+    return
   f.llStreamWrite em.content
   llStreamClose(f)
 
@@ -107,15 +112,16 @@ proc softLinebreak(em: var Emitter, lit: string) =
       for i in 1..em.indentLevel+moreIndent(em): wr(" ")
     else:
       # search backwards for a good split position:
-      for a in em.altSplitPos:
+      for a in mitems(em.altSplitPos):
         if a > em.fixedUntil:
           var spaces = 0
           while a+spaces < em.content.len and em.content[a+spaces] == ' ':
             inc spaces
           if spaces > 0: delete(em.content, a, a+spaces-1)
-          let ws = "\L" & repeat(' ',em.indentLevel+moreIndent(em))
           em.col = em.content.len - a
+          let ws = "\L" & repeat(' ', em.indentLevel+moreIndent(em))
           em.content.insert(ws, a)
+          a = -1
           break
 
 proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
@@ -188,12 +194,13 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
       wr(" ")
     em.fixedUntil = em.content.high
 
+  var lastTokWasTerse = false
   case tok.tokType
   of tokKeywordLow..tokKeywordHigh:
     if endsInAlpha(em):
       wr(" ")
     elif not em.inquote and not endsInWhite(em) and
-        em.lastTok notin openPars:
+        em.lastTok notin openPars and not em.lastTokWasTerse:
       #and tok.tokType in oprSet
       wr(" ")
 
@@ -229,14 +236,19 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
      tkBracketDotRi,
      tkCurlyDotRi,
      tkParDotRi,
-     tkColonColon, tkDot:
+     tkColonColon:
+    wr(TokTypeToStr[tok.tokType])
+  of tkDot:
+    lastTokWasTerse = true
     wr(TokTypeToStr[tok.tokType])
   of tkEquals:
     if not em.inquote and not em.endsInWhite: wr(" ")
     wr(TokTypeToStr[tok.tokType])
     if not em.inquote: wr(" ")
   of tkOpr, tkDotDot:
-    if tok.strongSpaceA == 0 and tok.strongSpaceB == 0:
+    if (tok.strongSpaceA == 0 and tok.strongSpaceB == 0) or em.inquote:
+      # bug #9504: remember to not spacify a keyword:
+      lastTokWasTerse = true
       # if not surrounded by whitespace, don't produce any whitespace either:
       wr(tok.ident.s)
     else:
@@ -246,8 +258,8 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
         tok.strongSpaceB == 0 and tok.strongSpaceA > 0
 
       if not isUnary(tok):
-        wr(" ")
         rememberSplit(splitBinary)
+        wr(" ")
   of tkAccent:
     if not em.inquote and endsInAlpha(em): wr(" ")
     wr(TokTypeToStr[tok.tokType])
@@ -270,6 +282,7 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
     wr lit
 
   em.lastTok = tok.tokType
+  em.lastTokWasTerse = lastTokWasTerse
   em.lastLineNumber = tok.line + em.lineSpan
   em.lineSpan = 0
 
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index f1b51af32..635e6f08d 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -224,7 +224,7 @@ proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream;
                  cache: IdentCache; config: ConfigRef) =
   openBaseLexer(lex, inputstream)
   lex.fileIdx = fileidx
-  lex.indentAhead = - 1
+  lex.indentAhead = -1
   lex.currLineIndent = 0
   inc(lex.lineNumber, inputstream.lineOffset)
   lex.cache = cache
@@ -635,7 +635,10 @@ proc handleHexChar(L: var TLexer, xi: var int) =
     inc(L.bufpos)
   else:
     lexMessage(L, errGenerated,
-      "expected a hex digit, but found: " & L.buf[L.bufpos])
+      "expected a hex digit, but found: " & L.buf[L.bufpos] &
+        " ; maybe prepend with 0")
+    # Need to progress for `nim check`
+    inc(L.bufpos)
 
 proc handleDecChars(L: var TLexer, xi: var int) =
   while L.buf[L.bufpos] in {'0'..'9'}:
@@ -964,7 +967,7 @@ proc getPrecedence*(tok: TToken, strongSpaces: bool): int =
     of '?': result = 2
     else: considerAsgn(2)
   of tkDiv, tkMod, tkShl, tkShr: result = 9
-  of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5
+  of tkIn, tkNotin, tkIs, tkIsnot, tkOf, tkAs: result = 5
   of tkDotDot: result = 6
   of tkAnd: result = 4
   of tkOr, tkXor, tkPtr, tkRef: result = 3
@@ -1116,8 +1119,10 @@ proc skip(L: var TLexer, tok: var TToken) =
   tok.strongSpaceA = 0
   when defined(nimpretty):
     var hasComment = false
+    var commentIndent = L.currLineIndent
     tok.commentOffsetA = L.offsetBase + pos
     tok.commentOffsetB = tok.commentOffsetA
+    tok.line = -1
   while true:
     case buf[pos]
     of ' ':
@@ -1128,9 +1133,6 @@ proc skip(L: var TLexer, tok: var TToken) =
       inc(pos)
     of CR, LF:
       tokenEndPrevious(tok, pos)
-      when defined(nimpretty):
-        # we are not yet in a comment, so update the comment token's line information:
-        if not hasComment: inc tok.line
       pos = handleCRLF(L, pos)
       buf = L.buf
       var indent = 0
@@ -1139,13 +1141,19 @@ proc skip(L: var TLexer, tok: var TToken) =
           inc(pos)
           inc(indent)
         elif buf[pos] == '#' and buf[pos+1] == '[':
-          when defined(nimpretty): hasComment = true
+          when defined(nimpretty):
+            hasComment = true
+            if tok.line < 0:
+              tok.line = L.lineNumber
+              commentIndent = indent
           skipMultiLineComment(L, tok, pos+2, false)
           pos = L.bufpos
           buf = L.buf
         else:
           break
       tok.strongSpaceA = 0
+      when defined(nimpretty):
+        if buf[pos] == '#' and tok.line < 0: commentIndent = indent
       if buf[pos] > ' ' and (buf[pos] != '#' or buf[pos+1] == '#'):
         tok.indent = indent
         L.currLineIndent = indent
@@ -1153,7 +1161,11 @@ proc skip(L: var TLexer, tok: var TToken) =
     of '#':
       # do not skip documentation comment:
       if buf[pos+1] == '#': break
-      when defined(nimpretty): hasComment = true
+      when defined(nimpretty):
+        hasComment = true
+        if tok.line < 0:
+          tok.line = L.lineNumber
+
       if buf[pos+1] == '[':
         skipMultiLineComment(L, tok, pos+2, false)
         pos = L.bufpos
@@ -1174,6 +1186,7 @@ proc skip(L: var TLexer, tok: var TToken) =
     if hasComment:
       tok.commentOffsetB = L.offsetBase + pos - 1
       tok.tokType = tkComment
+      tok.indent = commentIndent
     if gIndentationWidth <= 0:
       gIndentationWidth = tok.indent
 
diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim
index cd160313c..b1ecf779e 100644
--- a/compiler/lineinfos.nim
+++ b/compiler/lineinfos.nim
@@ -41,7 +41,7 @@ type
     hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
     hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
     hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
-    hintConditionAlwaysTrue, hintName, hintPattern,
+    hintConditionAlwaysTrue, hintConditionAlwaysFalse, hintName, hintPattern,
     hintExecuting, hintLinking, hintDependency,
     hintSource, hintPerformance, hintStackTrace, hintGCStats,
     hintGlobalVar,
@@ -107,6 +107,7 @@ const
     hintConf: "used config file '$1'",
     hintPath: "added path: '$1'",
     hintConditionAlwaysTrue: "condition is always true: '$1'",
+    hintConditionAlwaysFalse: "condition is always false: '$1'",
     hintName: "name should be: '$1'",
     hintPattern: "$1",
     hintExecuting: "$1",
@@ -140,7 +141,7 @@ const
     "Success", "SuccessX", "CC", "LineTooLong",
     "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
     "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
-    "Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency",
+    "Path", "CondTrue", "CondFalse", "Name", "Pattern", "Exec", "Link", "Dependency",
     "Source", "Performance", "StackTrace", "GCStats", "GlobalVar",
     "User", "UserRaw", "ExtendedContext",
   ]
diff --git a/compiler/linter.nim b/compiler/linter.nim
index 0b69db8cb..a881f2711 100644
--- a/compiler/linter.nim
+++ b/compiler/linter.nim
@@ -7,8 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-## This module implements the code "prettifier". This is part of the toolchain
-## to convert Nim code into a consistent style.
+## This module implements the style checker.
 
 import
   strutils, os, intsets, strtabs
@@ -23,9 +22,6 @@ proc identLen*(line: string, start: int): int =
   while start+result < line.len and line[start+result] in Letters:
     inc result
 
-when false:
-  import prettybase
-
 type
   StyleCheck* {.pure.} = enum None, Warn, Auto
 
@@ -71,9 +67,9 @@ proc beautifyName(s: string, k: TSymKind): string =
     if s =~ ["int", "uint", "cint", "cuint", "clong", "cstring", "string",
              "char", "byte", "bool", "openArray", "seq", "array", "void",
              "pointer", "float", "csize", "cdouble", "cchar", "cschar",
-             "cshort", "cu", "nil", "expr", "stmt", "typedesc", "auto", "any",
-             "range", "openarray", "varargs", "set", "cfloat"
-             ]:
+             "cshort", "cu", "nil", "typedesc", "auto", "any",
+             "range", "openarray", "varargs", "set", "cfloat", "ref", "ptr",
+             "untyped", "typed", "static", "sink", "lent", "type"]:
       result.add s[i]
     else:
       result.add toUpperAscii(s[i])
@@ -122,6 +118,12 @@ proc replaceInFile(conf: ConfigRef; info: TLineInfo; newName: string) =
     system.shallowCopy(conf.m.fileInfos[info.fileIndex.int].lines[info.line.int-1], x)
     conf.m.fileInfos[info.fileIndex.int].dirty = true
 
+proc lintReport(conf: ConfigRef; info: TLineInfo, beau: string) =
+  if optStyleError in conf.globalOptions:
+    localError(conf, info, "name should be: '$1'" % beau)
+  else:
+    message(conf, info, hintName, beau)
+
 proc checkStyle(conf: ConfigRef; cache: IdentCache; info: TLineInfo, s: string, k: TSymKind; sym: PSym) =
   let beau = beautifyName(s, k)
   if s != beau:
@@ -129,7 +131,7 @@ proc checkStyle(conf: ConfigRef; cache: IdentCache; info: TLineInfo, s: string,
       sym.name = getIdent(cache, beau)
       replaceInFile(conf, info, beau)
     else:
-      message(conf, info, hintName, beau)
+      lintReport(conf, info, beau)
 
 proc styleCheckDefImpl(conf: ConfigRef; cache: IdentCache; info: TLineInfo; s: PSym; k: TSymKind) =
   # operators stay as they are:
@@ -142,12 +144,14 @@ proc nep1CheckDefImpl(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) =
   # operators stay as they are:
   if k in {skResult, skTemp} or s.name.s[0] notin Letters: return
   if k in {skType, skGenericParam} and sfAnon in s.flags: return
+  if s.typ != nil and s.typ.kind == tyTypeDesc: return
+  if {sfImportc, sfExportc} * s.flags != {}: return
   let beau = beautifyName(s.name.s, k)
   if s.name.s != beau:
-    message(conf, info, hintName, beau)
+    lintReport(conf, info, beau)
 
 template styleCheckDef*(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) =
-  if optCheckNep1 in conf.globalOptions:
+  if {optStyleHint, optStyleError} * conf.globalOptions != {}:
     nep1CheckDefImpl(conf, info, s, k)
   when defined(nimfix):
     if gStyleCheck != StyleCheck.None: styleCheckDefImpl(conf, cache, info, s, k)
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index d2e7fdcfa..db03ac2e0 100644
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -168,8 +168,8 @@ 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:
-      if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}:
+    elif {sfUsed, sfExported} * s.flags == {}:
+      if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam, skEnumField}:
         # XXX: implicit type params are currently skTypes
         # maybe they can be made skGenericParam as well.
         if s.typ != nil and tfImplicitTypeParam notin s.typ.flags and
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/main.nim b/compiler/main.nim
index 6c8b0343e..4e28ed483 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -15,12 +15,15 @@ when not defined(nimcore):
 import
   llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs,
   os, condsyms, times,
-  wordrecg, sem, semdata, idents, passes, docgen, extccomp,
-  cgen, jsgen, json, nversion,
+  wordrecg, sem, semdata, idents, passes, extccomp,
+  cgen, json, nversion,
   platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
-  docgen2, parser, modules, ccgutils, sigmatch, ropes,
+  parser, modules, ccgutils, sigmatch, ropes,
   modulegraphs, tables, rod, lineinfos, pathutils
 
+when not defined(leanCompiler):
+  import jsgen, docgen, docgen2
+
 from magicsys import resetSysTypes
 
 proc codegenPass(g: ModuleGraph) =
@@ -57,13 +60,14 @@ proc commandCheck(graph: ModuleGraph) =
   semanticPasses(graph)  # use an empty backend for semantic checking only
   compileProject(graph)
 
-proc commandDoc2(graph: ModuleGraph; json: bool) =
-  graph.config.errorMax = high(int)  # do not stop after first error
-  semanticPasses(graph)
-  if json: registerPass(graph, docgen2JsonPass)
-  else: registerPass(graph, docgen2Pass)
-  compileProject(graph)
-  finishDoc2Pass(graph.config.projectName)
+when not defined(leanCompiler):
+  proc commandDoc2(graph: ModuleGraph; json: bool) =
+    graph.config.errorMax = high(int)  # do not stop after first error
+    semanticPasses(graph)
+    if json: registerPass(graph, docgen2JsonPass)
+    else: registerPass(graph, docgen2Pass)
+    compileProject(graph)
+    finishDoc2Pass(graph.config.projectName)
 
 proc commandCompileToC(graph: ModuleGraph) =
   let conf = graph.config
@@ -84,15 +88,16 @@ proc commandJsonScript(graph: ModuleGraph) =
   let proj = changeFileExt(graph.config.projectFull, "")
   extccomp.runJsonBuildInstructions(graph.config, proj)
 
-proc commandCompileToJS(graph: ModuleGraph) =
-  #incl(gGlobalOptions, optSafeCode)
-  setTarget(graph.config.target, osJS, cpuJS)
-  #initDefines()
-  defineSymbol(graph.config.symbols, "ecmascript") # For backward compatibility
-  defineSymbol(graph.config.symbols, "js")
-  semanticPasses(graph)
-  registerPass(graph, JSgenPass)
-  compileProject(graph)
+when not defined(leanCompiler):
+  proc commandCompileToJS(graph: ModuleGraph) =
+    #incl(gGlobalOptions, optSafeCode)
+    setTarget(graph.config.target, osJS, cpuJS)
+    #initDefines()
+    defineSymbol(graph.config.symbols, "ecmascript") # For backward compatibility
+    defineSymbol(graph.config.symbols, "js")
+    semanticPasses(graph)
+    registerPass(graph, JSgenPass)
+    compileProject(graph)
 
 proc interactivePasses(graph: ModuleGraph) =
   initDefines(graph.config.symbols)
@@ -177,49 +182,76 @@ proc mainCommand*(graph: ModuleGraph) =
     else:
       rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc")
   of "js", "compiletojs":
-    conf.cmd = cmdCompileToJS
-    commandCompileToJS(graph)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with JS code generator"
+    else:
+      conf.cmd = cmdCompileToJS
+      commandCompileToJS(graph)
   of "doc0":
-    wantMainModule(conf)
-    conf.cmd = cmdDoc
-    loadConfigs(DocConfig, cache, conf)
-    commandDoc(cache, conf)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      wantMainModule(conf)
+      conf.cmd = cmdDoc
+      loadConfigs(DocConfig, cache, conf)
+      commandDoc(cache, conf)
   of "doc2", "doc":
-    conf.cmd = cmdDoc
-    loadConfigs(DocConfig, cache, conf)
-    defineSymbol(conf.symbols, "nimdoc")
-    commandDoc2(graph, false)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      conf.cmd = cmdDoc
+      loadConfigs(DocConfig, cache, conf)
+      defineSymbol(conf.symbols, "nimdoc")
+      commandDoc2(graph, false)
   of "rst2html":
-    conf.cmd = cmdRst2html
-    loadConfigs(DocConfig, cache, conf)
-    commandRst2Html(cache, conf)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      conf.cmd = cmdRst2html
+      loadConfigs(DocConfig, cache, conf)
+      commandRst2Html(cache, conf)
   of "rst2tex":
-    conf.cmd = cmdRst2tex
-    loadConfigs(DocTexConfig, cache, conf)
-    commandRst2TeX(cache, conf)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      conf.cmd = cmdRst2tex
+      loadConfigs(DocTexConfig, cache, conf)
+      commandRst2TeX(cache, conf)
   of "jsondoc0":
-    wantMainModule(conf)
-    conf.cmd = cmdDoc
-    loadConfigs(DocConfig, cache, conf)
-    wantMainModule(conf)
-    defineSymbol(conf.symbols, "nimdoc")
-    commandJson(cache, conf)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      wantMainModule(conf)
+      conf.cmd = cmdDoc
+      loadConfigs(DocConfig, cache, conf)
+      wantMainModule(conf)
+      defineSymbol(conf.symbols, "nimdoc")
+      commandJson(cache, conf)
   of "jsondoc2", "jsondoc":
-    conf.cmd = cmdDoc
-    loadConfigs(DocConfig, cache, conf)
-    wantMainModule(conf)
-    defineSymbol(conf.symbols, "nimdoc")
-    commandDoc2(graph, true)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      conf.cmd = cmdDoc
+      loadConfigs(DocConfig, cache, conf)
+      wantMainModule(conf)
+      defineSymbol(conf.symbols, "nimdoc")
+      commandDoc2(graph, true)
   of "ctags":
-    wantMainModule(conf)
-    conf.cmd = cmdDoc
-    loadConfigs(DocConfig, cache, conf)
-    defineSymbol(conf.symbols, "nimdoc")
-    commandTags(cache, conf)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      wantMainModule(conf)
+      conf.cmd = cmdDoc
+      loadConfigs(DocConfig, cache, conf)
+      defineSymbol(conf.symbols, "nimdoc")
+      commandTags(cache, conf)
   of "buildindex":
-    conf.cmd = cmdDoc
-    loadConfigs(DocConfig, cache, conf)
-    commandBuildIndex(cache, conf)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      conf.cmd = cmdDoc
+      loadConfigs(DocConfig, cache, conf)
+      commandBuildIndex(cache, conf)
   of "gendepend":
     conf.cmd = cmdGenDepend
     commandGenDepend(graph)
@@ -234,11 +266,23 @@ proc mainCommand*(graph: ModuleGraph) =
       var libpaths = newJArray()
       for dir in conf.searchPaths: libpaths.elems.add(%dir.string)
 
-      var dumpdata = % [
+      var hints = newJObject() # consider factoring with `listHints`
+      for a in hintMin..hintMax:
+        let key = lineinfos.HintsToStr[ord(a) - ord(hintMin)]
+        hints[key] = %(a in conf.notes)
+      var warnings = newJObject()
+      for a in warnMin..warnMax:
+        let key = lineinfos.WarningsToStr[ord(a) - ord(warnMin)]
+        warnings[key] = %(a in conf.notes)
+
+      var dumpdata = %[
         (key: "version", val: %VersionAsString),
         (key: "project_path", val: %conf.projectFull.string),
         (key: "defined_symbols", val: definedSymbols),
-        (key: "lib_paths", val: libpaths)
+        (key: "lib_paths", val: %libpaths),
+        (key: "out", val: %conf.outFile.string),
+        (key: "hints", val: hints),
+        (key: "warnings", val: warnings),
       ]
 
       msgWriteln(conf, $dumpdata, {msgStdout, msgSkipHook})
@@ -265,6 +309,7 @@ proc mainCommand*(graph: ModuleGraph) =
     conf.cmd = cmdInteractive
     commandInteractive(graph)
   of "e":
+    incl conf.globalOptions, optWasNimscript
     commandEval(graph, mainCommandArg(conf))
   of "nop", "help":
     # prevent the "success" message:
diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim
index 16704fab6..63fa597ff 100644
--- a/compiler/modulegraphs.nim
+++ b/compiler/modulegraphs.nim
@@ -47,7 +47,7 @@ type
     doStopCompile*: proc(): bool {.closure.}
     usageSym*: PSym # for nimsuggest
     owners*: seq[PSym]
-    methods*: seq[tuple[methods: TSymSeq, dispatcher: PSym]] # needs serialization!
+    methods*: seq[tuple[methods: seq[PSym], dispatcher: PSym]] # needs serialization!
     systemModule*: PSym
     sysTypes*: array[TTypeKind, PType]
     compilerprocs*: TStrTable
@@ -63,6 +63,9 @@ type
     cacheCounters*: Table[string, BiggestInt]
     cacheTables*: Table[string, BTree[string, PNode]]
     passes*: seq[TPass]
+    onDefinition*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
+    onDefinitionResolveForward*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
+    onUsage*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
 
   TPassContext* = object of RootObj # the pass's context
   PPassContext* = ref TPassContext
@@ -78,6 +81,32 @@ type
 
 proc hash*(x: FileIndex): Hash {.borrow.}
 
+when defined(nimfind):
+  template onUse*(info: TLineInfo; s: PSym) =
+    when compiles(c.c.graph):
+      if c.c.graph.onUsage != nil: c.c.graph.onUsage(c.c.graph, s, info)
+    else:
+      if c.graph.onUsage != nil: c.graph.onUsage(c.graph, s, info)
+
+  template onDef*(info: TLineInfo; s: PSym) =
+    when compiles(c.c.graph):
+      if c.c.graph.onDefinition != nil: c.c.graph.onDefinition(c.c.graph, s, info)
+    else:
+      if c.graph.onDefinition != nil: c.graph.onDefinition(c.graph, s, info)
+
+  template onDefResolveForward*(info: TLineInfo; s: PSym) =
+    when compiles(c.c.graph):
+      if c.c.graph.onDefinitionResolveForward != nil:
+        c.c.graph.onDefinitionResolveForward(c.c.graph, s, info)
+    else:
+      if c.graph.onDefinitionResolveForward != nil:
+        c.graph.onDefinitionResolveForward(c.graph, s, info)
+
+else:
+  template onUse*(info: TLineInfo; s: PSym) = discard
+  template onDef*(info: TLineInfo; s: PSym) = discard
+  template onDefResolveForward*(info: TLineInfo; s: PSym) = discard
+
 proc stopCompile*(g: ModuleGraph): bool {.inline.} =
   result = g.doStopCompile != nil and g.doStopCompile()
 
diff --git a/compiler/modules.nim b/compiler/modules.nim
index 75e95e453..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,15 +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))
+    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):
@@ -128,6 +136,7 @@ proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIDX) =
 proc makeModule*(graph: ModuleGraph; filename: AbsoluteFile): PSym =
   result = graph.newModule(fileInfoIdx(graph.config, filename))
   result.id = getID()
+  registerModule(graph, result)
 
 proc makeModule*(graph: ModuleGraph; filename: string): PSym =
   result = makeModule(graph, AbsoluteFile filename)
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index dee1081f9..7e6b67cbe 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -190,10 +190,13 @@ template toFullPath*(conf: ConfigRef; info: TLineInfo): string =
 proc toMsgFilename*(conf: ConfigRef; info: TLineInfo): string =
   if info.fileIndex.int32 < 0:
     result = "???"
-  elif optListFullPaths in conf.globalOptions:
-    result = conf.m.fileInfos[info.fileIndex.int32].fullPath.string
+    return
+  let absPath = conf.m.fileInfos[info.fileIndex.int32].fullPath.string
+  let relPath = conf.m.fileInfos[info.fileIndex.int32].projPath.string
+  if optListFullPaths in conf.globalOptions:
+    result = absPath
   else:
-    result = conf.m.fileInfos[info.fileIndex.int32].projPath.string
+    result = if absPath.len < relPath.len: absPath else: relPath
 
 proc toLinenumber*(info: TLineInfo): int {.inline.} =
   result = int info.line
diff --git a/compiler/nim.nim b/compiler/nim.nim
index 5f3347255..cbd9d6f39 100644
--- a/compiler/nim.nim
+++ b/compiler/nim.nim
@@ -9,14 +9,14 @@
 
 when defined(gcc) and defined(windows):
   when defined(x86):
-    {.link: "icons/nim.res".}
+    {.link: "../icons/nim.res".}
   else:
-    {.link: "icons/nim_icon.o".}
+    {.link: "../icons/nim_icon.o".}
 
 when defined(amd64) and defined(windows) and defined(vcc):
-  {.link: "icons/nim-amd64-windows-vcc.res".}
+  {.link: "../icons/nim-amd64-windows-vcc.res".}
 when defined(i386) and defined(windows) and defined(vcc):
-  {.link: "icons/nim-i386-windows-vcc.res".}
+  {.link: "../icons/nim-i386-windows-vcc.res".}
 
 import
   commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
@@ -54,7 +54,8 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
     of cmdArgument:
       if processArgument(pass, p, argsCount, config): break
   if pass == passCmd2:
-    if optRun notin config.globalOptions and config.arguments.len > 0 and config.command.normalize != "run":
+    if {optRun, optWasNimscript} * config.globalOptions == {} and
+        config.arguments.len > 0 and config.command.normalize notin ["run", "e"]:
       rawMessage(config, errGenerated, errArgsNeedRunOption)
 
 proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
diff --git a/compiler/options.nim b/compiler/options.nim
index 4b7d664f4..80d665d62 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -45,7 +45,7 @@ type                          # please make sure we have under 32 options
   TOptions* = set[TOption]
   TGlobalOption* = enum       # **keep binary compatible**
     gloptNone, optForceFullMake,
-    optDeadCodeElimUnused,    # deprecated, always on
+    optWasNimscript,
     optListCmd, optCompileOnly, optNoLinking,
     optCDebug,                # turn on debugging information
     optGenDynLib,             # generate a dynamic library
@@ -54,7 +54,8 @@ type                          # please make sure we have under 32 options
     optGenScript,             # generate a script file to compile the *.c files
     optGenMapping,            # generate a mapping file
     optRun,                   # run the compiled project
-    optCheckNep1,             # check that the names adhere to NEP-1
+    optStyleHint,             # check that the names adhere to NEP-1
+    optStyleError,            # enforce that the names adhere to NEP-1
     optSkipSystemConfigFile,  # skip the system's cfg/nims config file
     optSkipProjConfigFile,    # skip the project's cfg/nims config file
     optSkipUserConfigFile,    # skip the users's cfg/nims config file
@@ -73,6 +74,7 @@ type                          # please make sure we have under 32 options
     optIdeTerse               # idetools: use terse descriptions
     optNoCppExceptions        # use C exception handling even with CPP
     optExcessiveStackTrace    # fully qualified module filenames
+    optShowAllMismatches      # show all overloading resolution candidates
     optWholeProject           # for 'doc2': output any dependency
     optMixedMode              # true if some module triggered C++ codegen
     optListFullPaths
@@ -400,7 +402,8 @@ proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in {cmdDoc,
 proc usesWriteBarrier*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc
 
 template compilationCachePresent*(conf: ConfigRef): untyped =
-  conf.symbolFiles in {v2Sf, writeOnlySf}
+  false
+#  conf.symbolFiles in {v2Sf, writeOnlySf}
 
 template optPreserveOrigSource*(conf: ConfigRef): untyped =
   optEmbedOrigSrc in conf.globalOptions
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 61736c923..54b360a24 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -37,8 +37,7 @@ type
   TParser* = object            # A TParser object represents a file that
                                # is being parsed
     currInd: int               # current indentation level
-    firstTok, strongSpaces: bool # Has the first token been read?
-                                 # Is strongSpaces on?
+    firstTok: bool             # Has the first token been read?
     hasProgress: bool          # some while loop requires progress ensurance
     lex*: TLexer               # The lexer that is used for parsing
     tok*: TToken               # The current token
@@ -46,7 +45,7 @@ type
     inSemiStmtList*: int
     emptyNode: PNode
     when defined(nimpretty2):
-      em: Emitter
+      em*: Emitter
 
   SymbolMode = enum
     smNormal, smAllowNil, smAfterDot
@@ -102,8 +101,7 @@ proc getTok(p: var TParser) =
       emitTok(p.em, p.lex, p.tok)
 
 proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream,
-                 cache: IdentCache; config: ConfigRef;
-                 strongSpaces=false) =
+                 cache: IdentCache; config: ConfigRef) =
   ## Open a parser, using the given arguments to set up its internal state.
   ##
   initToken(p.tok)
@@ -112,13 +110,11 @@ proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream,
     openEmitter(p.em, cache, config, fileIdx)
   getTok(p)                   # read the first token
   p.firstTok = true
-  p.strongSpaces = strongSpaces
   p.emptyNode = newNode(nkEmpty)
 
 proc openParser*(p: var TParser, filename: AbsoluteFile, inputStream: PLLStream,
-                 cache: IdentCache; config: ConfigRef;
-                 strongSpaces=false) =
-  openParser(p, fileInfoIdx(config, filename), inputStream, cache, config, strongSpaces)
+                 cache: IdentCache; config: ConfigRef) =
+  openParser(p, fileInfoIdx(config, filename), inputStream, cache, config)
 
 proc closeParser(p: var TParser) =
   ## Close a parser, freeing up its resources.
@@ -286,7 +282,7 @@ proc checkBinary(p: TParser) {.inline.} =
 #|
 #| prefixOperator = operator
 #|
-#| optInd = COMMENT?
+#| optInd = COMMENT? IND?
 #| optPar = (IND{>} | IND{=})?
 #|
 #| simpleExpr = arrowExpr (OP0 optInd arrowExpr)* pragma?
@@ -602,7 +598,7 @@ proc identOrLiteral(p: var TParser, mode: TPrimaryMode): PNode =
   #| tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')'
   #| arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']'
   case p.tok.tokType
-  of tkSymbol, tkBuiltInMagics:
+  of tkSymbol, tkBuiltInMagics, tkOut:
     result = newIdentNodeP(p.tok.ident, p)
     getTok(p)
     result = parseGStrLit(p, result)
@@ -706,8 +702,11 @@ proc namedParams(p: var TParser, callee: PNode,
   # progress guaranteed
   exprColonEqExprListAux(p, endTok, result)
 
-proc commandParam(p: var TParser, isFirstParam: var bool): PNode =
-  result = parseExpr(p)
+proc commandParam(p: var TParser, isFirstParam: var bool; mode: TPrimaryMode): PNode =
+  if mode == pmTypeDesc:
+    result = simpleExpr(p, mode)
+  else:
+    result = parseExpr(p)
   if p.tok.tokType == tkDo:
     result = postExprBlocks(p, result)
   elif p.tok.tokType == tkEquals and not isFirstParam:
@@ -780,7 +779,7 @@ proc primarySuffix(p: var TParser, r: PNode,
         when true:
           # progress NOT guaranteed
           p.hasProgress = false
-          addSon result, commandParam(p, isFirstParam)
+          addSon result, commandParam(p, isFirstParam, mode)
           if not p.hasProgress: break
         else:
           while p.tok.tokType != tkEof:
@@ -798,7 +797,7 @@ proc parseOperators(p: var TParser, headNode: PNode,
                     limit: int, mode: TPrimaryMode): PNode =
   result = headNode
   # expand while operators have priorities higher than 'limit'
-  var opPrec = getPrecedence(p.tok, p.strongSpaces)
+  var opPrec = getPrecedence(p.tok, false)
   let modeB = if mode == pmTypeDef: pmTypeDesc else: mode
   # the operator itself must not start on a new line:
   # progress guaranteed
@@ -815,7 +814,7 @@ proc parseOperators(p: var TParser, headNode: PNode,
     addSon(a, result)
     addSon(a, b)
     result = a
-    opPrec = getPrecedence(p.tok, p.strongSpaces)
+    opPrec = getPrecedence(p.tok, false)
 
 proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
   result = primary(p, mode)
@@ -1246,7 +1245,6 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
     optInd(p, result)
     addSon(result, primary(p, pmNormal))
   of tkVar: result = parseTypeDescKAux(p, nkVarTy, mode)
-  of tkOut: result = parseTypeDescKAux(p, nkVarTy, mode)
   of tkRef: result = parseTypeDescKAux(p, nkRefTy, mode)
   of tkPtr: result = parseTypeDescKAux(p, nkPtrTy, mode)
   of tkDistinct: result = parseTypeDescKAux(p, nkDistinctTy, mode)
@@ -1256,14 +1254,29 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
     if mode != pmSkipSuffix:
       result = primarySuffix(p, result, baseInd, mode)
 
+proc binaryNot(p: var TParser; a: PNode): PNode =
+  if p.tok.tokType == tkNot:
+    let notOpr = newIdentNodeP(p.tok.ident, p)
+    getTok(p)
+    optInd(p, notOpr)
+    let b = parseExpr(p)
+    result = newNodeP(nkInfix, p)
+    result.add notOpr
+    result.add a
+    result.add b
+  else:
+    result = a
+
 proc parseTypeDesc(p: var TParser): PNode =
-  #| typeDesc = simpleExpr
+  #| typeDesc = simpleExpr ('not' expr)?
   result = simpleExpr(p, pmTypeDesc)
+  result = binaryNot(p, result)
 
 proc parseTypeDefAux(p: var TParser): PNode =
-  #| typeDefAux = simpleExpr
+  #| typeDefAux = simpleExpr ('not' expr)?
   #|            | 'concept' typeClass
   result = simpleExpr(p, pmTypeDef)
+  result = binaryNot(p, result)
 
 proc makeCall(n: PNode): PNode =
   ## Creates a call if the given node isn't already a call.
@@ -1371,12 +1384,12 @@ proc parseExprStmt(p: var TParser): PNode =
       while true:
         getTok(p)
         optInd(p, result)
-        addSon(result, commandParam(p, isFirstParam))
+        addSon(result, commandParam(p, isFirstParam, pmNormal))
         if p.tok.tokType != tkComma: break
     elif p.tok.indent < 0 and isExprStart(p):
       result = newNode(nkCommand, a.info, @[a])
       while true:
-        addSon(result, commandParam(p, isFirstParam))
+        addSon(result, commandParam(p, isFirstParam, pmNormal))
         if p.tok.tokType != tkComma: break
         getTok(p)
         optInd(p, result)
@@ -2237,10 +2250,8 @@ proc parseString*(s: string; cache: IdentCache; config: ConfigRef;
   stream.lineOffset = line
 
   var parser: TParser
-  # XXX for now the builtin 'parseStmt/Expr' functions do not know about strong
-  # spaces...
   parser.lex.errorHandler = errorHandler
-  openParser(parser, AbsoluteFile filename, stream, cache, config, false)
+  openParser(parser, AbsoluteFile filename, stream, cache, config)
 
   result = parser.parseAll
   closeParser(parser)
diff --git a/compiler/pathutils.nim b/compiler/pathutils.nim
index 03fcfe07e..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]] == '.'
 
@@ -99,24 +82,26 @@ proc isDotDot(x: string; bounds: (int, int)): bool =
 proc isSlash(x: string; bounds: (int, int)): bool =
   bounds[1] == bounds[0] and x[bounds[0]] in {DirSep, AltSep}
 
+const canonDirSep = when isMainModule: '/' else: DirSep
+
 proc canon(x: string; result: var string; state: var int) =
   # state: 0th bit set if isAbsolute path. Other bits count
   # the number of path components.
   for b in dirs(x):
     if (state shr 1 == 0) and isSlash(x, b):
-      result.add DirSep
+      result.add canonDirSep
       state = state or 1
     elif result.len > (state and 1) and isDotDot(x, b):
       var d = result.len
       # f/..
-      while d > (state and 1) and result[d-1] != DirSep:
+      while (d-1) > (state and 1) and result[d-1] notin {DirSep, AltSep}:
         dec d
       if d > 0: setLen(result, d-1)
     elif isDot(x, b):
       discard "discard the dot"
     elif b[1] >= b[0]:
-      if result.len > 0 and result[^1] != DirSep:
-        result.add DirSep
+      if result.len > 0 and result[^1] notin {DirSep, AltSep}:
+        result.add canonDirSep
       result.add substr(x, b[0], b[1])
     inc state, 2
 
@@ -133,7 +118,7 @@ when FileSystemCaseSensitive:
 else:
   template `!=?`(a, b: char): bool = a != b
 
-proc relativeTo(full, base: string; sep = DirSep): string =
+proc relativeTo(full, base: string; sep = canonDirSep): string =
   if full.len == 0: return ""
   var f, b: PathIter
   var ff = (0, -1)
@@ -207,7 +192,7 @@ when true:
     canon(f.string, result.string, state)
 
   proc relativeTo*(fullPath: AbsoluteFile, baseFilename: AbsoluteDir;
-                   sep = DirSep): RelativeFile =
+                   sep = canonDirSep): RelativeFile =
     RelativeFile(relativeTo(fullPath.string, baseFilename.string, sep))
 
   proc toAbsolute*(file: string; base: AbsoluteDir): AbsoluteFile =
@@ -222,7 +207,7 @@ when true:
 
   proc writeFile*(x: AbsoluteFile; content: string) {.borrow.}
 
-when isMainModule and defined(posix):
+when isMainModule:
   doAssert canon"/foo/../bar" == "/bar"
   doAssert canon"foo/../bar" == "bar"
 
@@ -257,4 +242,4 @@ when isMainModule and defined(posix):
 
 when isMainModule and defined(windows):
   let nasty = string(AbsoluteDir(r"C:\Users\rumpf\projects\nim\tests\nimble\nimbleDir\linkedPkgs\pkgB-#head\../../simplePkgs/pkgB-#head/") / RelativeFile"pkgA/module.nim")
-  doAssert nasty == r"C:\Users\rumpf\projects\nim\tests\nimble\nimbleDir\simplePkgs\pkgB-#head\pkgA\module.nim"
+  doAssert nasty.replace('/', '\\') == r"C:\Users\rumpf\projects\nim\tests\nimble\nimbleDir\simplePkgs\pkgB-#head\pkgA\module.nim"
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index c69da1813..f67e74f11 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)
@@ -949,10 +950,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
         recordPragma(c, it, "warning", s)
         message(c.config, it.info, warnUser, s)
       of wError:
-        if sym != nil and (sym.isRoutine or sym.kind == skType):
+        if sym != nil and (sym.isRoutine or sym.kind == skType) and wUsed in validPragmas:
           # This is subtle but correct: the error *statement* is only
-          # allowed for top level statements. Seems to be easier than
-          # distinguishing properly between
+          # allowed when 'wUsed' is not in validPragmas. Here this is the easiest way to
+          # distinguish properly between
           # ``proc p() {.error}`` and ``proc p() = {.error: "msg".}``
           if it.kind in nkPragmaCallKinds: discard getStrLitNode(c, it)
           incl(sym.flags, sfError)
@@ -1019,8 +1020,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
         else: incl(sym.typ.flags, tfIncompleteStruct)
       of wUnchecked:
         noVal(c, it)
-        if sym.typ == nil: invalidPragma(c, it)
-        else: incl(sym.typ.flags, tfUncheckedArray)
+        if sym.typ == nil or sym.typ.kind notin {tyArray, tyUncheckedArray}:
+          invalidPragma(c, it)
+        else:
+          sym.typ.kind = tyUncheckedArray
       of wUnion:
         noVal(c, it)
         if sym.typ == nil: invalidPragma(c, it)
@@ -1060,6 +1063,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
           invalidPragma(c, it)
         else:
           sym.bitsize = expectIntLit(c, it)
+          if sym.bitsize <= 0:
+            localError(c.config, it.info, "bitsize needs to be positive")
       of wGuard:
         if sym == nil or sym.kind notin {skVar, skLet, skField}:
           invalidPragma(c, it)
@@ -1106,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 or (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) =
@@ -1119,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 and sym.ast != nil: 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/reorder.nim b/compiler/reorder.nim
index 07462bb3e..8c4d0d307 100644
--- a/compiler/reorder.nim
+++ b/compiler/reorder.nim
@@ -1,6 +1,6 @@
 
 import
-  intsets, ast, idents, algorithm, renderer, parser, ospaths, strutils,
+  intsets, ast, idents, algorithm, renderer, parser, os, strutils,
   sequtils, msgs, modulegraphs, syntaxes, options, modulepaths, tables,
   lineinfos
 
diff --git a/compiler/rod.nim b/compiler/rod.nim
index f6fc24ec0..bbd2f0c6c 100644
--- a/compiler/rod.nim
+++ b/compiler/rod.nim
@@ -16,12 +16,14 @@ 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
 
   template storeRemaining*(g: ModuleGraph; module: PSym) = discard
 
+  template registerModule*(g: ModuleGraph; module: PSym) = discard
+
 else:
   include rodimpl
 
diff --git a/compiler/rodimpl.nim b/compiler/rodimpl.nim
index 839a9c6ca..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:
@@ -752,6 +799,9 @@ proc loadSym(g; id: int; info: TLineInfo): PSym =
   result = loadSymFromBlob(g, b, info)
   doAssert id == result.id, "symbol ID is not consistent!"
 
+proc registerModule*(g; module: PSym) =
+  g.incr.r.syms.add(abs module.id, module)
+
 proc loadModuleSymTab(g; module: PSym) =
   ## goal: fill  module.tab
   g.incr.r.syms.add(module.id, module)
@@ -765,7 +815,8 @@ proc loadModuleSymTab(g; module: PSym) =
       b.s.add '\0'
       s = loadSymFromBlob(g, b, module.info)
     assert s != nil
-    strTableAdd(module.tab, s)
+    if s.kind != skField:
+      strTableAdd(module.tab, s)
   if sfSystemModule in module.flags:
     g.systemModule = module
 
@@ -843,8 +894,9 @@ proc replay(g: ModuleGraph; module: PSym; n: PNode) =
         internalAssert g.config, false
   of nkImportStmt:
     for x in n:
-      internalAssert g.config, x.kind == nkStrLit
-      let imported = g.importModuleCallback(g, module, fileInfoIdx(g.config, AbsoluteFile n[0].strVal))
+      internalAssert g.config, x.kind == nkSym
+      let modpath = AbsoluteFile toFullPath(g.config, x.sym.info)
+      let imported = g.importModuleCallback(g, module, fileInfoIdx(g.config, modpath))
       internalAssert g.config, imported.id < 0
   of nkStmtList, nkStmtListExpr:
     for x in n: replay(g, module, x)
@@ -868,16 +920,23 @@ proc setupModuleCache*(g: ModuleGraph) =
   let dbfile = getNimcacheDir(g.config) / RelativeFile"rodfiles.db"
   if g.config.symbolFiles == writeOnlySf:
     removeFile(dbfile)
+  createDir getNimcacheDir(g.config)
+  let ec = encodeConfig(g)
   if not fileExists(dbfile):
     db = open(connection=string dbfile, user="nim", password="",
               database="nim")
     createDb(db)
-    db.exec(sql"insert into config(config) values (?)", encodeConfig(g))
+    db.exec(sql"insert into config(config) values (?)", ec)
   else:
     db = open(connection=string dbfile, user="nim", password="",
               database="nim")
     let oldConfig = db.getValue(sql"select config from config")
-    g.incr.configChanged = oldConfig != encodeConfig(g)
+    g.incr.configChanged = oldConfig != ec
+    # ensure the filename IDs stay consistent:
+    for row in db.rows(sql"select fullpath, nimid from filenames order by nimid"):
+      let id = fileInfoIdx(g.config, AbsoluteFile row[0])
+      doAssert id.int == parseInt(row[1])
+    db.exec(sql"update config set config = ?", ec)
   db.exec(sql"pragma journal_mode=off")
   # This MUST be turned off, otherwise it's way too slow even for testing purposes:
   db.exec(sql"pragma SYNCHRONOUS=off")
diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim
index f94533177..bfff86479 100644
--- a/compiler/scriptconfig.nim
+++ b/compiler/scriptconfig.nim
@@ -123,6 +123,7 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
   cbconf setCommand:
     conf.command = a.getString 0
     let arg = a.getString 1
+    incl(conf.globalOptions, optWasNimscript)
     if arg.len > 0:
       conf.projectName = arg
       let path =
@@ -158,6 +159,8 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
 proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
                    freshDefines=true; conf: ConfigRef) =
   rawMessage(conf, hintConf, scriptName.string)
+  let oldSymbolFiles = conf.symbolFiles
+  conf.symbolFiles = disabledSf
 
   let graph = newModuleGraph(cache, conf)
   connectCallbacks(graph)
@@ -183,3 +186,4 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
   #initDefines()
   undefSymbol(conf.symbols, "nimscript")
   undefSymbol(conf.symbols, "nimconfig")
+  conf.symbolFiles = oldSymbolFiles
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 97a47ceca..8332af346 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -16,13 +16,16 @@ import
   procfind, lookups, pragmas, passes, semdata, semtypinst, sigmatch,
   intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
   evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity,
-  semparallel, lowerings, pluginsupport, plugins/active, rod, lineinfos
+  lowerings, pluginsupport, plugins/active, rod, lineinfos
 
-from modulegraphs import ModuleGraph, PPassContext
+from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward
 
 when defined(nimfix):
   import nimfix/prettybase
 
+when not defined(leanCompiler):
+  import semparallel
+
 # implementation
 
 proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.procvar.}
@@ -201,14 +204,15 @@ 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}:
-      # declarative context, so produce a fresh gensym:
-      result = copySym(result)
-      result.ast = n.sym.ast
-      put(c.p, n.sym, result)
+    when false:
+      if sfGenSym in result.flags and result.kind notin {skTemplate, skMacro, skParam}:
+        # declarative context, so produce a fresh gensym:
+        result = copySym(result)
+        result.ast = n.sym.ast
+        put(c.p, n.sym, result)
     # when there is a nested proc inside a template, semtmpl
     # will assign a wrong owner during the first pass over the
     # template; we must fix it here: see #909
@@ -447,7 +451,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
   pushInfoContext(c.config, nOrig.info, sym.detailedInfo)
 
   markUsed(c.config, n.info, sym, c.graph.usageSym)
-  styleCheckUse(n.info, sym)
+  onUse(n.info, sym)
   if sym == c.p.owner:
     globalError(c.config, n.info, "recursive dependency: '$1'" % sym.name.s)
 
diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim
index 7d6ae70de..5d676dc76 100644
--- a/compiler/semasgn.nim
+++ b/compiler/semasgn.nim
@@ -81,8 +81,8 @@ proc genAddr(c: PContext; x: PNode): PNode =
     addSon(result, x)
 
 proc newAsgnCall(c: PContext; op: PSym; x, y: PNode): PNode =
-  if sfError in op.flags:
-    localError(c.config, x.info, "usage of '$1' is a user-defined error" % op.name.s)
+  #if sfError in op.flags:
+  #  localError(c.config, x.info, "usage of '$1' is a user-defined error" % op.name.s)
   result = newNodeI(nkCall, x.info)
   result.add newSymNode(op)
   result.add genAddr(c, x)
@@ -121,8 +121,11 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
       op = field
       if op == nil:
         op = liftBody(c.c, t, c.kind, c.info)
-    markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
-    styleCheckUse(c.info, op)
+    if sfError in op.flags:
+      incl c.fn.flags, sfError
+    else:
+      markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
+    onUse(c.info, op)
     body.add newAsgnCall(c.c, op, x, y)
     result = true
 
@@ -132,7 +135,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
     let op = t.destructor
     if op != nil:
       markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
-      styleCheckUse(c.info, op)
+      onUse(c.info, op)
       body.add destructorCall(c.c, op, x)
       result = true
   of attachedAsgn:
@@ -143,7 +146,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
     let op = t.deepCopy
     if op != nil:
       markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
-      styleCheckUse(c.info, op)
+      onUse(c.info, op)
       body.add newDeepCopyCall(op, x, y)
       result = true
 
@@ -200,7 +203,7 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
       tyPtr, tyRef, tyOpt, tyUncheckedArray:
     defaultOp(c, t, body, x, y)
   of tyArray:
-    if {tfHasAsgn, tfUncheckedArray} * t.flags == {tfHasAsgn}:
+    if tfHasAsgn in t.flags:
       let i = declareCounter(c, body, firstOrd(c.c.config, t))
       let whileLoop = genWhileLoop(c, i, x)
       let elemType = t.lastSon
@@ -306,11 +309,15 @@ proc liftBody(c: PContext; typ: PType; kind: TTypeAttachedOp;
   liftBodyAux(a, typ, body, newSymNode(dest).newDeref, newSymNode(src))
   # recursion is handled explicitly, do not register the type based operation
   # before 'liftBodyAux':
-  case kind
-  of attachedAsgn: typ.assignment = result
-  of attachedSink: typ.sink = result
-  of attachedDeepCopy: typ.deepCopy = result
-  of attachedDestructor: typ.destructor = result
+  if c.config.selectedGC == gcDestructors and
+      typ.kind in {tySequence, tyString} and body.len == 0:
+    discard "do not cache it yet"
+  else:
+    case kind
+    of attachedAsgn: typ.assignment = result
+    of attachedSink: typ.sink = result
+    of attachedDeepCopy: typ.deepCopy = result
+    of attachedDestructor: typ.destructor = result
 
   var n = newNodeI(nkProcDef, info, bodyPos+1)
   for i in 0 ..< n.len: n.sons[i] = newNodeI(nkEmpty, info)
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 49b344274..7e0ea5490 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -138,6 +138,7 @@ proc effectProblem(f, a: PType; result: var string) =
 
 proc renderNotLValue(n: PNode): string =
   result = $n
+  let n = if n.kind == nkHiddenDeref: n[0] else: n
   if n.kind == nkHiddenCallConv and n.len > 1:
     result = $n[0] & "(" & result & ")"
   elif n.kind in {nkHiddenStdConv, nkHiddenSubConv} and n.len == 2:
@@ -166,20 +167,22 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
       prefer = preferModuleInfo
       break
 
-  when false:
-    # we pretend procs are attached to the type of the first
-    # argument in order to remove plenty of candidates. This is
-    # comparable to what C# does and C# is doing fine.
-    var filterOnlyFirst = false
+  # we pretend procs are attached to the type of the first
+  # argument in order to remove plenty of candidates. This is
+  # comparable to what C# does and C# is doing fine.
+  var filterOnlyFirst = false
+  if optShowAllMismatches notin c.config.globalOptions:
     for err in errors:
       if err.firstMismatch > 1:
         filterOnlyFirst = true
         break
 
   var candidates = ""
+  var skipped = 0
   for err in errors:
-    when false:
-      if filterOnlyFirst and err.firstMismatch == 1: continue
+    if filterOnlyFirst and err.firstMismatch == 1:
+      inc skipped
+      continue
     if err.sym.kind in routineKinds and err.sym.ast != nil:
       add(candidates, renderTree(err.sym.ast,
             {renderNoBody, renderNoComments, renderNoPragmas}))
@@ -216,7 +219,9 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
                       "' is immutable\n")
     for diag in err.diagnostics:
       candidates.add(diag & "\n")
-
+  if skipped > 0:
+    candidates.add($skipped & " other mismatching symbols have been " &
+        " suppressed; compile with --showAllMismatches:on to see them\n")
   result = (prefer, candidates)
 
 const
@@ -390,6 +395,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
         args])
 
 proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) =
+  let a = if a.kind == nkHiddenDeref: a[0] else: a
   if a.kind == nkHiddenCallConv and a.sons[0].kind == nkSym:
     let s = a.sons[0].sym
     if s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty:
@@ -450,7 +456,7 @@ proc semResolvedCall(c: PContext, x: TCandidate,
   assert x.state == csMatch
   var finalCallee = x.calleeSym
   markUsed(c.config, n.sons[0].info, finalCallee, c.graph.usageSym)
-  styleCheckUse(n.sons[0].info, finalCallee)
+  onUse(n.sons[0].info, finalCallee)
   assert finalCallee.ast != nil
   if x.hasFauxMatch:
     result = x.call
@@ -558,14 +564,17 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
   var newInst = generateInstance(c, s, m.bindings, n.info)
   newInst.typ.flags.excl tfUnresolved
   markUsed(c.config, n.info, s, c.graph.usageSym)
-  styleCheckUse(n.info, s)
+  onUse(n.info, s)
   result = newSymNode(newInst, n.info)
 
 proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
   assert n.kind == nkBracketExpr
   for i in 1..sonsLen(n)-1:
     let e = semExpr(c, n.sons[i])
-    n.sons[i].typ = e.typ.skipTypes({tyTypeDesc})
+    if e.typ == nil:
+      localError(c.config, e.info, "expression has no type")
+    else:
+      n.sons[i].typ = e.typ.skipTypes({tyTypeDesc})
   var s = s
   var a = n.sons[0]
   if a.kind == nkSym:
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index bec4a59a4..735c6f6b1 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -100,8 +100,8 @@ type
     compilesContextId*: int    # > 0 if we are in a ``compiles`` magic
     compilesContextIdGenerator*: int
     inGenericInst*: int        # > 0 if we are instantiating a generic
-    converters*: TSymSeq       # sequence of converters
-    patterns*: TSymSeq         # sequence of pattern matchers
+    converters*: seq[PSym]
+    patterns*: seq[PSym]       # sequence of pattern matchers
     optionStack*: seq[POptionEntry]
     symMapping*: TIdTable      # every gensym'ed symbol needs to be mapped
                                # to some new symbol in a generic instantiation
@@ -239,7 +239,7 @@ proc newContext*(graph: ModuleGraph; module: PSym): PContext =
   result.typesWithOps = @[]
   result.features = graph.config.features
 
-proc inclSym(sq: var TSymSeq, s: PSym) =
+proc inclSym(sq: var seq[PSym], s: PSym) =
   var L = len(sq)
   for i in countup(0, L - 1):
     if sq[i].id == s.id: return
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 883a8c0ae..ddec457a1 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -25,7 +25,7 @@ const
 proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
                      flags: TExprFlags = {}): PNode =
   markUsed(c.config, n.info, s, c.graph.usageSym)
-  styleCheckUse(n.info, s)
+  onUse(n.info, s)
   pushInfoContext(c.config, n.info, s.detailedInfo)
   result = evalTemplate(n, s, getCurrOwner(c), c.config, efFromHlo in flags)
   if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags)
@@ -201,7 +201,7 @@ proc semConv(c: PContext, n: PNode): PNode =
   if targetType.kind == tyTypeDesc:
     internalAssert c.config, targetType.len > 0
     if targetType.base.kind == tyNone:
-      return semTypeOf(c, n[1])
+      return semTypeOf(c, n)
     else:
       targetType = targetType.base
   elif targetType.kind == tyStatic:
@@ -265,7 +265,7 @@ proc semConv(c: PContext, n: PNode): PNode =
       let status = checkConvertible(c, result.typ, it.typ)
       if status in {convOK, convNotNeedeed}:
         markUsed(c.config, n.info, it.sym, c.graph.usageSym)
-        styleCheckUse(n.info, it.sym)
+        onUse(n.info, it.sym)
         markIndirect(c, it.sym)
         return it
     errorUseQualifier(c, n.info, op.sons[0].sym)
@@ -614,7 +614,8 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
   const
     FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl,
       mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap,
-      mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy}
+      mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy, mMove,
+      mWasMoved}
 
   # get the real type of the callee
   # it may be a proc var with a generic alias type, so we skip over them
@@ -640,6 +641,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
 
     return
   for i in countup(1, sonsLen(n) - 1):
+    let n = if n.kind == nkHiddenDeref: n[0] else: n
     if n.sons[i].kind == nkHiddenCallConv:
       # we need to recurse explicitly here as converters can create nested
       # calls and then they wouldn't be analysed otherwise
@@ -1036,7 +1038,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
   case s.kind
   of skConst:
     markUsed(c.config, n.info, s, c.graph.usageSym)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
     of  tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
         tyTuple, tySet, tyUInt..tyUInt64:
@@ -1061,7 +1063,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
     if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or
        (n.kind notin nkCallKinds and s.requiredParams > 0):
       markUsed(c.config, n.info, s, c.graph.usageSym)
-      styleCheckUse(n.info, s)
+      onUse(n.info, s)
       result = symChoice(c, n, s, scClosed)
     else:
       result = semMacroExpr(c, n, n, s, flags)
@@ -1070,17 +1072,19 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
        (n.kind notin nkCallKinds and s.requiredParams > 0) or
        sfCustomPragma in sym.flags:
       markUsed(c.config, n.info, s, c.graph.usageSym)
-      styleCheckUse(n.info, s)
+      onUse(n.info, s)
       result = symChoice(c, n, s, scClosed)
     else:
       result = semTemplateExpr(c, n, s, flags)
   of skParam:
     markUsed(c.config, n.info, s, c.graph.usageSym)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     if s.typ != nil and s.typ.kind == tyStatic and s.typ.n != nil:
       # XXX see the hack in sigmatch.nim ...
       return s.typ.n
     elif sfGenSym in s.flags:
+      # the owner should have been set by now by addParamOrResult
+      internalAssert c.config, s.owner != nil
       if c.p.wasForwarded:
         # gensym'ed parameters that nevertheless have been forward declared
         # need a special fixup:
@@ -1098,14 +1102,14 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
       localError(c.config, n.info, "illegal context for 'nimvm' magic")
 
     markUsed(c.config, n.info, s, c.graph.usageSym)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     result = newSymNode(s, n.info)
     # We cannot check for access to outer vars for example because it's still
     # not sure the symbol really ends up being used:
     # var len = 0 # but won't be called
     # genericThatUsesLen(x) # marked as taking a closure?
   of skGenericParam:
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     if s.typ.kind == tyStatic:
       result = newSymNode(s, n.info)
       result.typ = s.typ
@@ -1116,7 +1120,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
       return n
   of skType:
     markUsed(c.config, n.info, s, c.graph.usageSym)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     if s.typ.kind == tyStatic and s.typ.base.kind != tyNone and s.typ.n != nil:
       return s.typ.n
     result = newSymNode(s, n.info)
@@ -1138,7 +1142,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
             # is the access to a public field or in the same module or in a friend?
             doAssert f == s
             markUsed(c.config, n.info, f, c.graph.usageSym)
-            styleCheckUse(n.info, f)
+            onUse(n.info, f)
             result = newNodeIT(nkDotExpr, n.info, f.typ)
             result.add makeDeref(newSymNode(p.selfSym))
             result.add newSymNode(f) # we now have the correct field
@@ -1151,11 +1155,11 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
           ty = skipTypes(ty.sons[0], skipPtrs)
     # old code, not sure if it's live code:
     markUsed(c.config, n.info, s, c.graph.usageSym)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     result = newSymNode(s, n.info)
   else:
     markUsed(c.config, n.info, s, c.graph.usageSym)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     result = newSymNode(s, n.info)
 
 proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
@@ -1178,7 +1182,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
     else:
       markUsed(c.config, n.sons[1].info, s, c.graph.usageSym)
       result = semSym(c, n, s, flags)
-    styleCheckUse(n.sons[1].info, s)
+    onUse(n.sons[1].info, s)
     return
 
   n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType})
@@ -1241,7 +1245,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
         result.info = n.info
         result.typ = ty
         markUsed(c.config, n.info, f, c.graph.usageSym)
-        styleCheckUse(n.info, f)
+        onUse(n.info, f)
         return
     of tyObject, tyTuple:
       if ty.n != nil and ty.n.kind == nkRecList:
@@ -1272,7 +1276,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
       if fieldVisible(c, f):
         # is the access to a public field or in the same module or in a friend?
         markUsed(c.config, n.sons[1].info, f, c.graph.usageSym)
-        styleCheckUse(n.sons[1].info, f)
+        onUse(n.sons[1].info, f)
         n.sons[0] = makeDeref(n.sons[0])
         n.sons[1] = newSymNode(f) # we now have the correct field
         n.typ = f.typ
@@ -1286,7 +1290,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
     f = getSymFromList(ty.n, i)
     if f != nil:
       markUsed(c.config, n.sons[1].info, f, c.graph.usageSym)
-      styleCheckUse(n.sons[1].info, f)
+      onUse(n.sons[1].info, f)
       n.sons[0] = makeDeref(n.sons[0])
       n.sons[1] = newSymNode(f)
       n.typ = f.typ
@@ -1488,6 +1492,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]
@@ -1538,7 +1549,9 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
   # a = b # both are vars, means: a[] = b[]
   # a = b # b no 'var T' means: a = addr(b)
   var le = a.typ
-  if (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind != tyVar and
+  if le == nil:
+    localError(c.config, a.info, "expression has no type")
+  elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind != tyVar and
         isAssignable(c, a) == arNone) or
       skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs}:
     # Direct assignment to a discriminant is allowed!
@@ -1567,7 +1580,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)
 
@@ -1756,7 +1769,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
 
     macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
     markUsed(c.config, n.info, expandedSym, c.graph.usageSym)
-    styleCheckUse(n.info, expandedSym)
+    onUse(n.info, expandedSym)
 
   if isCallExpr(macroCall):
     for i in countup(1, macroCall.len-1):
@@ -1781,7 +1794,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
       let info = macroCall.sons[0].info
       macroCall.sons[0] = newSymNode(cand, info)
       markUsed(c.config, info, cand, c.graph.usageSym)
-      styleCheckUse(info, cand)
+      onUse(info, cand)
 
     # we just perform overloading resolution here:
     #n.sons[1] = semOverloadedCall(c, macroCall, macroCall, {skTemplate, skMacro})
@@ -1811,6 +1824,7 @@ proc processQuotations(c: PContext; n: var PNode, op: string,
     ids.add n
     return
 
+
   if n.kind == nkPrefix:
     checkSonsLen(n, 2, c.config)
     if n[0].kind == nkIdent:
@@ -1821,6 +1835,9 @@ proc processQuotations(c: PContext; n: var PNode, op: string,
         n.sons[0] = newIdentNode(getIdent(c.cache, examinedOp.substr(op.len)), n.info)
   elif n.kind == nkAccQuoted and op == "``":
     returnQuote n[0]
+  elif n.kind == nkIdent:
+    if n.ident.s == "result":
+      n = ids[0]
 
   for i in 0 ..< n.safeLen:
     processQuotations(c, n.sons[i], op, quotes, ids)
@@ -1832,15 +1849,18 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
   var
     quotedBlock = n[^1]
     op = if n.len == 3: expectString(c, n[1]) else: "``"
-    quotes = newSeq[PNode](1)
+    quotes = newSeq[PNode](2)
       # the quotes will be added to a nkCall statement
-      # leave some room for the callee symbol
-    ids = newSeq[PNode]()
+      # leave some room for the callee symbol and the result symbol
+    ids = newSeq[PNode](1)
       # this will store the generated param names
+      # leave some room for the result symbol
 
   if quotedBlock.kind != nkStmtList:
     localError(c.config, n.info, errXExpected, "block")
 
+  # This adds a default first field to pass the result symbol
+  ids[0] = newAnonSym(c, skParam, n.info).newSymNode
   processQuotations(c, quotedBlock, op, quotes, ids)
 
   var dummyTemplate = newProcNode(
@@ -1859,6 +1879,8 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
 
   var tmpl = semTemplateDef(c, dummyTemplate)
   quotes[0] = tmpl[namePos]
+  # This adds a call to newIdentNode("result") as the first argument to the template call
+  quotes[1] = newNode(nkCall, n.info, @[newIdentNode(getIdent(c.cache, "newIdentNode"), n.info), newStrNode(nkStrLit, "result")])
   result = newNode(nkCall, n.info, @[
      createMagic(c.graph, "getAst", mExpandToAst).newSymNode,
     newNode(nkCall, n.info, quotes)])
@@ -1955,6 +1977,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
@@ -1963,8 +2001,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
     checkSonsLen(n, 2, c.config)
     result = semAddr(c, n.sons[1], s.name.s == "unsafeAddr")
   of mTypeOf:
-    checkSonsLen(n, 2, c.config)
-    result = semTypeOf(c, n.sons[1])
+    result = semTypeOf(c, n)
   #of mArrGet: result = semArrGet(c, n, flags)
   #of mArrPut: result = semArrPut(c, n, flags)
   #of mAsgn: result = semAsgnOpr(c, n)
@@ -2027,6 +2064,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:
@@ -2040,13 +2078,9 @@ 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)
-    if n.sonsLen == 4:
-      let annotationStr = getConstExpr(c.module, semExpr(c, n[^1]), c.graph)
-      if annotationStr == nil or annotationStr.kind notin nkStrKinds:
-        localError(c.config, result[^1].info,
-          "The annotation string for `||` must be known at compile time")
     result = semDirectOp(c, n, flags)
   else:
     result = semDirectOp(c, n, flags)
@@ -2257,9 +2291,12 @@ proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode =
     var labl = newSymG(skLabel, n.sons[0], c)
     if sfGenSym notin labl.flags:
       addDecl(c, labl)
+    elif labl.owner == nil:
+      labl.owner = c.p.owner
     n.sons[0] = newSymNode(labl, n.sons[0].info)
     suggestSym(c.config, n.sons[0].info, labl, c.graph.usageSym)
     styleCheckDef(c.config, labl)
+    onDef(n[0].info, labl)
   n.sons[1] = semExpr(c, n.sons[1], flags)
   n.typ = n.sons[1].typ
   if isEmptyType(n.typ): n.kind = nkBlockStmt
@@ -2338,7 +2375,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)
@@ -2346,6 +2382,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
         markIndirect(c, result.sym)
         # if isGenericRoutine(result.sym):
         #   localError(c.config, n.info, errInstantiateXExplicitly, s.name.s)
+    else:
+      result = semSym(c, n, s, flags)
   of nkSym:
     # because of the changed symbol binding, this does not mean that we
     # don't have to check the symbol for semantics here again!
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 5565e8ed9..9e7ed5cee 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -15,6 +15,8 @@ import
   nversion, platform, math, msgs, os, condsyms, idents, renderer, types,
   commands, magicsys, modulegraphs, strtabs, lineinfos
 
+import system/helpers2
+
 proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode =
   case skipTypes(n.typ, abstractVarRange).kind
   of tyInt:
@@ -267,12 +269,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
   of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n, g)
   of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n, g)
   of mDivF64:
-    if getFloat(b) == 0.0:
-      if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n, g)
-      elif getFloat(b).classify == fcNegZero: result = newFloatNodeT(-Inf, n, g)
-      else: result = newFloatNodeT(Inf, n, g)
-    else:
-      result = newFloatNodeT(getFloat(a) / getFloat(b), n, g)
+    result = newFloatNodeT(getFloat(a) / getFloat(b), n, g)
   of mMaxF64:
     if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n, g)
     else: result = newFloatNodeT(getFloat(b), n, g)
@@ -413,15 +410,14 @@ proc getAppType(n: PNode; g: ModuleGraph): PNode =
     result = newStrNodeT("console", n, g)
 
 proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) =
-  if tfUncheckedArray notin n.typ.flags:
-    var err = false
-    if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}:
-      err = value <% firstOrd(g.config, n.typ) or value >% lastOrd(g.config, n.typ, fixedUnsigned=true)
-    else:
-      err = value < firstOrd(g.config, n.typ) or value > lastOrd(g.config, n.typ)
-    if err:
-      localError(g.config, n.info, "cannot convert " & $value &
-                                      " to " & typeToString(n.typ))
+  var err = false
+  if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}:
+    err = value <% firstOrd(g.config, n.typ) or value >% lastOrd(g.config, n.typ, fixedUnsigned=true)
+  else:
+    err = value < firstOrd(g.config, n.typ) or value > lastOrd(g.config, n.typ)
+  if err:
+    localError(g.config, n.info, "cannot convert " & $value &
+                                    " to " & typeToString(n.typ))
 
 proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode =
   let dstTyp = skipTypes(n.typ, abstractRange)
@@ -495,11 +491,11 @@ proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
       result = x.sons[int(idx)]
       if result.kind == nkExprColonExpr: result = result.sons[1]
     else:
-      localError(g.config, n.info, "index out of bounds: " & $n)
+      localError(g.config, n.info, formatErrorIndexBound(idx, sonsLen(x)+1) & $n)
   of nkBracket:
     idx = idx - firstOrd(g.config, x.typ)
     if idx >= 0 and idx < x.len: result = x.sons[int(idx)]
-    else: localError(g.config, n.info, "index out of bounds: " & $n)
+    else: localError(g.config, n.info, formatErrorIndexBound(idx, x.len+1) & $n)
   of nkStrLit..nkTripleStrLit:
     result = newNodeIT(nkCharLit, x.info, n.typ)
     if idx >= 0 and idx < len(x.strVal):
@@ -507,7 +503,7 @@ proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
     elif idx == len(x.strVal) and optLaxStrings in g.config.options:
       discard
     else:
-      localError(g.config, n.info, "index out of bounds: " & $n)
+      localError(g.config, n.info, formatErrorIndexBound(idx, len(x.strVal)-1) & $n)
   else: discard
 
 proc foldFieldAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
@@ -632,6 +628,14 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
         # It doesn't matter if the argument is const or not for mLengthArray.
         # This fixes bug #544.
         result = newIntNodeT(lengthOrd(g.config, n.sons[1].typ), n, g)
+      of mSizeOf:
+        let size = getSize(g.config, n[1].typ)
+        if size >= 0:
+          result = newIntNode(nkIntLit, size)
+          result.info = n.info
+          result.typ = getSysType(g, n.info, tyInt)
+        else:
+          result = nil
       of mAstToStr:
         result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, g)
       of mConStrStr:
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index e1a8390e1..5972f3b55 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -76,14 +76,14 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
     result = symChoice(c, n, s, scOpen)
   of skTemplate:
     if macroToExpandSym(s):
-      styleCheckUse(n.info, s)
+      onUse(n.info, s)
       result = semTemplateExpr(c, n, s, {efNoSemCheck})
       result = semGenericStmt(c, result, {}, ctx)
     else:
       result = symChoice(c, n, s, scOpen)
   of skMacro:
     if macroToExpandSym(s):
-      styleCheckUse(n.info, s)
+      onUse(n.info, s)
       result = semMacroExpr(c, n, n, s, {efNoSemCheck})
       result = semGenericStmt(c, result, {}, ctx)
     else:
@@ -96,20 +96,20 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
         result = n
     else:
       result = newSymNodeTypeDesc(s, n.info)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
   of skParam:
     result = n
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
   of skType:
     if (s.typ != nil) and
        (s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}):
       result = newSymNodeTypeDesc(s, n.info)
     else:
       result = n
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
   else:
     result = newSymNode(s, n.info)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
 
 proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
             ctx: var GenericCtx): PNode =
@@ -172,6 +172,7 @@ proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
   let s = newSymS(skUnknown, getIdentNode(c, n), c)
   addPrelimDecl(c, s)
   styleCheckDef(c.config, n.info, s, kind)
+  onDef(n.info, s)
 
 proc semGenericStmt(c: PContext, n: PNode,
                     flags: TSemGenericFlags, ctx: var GenericCtx): PNode =
@@ -230,7 +231,7 @@ proc semGenericStmt(c: PContext, n: PNode,
       case s.kind
       of skMacro:
         if macroToExpand(s) and sc.safeLen <= 1:
-          styleCheckUse(fn.info, s)
+          onUse(fn.info, s)
           result = semMacroExpr(c, n, n, s, {efNoSemCheck})
           result = semGenericStmt(c, result, flags, ctx)
         else:
@@ -239,7 +240,7 @@ proc semGenericStmt(c: PContext, n: PNode,
         mixinContext = true
       of skTemplate:
         if macroToExpand(s) and sc.safeLen <= 1:
-          styleCheckUse(fn.info, s)
+          onUse(fn.info, s)
           result = semTemplateExpr(c, n, s, {efNoSemCheck})
           result = semGenericStmt(c, result, flags, ctx)
         else:
@@ -262,17 +263,17 @@ proc semGenericStmt(c: PContext, n: PNode,
           inc first
       of skGenericParam:
         result.sons[0] = newSymNodeTypeDesc(s, fn.info)
-        styleCheckUse(fn.info, s)
+        onUse(fn.info, s)
         first = 1
       of skType:
         # bad hack for generics:
         if (s.typ != nil) and (s.typ.kind != tyGenericParam):
           result.sons[0] = newSymNodeTypeDesc(s, fn.info)
-          styleCheckUse(fn.info, s)
+          onUse(fn.info, s)
           first = 1
       else:
         result.sons[0] = newSymNode(s, fn.info)
-        styleCheckUse(fn.info, s)
+        onUse(fn.info, s)
         first = 1
     elif fn.kind == nkDotExpr:
       result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
@@ -322,7 +323,14 @@ proc semGenericStmt(c: PContext, n: PNode,
       n.sons[i] = semGenericStmtScope(c, n.sons[i], flags, ctx)
   of nkWhenStmt:
     for i in countup(0, sonsLen(n)-1):
-      n.sons[i] = semGenericStmt(c, n.sons[i], flags+{withinMixin}, ctx)
+      # bug #8603: conditions of 'when' statements are not
+      # in a 'mixin' context:
+      let it = n[i]
+      if it.kind in {nkElifExpr, nkElifBranch}:
+        n.sons[i].sons[0] = semGenericStmt(c, it[0], flags, ctx)
+        n.sons[i].sons[1] = semGenericStmt(c, it[1], flags+{withinMixin}, ctx)
+      else:
+        n.sons[i] = semGenericStmt(c, it, flags+{withinMixin}, ctx)
   of nkWhileStmt:
     openScope(c)
     for i in countup(0, sonsLen(n)-1):
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index de2e10a9b..09991048e 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -116,9 +116,9 @@ proc freshGenSyms(n: PNode, owner, orig: PSym, symMap: var TIdTable) =
     var x = PSym(idTableGet(symMap, s))
     if x != nil:
       n.sym = x
-    elif s.owner.kind == skPackage:
+    elif s.owner == nil or 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 5ab4d25e0..7e61854b8 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -21,8 +21,15 @@ proc semAddr(c: PContext; n: PNode; isUnsafeAddr=false): PNode =
   result.typ = makePtrType(c, x.typ)
 
 proc semTypeOf(c: PContext; n: PNode): PNode =
+  var m = BiggestInt 1 # typeOfIter
+  if n.len == 3:
+    let mode = semConstExpr(c, n[2])
+    if mode.kind != nkIntLit:
+      localError(c.config, n.info, "typeof: cannot evaluate 'mode' parameter at compile-time")
+    else:
+      m = mode.intVal
   result = newNodeI(nkTypeOfExpr, n.info)
-  let typExpr = semExprWithType(c, n, {efInTypeof})
+  let typExpr = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
   result.add typExpr
   result.typ = makeTypeDesc(c, typExpr.typ)
 
@@ -299,7 +306,13 @@ proc semOf(c: PContext, n: PNode): PNode =
         result.typ = getSysType(c.graph, n.info, tyBool)
         return result
       elif diff == high(int):
-        localError(c.config, n.info, "'$1' cannot be of this subtype" % typeToString(a))
+        if commonSuperclass(a, b) == nil:
+          localError(c.config, n.info, "'$1' cannot be of this subtype" % typeToString(a))
+        else:
+          message(c.config, n.info, hintConditionAlwaysFalse, renderTree(n))
+          result = newIntNode(nkIntLit, 0)
+          result.info = n.info
+          result.typ = getSysType(c.graph, n.info, tyBool)
   else:
     localError(c.config, n.info, "'of' takes 2 arguments")
   n.typ = getSysType(c.graph, n.info, tyBool)
@@ -308,8 +321,6 @@ proc semOf(c: PContext, n: PNode): PNode =
 proc magicsAfterOverloadResolution(c: PContext, n: PNode,
                                    flags: TExprFlags): PNode =
   ## This is the preferred code point to implement magics.
-  ## This function basically works like a macro, with the difference
-  ## that it is implemented in the compiler and not on the nimvm.
   ## ``c`` the current module, a symbol table to a very good approximation
   ## ``n`` the ast like it would be passed to a real macro
   ## ``flags`` Some flags for more contextual information on how the
@@ -320,26 +331,21 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
     checkSonsLen(n, 2, c.config)
     result = semAddr(c, n.sons[1], n[0].sym.name.s == "unsafeAddr")
   of mTypeOf:
-    checkSonsLen(n, 2, c.config)
-    result = semTypeOf(c, n.sons[1])
+    result = semTypeOf(c, n)
   of mSizeOf:
-      # TODO there is no proper way to find out if a type cannot be queried for the size.
-      let size = getSize(c.config, n[1].typ)
-      # We just assume here that the type might come from the c backend
-      if size == szUnknownSize:
-        # Forward to the c code generation to emit a `sizeof` in the C code.
-        result = n
-      elif size >= 0:
-        result = newIntNode(nkIntLit, size)
-        result.info = n.info
-        result.typ = n.typ
-      else:
-
-        localError(c.config, n.info, "cannot evaluate 'sizeof' because its type is not defined completely")
-
-        result = nil
-
-
+    # TODO there is no proper way to find out if a type cannot be queried for the size.
+    let size = getSize(c.config, n[1].typ)
+    # We just assume here that the type might come from the c backend
+    if size == szUnknownSize:
+      # Forward to the c code generation to emit a `sizeof` in the C code.
+      result = n
+    elif size >= 0:
+      result = newIntNode(nkIntLit, size)
+      result.info = n.info
+      result.typ = n.typ
+    else:
+      localError(c.config, n.info, "cannot evaluate 'sizeof' because its type is not defined completely, type: " & n[1].typ.typeToString)
+      result = n
   of mAlignOf:
     result = newIntNode(nkIntLit, getAlign(c.config, n[1].typ))
     result.info = n.info
@@ -373,7 +379,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 c1bdb08a8..75dea069f 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -9,9 +9,12 @@
 
 import
   intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
-  wordrecg, strutils, options, guards, writetracking, lineinfos, semfold,
+  wordrecg, strutils, options, guards, lineinfos, semfold,
   modulegraphs
 
+when not defined(leanCompiler):
+  import writetracking
+
 when defined(useDfa):
   import dfa
 
@@ -53,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
@@ -191,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) =
@@ -713,7 +717,7 @@ proc track(tracked: PEffects, n: PNode) =
       track(tracked, n.sons[i])
   of nkCallKinds:
     if getConstExpr(tracked.owner_module, n, tracked.graph) != nil:
-      return 
+      return
     # p's effects are ours too:
     var a = n.sons[0]
     let op = a.typ
@@ -843,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 b97a56178..aec03b492 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -41,8 +41,13 @@ proc semDiscard(c: PContext, n: PNode): PNode =
   checkSonsLen(n, 1, c.config)
   if n.sons[0].kind != nkEmpty:
     n.sons[0] = semExprWithType(c, n.sons[0])
-    if isEmptyType(n.sons[0].typ) or n.sons[0].typ.kind == tyNone or n.sons[0].kind == nkTypeOfExpr:
+    let sonType = n.sons[0].typ
+    let sonKind = n.sons[0].kind
+    if isEmptyType(sonType) or sonType.kind == tyNone or n.sons[0].kind == nkTypeOfExpr:
       localError(c.config, n.info, errInvalidDiscard)
+    if sonType.kind == tyProc and sonKind notin nkCallKinds:
+      # tyProc is disallowed to prevent ``discard foo`` to be valid, when ``discard foo()`` is meant.
+      localError(c.config, n.info, "illegal discard proc, did you mean: " & $n[0] & "()")
 
 proc semBreakOrContinue(c: PContext, n: PNode): PNode =
   result = n
@@ -61,7 +66,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
         incl(s.flags, sfUsed)
         n.sons[0] = x
         suggestSym(c.config, x.info, s, c.graph.usageSym)
-        styleCheckUse(x.info, s)
+        onUse(x.info, s)
       else:
         localError(c.config, n.info, errInvalidControlFlowX % s.name.s)
     else:
@@ -318,7 +323,6 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
     if result.owner.kind == skModule:
       incl(result.flags, sfGlobal)
   suggestSym(c.config, n.info, result, c.graph.usageSym)
-  styleCheckDef(c.config, result)
 
 proc checkNilable(c: PContext; v: PSym) =
   if {sfGlobal, sfImportC} * v.flags == {sfGlobal} and
@@ -359,6 +363,8 @@ proc semUsing(c: PContext; n: PNode): PNode =
       let typ = semTypeNode(c, a.sons[length-2], nil)
       for j in countup(0, length-3):
         let v = semIdentDef(c, a.sons[j], skParam)
+        styleCheckDef(c.config, v)
+        onDef(a[j].info, v)
         v.typ = typ
         strTableIncl(c.signatures, v)
     else:
@@ -489,8 +495,12 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
         addToVarSection(c, result, n, a)
         continue
       var v = semIdentDef(c, a.sons[j], symkind)
-      if sfGenSym notin v.flags and not isDiscardUnderscore(v):
-        addInterfaceDecl(c, v)
+      styleCheckDef(c.config, v)
+      onDef(a[j].info, v)
+      if sfGenSym notin v.flags:
+        if not isDiscardUnderscore(v): addInterfaceDecl(c, v)
+      else:
+        if v.owner == nil: v.owner = c.p.owner
       when oKeepVariableNames:
         if c.inUnrolledContext > 0: v.flags.incl(sfShadowed)
         else:
@@ -542,6 +552,8 @@ proc semConst(c: PContext, n: PNode): PNode =
     if a.kind != nkConstDef: illFormedAst(a, c.config)
     checkSonsLen(a, 3, c.config)
     var v = semIdentDef(c, a.sons[0], skConst)
+    styleCheckDef(c.config, v)
+    onDef(a[0].info, v)
     var typ: PType = nil
     if a.sons[1].kind != nkEmpty: typ = semTypeNode(c, a.sons[1], nil)
 
@@ -563,6 +575,7 @@ proc semConst(c: PContext, n: PNode): PNode =
     setVarType(c, v, typ)
     v.ast = def               # no need to copy
     if sfGenSym notin v.flags: addInterfaceDecl(c, v)
+    elif v.owner == nil: v.owner = getCurrOwner(c)
     var b = newNodeI(nkConstDef, a.info)
     if importantComments(c.config): b.comment = a.comment
     addSon(b, newSymNode(v))
@@ -585,6 +598,7 @@ proc symForVar(c: PContext, n: PNode): PSym =
   let m = if n.kind == nkPragmaExpr: n.sons[0] else: n
   result = newSymG(skForVar, m, c)
   styleCheckDef(c.config, result)
+  onDef(n.info, result)
   if n.kind == nkPragmaExpr:
     pragma(c, result, n.sons[1], forVarPragmas)
 
@@ -605,6 +619,7 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
       v.typ = iterBase
       n.sons[0] = newSymNode(v)
       if sfGenSym notin v.flags: addForVarDecl(c, v)
+      elif v.owner == nil: v.owner = getCurrOwner(c)
     else:
       localError(c.config, n.info, errWrongNumberOfVariables)
   elif length-2 != sonsLen(iter):
@@ -615,8 +630,9 @@ proc semForVars(c: PContext, n: PNode; flags: TExprFlags): PNode =
       if getCurrOwner(c).kind == skModule: incl(v.flags, sfGlobal)
       v.typ = iter.sons[i]
       n.sons[i] = newSymNode(v)
-      if sfGenSym notin v.flags and not isDiscardUnderscore(v):
-        addForVarDecl(c, v)
+      if sfGenSym notin v.flags:
+        if not isDiscardUnderscore(v): addForVarDecl(c, v)
+      elif v.owner == nil: v.owner = getCurrOwner(c)
   inc(c.p.nestedLoopCounter)
   openScope(c)
   n.sons[length-1] = semExprBranch(c, n.sons[length-1], flags)
@@ -690,7 +706,7 @@ proc handleCaseStmtMacro(c: PContext; n: PNode): PNode =
   if r.state == csMatch:
     var match = r.calleeSym
     markUsed(c.config, n[0].info, match, c.graph.usageSym)
-    styleCheckUse(n[0].info, match)
+    onUse(n[0].info, match)
 
     # but pass 'n' to the 'match' macro, not 'n[0]':
     r.call.sons[1] = n
@@ -873,6 +889,8 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
         let typsym = pkg.tab.strTableGet(typName)
         if typsym.isNil:
           s = semIdentDef(c, name[1], skType)
+          styleCheckDef(c.config, s)
+          onDef(name[1].info, s)
           s.typ = newTypeS(tyObject, c)
           s.typ.sym = s
           s.flags.incl sfForward
@@ -886,6 +904,8 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
           s = typsym
     else:
       s = semIdentDef(c, name, skType)
+      styleCheckDef(c.config, s)
+      onDef(name.info, s)
       s.typ = newTypeS(tyForward, c)
       s.typ.sym = s             # process pragmas:
       if name.kind == nkPragmaExpr:
@@ -907,6 +927,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
             s = typsym
       # add it here, so that recursive types are possible:
       if sfGenSym notin s.flags: addInterfaceDecl(c, s)
+      elif s.owner == nil: s.owner = getCurrOwner(c)
 
     if name.kind == nkPragmaExpr:
       a.sons[0].sons[0] = newSymNode(s)
@@ -1253,7 +1274,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
@@ -1605,7 +1626,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     else:
       s.typ.callConv = lastOptionEntry(c).defaultCC
     # add it here, so that recursive procs are possible:
-    if sfGenSym in s.flags: discard
+    if sfGenSym in s.flags:
+      if s.owner == nil: s.owner = getCurrOwner(c)
     elif kind in OverloadableSyms:
       if not typeIsDetermined:
         addInterfaceOverloadableSymAt(c, oldScope, s)
@@ -1616,6 +1638,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
       pragma(c, s, n.sons[pragmasPos], validPragmas)
     else:
       implicitPragmas(c, s, n, validPragmas)
+    styleCheckDef(c.config, s)
+    onDef(n[namePos].info, s)
   else:
     if n.sons[pragmasPos].kind != nkEmpty:
       pragma(c, s, n.sons[pragmasPos], validPragmas)
@@ -1628,6 +1652,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
       if proto.typ.callConv != s.typ.callConv or proto.typ.flags < s.typ.flags:
         localError(c.config, n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX %
           ("'" & proto.name.s & "' from " & c.config$proto.info))
+    styleCheckDef(c.config, s)
+    onDefResolveForward(n[namePos].info, proto)
     if sfForward notin proto.flags and proto.magic == mNone:
       wrongRedefinition(c, n.info, proto.name.s, proto.info)
     excl(proto.flags, sfForward)
@@ -1660,7 +1686,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
       localError(c.config, n.info, "the overloaded " & s.name.s &
         " operator has to be enabled with {.experimental: \"callOperator\".}")
 
-  if n.sons[bodyPos].kind != nkEmpty:
+  if n.sons[bodyPos].kind != nkEmpty and sfError notin s.flags:
     # for DLL generation it is annoying to check for sfImportc!
     if sfBorrow in s.flags:
       localError(c.config, n.sons[bodyPos].info, errImplOfXNotAllowed % s.name.s)
@@ -1817,35 +1843,49 @@ proc semMacroDef(c: PContext, n: PNode): PNode =
   if n.sons[bodyPos].kind == nkEmpty:
     localError(c.config, n.info, errImplOfXexpected % s.name.s)
 
+proc incMod(c: PContext, n: PNode, it: PNode, includeStmtResult: PNode) =
+  var f = checkModuleName(c.config, it)
+  if f != InvalidFileIDX:
+    if containsOrIncl(c.includedFiles, f.int):
+      localError(c.config, n.info, errRecursiveDependencyX % toFilename(c.config, f))
+    else:
+      addSon(includeStmtResult, semStmt(c, c.graph.includeFileCallback(c.graph, c.module, f), {}))
+      excl(c.includedFiles, f.int)
+
 proc evalInclude(c: PContext, n: PNode): PNode =
   result = newNodeI(nkStmtList, n.info)
   addSon(result, n)
   for i in countup(0, sonsLen(n) - 1):
-    var f = checkModuleName(c.config, n.sons[i])
-    if f != InvalidFileIDX:
-      if containsOrIncl(c.includedFiles, f.int):
-        localError(c.config, n.info, errRecursiveDependencyX % toFilename(c.config, f))
-      else:
-        addSon(result, semStmt(c, c.graph.includeFileCallback(c.graph, c.module, f), {}))
-        excl(c.includedFiles, f.int)
+    var imp: PNode
+    let it = n.sons[i]
+    if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket:
+      let sep = it[0]
+      let dir = it[1]
+      imp = newNodeI(nkInfix, it.info)
+      imp.add sep
+      imp.add dir
+      imp.add sep # dummy entry, replaced in the loop
+      for x in it[2]:
+        imp.sons[2] = x
+        incMod(c, n, imp, result)
+    else:
+      incMod(c, n, it, result)
 
 proc setLine(n: PNode, info: TLineInfo) =
   for i in 0 ..< safeLen(n): setLine(n.sons[i], info)
   n.info = info
 
 proc semPragmaBlock(c: PContext, n: PNode): PNode =
+  checkSonsLen(n, 2, c.config)
   let pragmaList = n.sons[0]
   pragma(c, nil, pragmaList, exprPragmas)
-  result = semExpr(c, n.sons[1])
-  n.sons[1] = result
+  n[1] = semExpr(c, n[1])
+  result = n
+  result.typ = n[1].typ
   for i in 0 ..< pragmaList.len:
     case whichPragma(pragmaList.sons[i])
     of wLine: setLine(result, pragmaList.sons[i].info)
-    of wLocks, wGcSafe:
-      result = n
-      result.typ = n.sons[1].typ
-    of wNoRewrite:
-      incl(result.flags, nfNoRewrite)
+    of wNoRewrite: incl(result.flags, nfNoRewrite)
     else: discard
 
 proc semStaticStmt(c: PContext, n: PNode): PNode =
@@ -1944,7 +1984,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/semtempl.nim b/compiler/semtempl.nim
index 484a7ddd6..14507cf9d 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -64,6 +64,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
     # for instance 'nextTry' is both in tables.nim and astalgo.nim ...
     result = newSymNode(s, n.info)
     markUsed(c.config, n.info, s, c.graph.usageSym)
+    onUse(n.info, s)
   else:
     # semantic checking requires a type; ``fitNode`` deals with it
     # appropriately
@@ -75,6 +76,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
       if a.kind != skModule:
         incl(a.flags, sfUsed)
         addSon(result, newSymNode(a, n.info))
+        onUse(n.info, a)
       a = nextOverloadIter(o, c, n)
 
 proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
@@ -160,7 +162,7 @@ proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode =
       if s.owner == c.owner and s.kind == skParam:
         incl(s.flags, sfUsed)
         result = newSymNode(s, n.info)
-        styleCheckUse(n.info, s)
+        onUse(n.info, s)
   else:
     for i in 0 ..< n.safeLen:
       result.sons[i] = onlyReplaceParams(c, n.sons[i])
@@ -208,19 +210,20 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
       # So we need only check the *current* scope.
       let s = localSearchInScope(c.c, considerQuotedIdent(c.c, ident))
       if s != nil and s.owner == c.owner and sfGenSym in s.flags:
-        styleCheckUse(n.info, s)
+        onUse(n.info, s)
         replaceIdentBySym(c.c, n, newSymNode(s, n.info))
       elif not (n.kind == nkSym and sfGenSym in n.sym.flags):
         let local = newGenSym(k, ident, c)
         addPrelimDecl(c.c, local)
         styleCheckDef(c.c.config, n.info, local)
+        onDef(n.info, local)
         replaceIdentBySym(c.c, n, newSymNode(local, n.info))
     else:
       replaceIdentBySym(c.c, n, ident)
 
 proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
   incl(s.flags, sfUsed)
-  # we do not call styleCheckUse here, as the identifier is not really
+  # we do not call onUse here, as the identifier is not really
   # resolved here. We will fixup the used identifiers later.
   case s.kind
   of skUnknown:
@@ -245,7 +248,7 @@ proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
       if s.owner == c.owner and (s.kind == skParam or sfGenSym in s.flags):
         incl(s.flags, sfUsed)
         result = newSymNode(s, n.info)
-        styleCheckUse(n.info, s)
+        onUse(n.info, s)
   else:
     for i in countup(0, safeLen(n) - 1):
       result.sons[i] = semRoutineInTemplName(c, n.sons[i])
@@ -261,6 +264,7 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
       s.ast = n
       addPrelimDecl(c.c, s)
       styleCheckDef(c.c.config, n.info, s)
+      onDef(n.info, s)
       n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
     else:
       n.sons[namePos] = ident
@@ -314,7 +318,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
       if s.owner == c.owner and s.kind == skParam:
         incl(s.flags, sfUsed)
         result = newSymNode(s, n.info)
-        styleCheckUse(n.info, s)
+        onUse(n.info, s)
       elif contains(c.toBind, s.id):
         result = symChoice(c.c, n, s, scClosed)
       elif contains(c.toMixin, s.name.id):
@@ -324,7 +328,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
         # var yz: T
         incl(s.flags, sfUsed)
         result = newSymNode(s, n.info)
-        styleCheckUse(n.info, s)
+        onUse(n.info, s)
       else:
         result = semTemplSymbol(c.c, n, s)
   of nkBind:
@@ -382,6 +386,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
         let s = newGenSym(skLabel, n.sons[0], c)
         addPrelimDecl(c.c, s)
         styleCheckDef(c.c.config, s)
+        onDef(n[0].info, s)
         n.sons[0] = newSymNode(s, n.sons[0].info)
     n.sons[1] = semTemplBody(c, n.sons[1])
     closeScope(c)
@@ -505,7 +510,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
       if s.owner == c.owner and s.kind == skParam and
           n.kind == nkAccQuoted and n.len == 1:
         incl(s.flags, sfUsed)
-        styleCheckUse(n.info, s)
+        onUse(n.info, s)
         return newSymNode(s, n.info)
       elif contains(c.toBind, s.id):
         return symChoice(c.c, n, s, scClosed)
@@ -553,6 +558,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
   else:
     s = semIdentVis(c, skTemplate, n.sons[0], {})
   styleCheckDef(c.config, s)
+  onDef(n[0].info, s)
   # check parameter list:
   #s.scope = c.currentScope
   pushOwner(c, s)
@@ -635,7 +641,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
     # semtypes.addParamOrResult). Within the pattern we have to ensure
     # to use the param with the proper type though:
     incl(s.flags, sfUsed)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     let x = c.owner.typ.n.sons[s.position+1].sym
     assert x.name == s.name
     result = newSymNode(x, n.info)
@@ -706,28 +712,26 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
       elif templToExpand(s):
         return semPatternBody(c, semTemplateExpr(c.c, n, s, {efNoSemCheck}))
 
-    if n.kind == nkInfix and n.sons[0].kind == nkIdent:
+    if n.kind == nkInfix and (let id = considerQuotedIdent(c.c, n[0]); id != nil):
       # we interpret `*` and `|` only as pattern operators if they occur in
       # infix notation, so that '`*`(a, b)' can be used for verbatim matching:
-      let opr = n.sons[0]
-      if opr.ident.s == "*" or opr.ident.s == "**":
+      if id.s == "*" or id.s == "**":
         result = newNodeI(nkPattern, n.info, n.len)
-        result.sons[0] = opr
+        result.sons[0] = newIdentNode(id, n.info)
         result.sons[1] = semPatternBody(c, n.sons[1])
         result.sons[2] = expectParam(c, n.sons[2])
         return
-      elif opr.ident.s == "|":
+      elif id.s == "|":
         result = newNodeI(nkPattern, n.info, n.len)
-        result.sons[0] = opr
+        result.sons[0] = newIdentNode(id, n.info)
         result.sons[1] = semPatternBody(c, n.sons[1])
         result.sons[2] = semPatternBody(c, n.sons[2])
         return
 
-    if n.kind == nkPrefix and n.sons[0].kind == nkIdent:
-      let opr = n.sons[0]
-      if opr.ident.s == "~":
+    if n.kind == nkPrefix and (let id = considerQuotedIdent(c.c, n[0]); id != nil):
+      if id.s == "~":
         result = newNodeI(nkPattern, n.info, n.len)
-        result.sons[0] = opr
+        result.sons[0] = newIdentNode(id, n.info)
         result.sons[1] = semPatternBody(c, n.sons[1])
         return
 
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index bbd966b38..f4ff97ba4 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -90,6 +90,8 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
         if sonsLen(v) == 2:
           strVal = v.sons[1] # second tuple part is the string value
           if skipTypes(strVal.typ, abstractInst).kind in {tyString, tyCString}:
+            if not isOrdinalType(v.sons[0].typ):
+              localError(c.config, v.sons[0].info, errOrdinalTypeExpected)
             x = getOrdValue(v.sons[0]) # first tuple part is the ordinal
           else:
             localError(c.config, strVal.info, errStringLiteralExpected)
@@ -99,6 +101,8 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
         strVal = v
         x = counter
       else:
+        if not isOrdinalType(v.typ):
+          localError(c.config, v.info, errOrdinalTypeExpected)
         x = getOrdValue(v)
       if i != 1:
         if x != counter: incl(result.flags, tfEnumHasHoles)
@@ -122,6 +126,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
       if not isPure: strTableAdd(c.module.tab, e)
     addSon(result.n, newSymNode(e))
     styleCheckDef(c.config, e)
+    onDef(e.info, e)
     if sfGenSym notin e.flags:
       if not isPure: addDecl(c, e)
       else: importPureEnumField(c, e)
@@ -377,7 +382,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
       result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
     if result != nil:
       markUsed(c.config, n.info, result, c.graph.usageSym)
-      styleCheckUse(n.info, result)
+      onUse(n.info, result)
 
       if result.kind == skParam and result.typ.kind == tyTypeDesc:
         # This is a typedesc param. is it already bound?
@@ -391,7 +396,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:
@@ -466,6 +471,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
         addSon(result.n, newSymNode(field))
         addSonSkipIntLit(result, typ)
       styleCheckDef(c.config, a.sons[j].info, field)
+      onDef(field.info, field)
   if result.n.len == 0: result.n = nil
 
 proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
@@ -505,7 +511,6 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
     else: discard
   else:
     result = semIdentVis(c, kind, n, allowed)
-  styleCheckDef(c.config, n.info, result)
 
 proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
   let ex = t[branchIndex][currentEx].skipConv
@@ -703,6 +708,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
       if a.kind == nkEmpty: addSon(father, newSymNode(f))
       else: addSon(a, newSymNode(f))
       styleCheckDef(c.config, f)
+      onDef(f.info, f)
     if a.kind != nkEmpty: addSon(father, a)
   of nkSym:
     # This branch only valid during generic object
@@ -819,7 +825,11 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
       a.typ = nn.typ
       addDecl(c, a)
   else:
-    if sfGenSym notin param.flags: addDecl(c, param)
+    if sfGenSym in param.flags:
+      # bug #XXX, fix the gensym'ed parameters owner:
+      if param.owner == nil:
+        param.owner = getCurrOwner(c)
+    else: addDecl(c, param)
 
 template shouldHaveMeta(t) =
   internalAssert c.config, tfHasMeta in t.flags
@@ -988,7 +998,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
 
   of tyGenericParam:
     markUsed(c.config, info, paramType.sym, c.graph.usageSym)
-    styleCheckUse(info, paramType.sym)
+    onUse(info, paramType.sym)
     if tfWildcard in paramType.flags:
       paramType.flags.excl tfWildcard
       paramType.sym.kind = skType
@@ -1110,6 +1120,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       rawAddSon(result, finalType)
       addParamOrResult(c, arg, kind)
       styleCheckDef(c.config, a.sons[j].info, arg)
+      onDef(a[j].info, arg)
 
   var r: PType
   if n.sons[0].kind != nkEmpty:
@@ -1414,6 +1425,20 @@ proc semTypeof(c: PContext; n: PNode; prev: PType): PType =
   fixupTypeOf(c, prev, t)
   result = t.typ
 
+proc semTypeof2(c: PContext; n: PNode; prev: PType): PType =
+  openScope(c)
+  var m = BiggestInt 1 # typeOfIter
+  if n.len == 3:
+    let mode = semConstExpr(c, n[2])
+    if mode.kind != nkIntLit:
+      localError(c.config, n.info, "typeof: cannot evaluate 'mode' parameter at compile-time")
+    else:
+      m = mode.intVal
+  let t = semExprWithType(c, n[1], if m == 1: {efInTypeof} else: {})
+  closeScope(c)
+  fixupTypeOf(c, prev, t)
+  result = t.typ
+
 proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   result = nil
   inc c.inTypeContext
@@ -1494,6 +1519,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
       elif op.id == ord(wType):
         checkSonsLen(n, 2, c.config)
         result = semTypeof(c, n[1], prev)
+      elif op.s == "typeof" and n[0].kind == nkSym and n[0].sym.magic == mTypeof:
+        result = semTypeOf2(c, n, prev)
       else:
         if c.inGenericContext > 0 and n.kind == nkCall:
           result = makeTypeFromExpr(c, n.copyTree)
@@ -1511,7 +1538,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
     case s.magic
     of mArray: result = semArray(c, n, prev)
     of mOpenArray: result = semContainer(c, n, tyOpenArray, "openarray", prev)
-    of mUncheckedArray: result = semContainer(c, n, tyUncheckedArray, "uncheckedarray", prev)
+    of mUncheckedArray: result = semContainer(c, n, tyUncheckedArray, "UncheckedArray", prev)
     of mRange: result = semRange(c, n, prev)
     of mSet: result = semSet(c, n, prev)
     of mOrdinal: result = semOrdinal(c, n, prev)
@@ -1605,8 +1632,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
         result = prev
   of nkSym:
     let s = getGenSym(c, n.sym)
-    if s.kind == skType and s.typ != nil or
-      s.kind == skParam and s.typ.kind == tyTypeDesc:
+    if s.typ != nil and (s.kind == skType or s.typ.kind == tyTypeDesc):
       var t =
         if s.kind == skType:
           s.typ
@@ -1622,7 +1648,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
         assignType(prev, t)
         result = prev
       markUsed(c.config, n.info, n.sym, c.graph.usageSym)
-      styleCheckUse(n.info, n.sym)
+      onUse(n.info, n.sym)
     else:
       if s.kind != skError: localError(c.config, n.info, errTypeExpected)
       result = newOrPrevType(tyError, prev, c)
@@ -1710,7 +1736,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:
@@ -1729,10 +1755,8 @@ proc processMagicType(c: PContext, m: PSym) =
       setMagicType(c.config, m, tyAnything, 0)
     else:
       setMagicType(c.config, m, tyExpr, 0)
-      if m.name.s == "expr": m.typ.flags.incl tfOldSchoolExprStmt
   of mStmt:
     setMagicType(c.config, m, tyStmt, 0)
-    if m.name.s == "stmt": m.typ.flags.incl tfOldSchoolExprStmt
   of mTypeDesc, mType:
     setMagicType(c.config, m, tyTypeDesc, 0)
     rawAddSon(m.typ, newTypeS(tyNone, c))
@@ -1742,28 +1766,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
@@ -1771,7 +1795,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 be6ffc586..ffa913f1d 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -30,11 +30,6 @@ proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) =
     localError(conf, info, "type 'var var' is not allowed")
   elif computeSize(conf, t) == szIllegalRecursion:
     localError(conf, info,  "illegal recursion in type '" & typeToString(t) & "'")
-
-  t = typ.skipTypes({tyGenericInst})
-  if t.kind == tyArray and tfUncheckedArray in t.flags:
-    t[0].flags.incl tfUncheckedArray # mark range of unchecked array also unchecked
-
   when false:
     if t.kind == tyObject and t.sons[0] != nil:
       if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
@@ -238,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 4dc7690ef..d66e8d121 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -13,9 +13,9 @@
 import
   intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
   magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees,
-  linter, lineinfos
+  linter, lineinfos, lowerings, modulegraphs
 
-when defined(booting) or defined(nimsuggest):
+when (defined(booting) or defined(nimsuggest)) and not defined(leanCompiler):
   import docgen
 
 type
@@ -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))
@@ -1210,9 +1210,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
     if f.kind == tyVarargs:
       if tfVarargs in a.flags:
         return typeRel(c, f.base, a.lastSon)
-      if tfOldSchoolExprStmt in f.sons[0].flags:
-        if f.sons[0].kind == tyExpr: return
-      elif f.sons[0].kind == tyStmt: return
+      if f.sons[0].kind == tyStmt: return
 
     template matchArrayOrSeq(aBase: PType) =
       let ff = f.base
@@ -1758,7 +1756,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
         result = isNone
 
   of tyStmt:
-    if aOrig != nil and tfOldSchoolExprStmt notin f.flags:
+    if aOrig != nil:
       put(c, f, aOrig)
     result = isGeneric
 
@@ -1837,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
@@ -1857,8 +1855,14 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
       else:
         param = copyTree(arg)
       addSon(result, param)
+
+      if dest.kind in {tyVar, tyLent}:
+        dest.flags.incl tfVarIsPtr
+        result = newDeref(result)
+
       inc(m.convMatches)
-      m.genericConverter = srca == isGeneric or destIsGeneric
+      if m.genericConverter == false:
+        m.genericConverter = srca == isGeneric or destIsGeneric
       return result
 
 proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
@@ -2151,7 +2155,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
     else:
       # only one valid interpretation found:
       markUsed(m.c.config, arg.info, arg.sons[best].sym, m.c.graph.usageSym)
-      styleCheckUse(arg.info, arg.sons[best].sym)
+      onUse(arg.info, arg.sons[best].sym)
       result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
                                   argOrig)
   when false:
@@ -2215,8 +2219,7 @@ proc incrIndexType(t: PType) =
   inc t.sons[0].n.sons[1].intVal
 
 template isVarargsUntyped(x): untyped =
-  x.kind == tyVarargs and x.sons[0].kind == tyExpr and
-    tfOldSchoolExprStmt notin x.sons[0].flags
+  x.kind == tyVarargs and x.sons[0].kind == tyExpr
 
 proc matchesAux(c: PContext, n, nOrig: PNode,
                 m: var TCandidate, marker: var IntSet) =
@@ -2228,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
@@ -2240,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)
@@ -2294,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
@@ -2331,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)
@@ -2365,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 dcff992a1..a34383d9f 100644
--- a/compiler/sizealignoffsetimpl.nim
+++ b/compiler/sizealignoffsetimpl.nim
@@ -1,3 +1,12 @@
+#
+#
+#           The Nim Compiler
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+## code owner: Arne Döring
+## e-mail: arne.doering@gmx.net
 
 proc align(address, alignment: BiggestInt): BiggestInt =
   result = (address + (alignment - 1)) and not (alignment - 1)
@@ -43,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
@@ -118,11 +128,16 @@ proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, initialOffset:
       result.offset = align(offset, result.align)
 
   of nkSym:
-    computeSizeAlign(conf, n.sym.typ)
-    let size = n.sym.typ.size
-    let align = n.sym.typ.align
+    var size = szUnknownSize
+    var align = szUnknownSize
+
+    if n.sym.bitsize == 0: # 0 represents bitsize not set
+      computeSizeAlign(conf, n.sym.typ)
+      size = n.sym.typ.size.int
+      align = n.sym.typ.align.int
+
     result.align = align
-    if initialOffset == szUnknownSize:
+    if initialOffset == szUnknownSize or size == szUnknownSize:
       n.sym.offset = szUnknownSize
       result.offset = szUnknownSize
     else:
@@ -163,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
 
@@ -206,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
@@ -223,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
@@ -296,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
@@ -309,16 +324,24 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
     var headerAlign: int16
     if typ.sons[0] != nil:
       # compute header size
-      var st = typ.sons[0]
-      while st.kind in skipPtrs:
-        st = st.sons[^1]
-      computeSizeAlign(conf, st)
-      if st.size == szIllegalRecursion:
-        typ.size = st.size
-        typ.align = st.align
-        return
-      headerSize = st.size
-      headerAlign = st.align
+
+      if conf.cmd == cmdCompileToCpp:
+        # if the target is C++ the members of this type are written
+        # into the padding byets at the end of the parent type. At the
+        # moment it is not supported to calculate that.
+        headerSize = szUnknownSize
+        headerAlign = szUncomputedSize
+      else:
+        var st = typ.sons[0]
+        while st.kind in skipPtrs:
+          st = st.sons[^1]
+        computeSizeAlign(conf, st)
+        if st.size == szIllegalRecursion:
+          typ.size = st.size
+          typ.align = st.align
+          return
+        headerSize = st.size
+        headerAlign = st.align
     elif isObjectWithTypeFieldPredicate(typ):
       # this branch is taken for RootObj
       headerSize = conf.target.intSize
@@ -357,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/suggest.nim b/compiler/suggest.nim
index b264415d8..dfa6e5ddb 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -115,7 +115,7 @@ proc symToSuggest(conf: ConfigRef; s: PSym, isLocal: bool, section: IdeCmd, info
       result.forth = typeToString(s.typ)
     else:
       result.forth = ""
-    when defined(nimsuggest) and not defined(noDocgen):
+    when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
       result.doc = s.extractDocComment
   let infox = if section in {ideUse, ideHighlight, ideOutline}: info else: s.info
   result.filePath = toFullPath(conf, infox)
@@ -153,7 +153,7 @@ proc `$`*(suggest: Suggest): string =
     result.add(sep)
     result.add($suggest.column)
     result.add(sep)
-    when defined(nimsuggest) and not defined(noDocgen):
+    when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
       result.add(suggest.doc.escape)
     if suggest.version == 0:
       result.add(sep)
diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim
index decdf1715..60246b9bf 100644
--- a/compiler/syntaxes.nim
+++ b/compiler/syntaxes.nim
@@ -17,10 +17,10 @@ type
   TFilterKind* = enum
     filtNone, filtTemplate, filtReplace, filtStrip
   TParserKind* = enum
-    skinStandard, skinStrongSpaces, skinEndX
+    skinStandard, skinEndX
 
 const
-  parserNames*: array[TParserKind, string] = ["standard", "strongspaces",
+  parserNames*: array[TParserKind, string] = ["standard",
                                               "endx"]
   filterNames*: array[TFilterKind, string] = ["none", "stdtmpl", "replace",
                                               "strip"]
@@ -34,14 +34,14 @@ template config(p: TParsers): ConfigRef = p.parser.lex.config
 
 proc parseAll*(p: var TParsers): PNode =
   case p.skin
-  of skinStandard, skinStrongSpaces:
+  of skinStandard:
     result = parser.parseAll(p.parser)
   of skinEndX:
     internalError(p.config, "parser to implement")
 
 proc parseTopLevelStmt*(p: var TParsers): PNode =
   case p.skin
-  of skinStandard, skinStrongSpaces:
+  of skinStandard:
     result = parser.parseTopLevelStmt(p.parser)
   of skinEndX:
     internalError(p.config, "parser to implement")
@@ -153,21 +153,23 @@ proc openParsers*(p: var TParsers, fileIdx: FileIndex, inputstream: PLLStream;
   else: s = inputstream
   case p.skin
   of skinStandard, skinEndX:
-    parser.openParser(p.parser, fileIdx, s, cache, config, false)
-  of skinStrongSpaces:
-    parser.openParser(p.parser, fileIdx, s, cache, config, true)
+    parser.openParser(p.parser, fileIdx, s, cache, config)
 
 proc closeParsers*(p: var TParsers) =
   parser.closeParser(p.parser)
 
-proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode {.procvar.} =
-  var
-    p: TParsers
-    f: File
+proc setupParsers*(p: var TParsers; fileIdx: FileIndex; cache: IdentCache;
+                   config: ConfigRef): bool =
+  var f: File
   let filename = toFullPathConsiderDirty(config, fileIdx)
   if not open(f, filename.string):
     rawMessage(config, errGenerated, "cannot open file: " & filename.string)
-    return
+    return false
   openParsers(p, fileIdx, llStreamOpen(f), cache, config)
-  result = parseAll(p)
-  closeParsers(p)
+  result = true
+
+proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode {.procvar.} =
+  var p: TParsers
+  if setupParsers(p, fileIdx, cache, config):
+    result = parseAll(p)
+    closeParsers(p)
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 800d56b3a..7b2979dea 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -24,7 +24,8 @@ import
   sempass2, lowerings, destroyer, liftlocals,
   modulegraphs, lineinfos
 
-proc transformBody*(g: ModuleGraph, prc: PSym, cache = true): PNode
+proc transformBody*(g: ModuleGraph, prc: PSym, cache = true;
+                    noDestructors = false): PNode
 
 import closureiters, lambdalifting
 
@@ -48,7 +49,7 @@ type
     inlining: int            # > 0 if we are in inlining context (copy vars)
     nestedProcs: int         # > 0 if we are in a nested proc
     contSyms, breakSyms: seq[PSym]  # to transform 'continue' and 'break'
-    deferDetected, tooEarly, needsDestroyPass: bool
+    deferDetected, tooEarly, needsDestroyPass, noDestructors: bool
     graph: ModuleGraph
   PTransf = ref TTransfContext
 
@@ -130,7 +131,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
   let s = n.sym
   if s.typ != nil and s.typ.callConv == ccClosure:
     if s.kind in routineKinds:
-      discard transformBody(c.graph, s)
+      discard transformBody(c.graph, s, true, c.noDestructors)
     if s.kind == skIterator:
       if c.tooEarly: return n
       else: return liftIterSym(c.graph, n, getCurrOwner(c))
@@ -159,7 +160,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
       return
     tc = tc.next
   result = b
-  
+
 proc transformSym(c: PTransf, n: PNode): PTransNode =
   result = PTransNode(transformSymAux(c, n))
 
@@ -243,7 +244,7 @@ proc newLabel(c: PTransf, n: PNode): PSym =
   result.name = getIdent(c.graph.cache, genPrefix & $result.id)
 
 proc transformBlock(c: PTransf, n: PNode): PTransNode =
-  var labl: PSym 
+  var labl: PSym
   if c.inlining > 0:
     labl = newLabel(c, n[0])
     idNodeTablePut(c.transCon.mapping, n[0].sym, newSymNode(labl))
@@ -611,7 +612,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
       add(stmtList, newAsgnStmt(c, nkFastAsgn, temp, arg.PTransNode))
       idNodeTablePut(newC.mapping, formal, temp)
 
-  let body = transformBody(c.graph, iter)
+  let body = transformBody(c.graph, iter, true, c.noDestructors)
   pushInfoContext(c.graph.config, n.info)
   inc(c.inlining)
   add(stmtList, transform(c, body))
@@ -1029,7 +1030,8 @@ template liftDefer(c, root) =
   if c.deferDetected:
     liftDeferAux(root)
 
-proc transformBody*(g: ModuleGraph, prc: PSym, cache = true): PNode =
+proc transformBody*(g: ModuleGraph, prc: PSym, cache = true;
+                    noDestructors = false): PNode =
   assert prc.kind in routineKinds
 
   if prc.transformedBody != nil:
@@ -1037,22 +1039,22 @@ proc transformBody*(g: ModuleGraph, prc: PSym, cache = true): PNode =
   elif nfTransf in prc.ast[bodyPos].flags or prc.kind in {skTemplate}:
     result = prc.ast[bodyPos]
   else:
-
     prc.transformedBody = newNode(nkEmpty) # protects from recursion
     var c = openTransf(g, prc.getModule, "")
+    c.noDestructors = noDestructors
     result = liftLambdas(g, prc, prc.ast[bodyPos], c.tooEarly)
     result = processTransf(c, result, prc)
     liftDefer(c, result)
     result = liftLocalsIfRequested(prc, result, g.cache, g.config)
-    if c.needsDestroyPass: #and newDestructors:
+    if c.needsDestroyPass and not noDestructors:
       result = injectDestructorCalls(g, prc, result)
 
     if prc.isIterator:
       result = g.transformClosureIterator(prc, result)
-  
+
     incl(result.flags, nfTransf)
 
-    let cache = cache or prc.typ.callConv == ccInline 
+    let cache = cache or prc.typ.callConv == ccInline
     if cache:
       # genProc for inline procs will be called multiple times from diffrent modules,
       # it is important to transform exactly once to get sym ids and locations right
@@ -1072,7 +1074,8 @@ proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
       result = injectDestructorCalls(g, module, result)
     incl(result.flags, nfTransf)
 
-proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode =
+proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode;
+                    noDestructors = false): PNode =
   if nfTransf in n.flags:
     result = n
   else:
@@ -1081,6 +1084,6 @@ proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode =
     liftDefer(c, result)
     # expressions are not to be injected with destructor calls as that
     # the list of top level statements needs to be collected before.
-    if c.needsDestroyPass:
+    if c.needsDestroyPass and not noDestructors:
       result = injectDestructorCalls(g, module, result)
     incl(result.flags, nfTransf)
diff --git a/compiler/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/types.nim b/compiler/types.nim
index 05bae401c..b163ca4e9 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -528,7 +528,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
       result = "array[" & typeToString(t.sons[0]) & ", " &
           typeToString(t.sons[1]) & ']'
   of tyUncheckedArray:
-    result = "uncheckedArray[" & typeToString(t.sons[0]) & ']'
+    result = "UncheckedArray[" & typeToString(t.sons[0]) & ']'
   of tySequence:
     result = "seq[" & typeToString(t.sons[0]) & ']'
   of tyOpt:
@@ -1086,8 +1086,8 @@ proc inheritanceDiff*(a, b: PType): int =
   # | returns: +x iff `a` is the x'th direct subclass of `b`
   # | returns: `maxint` iff `a` and `b` are not compatible at all
   if a == b or a.kind == tyError or b.kind == tyError: return 0
-  assert a.kind == tyObject
-  assert b.kind == tyObject
+  assert a.kind in {tyObject} + skipPtrs
+  assert b.kind in {tyObject} + skipPtrs
   var x = a
   result = 0
   while x != nil:
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 420934470..c8784c3e7 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -413,26 +413,12 @@ proc recSetFlagIsRef(arg: PNode) =
     arg.sons[i].recSetFlagIsRef
 
 proc setLenSeq(c: PCtx; node: PNode; newLen: int; info: TLineInfo) =
-  # FIXME: this doesn't attempt to solve incomplete
-  # support of tyPtr, tyRef in VM.
   let typ = node.typ.skipTypes(abstractInst+{tyRange}-{tyTypeDesc})
-  let typeEntry = typ.sons[0].skipTypes(abstractInst+{tyRange}-{tyTypeDesc})
-  let typeKind = case typeEntry.kind
-                 of tyUInt..tyUInt64: nkUIntLit
-                 of tyRange, tyEnum, tyBool, tyChar, tyInt..tyInt64: nkIntLit
-                 of tyFloat..tyFloat128: nkFloatLit
-                 of tyString: nkStrLit
-                 of tyObject: nkObjConstr
-                 of tySequence: nkNilLit
-                 of tyProc, tyTuple: nkTupleConstr
-                 else: nkEmpty
-
   let oldLen = node.len
   setLen(node.sons, newLen)
   if oldLen < newLen:
-    # TODO: This is still not correct for tyPtr, tyRef default value
     for i in oldLen ..< newLen:
-      node.sons[i] = newNodeI(typeKind, info)
+      node.sons[i] = getNullValue(typ.sons[0], info, c.config)
 
 const
   errIndexOutOfBounds = "index out of bounds"
@@ -458,7 +444,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     #if c.traceActive:
     when traceCode:
       echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra, " rb ", instr.regB, " rc ", instr.regC
-    #  message(c.config, c.debug[pc], warnUser, "Trace")
+      # message(c.config, c.debug[pc], warnUser, "Trace")
 
     case instr.opcode
     of opcEof: return regs[ra]
@@ -488,6 +474,22 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcAsgnFloat:
       decodeB(rkFloat)
       regs[ra].floatVal = regs[rb].floatVal
+    of opcAsgnIntFromFloat32:
+      let rb = instr.regB
+      ensureKind(rkInt)
+      regs[ra].intVal = cast[int32](float32(regs[rb].floatVal))
+    of opcAsgnIntFromFloat64:
+      let rb = instr.regB
+      ensureKind(rkInt)
+      regs[ra].intVal = cast[int64](regs[rb].floatVal)
+    of opcAsgnFloat32FromInt:
+      let rb = instr.regB
+      ensureKind(rkFloat)
+      regs[ra].floatVal = cast[float32](int32(regs[rb].intVal))
+    of opcAsgnFloat64FromInt:
+      let rb = instr.regB
+      ensureKind(rkFloat)
+      regs[ra].floatVal = cast[float64](int64(regs[rb].intVal))
     of opcAsgnComplex:
       asgnComplex(regs[ra], regs[instr.regB])
     of opcAsgnRef:
@@ -929,10 +931,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       let a = regs[rb].node
       if a.kind == nkSym:
         regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit)
-                        else: 
+                        else:
                           let ast = a.sym.ast.shallowCopy
                           for i in 0..<a.sym.ast.len:
-                            ast[i] = a.sym.ast[i]                        
+                            ast[i] = a.sym.ast[i]
                           ast[bodyPos] = transformBody(c.graph, a.sym)
                           ast.copyTree()
     of opcSymOwner:
@@ -944,6 +946,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:
@@ -1212,7 +1225,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcOf:
       decodeBC(rkInt)
       let typ = c.types[regs[rc].intVal.int]
-      regs[ra].intVal = ord(inheritanceDiff(regs[rb].node.typ, typ) >= 0)
+      regs[ra].intVal = ord(inheritanceDiff(regs[rb].node.typ, typ) <= 0)
     of opcIs:
       decodeBC(rkInt)
       let t1 = regs[rb].node.typ.skipTypes({tyTypeDesc})
@@ -1806,7 +1819,7 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
       "NimScript: attempt to call non-routine: " & sym.name.s)
 
 proc evalStmt*(c: PCtx, n: PNode) =
-  let n = transformExpr(c.graph, c.module, n)
+  let n = transformExpr(c.graph, c.module, n, noDestructors = true)
   let start = genStmt(c, n)
   # execute new instructions; this redundant opcEof check saves us lots
   # of allocations in 'execute':
@@ -1814,7 +1827,7 @@ proc evalStmt*(c: PCtx, n: PNode) =
     discard execute(c, start)
 
 proc evalExpr*(c: PCtx, n: PNode): PNode =
-  let n = transformExpr(c.graph, c.module, n)
+  let n = transformExpr(c.graph, c.module, n, noDestructors = true)
   let start = genExpr(c, n)
   assert c.code[start].opcode != opcEof
   result = execute(c, start)
@@ -1861,7 +1874,7 @@ const evalPass* = makePass(myOpen, myProcess, myClose)
 proc evalConstExprAux(module: PSym;
                       g: ModuleGraph; prc: PSym, n: PNode,
                       mode: TEvalMode): PNode =
-  let n = transformExpr(g, module, n)
+  let n = transformExpr(g, module, n, noDestructors = true)
   setupGlobalCtx(module, g)
   var c = PCtx g.vm
   let oldMode = c.mode
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index 875ae5a52..493078f74 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -35,6 +35,10 @@ type
     opcAsgnStr,
     opcAsgnFloat,
     opcAsgnRef,
+    opcAsgnIntFromFloat32,    # int and float must be of the same byte size
+    opcAsgnIntFromFloat64,    # int and float must be of the same byte size
+    opcAsgnFloat32FromInt,    # int and float must be of the same byte size
+    opcAsgnFloat64FromInt,    # int and float must be of the same byte size
     opcAsgnComplex,
     opcNodeToReg,
 
@@ -143,7 +147,8 @@ type
     opcTypeTrait,
     opcMarshalLoad, opcMarshalStore,
     opcToNarrowInt,
-    opcSymOwner
+    opcSymOwner,
+    opcSymIsInstantiationOf
 
   TBlock* = object
     label*: PSym
diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim
index b39f85b50..f160a3096 100644
--- a/compiler/vmdeps.nim
+++ b/compiler/vmdeps.nim
@@ -82,12 +82,9 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
     id
   template newIdentDefs(s): untyped = newIdentDefs(s, s.typ)
 
-  if inst:
-    if t.sym != nil:  # if this node has a symbol
-      if not allowRecursion:  # getTypeInst behavior: return symbol
-        return atomicType(t.sym)
-      #else:  # getTypeImpl behavior: turn off recursion
-      #  allowRecursion = false
+  if inst and not allowRecursion and t.sym != nil:
+    # getTypeInst behavior: return symbol
+    return atomicType(t.sym)
 
   case t.kind
   of tyNone: result = atomicType("none", mNone)
@@ -100,7 +97,7 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
   of tyEmpty: result = atomicType("empty", mNone)
   of tyUncheckedArray:
     result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
-    result.add atomicType("uncheckedArray", mUncheckedArray)
+    result.add atomicType("UncheckedArray", mUncheckedArray)
     result.add mapTypeToAst(t.sons[0], info)
   of tyArray:
     result = newNodeIT(nkBracketExpr, if t.n.isNil: info else: t.n.info, t)
@@ -160,9 +157,13 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
   of tyObject:
     if inst:
       result = newNodeX(nkObjectTy)
-      result.add newNodeI(nkEmpty, info)  # pragmas not reconstructed yet
-      if t.sons[0] == nil: result.add newNodeI(nkEmpty, info)  # handle parent object
+      if t.sym.ast != nil:
+        result.add t.sym.ast[2][0].copyTree  # copy object pragmas
       else:
+        result.add newNodeI(nkEmpty, info)
+      if t.sons[0] == nil:
+        result.add newNodeI(nkEmpty, info)
+      else:  # handle parent object
         var nn = newNodeX(nkOfInherit)
         nn.add mapTypeToAst(t.sons[0], info)
         result.add nn
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index c59581aca..1f2a3e6d1 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -182,7 +182,10 @@ const
   HighRegisterPressure = 40
 
 proc bestEffort(c: PCtx): TLineInfo =
-  (if c.prc == nil: c.module.info else: c.prc.sym.info)
+  if c.prc != nil and c.prc.sym != nil:
+    c.prc.sym.info
+  else:
+    c.module.info
 
 proc getTemp(cc: PCtx; tt: PType): TRegister =
   let typ = tt.skipTypesOrNil({tyStatic})
@@ -769,18 +772,18 @@ proc genCard(c: PCtx; n: PNode; dest: var TDest) =
   c.gABC(n, opcCard, dest, tmp)
   c.freeTemp(tmp)
 
-proc genIntCast(c: PCtx; n: PNode; dest: var TDest) =
+proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
   const allowedIntegers = {tyInt..tyInt64, tyUInt..tyUInt64, tyChar}
   var signedIntegers = {tyInt8..tyInt32}
   var unsignedIntegers = {tyUInt8..tyUInt32, tyChar}
   let src = n.sons[1].typ.skipTypes(abstractRange)#.kind
   let dst = n.sons[0].typ.skipTypes(abstractRange)#.kind
   let src_size = getSize(c.config, src)
-
+  let dst_size = getSize(c.config, dst)
   if c.config.target.intSize < 8:
     signedIntegers.incl(tyInt)
     unsignedIntegers.incl(tyUInt)
-  if src_size == getSize(c.config, dst) and src.kind in allowedIntegers and
+  if src_size == dst_size and src.kind in allowedIntegers and
                                  dst.kind in allowedIntegers:
     let tmp = c.genx(n.sons[1])
     var tmp2 = c.getTemp(n.sons[1].typ)
@@ -809,8 +812,28 @@ proc genIntCast(c: PCtx; n: PNode; dest: var TDest) =
     c.freeTemp(tmp)
     c.freeTemp(tmp2)
     c.freeTemp(tmp3)
+  elif src_size == dst_size and src.kind in allowedIntegers and
+                           dst.kind in {tyFloat, tyFloat32, tyFloat64}:
+    let tmp = c.genx(n[1])
+    if dest < 0: dest = c.getTemp(n[0].typ)
+    if dst.kind == tyFloat32:
+      c.gABC(n, opcAsgnFloat32FromInt, dest, tmp)
+    else:
+      c.gABC(n, opcAsgnFloat64FromInt, dest, tmp)
+    c.freeTemp(tmp)
+
+  elif src_size == dst_size and src.kind in {tyFloat, tyFloat32, tyFloat64} and
+                           dst.kind in allowedIntegers:
+    let tmp = c.genx(n[1])
+    if dest < 0: dest = c.getTemp(n[0].typ)
+    if src.kind == tyFloat32:
+      c.gABC(n, opcAsgnIntFromFloat32, dest, tmp)
+    else:
+      c.gABC(n, opcAsgnIntFromFloat64, dest, tmp)
+    c.freeTemp(tmp)
+
   else:
-    globalError(c.config, n.info, "VM is only allowed to 'cast' between integers of same size")
+    globalError(c.config, n.info, "VM is only allowed to 'cast' between integers and/or floats of same size")
 
 proc genVoidABC(c: PCtx, n: PNode, dest: TDest, opcode: TOpcode) =
   unused(c, n, dest)
@@ -1075,7 +1098,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     var tmp = c.genx(n.sons[1])
     var idx = c.getTemp(getSysType(c.graph, n.info, tyInt))
     var typ = n.sons[2].typ
-    if m == mOf: typ = typ.skipTypes(abstractPtrs-{tyTypeDesc})
+    if m == mOf: typ = typ.skipTypes(abstractPtrs)
     c.gABx(n, opcLdImmInt, idx, c.genType(typ))
     c.gABC(n, if m == mOf: opcOf else: opcIs, dest, tmp, idx)
     c.freeTemp(tmp)
@@ -1092,13 +1115,14 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mEcho:
     unused(c, n, dest)
     let n = n[1].skipConv
-    let x = c.getTempRange(n.len, slotTempUnknown)
-    internalAssert c.config, n.kind == nkBracket
-    for i in 0..<n.len:
-      var r: TRegister = x+i
-      c.gen(n.sons[i], r)
-    c.gABC(n, opcEcho, x, n.len)
-    c.freeTempRange(x, n.len)
+    if n.kind == nkBracket:
+      # can happen for nim check, see bug #9609
+      let x = c.getTempRange(n.len, slotTempUnknown)
+      for i in 0..<n.len:
+        var r: TRegister = x+i
+        c.gen(n.sons[i], r)
+      c.gABC(n, opcEcho, x, n.len)
+      c.freeTempRange(x, n.len)
   of mAppendStrCh:
     unused(c, n, dest)
     genBinaryStmtVar(c, n, opcAddStrCh)
@@ -1124,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)
@@ -1214,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:
@@ -1234,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)
@@ -2008,7 +2033,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     if allowCast in c.features:
       genConv(c, n, n.sons[1], dest, opcCast)
     else:
-      genIntCast(c, n, dest)
+      genCastIntFloat(c, n, dest)
   of nkTypeOfExpr:
     genTypeLit(c, n.typ, dest)
   of nkComesFrom:
@@ -2130,7 +2155,8 @@ proc genProc(c: PCtx; s: PSym): int =
     s.ast.sons[miscPos] = x
     # thanks to the jmp we can add top level statements easily and also nest
     # procs easily:
-    let body = transformBody(c.graph, s, cache = not isCompileTimeProc(s))
+    let body = transformBody(c.graph, s, cache = not isCompileTimeProc(s),
+                             noDestructors = true)
     let procStart = c.xjmp(body, opcJmp, 0)
     var p = PProc(blocks: @[], sym: s)
     let oldPrc = c.prc
diff --git a/compiler/vmops.nim b/compiler/vmops.nim
index 83e65279a..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, fmod
+  floor, ceil, `mod`
 
 from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir
 
@@ -21,9 +21,6 @@ template mathop(op) {.dirty.} =
 template osop(op) {.dirty.} =
   registerCallback(c, "stdlib.os." & astToStr(op), `op Wrapper`)
 
-template ospathsop(op) {.dirty.} =
-  registerCallback(c, "stdlib.ospaths." & astToStr(op), `op Wrapper`)
-
 template systemop(op) {.dirty.} =
   registerCallback(c, "stdlib.system." & astToStr(op), `op Wrapper`)
 
@@ -105,12 +102,15 @@ 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)))
+  registerCallback(c, "stdlib.math.mod", `mod Wrapper`)
 
   when defined(nimcore):
-    wrap2s(getEnv, ospathsop)
-    wrap1s(existsEnv, ospathsop)
-    wrap2svoid(putEnv, ospathsop)
+    wrap2s(getEnv, osop)
+    wrap1s(existsEnv, osop)
+    wrap2svoid(putEnv, osop)
     wrap1s(dirExists, osop)
     wrap1s(fileExists, osop)
     wrap2svoid(writeFile, systemop)
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index 800b5dc18..41bdc9fcb 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -69,13 +69,13 @@ type
     wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wLocks,
     wPartial, wExplain, wLiftLocals,
 
-    wAuto, wBool, wCatch, wChar, wClass,
+    wAuto, wBool, wCatch, wChar, wClass, wCompl
     wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast,
     wExplicit, wExtern, wFalse, wFloat, wFriend,
     wGoto, wInt, wLong, wMutable, wNamespace, wNew, wOperator,
-    wPrivate, wProtected, wPublic, wRegister, wReinterpret_cast,
+    wPrivate, wProtected, wPublic, wRegister, wReinterpret_cast, wRestrict,
     wShort, wSigned, wSizeof, wStatic_cast, wStruct, wSwitch,
-    wThis, wThrow, wTrue, wTypedef, wTypeid, wTypename,
+    wThis, wThrow, wTrue, wTypedef, wTypeid, wTypeof, wTypename,
     wUnion, wPacked, wUnsigned, wVirtual, wVoid, wVolatile, wWchar_t,
 
     wAlignas, wAlignof, wConstexpr, wDecltype, wNullptr, wNoexcept,
@@ -156,14 +156,14 @@ const
     "asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked",
     "guard", "locks", "partial", "explain", "liftlocals",
 
-    "auto", "bool", "catch", "char", "class",
+    "auto", "bool", "catch", "char", "class", "compl",
     "const_cast", "default", "delete", "double",
     "dynamic_cast", "explicit", "extern", "false",
     "float", "friend", "goto", "int", "long", "mutable",
     "namespace", "new", "operator",
-    "private", "protected", "public", "register", "reinterpret_cast",
+    "private", "protected", "public", "register", "reinterpret_cast", "restrict",
     "short", "signed", "sizeof", "static_cast", "struct", "switch",
-    "this", "throw", "true", "typedef", "typeid",
+    "this", "throw", "true", "typedef", "typeid", "typeof",
     "typename", "union", "packed", "unsigned", "virtual", "void", "volatile",
     "wchar_t",
 
diff --git a/config/nim.cfg b/config/nim.cfg
index 9626a3197..932e80331 100644
--- a/config/nim.cfg
+++ b/config/nim.cfg
@@ -73,6 +73,19 @@ path="$lib/pure"
   opt:speed
 @end
 
+@if unix and mingw:
+  # Cross compile for Windows from Linux/OSX using MinGW
+  os = windows
+
+  i386.windows.gcc.path = "/usr/bin"
+  i386.windows.gcc.exe = "i686-w64-mingw32-gcc"
+  i386.windows.gcc.linkerexe = "i686-w64-mingw32-gcc"
+
+  amd64.windows.gcc.path = "/usr/bin"
+  amd64.windows.gcc.exe = "x86_64-w64-mingw32-gcc"
+  amd64.windows.gcc.linkerexe = "x86_64-w64-mingw32-gcc"
+@end
+
 @if unix:
   @if not bsd or haiku:
     # -fopenmp
diff --git a/doc/advopt.txt b/doc/advopt.txt
index a1b709f04..60cae7fd0 100644
--- a/doc/advopt.txt
+++ b/doc/advopt.txt
@@ -11,8 +11,9 @@ Advanced commands:
   //buildIndex              build an index for the whole documentation
   //run                     run the project (with Tiny C backend; buggy!)
   //genDepend               generate a DOT file containing the
-                            module dependency graph
+                          module dependency graph
   //dump                    dump all defined conditionals and search paths
+                            see also: --dump.format:json (useful with: ` | jq`)
   //check                   checks the project for syntax and semantic
 
 Advanced options:
@@ -25,6 +26,13 @@ Advanced options:
   --warning[X]:on|off       turn specific warning X on|off
   --hints:on|off|list       turn all hints on|off or list all available
   --hint[X]:on|off          turn specific hint X on|off
+  --styleCheck:off|hint|error
+                            produce hints or errors for Nim identifiers that
+                            do not adhere to Nim's official style guide
+                            https://nim-lang.org/docs/nep1.html
+  --showAllMismatches:on|off
+                            show all mismatching candidates in overloading
+                            resolution
   --lib:PATH                set the system library path
   --import:PATH             add an automatically imported module
   --include:PATH            add an automatically included module
@@ -94,7 +102,9 @@ 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)
+  --errorMax:N              stop compilation after N errors; 0 means unlimited
   --experimental:$1
                             enable experimental language feature
   -v, --version             show detailed version information
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/codeowners.rst b/doc/codeowners.rst
index 0758e3ffb..129c47cfc 100644
--- a/doc/codeowners.rst
+++ b/doc/codeowners.rst
@@ -51,7 +51,7 @@ async                          dom96
 strutils                       araq
 sequtils                       dom96, araq
 times                          GULPF
-os, ospaths                    dom96, araq
+os                             dom96, araq
 re                             araq
 nre                            flaviu
 math, fenv                     krux02, cooldome
diff --git a/doc/contributing.rst b/doc/contributing.rst
index 35cdd9f09..e3ab697d3 100644
--- a/doc/contributing.rst
+++ b/doc/contributing.rst
@@ -22,7 +22,7 @@ There are 3 types of tests:
 2. tests in ``when isMainModule:`` block, ran by ``nim c mymod.nim``
    ``nimble test`` also typially runs these in external nimble packages.
 
-3. testament tests, eg: tests/stdlib/tospaths.nim (only used for Nim repo).
+3. testament tests, eg: tests/stdlib/tos.nim (only used for Nim repo).
 
 Not all the tests follow the convention here, feel free to change the ones
 that don't. Always leave the code cleaner than you found it.
@@ -30,7 +30,7 @@ that don't. Always leave the code cleaner than you found it.
 Stdlib
 ------
 
-If you change the stdlib (anything under ``lib/``, eg ``lib/pure/ospaths.nim``),
+If you change the stdlib (anything under ``lib/``, eg ``lib/pure/os.nim``),
 put a test in the file you changed. Add the tests under a ``when isMainModule:``
 condition so they only get executed when the tester is building the
 file. Each test should be in a separate ``block:`` statement, such that
@@ -53,7 +53,7 @@ Sample test:
       doAssert: not 1 == 2
 
 Newer tests tend to be run via ``testament`` rather than via ``when isMainModule:``,
-eg ``tests/stdlib/tospaths.nim``; this allows additional features such as custom
+eg ``tests/stdlib/tos.nim``; this allows additional features such as custom
 compiler flags; for more details see below.
 
 Compiler
@@ -197,7 +197,7 @@ as well as ``testament`` and guarantee they stay in sync.
 
      result = a & "Bar"
 
-See `parentDir <https://nim-lang.github.io/Nim/ospaths.html#parentDir%2Cstring>`_
+See `parentDir <https://nim-lang.github.io/Nim/os.html#parentDir%2Cstring>`_
 example.
 
 The RestructuredText Nim uses has a special syntax for including code snippets
@@ -263,17 +263,8 @@ Take advantage of no implicit bool conversion
   doAssert isValid() == true
   doAssert isValid() # preferred
 
-.. _immediately_invoked_lambdas:
-Immediately invoked lambdas (https://en.wikipedia.org/wiki/Immediately-invoked_function_expression)
-
-.. code-block:: nim
-
-  let a = (proc (): auto = getFoo())()
-  let a = block:  # preferred
-    getFoo()
-
 .. _design_for_mcs:
-Design with method call syntax (UFCS in other languages) chaining in mind
+Design with method call syntax chaining in mind
 
 .. code-block:: nim
 
@@ -334,7 +325,14 @@ The Git stuff
 General commit rules
 --------------------
 
-1. All changes introduced by the commit (diff lines) must be related to the
+1. Bugfixes that should be backported to the latest stable release should
+   contain the string ``[backport]`` in the commit message! There will be an
+   outmated process relying on these. However, bugfixes also have the inherent
+   risk of causing regressions which are worse for a "stable, bugfixes-only"
+   branch, so in doubt, leave out the ``[backport]``. Standard library bugfixes
+   are less critical than compiler bugfixes.
+
+2. All changes introduced by the commit (diff lines) must be related to the
    subject of the commit.
 
    If you change something unrelated to the subject parts of the file, because
@@ -344,7 +342,7 @@ General commit rules
    *Tip:* Never commit everything as is using ``git commit -a``, but review
    carefully your changes with ``git add -p``.
 
-2. Changes should not introduce any trailing whitespace.
+3. Changes should not introduce any trailing whitespace.
 
    Always check your changes for whitespace errors using ``git diff --check``
    or add following ``pre-commit`` hook:
@@ -354,7 +352,7 @@ General commit rules
       #!/bin/sh
       git diff --check --cached || exit $?
 
-3. Describe your commit and use your common sense.
+4. Describe your commit and use your common sense.
 
    Example Commit messages: ``Fixes #123; refs #124``
 
@@ -362,7 +360,7 @@ General commit rules
    close it when the PR is committed), wheres issue ``#124`` is referenced
    (eg: partially fixed) and won't close the issue when committed.
 
-4. Commits should be always be rebased against devel (so a fast forward
+5. Commits should be always be rebased against devel (so a fast forward
    merge can happen)
 
    eg: use ``git pull --rebase origin devel``. This is to avoid messing up
@@ -372,7 +370,7 @@ General commit rules
    https://github.com/nim-lang/Nim/pull/9356
 
 
-5. Do not mix pure formatting changes (eg whitespace changes, nimpretty) or
+6. Do not mix pure formatting changes (eg whitespace changes, nimpretty) or
    automated changes (eg nimfix) with other code changes: these should be in
    separate commits (and the merge on github should not squash these into 1).
 
diff --git a/doc/filters.rst b/doc/filters.rst
index e8106749e..40346ecaf 100644
--- a/doc/filters.rst
+++ b/doc/filters.rst
@@ -31,13 +31,16 @@ Usage
 =====
 
 First, put your SCF code in a separate file with filters specified in the first line. 
-**Note:** You can name your SCF file with any file extension you want, but the conventional extension is ``.tmpl``.
+**Note:** You can name your SCF file with any file extension you want, but the
+conventional extension is ``.nimf``
+(it used to be ``.tmpl`` but that was too generic, for example preventing github to
+recognize it as Nim source file).
 
-If we use `generateXML` code shown above and call the SCF file `xmlGen.tmpl`
+If we use `generateXML` code shown above and call the SCF file `xmlGen.nimf`
 In your `main.nim`:
 
 .. code-block:: nim
-  include "xmlGen.tmpl"
+  include "xmlGen.nimf"
   
   echo generateXML("John Smith","42")
 
diff --git a/doc/grammar.txt b/doc/grammar.txt
index e06ebd5d9..b5aa6fd5a 100644
--- a/doc/grammar.txt
+++ b/doc/grammar.txt
@@ -9,7 +9,7 @@ operator =  OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9
          | 'is' | 'isnot' | 'in' | 'notin' | 'of'
          | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'static' | '..'
 prefixOperator = operator
-optInd = COMMENT?
+optInd = COMMENT? IND?
 optPar = (IND{>} | IND{=})?
 simpleExpr = arrowExpr (OP0 optInd arrowExpr)* pragma?
 arrowExpr = assignExpr (OP1 optInd assignExpr)*
@@ -85,17 +85,19 @@ paramListColon = paramList? (':' optInd typeDesc)?
 doBlock = 'do' paramListArrow pragmas? colcom stmt
 procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
 distinct = 'distinct' optInd typeDesc
+forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt
+forExpr = forStmt
 expr = (blockExpr
       | ifExpr
       | whenExpr
       | caseExpr
+      | forExpr
       | tryExpr)
       / simpleExpr
 typeKeyw = 'var' | 'out' | 'ref' | 'ptr' | 'shared' | 'tuple'
          | 'proc' | 'iterator' | 'distinct' | 'object' | 'enum'
 primary = typeKeyw typeDescK
         /  prefixOperator* identOrLiteral primarySuffix*
-        / 'static' primary
         / 'bind' primary
 typeDesc = simpleExpr
 typeDefAux = simpleExpr
@@ -142,12 +144,11 @@ tryExpr = 'try' colcom stmt &(optInd 'except'|'finally')
            (optInd 'except' exprList colcom stmt)*
            (optInd 'finally' colcom stmt)?
 exceptBlock = 'except' colcom stmt
-forStmt = 'for' (identWithPragma ^+ comma) 'in' expr colcom stmt
 blockStmt = 'block' symbol? colcom stmt
 blockExpr = 'block' symbol? colcom stmt
 staticStmt = 'static' colcom stmt
 deferStmt = 'defer' colcom stmt
-asmStmt = 'asm' pragma? (STR_LIT | RSTR_LIT | TRIPLE_STR_LIT)
+asmStmt = 'asm' pragma? (STR_LIT | RSTR_LIT | TRIPLESTR_LIT)
 genericParam = symbol (comma symbol)* (colon expr)? ('=' optInd expr)?
 genericParamList = '[' optInd
   genericParam ^* (comma/semicolon) optPar ']'
diff --git a/doc/intern.rst b/doc/intern.rst
index 0fa4fd7b6..b71ad592f 100644
--- a/doc/intern.rst
+++ b/doc/intern.rst
@@ -31,7 +31,7 @@ Path           Purpose
                reStructuredText files
 ``lib``        the Nim library
 ``web``        website of Nim; generated by ``nimweb``
-               from the ``*.txt`` and ``*.tmpl`` files
+               from the ``*.txt`` and ``*.nimf`` files
 ============   ===================================================
 
 
diff --git a/doc/lib.rst b/doc/lib.rst
index 89ab26d81..c0119d36d 100644
--- a/doc/lib.rst
+++ b/doc/lib.rst
@@ -147,10 +147,17 @@ String handling
 * `subexes <subexes.html>`_
   This module implements advanced string substitution operations.
 
-* `editdistance <editdistance>`_
+* `std/editdistance <editdistance.html>`_
   This module contains an algorithm to compute the edit distance between two
   Unicode strings.
 
+* `std/wordwrap <wordwrap.html>`_
+  This module contains an algorithm to wordwrap a Unicode string.
+
+* `std/diff <diff.html>`_
+  This module contains an algorithm to compute the famous "diff"
+  of two texts by line.
+
 
 Generic Operating System Services
 ---------------------------------
diff --git a/doc/manual.rst b/doc/manual.rst
index 98943619d..a646b7963 100644
--- a/doc/manual.rst
+++ b/doc/manual.rst
@@ -514,6 +514,9 @@ are used for other notational purposes.
 ``*:`` is as a special case treated as the two tokens `*`:tok: and `:`:tok:
 (to support ``var v*: T``).
 
+The ``not`` keyword is always a unary operator, ``a not b`` is parsed
+as ``a(not b)``, not as ``(a) not (b)``.
+
 
 Other tokens
 ------------
@@ -1231,6 +1234,37 @@ so that the builtin ``echo`` proc does what is expected:
   # prints "@[1, 2, 3]" and not "123"
 
 
+Unchecked arrays
+----------------
+The ``UncheckedArray[T]`` type is a special kind of ``array`` where its bounds
+are not checked. This is often useful to implement customized flexibly sized
+arrays. Additionally an unchecked array is translated into a C array of
+undetermined size:
+
+.. code-block:: nim
+  type
+    MySeq = object
+      len, cap: int
+      data: UncheckedArray[int]
+
+Produces roughly this C code:
+
+.. code-block:: C
+  typedef struct {
+    NI len;
+    NI cap;
+    NI data[];
+  } MySeq;
+
+The base type of the unchecked array may not contain any GC'ed memory but this
+is currently not checked.
+
+**Future directions**: GC'ed memory should be allowed in unchecked arrays and
+there should be an explicit annotation of how the GC is to determine the
+runtime size of the array.
+
+
+
 Tuples and object types
 -----------------------
 A variable of a tuple or object type is a heterogeneous storage
@@ -2349,7 +2383,8 @@ Automatic self insertions
 Starting with version 0.14 of the language, Nim supports ``field`` as a
 shortcut for ``self.field`` comparable to the `this`:idx: keyword in Java
 or C++. This feature has to be explicitly enabled via a ``{.this: self.}``
-statement pragma. This pragma is active for the rest of the module:
+statement pragma (instead of ``self`` any other identifier can be used too).
+This pragma is active for the rest of the module:
 
 .. code-block:: nim
   type
@@ -2364,10 +2399,6 @@ statement pragma. This pragma is active for the rest of the module:
     # is rewritten to:
     # result = self.parentField + self.childField
 
-Instead of ``self`` any other identifier can be used too, but
-``{.this: self.}`` will become the default directive for the whole language
-eventually.
-
 In addition to fields, routine applications are also rewritten, but only
 if no other interpretation of the call is possible:
 
@@ -6724,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
@@ -7897,36 +7938,6 @@ defined, and it should not be used with GC'ed memory (ref's).
 **Future directions**: Using GC'ed memory in packed pragma will result in
 compile-time error. Usage with inheritance should be defined and documented.
 
-Unchecked pragma
-----------------
-The ``unchecked`` pragma can be used to mark a named array as ``unchecked``
-meaning its bounds are not checked. This is often useful to
-implement customized flexibly sized arrays. Additionally an unchecked array is
-translated into a C array of undetermined size:
-
-.. code-block:: nim
-  type
-    ArrayPart{.unchecked.} = array[0, int]
-    MySeq = object
-      len, cap: int
-      data: ArrayPart
-
-Produces roughly this C code:
-
-.. code-block:: C
-  typedef struct {
-    NI len;
-    NI cap;
-    NI data[];
-  } MySeq;
-
-The base type of the unchecked array may not contain any GC'ed memory but this
-is currently not checked.
-
-**Future directions**: GC'ed memory should be allowed in unchecked arrays and
-there should be an explicit annotation of how the GC is to determine the
-runtime size of the array.
-
 
 Dynlib pragma for import
 ------------------------
diff --git a/doc/nimc.rst b/doc/nimc.rst
index 0fa2cd038..e1bf98ece 100644
--- a/doc/nimc.rst
+++ b/doc/nimc.rst
@@ -261,6 +261,21 @@ configuration file should contain something like::
   arm.linux.gcc.exe = "arm-linux-gcc"
   arm.linux.gcc.linkerexe = "arm-linux-gcc"
 
+Cross compilation for Windows
+=============================
+
+To cross compile for Windows from Linux or OSX using the MinGW-w64 toolchain::
+
+  nim c -d:mingw myproject.nim
+
+Use ``--cpu:i386`` or ``--cpu:amd64`` to switch the cpu arch.
+
+The MinGW-w64 toolchain can be installed as follows::
+
+  Ubuntu: apt install mingw-w64
+  CentOS: yum install mingw32-gcc | mingw64-gcc - requires EPEL
+  OSX: brew install mingw-w64
+
 Cross compilation for Nintendo Switch
 =====================================
 
diff --git a/doc/nims.rst b/doc/nims.rst
index dea09e1e8..034ad1fda 100644
--- a/doc/nims.rst
+++ b/doc/nims.rst
@@ -31,7 +31,7 @@ available. So the stdlib modules using ``importc`` cannot be used with
 Nim's VM. However, at least the following modules are available:
 
 * `macros <macros.html>`_
-* `ospaths <ospaths.html>`_
+* `os <os.html>`_
 * `strutils <strutils.html>`_
 * `math <math.html>`_
 * `distros <distros.html>`_
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/install.txt b/install.txt
deleted file mode 100644
index 6ab562b07..000000000
--- a/install.txt
+++ /dev/null
@@ -1,88 +0,0 @@
-Installation
-============
-
-Installation on Linux/UNIX
---------------------------
-
-The GNU C Compiler is fully supported, other compilers may work. The C compiler
-should be in your ``$PATH`` (most likely the case). Note that some few Linux
-distributions do not ship with a GCC compiler preinstalled - then you have to
-install it.
-
-Install Nim by downloading the appropriate ``.tar.xz`` file and extracting it
-to a directory of your choice. The Nim Compiler will stay in this
-directory (unless you copy it somewhere else). The compiler does not need
-write access to its directory, so copying the nim folder to ``/opt``
-works.
-
-Then run the following command::
-
-  sh build.sh
-
-Unlike other software, Nim does not distribute its files over the whole file
-hierarchy. This has the advantage that you can deinstall it by just deleting
-its folder. The disadvantage is that you have to add it to your ``PATH``
-manually. An alternative is to create a symbolic link in ``/usr/bin``::
-
-  [sudo] ln -s $your_install_dir/bin/nim  /usr/bin/nim
-
-There are also ``install.sh`` and ``deinstall.sh`` scripts for distributing
-the files over the UNIX hierarchy. However, updating your Nim installation
-is more cumbersome then.
-
-To complete the installation you should also build Nim's tools like
-``nimsuggest``, ``nimble`` or ``nimgrep`` via::
-
-  nim c koch
-  koch tools
-
-Note that these tools should also end up in your ``PATH`` so adding
-``$your_install_dir/bin/nim`` to your ``PATH`` is preferred over the symlink
-solution.
-
-
-Installation on the Macintosh
------------------------------
-
-Only MacOS X is supported.
-Since MacOS X is UNIX based too, it works like the installation on Linux.
-However, for unknown reasons the symbolic link method does not work on MacOS X.
-You need to install Apple's developer's tools for the GNU Compiler Collection
-or clang.
-
-
-Installation on Windows
------------------------
-
-Install Nim by downloading and unzipping the ``nim_$version.zip`` file.
-Run ``finish.exe`` to detect and setup your MingW environment.
-
-Currently, the following C compilers are supported under Windows:
-
-- | Microsoft's Visual C++
-  | http://msdn.microsoft.com/visualc
-  | (You need the SDK too - but not the full one: Only
-    the win32api header files and import libraries are essential.)
-- | Gnu C Compiler (the mingw version; the cygwin version has not been tested!)
-  | http://www.mingw.org/download.shtml
-- | LLVM with Clang or GNU C/C++ frontend
-  | http://llvm.org/releases/download.html
-
-However, most testing is done with GCC.
-
-Bootstrapping from GitHub
--------------------------
-
-Take a look at the readme file on github `here <https://github.com/nim-lang/Nim#readme>`_
-for instructions.
-
-
-Installation of Nimble
-----------------------
-
-Nimble is Nim's package manager. For the source based installations where you
-added Nim's ``bin`` directory to your ``$PATH`` the easiest way of installing
-Nimble is via::
-
-  nim c koch
-  koch nimble
diff --git a/issue_template.md b/issue_template.md
deleted file mode 100644
index 42e29eacd..000000000
--- a/issue_template.md
+++ /dev/null
@@ -1,14 +0,0 @@
-<!--- Summarize the Problem here, keep it simple. -->
-<!--- Think about the title twice. -->
-
-## Example
-<!--- This could be a source code block -->
-
-## Possible Solution/Expected Behavior
-<!--- Without a solution the problem can't be fixed. -->
-
-## Additional Information
-<!--- For Example:
-   A link to a project where the issue is relevant.
-   A link to a related issue or discussion.
-   -->
diff --git a/koch.nim b/koch.nim
index a77f5cc3a..3f528a1b2 100644
--- a/koch.nim
+++ b/koch.nim
@@ -51,6 +51,9 @@ Boot options:
   -d:release               produce a release version of the compiler
   -d:useLinenoise          use the linenoise library for interactive mode
                            (not needed on Windows)
+  -d:leanCompiler          produce a compiler without JS codegen or
+                           documentation generator in order to use less RAM
+                           for bootstrapping
 
 Commands for core developers:
   docs [options]           generates the full documentation
@@ -76,6 +79,9 @@ template withDir(dir, body) =
   finally:
     setCurrentdir(old)
 
+let origDir = getCurrentDir()
+setCurrentDir(getAppDir())
+
 proc tryExec(cmd: string): bool =
   echo(cmd)
   result = execShellCmd(cmd) == 0
@@ -112,10 +118,11 @@ proc bundleNimbleSrc(latest: bool) =
 
 proc bundleNimbleExe(latest: bool) =
   bundleNimbleSrc(latest)
-  # now compile Nimble and copy it to $nim/bin for the installer.ini
-  # to pick it up:
-  nimexec("c -d:release --nilseqs:on dist/nimble/src/nimble.nim")
-  copyExe("dist/nimble/src/nimble".exe, "bin/nimble".exe)
+  # installer.ini expects it under $nim/bin
+  nimCompile("dist/nimble/src/nimble.nim", options = "-d:release --nilseqs:on")
+
+proc buildNimfind() =
+  nimCompile("tools/nimfind.nim", options = "-d:release")
 
 proc buildNimble(latest: bool) =
   # old installations created nim/nimblepkg/*.nim files. We remove these
@@ -141,33 +148,28 @@ proc buildNimble(latest: bool) =
       else:
         exec("git checkout -f stable")
       exec("git pull")
-  nimexec("c --noNimblePath -p:compiler --nilseqs:on -d:release " & installDir / "src/nimble.nim")
-  copyExe(installDir / "src/nimble".exe, "bin/nimble".exe)
+  nimCompile(installDir / "src/nimble.nim", options = "--noNimblePath --nilseqs:on -d:release")
 
-proc bundleNimsuggest(buildExe: bool) =
-  if buildExe:
-    nimexec("c --noNimblePath -d:release -p:compiler nimsuggest/nimsuggest.nim")
-    copyExe("nimsuggest/nimsuggest".exe, "bin/nimsuggest".exe)
-    removeFile("nimsuggest/nimsuggest".exe)
+proc bundleNimsuggest() =
+  nimCompile("nimsuggest/nimsuggest.nim", options = "-d:release")
 
 proc buildVccTool() =
-  nimexec("c -o:bin/vccexe.exe tools/vccenv/vccexe")
+  nimCompile("tools/vccenv/vccexe.nim")
 
 proc bundleWinTools() =
-  nimexec("c tools/finish.nim")
-  copyExe("tools/finish".exe, "finish".exe)
-  removeFile("tools/finish".exe)
+  # TODO: consider building under `bin` instead of `.`
+  nimCompile("tools/finish.nim", outputDir = "")
+
   buildVccTool()
-  nimexec("c -o:bin/nimgrab.exe -d:ssl tools/nimgrab.nim")
-  nimexec("c -o:bin/nimgrep.exe tools/nimgrep.nim")
+  nimCompile("tools/nimgrab.nim", options = "-d:ssl")
+  nimCompile("tools/nimgrep.nim")
   when false:
     # not yet a tool worth including
-    nimexec(r"c --cc:vcc --app:gui -o:bin\downloader.exe -d:ssl --noNimblePath " &
-            r"--path:..\ui tools\downloader.nim")
+    nimCompile(r"tools\downloader.nim", options = r"--cc:vcc --app:gui -d:ssl --noNimblePath --path:..\ui")
 
 proc zip(latest: bool; args: string) =
   bundleNimbleExe(latest)
-  bundleNimsuggest(true)
+  bundleNimsuggest()
   bundleWinTools()
   nimexec("cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" %
        [VersionAsString, compileNimInst])
@@ -184,7 +186,8 @@ proc ensureCleanGit() =
 proc xz(latest: bool; args: string) =
   ensureCleanGit()
   bundleNimbleSrc(latest)
-  bundleNimsuggest(false)
+  when false:
+    bundleNimsuggest()
   nimexec("cc -r $2 --var:version=$1 --var:mingw=none --main:compiler/nim.nim scripts compiler/installer.ini" %
        [VersionAsString, compileNimInst])
   exec("$# --var:version=$# --var:mingw=none --main:compiler/nim.nim xz compiler/installer.ini" %
@@ -195,19 +198,16 @@ proc buildTool(toolname, args: string) =
   copyFile(dest="bin" / splitFile(toolname).name.exe, source=toolname.exe)
 
 proc buildTools(latest: bool) =
-  nimexec "c --noNimblePath -p:compiler -d:release -o:" & ("bin/nimsuggest".exe) &
-      " nimsuggest/nimsuggest.nim"
-
-  nimexec "c -d:release -o:" & ("bin/nimgrep".exe) & " tools/nimgrep.nim"
+  bundleNimsuggest()
+  nimCompile("tools/nimgrep.nim", options = "-d:release")
   when defined(windows): buildVccTool()
-
-  nimexec "c -o:" & ("bin/nimpretty".exe) & " nimpretty/nimpretty.nim"
-
+  nimCompile("nimpretty/nimpretty.nim", options = "-d:release")
   buildNimble(latest)
+  buildNimfind()
 
 proc nsis(latest: bool; args: string) =
   bundleNimbleExe(latest)
-  bundleNimsuggest(true)
+  bundleNimsuggest()
   bundleWinTools()
   # make sure we have generated the niminst executables:
   buildTool("tools/niminst/niminst", args)
@@ -379,9 +379,7 @@ proc winRelease*() =
 template `|`(a, b): string = (if a.len > 0: a else: b)
 
 proc tests(args: string) =
-  # we compile the tester with taintMode:on to have a basic
-  # taint mode test :-)
-  nimexec "cc --taintMode:on --opt:speed testament/tester"
+  nimexec "cc --opt:speed testament/tester"
   # Since tests take a long time (on my machine), and we want to defy Murhpys
   # law - lets make sure the compiler really is freshly compiled!
   nimexec "c --lib:lib -d:release --opt:speed compiler/nim.nim"
@@ -407,14 +405,16 @@ proc temp(args: string) =
       result[1].add " " & quoteShell(args[i])
       inc i
 
-  var output = "compiler" / "nim".exe
-  var finalDest = "bin" / "nim_temp".exe
+  let d = getAppDir()
+  var output = d / "compiler" / "nim".exe
+  var finalDest = d / "bin" / "nim_temp".exe
   # 125 is the magic number to tell git bisect to skip the current
   # commit.
   let (bootArgs, programArgs) = splitArgs(args)
   let nimexec = findNim()
-  exec(nimexec & " c -d:debug --debugger:native " & bootArgs & " compiler" / "nim", 125)
+  exec(nimexec & " c -d:debug --debugger:native " & bootArgs & " " & (d / "compiler" / "nim"), 125)
   copyExe(output, finalDest)
+  setCurrentDir(origDir)
   if programArgs.len > 0: exec(finalDest & " " & programArgs)
 
 proc xtemp(cmd: string) =
@@ -544,7 +544,7 @@ when isMainModule:
       of "nimble":
         if stable: buildNimble(false)
         else: buildNimble(existsDir(".git") or latest)
-      of "nimsuggest": bundleNimsuggest(buildExe=true)
+      of "nimsuggest": bundleNimsuggest()
       of "tools":
         if stable: buildTools(false)
         else: buildTools(existsDir(".git") or latest)
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/locks.nim b/lib/core/locks.nim
index f9add0037..d6d579ba0 100644
--- a/lib/core/locks.nim
+++ b/lib/core/locks.nim
@@ -17,8 +17,6 @@ type
                   ## or not is unspecified!
   Cond* = SysCond ## Nim condition variable
 
-{.deprecated: [TLock: Lock, TCond: Cond].}
-
 {.push stackTrace: off.}
 
 proc initLock*(lock: var Lock) {.inline.} =
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 3801adfc5..f45ca3f82 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -168,6 +168,18 @@ proc `[]`*(n: NimNode, i: int): NimNode {.magic: "NChild", noSideEffect.}
 proc `[]`*(n: NimNode, i: BackwardsIndex): NimNode = n[n.len - i.int]
   ## get `n`'s `i`'th child.
 
+template `^^`(n: NimNode, i: untyped): untyped =
+  (when i is BackwardsIndex: n.len - int(i) else: int(i))
+
+proc `[]`*[T, U](n: NimNode, x: HSlice[T, U]): seq[NimNode] =
+  ## slice operation for NimNode.
+  ## returns a seq of child of `n` who inclusive range [n[x.a], n[x.b]].
+  let xa = n ^^ x.a
+  let L = (n ^^ x.b) - xa + 1
+  result = newSeq[NimNode](L)
+  for i in 0..<L:
+    result[i] = n[i + xa]
+
 proc `[]=`*(n: NimNode, i: int, child: NimNode) {.magic: "NSetChild",
   noSideEffect.}
   ## set `n`'s `i`'th child to `child`.
@@ -262,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
@@ -406,8 +424,6 @@ type
                          ## if not ambiguous (this cannot be achieved with
                          ## any other means in the language currently)
 
-{.deprecated: [TBindSymRule: BindSymRule].}
-
 proc bindSym*(ident: string | NimNode, rule: BindSymRule = brClosed): NimNode {.
               magic: "NBindSym", noSideEffect.}
   ## creates a node that binds `ident` to a symbol node. The bound symbol
@@ -696,6 +712,16 @@ proc newLit*[T](arg: seq[T]): NimNode {.compileTime.} =
     ),
     bracket
   )
+proc newLit*(arg: enum): NimNode {.compileTime.} =
+  result = newCall(
+    arg.type.getTypeInst[1],
+    newLit(int(arg))
+  )
+
+proc newLit*[T](s: set[T]): NimNode {.compileTime.} =
+  result = nnkCurly.newTree
+  for x in s:
+    result.add newLit(x)
 
 proc newLit*(arg: tuple): NimNode {.compileTime.} =
   result = nnkPar.newTree
@@ -732,72 +758,56 @@ proc nestList*(theProc: NimIdent, x: NimNode): NimNode {.compileTime, deprecated
   for i in countdown(L-3, 0):
     result = newCall(theProc, x[i], result)
 
-proc treeRepr*(n: NimNode): string {.compileTime, benign.} =
-  ## Convert the AST `n` to a human-readable tree-like string.
-  ##
-  ## See also `repr`, `lispRepr`, and `astGenRepr`.
-
-  proc traverse(res: var string, level: int, n: NimNode) {.benign.} =
-    for i in 0..level-1: res.add "  "
-    res.add(($n.kind).substr(3))
-
-    case n.kind
-    of nnkEmpty, nnkNilLit: discard # same as nil node in this representation
-    of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal)
-    of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal)
-    of nnkStrLit..nnkTripleStrLit, nnkIdent, nnkSym:
-      res.add(" " & $n.strVal.newLit.repr)
-    of nnkNone: assert false
+proc treeTraverse(n: NimNode; res: var string; level = 0; isLisp = false, indented = false) {.benign.} =
+  if level > 0:
+    if indented:
+      res.add("\n")
+      for i in 0 .. level-1:
+        if isLisp:
+          res.add(" ")          # dumpLisp indentation
+        else:
+          res.add("  ")         # dumpTree indentation
     else:
-      for j in 0..n.len-1:
-        res.add "\n"
-        traverse(res, level + 1, n[j])
-
-  result = ""
-  traverse(result, 0, n)
+      res.add(" ")
 
-proc lispRepr*(n: NimNode): string {.compileTime, benign.} =
-  ## Convert the AST `n` to a human-readable lisp-like string,
-  ##
-  ## See also `repr`, `treeRepr`, and `astGenRepr`.
-
-  result = ($n.kind).substr(3)
-  add(result, "(")
+  if isLisp:
+    res.add("(")
+  res.add(($n.kind).substr(3))
 
   case n.kind
-  of nnkEmpty, nnkNilLit: discard # same as nil node in this representation
-  of nnkCharLit..nnkInt64Lit: add(result, $n.intVal)
-  of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
-  of nnkStrLit..nnkTripleStrLit, nnkCommentStmt, nnkident, nnkSym:
-    add(result, n.strVal.newLit.repr)
-  of nnkNone: assert false
+  of nnkEmpty, nnkNilLit:
+    discard # same as nil node in this representation
+  of nnkCharLit .. nnkInt64Lit:
+    res.add(" " & $n.intVal)
+  of nnkFloatLit .. nnkFloat64Lit:
+    res.add(" " & $n.floatVal)
+  of nnkStrLit .. nnkTripleStrLit, nnkCommentStmt, nnkIdent, nnkSym:
+    res.add(" " & $n.strVal.newLit.repr)
+  of nnkNone:
+    assert false
   else:
-    if n.len > 0:
-      add(result, lispRepr(n[0]))
-      for j in 1..n.len-1:
-        add(result, ", ")
-        add(result, lispRepr(n[j]))
+    for j in 0 .. n.len-1:
+      n[j].treeTraverse(res, level+1, isLisp, indented)
 
-  add(result, ")")
+  if isLisp:
+    res.add(")")
 
-proc astGenRepr*(n: NimNode): string {.compileTime, benign.} =
-  ## Convert the AST `n` to the code required to generate that AST. So for example
-  ##
-  ## .. code-block:: nim
-  ##   astGenRepr:
-  ##     echo "Hello world"
+proc treeRepr*(n: NimNode): string {.compileTime, benign.} =
+  ## Convert the AST `n` to a human-readable tree-like string.
   ##
-  ## Would output:
+  ## See also `repr`, `lispRepr`, and `astGenRepr`.
+  n.treeTraverse(result, isLisp = false, indented = true)
+
+proc lispRepr*(n: NimNode; indented = false): string {.compileTime, benign.} =
+  ## Convert the AST ``n`` to a human-readable lisp-like string.
   ##
-  ## .. code-block:: nim
-  ##   nnkStmtList.newTree(
-  ##     nnkCommand.newTree(
-  ##       newIdentNode("echo"),
-  ##       newLit("Hello world")
-  ##     )
-  ##   )
+  ## See also ``repr``, ``treeRepr``, and ``astGenRepr``.
+  n.treeTraverse(result, isLisp = true, indented = indented)
+
+proc astGenRepr*(n: NimNode): string {.compileTime, benign.} =
+  ## Convert the AST ``n`` to the code required to generate that AST.
   ##
-  ## See also `repr`, `treeRepr`, and `lispRepr`.
+  ## See also ``repr``, ``treeRepr``, and ``lispRepr``.
 
   const
     NodeKinds = {nnkEmpty, nnkIdent, nnkSym, nnkNone, nnkCommentStmt}
@@ -842,26 +852,76 @@ proc astGenRepr*(n: NimNode): string {.compileTime, benign.} =
 
 macro dumpTree*(s: untyped): untyped = echo s.treeRepr
   ## Accepts a block of nim code and prints the parsed abstract syntax
-  ## tree using the `treeRepr` function. Printing is done *at compile time*.
+  ## tree using the ``treeRepr`` proc. Printing is done *at compile time*.
   ##
   ## You can use this as a tool to explore the Nim's abstract syntax
   ## tree and to discover what kind of nodes must be created to represent
   ## a certain expression/statement.
+  ##
+  ## For example:
+  ##
+  ## .. code-block:: nim
+  ##    dumpTree:
+  ##      echo "Hello, World!"
+  ##
+  ## Outputs:
+  ##
+  ## .. code-block::
+  ##    StmtList
+  ##      Command
+  ##        Ident "echo"
+  ##        StrLit "Hello, World!"
+  ##
+  ## Also see ``dumpAstGen`` and ``dumpLisp``.
 
-macro dumpLisp*(s: untyped): untyped = echo s.lispRepr
+macro dumpLisp*(s: untyped): untyped = echo s.lispRepr(indented = true)
   ## Accepts a block of nim code and prints the parsed abstract syntax
-  ## tree using the `lispRepr` function. Printing is done *at compile time*.
+  ## tree using the ``lispRepr`` proc. Printing is done *at compile time*.
+  ##
+  ## You can use this as a tool to explore the Nim's abstract syntax
+  ## tree and to discover what kind of nodes must be created to represent
+  ## a certain expression/statement.
   ##
-  ## See `dumpTree`.
+  ## For example:
+  ##
+  ## .. code-block:: nim
+  ##    dumpLisp:
+  ##      echo "Hello, World!"
+  ##
+  ## Outputs:
+  ##
+  ## .. code-block::
+  ##    (StmtList
+  ##     (Command
+  ##      (Ident "echo")
+  ##      (StrLit "Hello, World!")))
+  ##
+  ## Also see ``dumpAstGen`` and ``dumpTree``.
 
 macro dumpAstGen*(s: untyped): untyped = echo s.astGenRepr
   ## Accepts a block of nim code and prints the parsed abstract syntax
-  ## tree using the `astGenRepr` function. Printing is done *at compile time*.
+  ## tree using the ``astGenRepr`` proc. Printing is done *at compile time*.
   ##
   ## You can use this as a tool to write macros quicker by writing example
   ## outputs and then copying the snippets into the macro for modification.
   ##
-  ## See `dumpTree`.
+  ## For example:
+  ##
+  ## .. code-block:: nim
+  ##    dumpAstGen:
+  ##      echo "Hello, World!"
+  ##
+  ## Outputs:
+  ##
+  ## .. code-block:: nim
+  ##    nnkStmtList.newTree(
+  ##      nnkCommand.newTree(
+  ##        newIdentNode("echo"),
+  ##        newLit("Hello, World!")
+  ##      )
+  ##    )
+  ##
+  ## Also see ``dumpTree`` and ``dumpLisp``.
 
 macro dumpTreeImm*(s: untyped): untyped {.deprecated.} = echo s.treeRepr
   ## Deprecated. Use `dumpTree` instead.
@@ -1053,10 +1113,18 @@ proc name*(someProc: NimNode): NimNode {.compileTime.} =
   someProc.expectRoutine
   result = someProc[0]
   if result.kind == nnkPostfix:
-    result = result[1]
+    if result[1].kind == nnkAccQuoted:
+      result = result[1][0]
+    else:
+      result = result[1]
+  elif result.kind == nnkAccQuoted:
+    result = result[0]
+
 proc `name=`*(someProc: NimNode; val: NimNode) {.compileTime.} =
   someProc.expectRoutine
-  someProc[0] = val
+  if someProc[0].kind == nnkPostfix:
+    someProc[0][1] = val
+  else: someProc[0] = val
 
 proc params*(someProc: NimNode): NimNode {.compileTime.} =
   someProc.expectRoutine
diff --git a/lib/core/seqs.nim b/lib/core/seqs.nim
index 4dcf6cbbb..a41ef10ab 100644
--- a/lib/core/seqs.nim
+++ b/lib/core/seqs.nim
@@ -8,9 +8,11 @@
 #
 
 
-import typetraits
+# import typetraits
 # strs already imported allocators for us.
 
+proc supportsCopyMem(t: typedesc): bool {.magic: "TypeTrait".}
+
 ## Default seq implementation used by Nim's core.
 type
   NimSeqPayload {.core.}[T] = object
@@ -83,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
@@ -92,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'"
@@ -122,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 = 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 c78752360..cfb8f8f5d 100644
--- a/lib/core/typeinfo.nim
+++ b/lib/core/typeinfo.nim
@@ -83,8 +83,6 @@ when not defined(js):
   template `rawType=`(x: var Any, p: PNimType) =
     x.rawTypePtr = cast[pointer](p)
 
-{.deprecated: [TAny: Any, TAnyKind: AnyKind].}
-
 when defined(gogc):
   const GenericSeqSize = (3 * sizeof(int))
 else:
@@ -108,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/deprecated/pure/actors.nim b/lib/deprecated/pure/actors.nim
index 451668825..77c67a3e4 100644
--- a/lib/deprecated/pure/actors.nim
+++ b/lib/deprecated/pure/actors.nim
@@ -111,7 +111,6 @@ type
     actors: seq[PActor[In, Out]]
     when Out isnot void:
       outputs: Channel[Out]
-{.deprecated: [TActorPool: ActorPool].}
 
 proc `^`*[T](f: ptr Channel[T]): T =
   ## alias for 'recv'.
diff --git a/lib/deprecated/pure/asyncio.nim b/lib/deprecated/pure/asyncio.nim
index 161941e53..2dd08024d 100644
--- a/lib/deprecated/pure/asyncio.nim
+++ b/lib/deprecated/pure/asyncio.nim
@@ -147,11 +147,6 @@ type
     SockIdle, SockConnecting, SockConnected, SockListening, SockClosed,
     SockUDPBound
 
-{.deprecated: [TDelegate: DelegateObj, PDelegate: Delegate,
-  TInfo: SocketStatus, PAsyncSocket: AsyncSocket, TAsyncSocket: AsyncSocketObj,
-  TDispatcher: DispatcherObj, PDispatcher: Dispatcher,
-  ].}
-
 
 proc newDelegate*(): Delegate =
   ## Creates a new delegate.
@@ -180,7 +175,7 @@ proc asyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
                   protocol: Protocol = IPPROTO_TCP,
                   buffered = true): AsyncSocket =
   ## Initialises an AsyncSocket object. If a socket cannot be initialised
-  ## EOS is raised.
+  ## OSError is raised.
   result = newAsyncSocket()
   result.socket = socket(domain, typ, protocol, buffered)
   result.proto = protocol
@@ -476,7 +471,7 @@ proc recvLine*(s: AsyncSocket, line: var TaintedString): bool {.deprecated.} =
   ## if this function can only retrieve some data; it will save this data and
   ## add it to the result when a full line is retrieved.
   ##
-  ## Unlike ``sockets.recvLine`` this function will raise an EOS or ESSL
+  ## Unlike ``sockets.recvLine`` this function will raise an OSError or SslError
   ## exception if an error occurs.
   ##
   ## **Deprecated since version 0.9.2**: This function has been deprecated in
@@ -512,7 +507,7 @@ proc readLine*(s: AsyncSocket, line: var TaintedString): bool =
   ## retrieved or the socket has been disconnected in which case ``line`` will
   ## be set to "".
   ##
-  ## This function will raise an EOS exception when a socket error occurs.
+  ## This function will raise an OSError exception when a socket error occurs.
   setLen(line.string, 0)
   var dataReceived = "".TaintedString
   var ret = s.socket.readLineAsync(dataReceived)
diff --git a/lib/deprecated/pure/ftpclient.nim b/lib/deprecated/pure/ftpclient.nim
index 7645258b6..d70f9556a 100644
--- a/lib/deprecated/pure/ftpclient.nim
+++ b/lib/deprecated/pure/ftpclient.nim
@@ -108,11 +108,6 @@ type
   ReplyError* = object of IOError
   FTPError* = object of IOError
 
-{.deprecated: [
-  TFTPClient: FTPClientObj, TFTPJob: FTPJob, PAsyncFTPClient: AsyncFTPClient,
-  TAsyncFTPClient: AsyncFTPClientObj, TFTPEvent: FTPEvent,
-  EInvalidReply: ReplyError, EFTP: FTPError
-].}
 
 const multiLineLimit = 10000
 
diff --git a/lib/deprecated/pure/ospaths.nim b/lib/deprecated/pure/ospaths.nim
new file mode 100644
index 000000000..34d452fd2
--- /dev/null
+++ b/lib/deprecated/pure/ospaths.nim
@@ -0,0 +1,21 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2015 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module is deprecated, ``import os`` instead.
+{.deprecated: "import os.nim instead".}
+
+import os
+export ReadEnvEffect, WriteEnvEffect, ReadDirEffect, WriteDirEffect, OSErrorCode,
+  doslikeFileSystem, CurDir, ParDir, DirSep, AltSep, PathSep, FileSystemCaseSensitive,
+  ExeExt, ScriptExt, DynlibFormat, ExtSep, joinPath, `/`, splitPath, parentDir,
+  tailDir, isRootDir, parentDirs, `/../`, searchExtPos, splitFile, extractFilename,
+  lastPathPart, changeFileExt, addFileExt, cmpPaths, isAbsolute, unixToNativePath,
+  `==`, `$`, osErrorMsg, raiseOSError, osLastError, getEnv, existsEnv, putEnv,
+  getHomeDir, getConfigDir, getTempDir, expandTilde, quoteShellWindows,
+  quoteShellPosix, quoteShell, quoteShellCommand
diff --git a/lib/deprecated/pure/parseurl.nim b/lib/deprecated/pure/parseurl.nim
index 6d58e8a73..b19f6dc85 100644
--- a/lib/deprecated/pure/parseurl.nim
+++ b/lib/deprecated/pure/parseurl.nim
@@ -22,8 +22,6 @@ type
     scheme, username, password,
     hostname, port, path, query, anchor: string]
 
-{.deprecated: [TUrl: Url].}
-
 proc parseUrl*(url: string): Url {.deprecated.} =
   var i = 0
 
diff --git a/lib/deprecated/pure/sockets.nim b/lib/deprecated/pure/sockets.nim
index ed15f67e2..f78df0b2b 100644
--- a/lib/deprecated/pure/sockets.nim
+++ b/lib/deprecated/pure/sockets.nim
@@ -23,7 +23,7 @@
 ##
 ## SSL is supported through the OpenSSL library. This support can be activated
 ## by compiling with the ``-d:ssl`` switch. When an SSL socket is used it will
-## raise ESSL exceptions when SSL errors occur.
+## raise SslError exceptions when SSL errors occur.
 ##
 ## Asynchronous sockets are supported, however a better alternative is to use
 ## the `asyncio <asyncio.html>`_ module.
@@ -70,9 +70,6 @@ when defined(ssl):
     SSLAcceptResult* = enum
       AcceptNoClient = 0, AcceptNoHandshake, AcceptSuccess
 
-  {.deprecated: [ESSL: SSLError, TSSLCVerifyMode: SSLCVerifyMode,
-     TSSLProtVersion: SSLProtVersion, PSSLContext: SSLContext,
-     TSSLAcceptResult: SSLAcceptResult].}
 
 const
   BufferSize*: int = 4000 ## size of a buffered socket's buffer
@@ -147,12 +144,6 @@ type
 
   TimeoutError* = object of Exception
 
-{.deprecated: [TSocket: Socket, TType: SockType, TPort: Port, TDomain: Domain,
-    TProtocol: Protocol, TServent: Servent, THostent: Hostent,
-    TSOBool: SOBool, TRecvLineResult: RecvLineResult,
-    TReadLineResult: ReadLineResult, ETimeout: TimeoutError,
-    TSocketImpl: SocketImpl].}
-
 when defined(booting):
   let invalidSocket*: Socket = nil ## invalid socket
 else:
@@ -262,7 +253,7 @@ proc socket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM,
              protocol: Protocol = IPPROTO_TCP, buffered = true): Socket =
   ## Creates a new socket; returns `InvalidSocket` if an error occurs.
 
-  # TODO: Perhaps this should just raise EOS when an error occurs.
+  # TODO: Perhaps this should just raise OSError when an error occurs.
   when defined(Windows):
     result = newTSocket(winlean.socket(cint(domain), cint(typ), cint(protocol)), buffered)
   else:
@@ -422,7 +413,7 @@ proc parseIp4*(s: string): BiggestInt =
   ##
   ## This is equivalent to `inet_ntoa`:idx:.
   ##
-  ## Raises EInvalidValue in case of an error.
+  ## Raises ValueError in case of an error.
   var a, b, c, d: int
   var i = 0
   var j = parseInt(s, a, i)
@@ -543,7 +534,7 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string) {.
   ## If ``server`` is non-blocking then this function returns immediately, and
   ## if there are no connections queued the returned socket will be
   ## ``InvalidSocket``.
-  ## This function will raise EOS if an error occurs.
+  ## This function will raise OSError if an error occurs.
   ##
   ## The resulting client will inherit any properties of the server socket. For
   ## example: whether the socket is buffered or not.
@@ -664,7 +655,7 @@ proc close*(socket: Socket) =
     discard winlean.closesocket(socket.fd)
   else:
     discard posix.close(socket.fd)
-  # TODO: These values should not be discarded. An EOS should be raised.
+  # TODO: These values should not be discarded. An OSError should be raised.
   # http://stackoverflow.com/questions/12463473/what-happens-if-you-call-close-on-a-bsd-socket-multiple-times
   when defined(ssl):
     if socket.isSSL:
@@ -920,7 +911,7 @@ when defined(ssl):
     ## Returns ``False`` whenever the socket is not yet ready for a handshake,
     ## ``True`` whenever handshake completed successfully.
     ##
-    ## A ESSL error is raised on any other errors.
+    ## A SslError error is raised on any other errors.
     result = true
     if socket.isSSL:
       var ret = SSLConnect(socket.sslHandle)
@@ -946,7 +937,7 @@ when defined(ssl):
     ## Determines whether a handshake has occurred between a client (``socket``)
     ## and the server that ``socket`` is connected to.
     ##
-    ## Throws ESSL if ``socket`` is not an SSL socket.
+    ## Throws SslError if ``socket`` is not an SSL socket.
     if socket.isSSL:
       return not socket.sslNoHandshake
     else:
@@ -1215,7 +1206,7 @@ proc recv*(socket: Socket, data: var string, size: int, timeout = -1): int =
   ##
   ## When 0 is returned the socket's connection has been closed.
   ##
-  ## This function will throw an EOS exception when an error occurs. A value
+  ## This function will throw an OSError exception when an error occurs. A value
   ## lower than 0 is never returned.
   ##
   ## A timeout may be specified in milliseconds, if enough data is not received
@@ -1273,7 +1264,7 @@ proc recvLine*(socket: Socket, line: var TaintedString, timeout = -1): bool {.
   ## will be set to it.
   ##
   ## ``True`` is returned if data is available. ``False`` suggests an
-  ## error, EOS exceptions are not raised and ``False`` is simply returned
+  ## error, OSError exceptions are not raised and ``False`` is simply returned
   ## instead.
   ##
   ## If the socket is disconnected, ``line`` will be set to ``""`` and ``True``
@@ -1321,7 +1312,7 @@ proc readLine*(socket: Socket, line: var TaintedString, timeout = -1) {.
   ##
   ## If the socket is disconnected, ``line`` will be set to ``""``.
   ##
-  ## An EOS exception will be raised in the case of a socket error.
+  ## An OSError exception will be raised in the case of a socket error.
   ##
   ## A timeout can be specified in milliseconds, if data is not received within
   ## the specified time an ETimeout exception will be raised.
@@ -1394,7 +1385,7 @@ proc readLineAsync*(socket: Socket,
   ##   * If some data has been retrieved; ``ReadPartialLine`` is returned.
   ##   * If the socket has been disconnected; ``ReadDisconnected`` is returned.
   ##   * If no data could be retrieved; ``ReadNone`` is returned.
-  ##   * If call to ``recv`` failed; **an EOS exception is raised.**
+  ##   * If call to ``recv`` failed; **an OSError exception is raised.**
   setLen(line.string, 0)
 
   template errorOrNone =
@@ -1421,7 +1412,7 @@ proc readLineAsync*(socket: Socket,
 
 proc recv*(socket: Socket): TaintedString {.tags: [ReadIOEffect], deprecated.} =
   ## receives all the available data from the socket.
-  ## Socket errors will result in an ``EOS`` error.
+  ## Socket errors will result in an ``OSError`` error.
   ## If socket is not a connectionless socket and socket is not connected
   ## ``""`` will be returned.
   ##
@@ -1470,7 +1461,7 @@ proc recvAsync*(socket: Socket, s: var TaintedString): bool {.
   tags: [ReadIOEffect], deprecated.} =
   ## receives all the data from a non-blocking socket. If socket is non-blocking
   ## and there are no messages available, `False` will be returned.
-  ## Other socket errors will result in an ``EOS`` error.
+  ## Other socket errors will result in an ``OSError`` error.
   ## If socket is not a connectionless socket and socket is not connected
   ## ``s`` will be set to ``""``.
   ##
@@ -1547,7 +1538,7 @@ proc recvFromAsync*(socket: Socket, data: var string, length: int,
                     address: var string, port: var Port,
                     flags = 0'i32): bool {.tags: [ReadIOEffect].} =
   ## Variant of ``recvFrom`` for non-blocking sockets. Unlike ``recvFrom``,
-  ## this function will raise an EOS error whenever a socket error occurs.
+  ## this function will raise an OSError error whenever a socket error occurs.
   ##
   ## If there is no data to be read from the socket ``False`` will be returned.
   result = true
@@ -1622,7 +1613,7 @@ proc sendAsync*(socket: Socket, data: string): int {.tags: [WriteIOEffect].} =
   ## returns the amount of bytes of ``data`` that was successfully sent. This
   ## number may not always be the length of ``data`` but typically is.
   ##
-  ## An EOS (or ESSL if socket is an SSL socket) exception is raised if an error
+  ## An OSError (or SslError if socket is an SSL socket) exception is raised if an error
   ## occurs.
   result = send(socket, cstring(data), data.len)
   when defined(ssl):
@@ -1656,7 +1647,7 @@ proc sendAsync*(socket: Socket, data: string): int {.tags: [WriteIOEffect].} =
 
 
 proc trySend*(socket: Socket, data: string): bool {.tags: [WriteIOEffect].} =
-  ## safe alternative to ``send``. Does not raise an EOS when an error occurs,
+  ## safe alternative to ``send``. Does not raise an OSError when an error occurs,
   ## and instead returns ``false`` on failure.
   result = send(socket, cstring(data), data.len) == data.len
 
diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim
index 26bc7d0ad..2fcb56202 100644
--- a/lib/impure/db_mysql.nim
+++ b/lib/impure/db_mysql.nim
@@ -96,7 +96,6 @@ type
                        ## column text on demand
     row: cstringArray
     len: int
-{.deprecated: [TRow: Row, TDbConn: DbConn].}
 
 proc dbError*(db: DbConn) {.noreturn.} =
   ## raises a DbError exception.
diff --git a/lib/impure/db_odbc.nim b/lib/impure/db_odbc.nim
index 224bcbb50..72d7aa800 100644
--- a/lib/impure/db_odbc.nim
+++ b/lib/impure/db_odbc.nim
@@ -101,8 +101,6 @@ type
                                                     ## used to get a row's
                                                     ## column text on demand
 
-{.deprecated: [TRow: Row, TSqlQuery: SqlQuery, TDbConn: DbConn].}
-
 var
   buf: array[0..4096, char]
 
diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim
index e765cc197..800673ca0 100644
--- a/lib/impure/db_postgres.nim
+++ b/lib/impure/db_postgres.nim
@@ -76,7 +76,6 @@ type
     res: PPGresult     ## used to get a row's
     line: int          ## column text on demand
   SqlPrepared* = distinct string ## a identifier for the prepared queries
-{.deprecated: [TRow: Row, TDbConn: DbConn, TSqlPrepared: SqlPrepared].}
 
 proc dbError*(db: DbConn) {.noreturn.} =
   ## raises a DbError exception.
diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim
index 52a168096..c7e373098 100644
--- a/lib/impure/db_sqlite.nim
+++ b/lib/impure/db_sqlite.nim
@@ -94,7 +94,6 @@ type
                        ## converted to nil.
   InstantRow* = Pstmt  ## a handle that can be used to get a row's column
                        ## text on demand
-{.deprecated: [TRow: Row, TDbConn: DbConn].}
 
 proc dbError*(db: DbConn) {.noreturn.} =
   ## raises a DbError exception.
diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim
index ce3fb2aff..94dd89db5 100644
--- a/lib/impure/nre.nim
+++ b/lib/impure/nre.nim
@@ -8,7 +8,7 @@
 
 
 from pcre import nil
-import nre.private.util
+import nre/private/util
 import tables
 from strutils import `%`
 from math import ceil
@@ -23,6 +23,12 @@ export options
 ##
 ## A regular expression library for Nim using PCRE to do the hard work.
 ##
+## For documentation on how to write patterns, there exists `the official PCRE
+## pattern documentation
+## <https://www.pcre.org/original/doc/html/pcrepattern.html>`_. You can also
+## search the internet for a wide variety of third-party documentation and
+## tools.
+##
 ## **Note**: If you love ``sequtils.toSeq`` we have bad news for you. This
 ## library doesn't work with it due to documented compiler limitations. As
 ## a workaround, use this:
@@ -59,7 +65,7 @@ runnableExamples:
   let hasVowel = firstVowel.isSome()
   if hasVowel:
     let matchBounds = firstVowel.get().captureBounds[-1]
-    doAssert matchBounds.get().a == 1
+    doAssert matchBounds.a == 1
 
 
 # Type definitions {{{
@@ -70,7 +76,10 @@ type
     ## comment".``
     ##
     ## ``pattern: string``
-    ##     the string that was used to create the pattern.
+    ##     the string that was used to create the pattern. For details on how
+    ##     to write a pattern, please see `the official PCRE pattern
+    ##     documentation.
+    ##     <https://www.pcre.org/original/doc/html/pcrepattern.html>`_
     ##
     ## ``captureCount: int``
     ##     the number of captures that the pattern has.
@@ -126,6 +135,12 @@ type
     ## Convention <http://man7.org/linux/man-pages/man3/pcresyntax.3.html#NEWLINE_CONVENTION>`_
     ## sections of the `PCRE syntax
     ## manual <http://man7.org/linux/man-pages/man3/pcresyntax.3.html>`_.
+    ##
+    ## Some of these options are not part of PCRE and are converted by nre
+    ## into PCRE flags. These include ``NEVER_UTF``, ``ANCHORED``,
+    ## ``DOLLAR_ENDONLY``, ``FIRSTLINE``, ``NO_AUTO_CAPTURE``,
+    ## ``JAVASCRIPT_COMPAT``, ``U``, ``NO_STUDY``. In other PCRE wrappers, you
+    ## will need to pass these as seperate flags to PCRE.
     pattern*: string  ## not nil
     pcreObj: ptr pcre.Pcre  ## not nil
     pcreExtra: ptr pcre.ExtraData  ## nil
@@ -152,14 +167,15 @@ type
     ##     -  ``"abc".match(re"(?<letter>\w)").get.captures["letter"] == "a"``
     ##     -  ``"abc".match(re"(\w)\w").get.captures[-1] == "ab"``
     ##
-    ## ``captureBounds[]: Option[HSlice[int, int]]``
+    ## ``captureBounds[]: HSlice[int, int]``
     ##     gets the bounds of the given capture according to the same rules as
     ##     the above. If the capture is not filled, then ``None`` is returned.
     ##     The bounds are both inclusive.
     ##
-    ##     -  ``"abc".match(re"(\w)").get.captureBounds[0].get == 0 .. 0``
-    ##     -  ``"abc".match(re"").get.captureBounds[-1].get == 0 .. -1``
-    ##     -  ``"abc".match(re"abc").get.captureBounds[-1].get == 0 .. 2``
+    ##     -  ``"abc".match(re"(\w)").get.captureBounds[0] == 0 .. 0``
+    ##     -  ``0 in "abc".match(re"(\w)").get.captureBounds == true``
+    ##     -  ``"abc".match(re"").get.captureBounds[-1] == 0 .. -1``
+    ##     -  ``"abc".match(re"abc").get.captureBounds[-1] == 0 .. 2``
     ##
     ## ``match: string``
     ##     the full text of the match.
@@ -212,9 +228,10 @@ runnableExamples:
     doAssert "abc".match(re"(?<letter>\w)").get.captures["letter"] == "a"
     doAssert "abc".match(re"(\w)\w").get.captures[-1] == "ab"
 
-    doAssert "abc".match(re"(\w)").get.captureBounds[0].get == 0 .. 0
-    doAssert "abc".match(re"").get.captureBounds[-1].get == 0 .. -1
-    doAssert "abc".match(re"abc").get.captureBounds[-1].get == 0 .. 2
+    doAssert "abc".match(re"(\w)").get.captureBounds[0] == 0 .. 0
+    doAssert 0 in "abc".match(re"(\w)").get.captureBounds == true
+    doAssert "abc".match(re"").get.captureBounds[-1] == 0 .. -1
+    doAssert "abc".match(re"abc").get.captureBounds[-1] == 0 .. 2
 # }}}
 
 proc getinfo[T](pattern: Regex, opt: cint): T =
@@ -254,78 +271,99 @@ proc matchesCrLf(pattern: Regex): bool =
 # }}}
 
 # Capture accessors {{{
-proc captureBounds*(pattern: RegexMatch): CaptureBounds = return CaptureBounds(pattern)
+func captureBounds*(pattern: RegexMatch): CaptureBounds = return CaptureBounds(pattern)
 
-proc captures*(pattern: RegexMatch): Captures = return Captures(pattern)
+func captures*(pattern: RegexMatch): Captures = return Captures(pattern)
 
-proc `[]`*(pattern: CaptureBounds, i: int): Option[HSlice[int, int]] =
+func contains*(pattern: CaptureBounds, i: int): bool =
   let pattern = RegexMatch(pattern)
-  if pattern.pcreMatchBounds[i + 1].a != -1:
-    let bounds = pattern.pcreMatchBounds[i + 1]
-    return some(int(bounds.a) .. int(bounds.b-1))
-  else:
-    return none(HSlice[int, int])
+  pattern.pcreMatchBounds[i + 1].a != -1
+
+func contains*(pattern: Captures, i: int): bool =
+  i in CaptureBounds(pattern)
 
-proc `[]`*(pattern: Captures, i: int): string =
+func `[]`*(pattern: CaptureBounds, i: int): HSlice[int, int] =
+  let pattern = RegexMatch(pattern)
+  if not (i in pattern.captureBounds):
+    raise newException(IndexError, "Group '" & $i & "' was not captured")
+
+  let bounds = pattern.pcreMatchBounds[i + 1]
+  int(bounds.a)..int(bounds.b-1)
+
+func `[]`*(pattern: Captures, i: int): string =
   let pattern = RegexMatch(pattern)
   let bounds = pattern.captureBounds[i]
 
-  if bounds.isSome:
-    let bounds = bounds.get
-    return pattern.str.substr(bounds.a, bounds.b)
-  else:
-    return ""
+  pattern.str.substr(bounds.a, bounds.b)
 
-proc match*(pattern: RegexMatch): string =
+func match*(pattern: RegexMatch): string =
   return pattern.captures[-1]
 
-proc matchBounds*(pattern: RegexMatch): HSlice[int, int] =
-  return pattern.captureBounds[-1].get
+func matchBounds*(pattern: RegexMatch): HSlice[int, int] =
+  return pattern.captureBounds[-1]
 
-proc `[]`*(pattern: CaptureBounds, name: string): Option[HSlice[int, int]] =
+func contains*(pattern: CaptureBounds, name: string): bool =
   let pattern = RegexMatch(pattern)
-  return pattern.captureBounds[pattern.pattern.captureNameToId.fget(name)]
+  let nameToId = pattern.pattern.captureNameToId
+  if not (name in nameToId):
+      return false
+  nameToId[name] in pattern.captureBounds
 
-proc `[]`*(pattern: Captures, name: string): string =
+func contains*(pattern: Captures, name: string): bool =
+  name in CaptureBounds(pattern)
+
+func checkNamedCaptured(pattern: RegexMatch, name: string): void =
+  if not (name in pattern.captureBounds):
+    raise newException(KeyError, "Group '" & name & "' was not captured")
+
+func `[]`*(pattern: CaptureBounds, name: string): HSlice[int, int] =
+  let pattern = RegexMatch(pattern)
+  checkNamedCaptured(pattern, name)
+  pattern.captureBounds[pattern.pattern.captureNameToId[name]]
+
+func `[]`*(pattern: Captures, name: string): string =
   let pattern = RegexMatch(pattern)
-  return pattern.captures[pattern.pattern.captureNameToId.fget(name)]
+  checkNamedCaptured(pattern, name)
+  return pattern.captures[pattern.pattern.captureNameToId[name]]
 
-template toTableImpl(cond: untyped) {.dirty.} =
+template toTableImpl() {.dirty.} =
   for key in RegexMatch(pattern).pattern.captureNameId.keys:
-    let nextVal = pattern[key]
-    if cond:
-      result[key] = default
-    else:
-      result[key] = nextVal
+    if key in pattern:
+        result[key] = pattern[key]
 
-proc toTable*(pattern: Captures, default: string = ""): Table[string, string] =
+func toTable*(pattern: Captures): Table[string, string] =
   result = initTable[string, string]()
-  toTableImpl(nextVal.len == 0)
+  toTableImpl()
 
-proc toTable*(pattern: CaptureBounds, default = none(HSlice[int, int])):
-    Table[string, Option[HSlice[int, int]]] =
-  result = initTable[string, Option[HSlice[int, int]]]()
-  toTableImpl(nextVal.isNone)
+func toTable*(pattern: CaptureBounds): Table[string, HSlice[int, int]] =
+  result = initTable[string, HSlice[int, int]]()
+  toTableImpl()
 
-template itemsImpl(cond: untyped) {.dirty.} =
+template itemsImpl() {.dirty.} =
   for i in 0 ..< RegexMatch(pattern).pattern.captureCount:
-    let nextVal = pattern[i]
     # done in this roundabout way to avoid multiple yields (potential code
     # bloat)
-    let nextYieldVal = if cond: default else: nextVal
-    yield nextYieldVal
+    let nextYieldVal = if i in pattern:
+      some(pattern[i])
+    else:
+      default
 
+    yield nextYieldVal
 
-iterator items*(pattern: CaptureBounds, default = none(HSlice[int, int])): Option[HSlice[int, int]] =
-  itemsImpl(nextVal.isNone)
+iterator items*(pattern: CaptureBounds,
+                default = none(HSlice[int, int])): Option[HSlice[int, int]] =
+  itemsImpl()
 
-iterator items*(pattern: Captures, default: string = ""): string =
-  itemsImpl(nextVal.len == 0)
+iterator items*(pattern: Captures,
+                default: Option[string] = none(string)): Option[string] =
+  itemsImpl()
 
-proc toSeq*(pattern: CaptureBounds, default = none(HSlice[int, int])): seq[Option[HSlice[int, int]]] =
+proc toSeq*(pattern: CaptureBounds,
+            default = none(HSlice[int, int])): seq[Option[HSlice[int, int]]] =
   accumulateResult(pattern.items(default))
 
-proc toSeq*(pattern: Captures, default: string = ""): seq[string] =
+proc toSeq*(pattern: Captures,
+            default: Option[string] = none(string)): seq[Option[string]] =
   accumulateResult(pattern.items(default))
 
 proc `$`*(pattern: RegexMatch): string =
@@ -469,7 +507,8 @@ proc matchImpl(str: string, pattern: Regex, start, endpos: int, flags: int): Opt
   # 1x capture count as slack space for PCRE
   let vecsize = (pattern.captureCount() + 1) * 3
   # div 2 because each element is 2 cints long
-  myResult.pcreMatchBounds = newSeq[HSlice[cint, cint]](ceil(vecsize / 2).int)
+  # plus 1 because we need the ceiling, not the floor
+  myResult.pcreMatchBounds = newSeq[HSlice[cint, cint]]((vecsize + 1) div 2)
   myResult.pcreMatchBounds.setLen(vecsize div 3)
 
   let strlen = if endpos == int.high: str.len else: endpos+1
@@ -636,7 +675,8 @@ proc split*(str: string, pattern: Regex, maxSplit = -1, start = 0): seq[string]
 
     for cap in match.captures:
       # if there are captures, include them in the result
-      result.add(cap)
+      if cap.isSome:
+        result.add(cap.get)
 
     if splits == maxSplit - 1:
       break
@@ -690,7 +730,8 @@ proc replace*(str: string, pattern: Regex,
   ## -  ``$#`` - first capture
   ## -  ``$0`` - full match
   ##
-  ## If a given capture is missing, a ``ValueError`` exception is thrown.
+  ## If a given capture is missing, ``IndexError`` thrown for un-named captures
+  ## and ``KeyError`` for named captures.
   replaceImpl(str, pattern, subproc(match))
 
 proc replace*(str: string, pattern: Regex,
diff --git a/lib/impure/nre/private/util.nim b/lib/impure/nre/private/util.nim
index a3ae84007..f7d8b1d60 100644
--- a/lib/impure/nre/private/util.nim
+++ b/lib/impure/nre/private/util.nim
@@ -1,17 +1,9 @@
 ## INTERNAL FILE FOR USE ONLY BY nre.nim.
 import tables
 
-proc fget*[K, V](self: Table[K, V], key: K): V =
-  if self.hasKey(key):
-    return self[key]
-  else:
-    raise newException(KeyError, "Key does not exist in table: " & $key)
-
 const Ident = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'}
 const StartIdent = Ident - {'0'..'9'}
 
-template checkNil(arg: string): string = arg
-
 template formatStr*(howExpr, namegetter, idgetter): untyped =
   let how = howExpr
   var val = newStringOfCap(how.len)
@@ -28,7 +20,7 @@ template formatStr*(howExpr, namegetter, idgetter): untyped =
         i += 2
       elif how[i + 1] == '#':
         var id {.inject.} = lastNum
-        val.add(checkNil(idgetter))
+        val.add(idgetter)
         lastNum += 1
         i += 2
       elif how[i + 1] in {'0'..'9'}:
@@ -37,7 +29,7 @@ template formatStr*(howExpr, namegetter, idgetter): untyped =
         while i < how.len and how[i] in {'0'..'9'}:
           id += (id * 10) + (ord(how[i]) - ord('0'))
           i += 1
-        val.add(checkNil(idgetter))
+        val.add(idgetter)
         lastNum = id + 1
       elif how[i + 1] in StartIdent:
         i += 1
@@ -45,7 +37,7 @@ template formatStr*(howExpr, namegetter, idgetter): untyped =
         while i < how.len and how[i] in Ident:
           name.add(how[i])
           i += 1
-        val.add(checkNil(namegetter))
+        val.add(namegetter)
       elif how[i + 1] == '{':
         i += 2
         var name {.inject.} = ""
@@ -53,7 +45,7 @@ template formatStr*(howExpr, namegetter, idgetter): untyped =
           name.add(how[i])
           i += 1
         i += 1
-        val.add(checkNil(namegetter))
+        val.add(namegetter)
       else:
         raise newException(Exception, "Syntax error in format string at " & $i)
   val
diff --git a/lib/impure/re.nim b/lib/impure/re.nim
index b142f58cd..dc4ee326f 100644
--- a/lib/impure/re.nim
+++ b/lib/impure/re.nim
@@ -547,7 +547,7 @@ proc split*(s: string, sep: Regex, maxsplit = -1): seq[string] {.inline.} =
   ##
   ## The portion matched by ``sep`` is not returned.
   result = @[]
-  for x in split(s, sep): result.add x
+  for x in split(s, sep, maxsplit): result.add x
 
 proc escapeRe*(s: string): string =
   ## escapes ``s`` so that it is matched verbatim when used as a regular
@@ -636,6 +636,11 @@ when isMainModule:
   doAssert(accum == @["", "this", "is", "an", "example", ""])
 
   accum = @[]
+  for word in split("00232this02939is39an22example111", re"\d+", maxsplit=2):
+    accum.add(word)
+  doAssert(accum == @["", "this", "is39an22example111"])
+
+  accum = @[]
   for word in split("AAA :   : BBB", re"\s*:\s*"):
     accum.add(word)
   doAssert(accum == @["AAA", "", "BBB"])
@@ -647,6 +652,8 @@ when isMainModule:
   doAssert(split(";a;b;c", re";") == @["", "a", "b", "c"])
   doAssert(split(";a;b;c;", re";") == @["", "a", "b", "c", ""])
   doAssert(split("a;b;c;", re";") == @["a", "b", "c", ""])
+  doAssert(split("00232this02939is39an22example111", re"\d+", maxsplit=2) == @["", "this", "is39an22example111"])
+
 
   for x in findAll("abcdef", re"^{.}", 3):
     doAssert x == "d"
diff --git a/lib/impure/ssl.nim b/lib/impure/ssl.nim
index 5b0e899f6..0bcb3f217 100644
--- a/lib/impure/ssl.nim
+++ b/lib/impure/ssl.nim
@@ -21,7 +21,6 @@ type
   SecureSocket* = object
     ssl: SslPtr
     bio: BIO
-{.deprecated: [TSecureSocket: SecureSocket].}
 
 proc connect*(sock: var SecureSocket, address: string,
     port: int): int =
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/packages/fsmonitor.nim b/lib/packages/fsmonitor.nim
deleted file mode 100644
index b22e84f44..000000000
--- a/lib/packages/fsmonitor.nim
+++ /dev/null
@@ -1,229 +0,0 @@
-#
-#
-#            Nim's Runtime Library
-#        (c) Copyright 2012 Dominik Picheta
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## This module allows you to monitor files or directories for changes using
-## asyncio.
-##
-## **Warning**: This module will likely disappear soon and be moved into a
-## new Nimble package.
-##
-## Windows support is not yet implemented.
-##
-## **Note:** This module uses ``inotify`` on Linux (Other Unixes are not yet
-## supported). ``inotify`` was merged into the 2.6.13 Linux kernel, this
-## module will therefore not work with any Linux kernel prior to that, unless
-## it has been patched to support inotify.
-
-when defined(linux) or defined(nimdoc):
-  from posix import read
-else:
-  {.error: "Your platform is not supported.".}
-
-import inotify, os, asyncio, tables
-
-type
-  FSMonitor* = ref FSMonitorObj
-  FSMonitorObj = object of RootObj
-    fd: cint
-    handleEvent: proc (m: FSMonitor, ev: MonitorEvent) {.closure.}
-    targets: Table[cint, string]
-
-  MonitorEventType* = enum ## Monitor event type
-    MonitorAccess,       ## File was accessed.
-    MonitorAttrib,       ## Metadata changed.
-    MonitorCloseWrite,   ## Writable file was closed.
-    MonitorCloseNoWrite, ## Non-writable file closed.
-    MonitorCreate,       ## Subfile was created.
-    MonitorDelete,       ## Subfile was deleted.
-    MonitorDeleteSelf,   ## Watched file/directory was itself deleted.
-    MonitorModify,       ## File was modified.
-    MonitorMoveSelf,     ## Self was moved.
-    MonitorMoved,        ## File was moved.
-    MonitorOpen,         ## File was opened.
-    MonitorAll           ## Filter for all event types.
-
-  MonitorEvent* = object
-    case kind*: MonitorEventType  ## Type of the event.
-    of MonitorMoveSelf, MonitorMoved:
-      oldPath*: string          ## Old absolute location
-      newPath*: string          ## New absolute location
-    else:
-      fullname*: string         ## Absolute filename of the file/directory affected.
-    name*: string             ## Non absolute filepath of the file/directory
-                              ## affected relative to the directory watched.
-                              ## "" if this event refers to the file/directory
-                              ## watched.
-    wd*: cint                 ## Watch descriptor.
-
-{.deprecated: [PFSMonitor: FSMonitor, TFSMonitor: FSMonitorObj,
-  TMonitorEventType: MonitorEventType, TMonitorEvent: MonitorEvent].}
-
-const
-  MaxEvents = 100
-
-proc newMonitor*(): FSMonitor =
-  ## Creates a new file system monitor.
-  new(result)
-  result.targets = initTable[cint, string]()
-  result.fd = inotifyInit()
-  if result.fd < 0:
-    raiseOSError(osLastError())
-
-proc add*(monitor: FSMonitor, target: string,
-               filters = {MonitorAll}): cint {.discardable.} =
-  ## Adds ``target`` which may be a directory or a file to the list of
-  ## watched paths of ``monitor``.
-  ## You can specify the events to report using the ``filters`` parameter.
-
-  var INFilter = 0
-  for f in filters:
-    case f
-    of MonitorAccess: INFilter = INFilter or IN_ACCESS
-    of MonitorAttrib: INFilter = INFilter or IN_ATTRIB
-    of MonitorCloseWrite: INFilter = INFilter or IN_CLOSE_WRITE
-    of MonitorCloseNoWrite: INFilter = INFilter or IN_CLOSE_NO_WRITE
-    of MonitorCreate: INFilter = INFilter or IN_CREATE
-    of MonitorDelete: INFilter = INFilter or IN_DELETE
-    of MonitorDeleteSelf: INFilter = INFilter or IN_DELETE_SELF
-    of MonitorModify: INFilter = INFilter or IN_MODIFY
-    of MonitorMoveSelf: INFilter = INFilter or IN_MOVE_SELF
-    of MonitorMoved: INFilter = INFilter or IN_MOVED_FROM or IN_MOVED_TO
-    of MonitorOpen: INFilter = INFilter or IN_OPEN
-    of MonitorAll: INFilter = INFilter or IN_ALL_EVENTS
-
-  result = inotifyAddWatch(monitor.fd, target, INFilter.uint32)
-  if result < 0:
-    raiseOSError(osLastError())
-  monitor.targets.add(result, target)
-
-proc del*(monitor: FSMonitor, wd: cint) =
-  ## Removes watched directory or file as specified by ``wd`` from ``monitor``.
-  ##
-  ## If ``wd`` is not a part of ``monitor`` an EOS error is raised.
-  if inotifyRmWatch(monitor.fd, wd) < 0:
-    raiseOSError(osLastError())
-
-proc getEvent(m: FSMonitor, fd: cint): seq[MonitorEvent] =
-  result = @[]
-  let size = (sizeof(INotifyEvent)+2000)*MaxEvents
-  var buffer = newString(size)
-
-  let le = read(fd, addr(buffer[0]), size)
-
-  var movedFrom = initTable[cint, tuple[wd: cint, old: string]]()
-
-  var i = 0
-  while i < le:
-    var event = cast[ptr INotifyEvent](addr(buffer[i]))
-    var mev: MonitorEvent
-    mev.wd = event.wd
-    if event.len.int != 0:
-      let cstr = event.name.addr.cstring
-      mev.name = $cstr
-    else:
-      mev.name = ""
-
-    if (event.mask.int and IN_MOVED_FROM) != 0:
-      # Moved from event, add to m's collection
-      movedFrom.add(event.cookie.cint, (mev.wd, mev.name))
-      inc(i, sizeof(INotifyEvent) + event.len.int)
-      continue
-    elif (event.mask.int and IN_MOVED_TO) != 0:
-      mev.kind = MonitorMoved
-      assert movedFrom.hasKey(event.cookie.cint)
-      # Find the MovedFrom event.
-      mev.oldPath = movedFrom[event.cookie.cint].old
-      mev.newPath = "" # Set later
-      # Delete it from the Table
-      movedFrom.del(event.cookie.cint)
-    elif (event.mask.int and IN_ACCESS) != 0: mev.kind = MonitorAccess
-    elif (event.mask.int and IN_ATTRIB) != 0: mev.kind = MonitorAttrib
-    elif (event.mask.int and IN_CLOSE_WRITE) != 0:
-      mev.kind = MonitorCloseWrite
-    elif (event.mask.int and IN_CLOSE_NOWRITE) != 0:
-      mev.kind = MonitorCloseNoWrite
-    elif (event.mask.int and IN_CREATE) != 0: mev.kind = MonitorCreate
-    elif (event.mask.int and IN_DELETE) != 0:
-      mev.kind = MonitorDelete
-    elif (event.mask.int and IN_DELETE_SELF) != 0:
-      mev.kind = MonitorDeleteSelf
-    elif (event.mask.int and IN_MODIFY) != 0: mev.kind = MonitorModify
-    elif (event.mask.int and IN_MOVE_SELF) != 0:
-      mev.kind = MonitorMoveSelf
-    elif (event.mask.int and IN_OPEN) != 0: mev.kind = MonitorOpen
-
-    if mev.kind != MonitorMoved:
-      mev.fullname = ""
-
-    result.add(mev)
-    inc(i, sizeof(INotifyEvent) + event.len.int)
-
-  # If movedFrom events have not been matched with a moveTo. File has
-  # been moved to an unwatched location, emit a MonitorDelete.
-  for cookie, t in pairs(movedFrom):
-    var mev: MonitorEvent
-    mev.kind = MonitorDelete
-    mev.wd = t.wd
-    mev.name = t.old
-    result.add(mev)
-
-proc FSMonitorRead(h: RootRef) =
-  var events = FSMonitor(h).getEvent(FSMonitor(h).fd)
-  #var newEv: MonitorEvent
-  for ev in events:
-    var target = FSMonitor(h).targets[ev.wd]
-    var newEv = ev
-    if newEv.kind == MonitorMoved:
-      newEv.oldPath = target / newEv.oldPath
-      newEv.newPath = target / newEv.name
-    else:
-      newEv.fullName = target / newEv.name
-    FSMonitor(h).handleEvent(FSMonitor(h), newEv)
-
-proc toDelegate(m: FSMonitor): Delegate =
-  result = newDelegate()
-  result.deleVal = m
-  result.fd = (type(result.fd))(m.fd)
-  result.mode = fmRead
-  result.handleRead = FSMonitorRead
-  result.open = true
-
-proc register*(d: Dispatcher, monitor: FSMonitor,
-               handleEvent: proc (m: FSMonitor, ev: MonitorEvent) {.closure.}) =
-  ## Registers ``monitor`` with dispatcher ``d``.
-  monitor.handleEvent = handleEvent
-  var deleg = toDelegate(monitor)
-  d.register(deleg)
-
-when not defined(testing) and isMainModule:
-  proc main =
-    var
-      disp = newDispatcher()
-      monitor = newMonitor()
-      n = 0
-    n = monitor.add("/tmp")
-    assert n == 1
-    n = monitor.add("/tmp", {MonitorAll})
-    assert n == 1
-    n = monitor.add("/tmp", {MonitorCloseWrite, MonitorCloseNoWrite})
-    assert n == 1
-    n = monitor.add("/tmp", {MonitorMoved, MonitorOpen, MonitorAccess})
-    assert n == 1
-    disp.register(monitor,
-      proc (m: FSMonitor, ev: MonitorEvent) =
-        echo("Got event: ", ev.kind)
-        if ev.kind == MonitorMoved:
-          echo("From ", ev.oldPath, " to ", ev.newPath)
-          echo("Name is ", ev.name)
-        else:
-          echo("Name ", ev.name, " fullname ", ev.fullName))
-
-    while true:
-      if not disp.poll(): break
-  main()
diff --git a/lib/posix/inotify.nim b/lib/posix/inotify.nim
index 359e88617..f88e48a2d 100644
--- a/lib/posix/inotify.nim
+++ b/lib/posix/inotify.nim
@@ -19,7 +19,6 @@ type
     cookie*{.importc: "cookie".}: uint32 # Cookie to synchronize two events.
     len*{.importc: "len".}: uint32 # Length (including NULs) of name.
     name*{.importc: "name".}: char # Name.
-{.deprecated: [Tinotify_event: InotifyEvent].}
 
 # Supported events suitable for MASK parameter of INOTIFY_ADD_WATCH.
 const
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim
index fa589e905..175f6a61d 100644
--- a/lib/posix/posix.nim
+++ b/lib/posix/posix.nim
@@ -100,7 +100,6 @@ else:
   include posix_other
 
 # There used to be this name in posix.nim a long time ago, not sure why!
-{.deprecated: [cSIG_HOLD: SIG_HOLD].}
 
 when StatHasNanoseconds:
   proc st_atime*(s: Stat): Time {.inline.} =
@@ -824,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/posix/posix_linux_amd64.nim b/lib/posix/posix_linux_amd64.nim
index 6e69409ea..f37ddfa37 100644
--- a/lib/posix/posix_linux_amd64.nim
+++ b/lib/posix/posix_linux_amd64.nim
@@ -27,13 +27,10 @@ type
   DIR* {.importc: "DIR", header: "<dirent.h>",
           incompleteStruct.} = object
     ## A type representing a directory stream.
-{.deprecated: [TDIR: DIR].}
 
 type
   SocketHandle* = distinct cint # The type used to represent socket descriptors
 
-{.deprecated: [TSocketHandle: SocketHandle].}
-
 # not detected by detect.nim, guarded by #ifdef __USE_UNIX98 in glibc
 const SIG_HOLD* = cast[SigHandler](2)
 
@@ -375,29 +372,6 @@ type
                             ## context is active.
     # todo fpregds_mem
 
-{.deprecated: [TOff: Off, TPid: Pid, TGid: Gid, TMode: Mode, TDev: Dev,
-              TNlink: Nlink, TStack: Stack, TGroup: Group, TMqd: Mqd,
-              TPasswd: Passwd, TClock: Clock, TClockId: ClockId, TKey: Key,
-              TSem: Sem, Tpthread_attr: PthreadAttr, Ttimespec: Timespec,
-              Tdirent: Dirent, TGlob: Glob,
-              # Tflock: Flock, # Naming conflict if we drop the `T`
-              Ticonv: Iconv, Tlconv: Lconv, TMqAttr: MqAttr, Tblkcnt: Blkcnt,
-              Tblksize: Blksize, Tfsblkcnt: Fsblkcnt, Tfsfilcnt: Fsfilcnt,
-              Tid: Id, Tino: Ino, Tpthread_barrier: Pthread_barrier,
-              Tpthread_barrierattr: Pthread_barrierattr, Tpthread_cond: Pthread_cond,
-              TPthread_condattr: Pthread_condattr, Tpthread_key: Pthread_key,
-              Tpthread_mutex: Pthread_mutex, Tpthread_mutexattr: Pthread_mutexattr,
-              Tpthread_once: Pthread_once, Tpthread_rwlock: Pthread_rwlock,
-              Tpthread_rwlockattr: Pthread_rwlockattr, Tpthread_spinlock: Pthread_spinlock,
-              Tpthread: Pthread, Tsuseconds: Suseconds, Ttimer: Timer,
-              Tuid: Uid, Tuseconds: Useconds, Tutsname: Utsname, Tipc_perm: Ipc_perm,
-              TStat: Stat, TStatvfs: Statvfs,
-              Ttm: Tm, titimerspec: Itimerspec, Tsig_atomic: Sig_atomic, Tsigset: Sigset,
-              TsigEvent: SigEvent, TsigVal: SigVal, TSigaction: Sigaction,
-              TSigStack: SigStack, TsigInfo: SigInfo, Tnl_item: Nl_item,
-              Tnl_catd: Nl_catd, Tsched_param: Sched_param,
-              # TFdSet: FdSet, # Naming conflict if we drop the `T`
-              Tmcontext: Mcontext, Tucontext: Ucontext].}
 type
   Taiocb* {.importc: "struct aiocb", header: "<aio.h>",
             final, pure.} = object ## struct aiocb
@@ -587,13 +561,6 @@ type
 
   Tnfds* {.importc: "nfds_t", header: "<poll.h>".} = culong
 
-{.deprecated: [TSockaddr_in: Sockaddr_in, TAddrinfo: AddrInfo,
-    TSockAddr: SockAddr, TSockLen: SockLen, TTimeval: Timeval,
-    Tsockaddr_storage: Sockaddr_storage, Tsockaddr_in6: Sockaddr_in6,
-    Thostent: Hostent, TServent: Servent,
-    TInAddr: InAddr, TIOVec: IOVec, TInPort: InPort, TInAddrT: InAddrT,
-    TIn6Addr: In6Addr, TInAddrScalar: InAddrScalar, TProtoent: Protoent].}
-
 var
   errno* {.importc, header: "<errno.h>".}: cint ## error variable
   h_errno* {.importc, header: "<netdb.h>".}: cint
diff --git a/lib/posix/posix_other.nim b/lib/posix/posix_other.nim
index ba1dd89ed..261550d96 100644
--- a/lib/posix/posix_other.nim
+++ b/lib/posix/posix_other.nim
@@ -26,13 +26,10 @@ type
   DIR* {.importc: "DIR", header: "<dirent.h>",
           incompleteStruct.} = object
     ## A type representing a directory stream.
-{.deprecated: [TDIR: DIR].}
 
 type
   SocketHandle* = distinct cint # The type used to represent socket descriptors
 
-{.deprecated: [TSocketHandle: SocketHandle].}
-
 type
   Time* {.importc: "time_t", header: "<time.h>".} = distinct clong
 
@@ -356,31 +353,7 @@ type
     uc_stack*: Stack        ## The stack used by this context.
     uc_mcontext*: Mcontext  ## A machine-specific representation of the saved
                             ## context.
-{.deprecated: [TOff: Off, TPid: Pid, TGid: Gid, TMode: Mode, TDev: Dev,
-              TNlink: Nlink, TStack: Stack, TGroup: Group, TMqd: Mqd,
-              TPasswd: Passwd, TClock: Clock, TClockId: ClockId, TKey: Key,
-              TSem: Sem, Tpthread_attr: PthreadAttr, Ttimespec: Timespec,
-              Tdirent: Dirent, TFTW: FTW, TGlob: Glob,
-              # Tflock: Flock, # Naming conflict if we drop the `T`
-              Ticonv: Iconv, Tlconv: Lconv, TMqAttr: MqAttr, Tblkcnt: Blkcnt,
-              Tblksize: Blksize, Tfsblkcnt: Fsblkcnt, Tfsfilcnt: Fsfilcnt,
-              Tid: Id, Tino: Ino, Tpthread_barrier: Pthread_barrier,
-              Tpthread_barrierattr: Pthread_barrierattr, Tpthread_cond: Pthread_cond,
-              TPthread_condattr: Pthread_condattr, Tpthread_key: Pthread_key,
-              Tpthread_mutex: Pthread_mutex, Tpthread_mutexattr: Pthread_mutexattr,
-              Tpthread_once: Pthread_once, Tpthread_rwlock: Pthread_rwlock,
-              Tpthread_rwlockattr: Pthread_rwlockattr, Tpthread_spinlock: Pthread_spinlock,
-              Tpthread: Pthread, Tsuseconds: Suseconds, Ttimer: Timer,
-              Ttrace_attr: Trace_attr, Ttrace_event_id: Trace_event_id,
-              Ttrace_event_set: Trace_event_set, Ttrace_id: Trace_id,
-              Tuid: Uid, Tuseconds: Useconds, Tutsname: Utsname, Tipc_perm: Ipc_perm,
-              TStat: Stat, TStatvfs: Statvfs, Tposix_typed_mem_info: Posix_typed_mem_info,
-              Ttm: Tm, titimerspec: Itimerspec, Tsig_atomic: Sig_atomic, Tsigset: Sigset,
-              TsigEvent: SigEvent, TsigVal: SigVal, TSigaction: Sigaction,
-              TSigStack: SigStack, TsigInfo: SigInfo, Tnl_item: Nl_item,
-              Tnl_catd: Nl_catd, Tsched_param: Sched_param,
-              # TFdSet: FdSet, # Naming conflict if we drop the `T`
-              Tmcontext: Mcontext, Tucontext: Ucontext].}
+
 when hasAioH:
   type
     Taiocb* {.importc: "struct aiocb", header: "<aio.h>",
@@ -553,13 +526,6 @@ type
 
   Tnfds* {.importc: "nfds_t", header: "<poll.h>".} = cint
 
-{.deprecated: [TSockaddr_in: Sockaddr_in, TAddrinfo: AddrInfo,
-    TSockAddr: SockAddr, TSockLen: SockLen, TTimeval: Timeval,
-    Tsockaddr_storage: Sockaddr_storage, Tsockaddr_in6: Sockaddr_in6,
-    Thostent: Hostent, TServent: Servent,
-    TInAddr: InAddr, TIOVec: IOVec, TInPort: InPort, TInAddrT: InAddrT,
-    TIn6Addr: In6Addr, TInAddrScalar: InAddrScalar, TProtoent: Protoent].}
-
 var
   errno* {.importc, header: "<errno.h>".}: cint ## error variable
   h_errno* {.importc, header: "<netdb.h>".}: cint
diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim
index c08de7342..34bb47f93 100644
--- a/lib/posix/termios.nim
+++ b/lib/posix/termios.nim
@@ -13,7 +13,6 @@ import posix
 type
   Speed* = cuint
   Cflag* = cuint
-{.deprecated: [Tcflag: Cflag].}
 
 const
   NCCS* = when defined(macosx): 20 else: 32
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index edd509f50..36319a317 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -16,7 +16,8 @@ import asyncfutures except callSoon
 import nativesockets, net, deques
 
 export Port, SocketFlag
-export asyncfutures, asyncstreams
+export asyncfutures except callSoon
+export asyncstreams
 
 #{.injectStmt: newGcInvariant().}
 
@@ -145,7 +146,9 @@ export asyncfutures, asyncstreams
 ##
 ## Futures should **never** be discarded. This is because they may contain
 ## errors. If you do not care for the result of a Future then you should
-## use the ``asyncCheck`` procedure instead of the ``discard`` keyword.
+## use the ``asyncCheck`` procedure instead of the ``discard`` keyword. Note
+## however that this does not wait for completion, and you should use
+## ``waitFor`` for that purpose.
 ##
 ## Examples
 ## --------
@@ -197,7 +200,7 @@ proc adjustTimeout(pollTimeout: int, nextTimer: Option[int]): int {.inline.} =
   if pollTimeout == -1: return
   result = min(pollTimeout, result)
 
-proc callSoon(cbproc: proc ()) {.gcsafe.}
+proc callSoon*(cbproc: proc ()) {.gcsafe.}
 
 proc initCallSoonProc =
   if asyncfutures.getCallSoonProc().isNil:
@@ -241,8 +244,6 @@ when defined(windows) or defined(nimdoc):
     AsyncEvent* = ptr AsyncEventImpl
 
     Callback = proc (fd: AsyncFD): bool {.closure,gcsafe.}
-  {.deprecated: [TCompletionKey: CompletionKey, TAsyncFD: AsyncFD,
-                TCustomOverlapped: CustomOverlapped, TCompletionData: CompletionData].}
 
   proc hash(x: AsyncFD): Hash {.borrow.}
   proc `==`*(x: AsyncFD, y: AsyncFD): bool {.borrow.}
@@ -1077,7 +1078,6 @@ else:
 
     PDispatcher* = ref object of PDispatcherBase
       selector: Selector[AsyncData]
-  {.deprecated: [TAsyncFD: AsyncFD, TCallback: Callback].}
 
   proc `==`*(x, y: AsyncFD): bool {.borrow.}
   proc `==`*(x, y: AsyncEvent): bool {.borrow.}
@@ -1513,8 +1513,217 @@ proc poll*(timeout = 500) =
   ## `epoll`:idx: or `kqueue`:idx: primitive only once.
   discard runOnce(timeout)
 
-# Common procedures between current and upcoming asyncdispatch
-include includes/asynccommon
+template createAsyncNativeSocketImpl(domain, sockType, protocol) =
+  let handle = newNativeSocket(domain, sockType, protocol)
+  if handle == osInvalidSocket:
+    return osInvalidSocket.AsyncFD
+  handle.setBlocking(false)
+  when defined(macosx) and not defined(nimdoc):
+    handle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
+  result = handle.AsyncFD
+  register(result)
+
+proc createAsyncNativeSocket*(domain: cint, sockType: cint,
+                           protocol: cint): AsyncFD =
+  createAsyncNativeSocketImpl(domain, sockType, protocol)
+
+proc createAsyncNativeSocket*(domain: Domain = Domain.AF_INET,
+                           sockType: SockType = SOCK_STREAM,
+                           protocol: Protocol = IPPROTO_TCP): AsyncFD =
+  createAsyncNativeSocketImpl(domain, sockType, protocol)
+
+proc newAsyncNativeSocket*(domain: cint, sockType: cint,
+                           protocol: cint): AsyncFD {.deprecated: "use createAsyncNativeSocket instead".} =
+  createAsyncNativeSocketImpl(domain, sockType, protocol)
+
+proc newAsyncNativeSocket*(domain: Domain = Domain.AF_INET,
+                           sockType: SockType = SOCK_STREAM,
+                           protocol: Protocol = IPPROTO_TCP): AsyncFD
+                           {.deprecated: "use createAsyncNativeSocket instead".} =
+  createAsyncNativeSocketImpl(domain, sockType, protocol)
+
+when defined(windows) or defined(nimdoc):
+  proc bindToDomain(handle: SocketHandle, domain: Domain) =
+    # Extracted into a separate proc, because connect() on Windows requires
+    # the socket to be initially bound.
+    template doBind(saddr) =
+      if bindAddr(handle, cast[ptr SockAddr](addr(saddr)),
+                  sizeof(saddr).SockLen) < 0'i32:
+        raiseOSError(osLastError())
+
+    if domain == Domain.AF_INET6:
+      var saddr: Sockaddr_in6
+      saddr.sin6_family = uint16(toInt(domain))
+      doBind(saddr)
+    else:
+      var saddr: Sockaddr_in
+      saddr.sin_family = uint16(toInt(domain))
+      doBind(saddr)
+
+  proc doConnect(socket: AsyncFD, addrInfo: ptr AddrInfo): Future[void] =
+    let retFuture = newFuture[void]("doConnect")
+    result = retFuture
+
+    var ol = PCustomOverlapped()
+    GC_ref(ol)
+    ol.data = CompletionData(fd: socket, cb:
+      proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
+        if not retFuture.finished:
+          if errcode == OSErrorCode(-1):
+            retFuture.complete()
+          else:
+            retFuture.fail(newException(OSError, osErrorMsg(errcode)))
+    )
+
+    let ret = connectEx(socket.SocketHandle, addrInfo.ai_addr,
+                        cint(addrInfo.ai_addrlen), nil, 0, nil,
+                        cast[POVERLAPPED](ol))
+    if ret:
+      # Request to connect completed immediately.
+      retFuture.complete()
+      # We don't deallocate ``ol`` here because even though this completed
+      # immediately poll will still be notified about its completion and it
+      # will free ``ol``.
+    else:
+      let lastError = osLastError()
+      if lastError.int32 != ERROR_IO_PENDING:
+        # With ERROR_IO_PENDING ``ol`` will be deallocated in ``poll``,
+        # and the future will be completed/failed there, too.
+        GC_unref(ol)
+        retFuture.fail(newException(OSError, osErrorMsg(lastError)))
+else:
+  proc doConnect(socket: AsyncFD, addrInfo: ptr AddrInfo): Future[void] =
+    let retFuture = newFuture[void]("doConnect")
+    result = retFuture
+
+    proc cb(fd: AsyncFD): bool =
+      let ret = SocketHandle(fd).getSockOptInt(
+        cint(SOL_SOCKET), cint(SO_ERROR))
+      if ret == 0:
+        # We have connected.
+        retFuture.complete()
+        return true
+      elif ret == EINTR:
+        # interrupted, keep waiting
+        return false
+      else:
+        retFuture.fail(newException(OSError, osErrorMsg(OSErrorCode(ret))))
+        return true
+
+    let ret = connect(socket.SocketHandle,
+                      addrInfo.ai_addr,
+                      addrInfo.ai_addrlen.Socklen)
+    if ret == 0:
+      # Request to connect completed immediately.
+      retFuture.complete()
+    else:
+      let lastError = osLastError()
+      if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
+        addWrite(socket, cb)
+      else:
+        retFuture.fail(newException(OSError, osErrorMsg(lastError)))
+
+template asyncAddrInfoLoop(addrInfo: ptr AddrInfo, fd: untyped,
+                           protocol: Protocol = IPPROTO_RAW) =
+  ## Iterates through the AddrInfo linked list asynchronously
+  ## until the connection can be established.
+  const shouldCreateFd = not declared(fd)
+
+  when shouldCreateFd:
+    let sockType = protocol.toSockType()
+
+    var fdPerDomain: array[low(Domain).ord..high(Domain).ord, AsyncFD]
+    for i in low(fdPerDomain)..high(fdPerDomain):
+      fdPerDomain[i] = osInvalidSocket.AsyncFD
+    template closeUnusedFds(domainToKeep = -1) {.dirty.} =
+      for i, fd in fdPerDomain:
+        if fd != osInvalidSocket.AsyncFD and i != domainToKeep:
+          fd.closeSocket()
+
+  var lastException: ref Exception
+  var curAddrInfo = addrInfo
+  var domain: Domain
+  when shouldCreateFd:
+    var curFd: AsyncFD
+  else:
+    var curFd = fd
+  proc tryNextAddrInfo(fut: Future[void]) {.gcsafe.} =
+    if fut == nil or fut.failed:
+      if fut != nil:
+        lastException = fut.readError()
+
+      while curAddrInfo != nil:
+        let domainOpt = curAddrInfo.ai_family.toKnownDomain()
+        if domainOpt.isSome:
+          domain = domainOpt.unsafeGet()
+          break
+        curAddrInfo = curAddrInfo.ai_next
+
+      if curAddrInfo == nil:
+        freeAddrInfo(addrInfo)
+        when shouldCreateFd:
+          closeUnusedFds()
+        if lastException != nil:
+          retFuture.fail(lastException)
+        else:
+          retFuture.fail(newException(
+            IOError, "Couldn't resolve address: " & address))
+        return
+
+      when shouldCreateFd:
+        curFd = fdPerDomain[ord(domain)]
+        if curFd == osInvalidSocket.AsyncFD:
+          try:
+            curFd = newAsyncNativeSocket(domain, sockType, protocol)
+          except:
+            freeAddrInfo(addrInfo)
+            closeUnusedFds()
+            raise getCurrentException()
+          when defined(windows):
+            curFd.SocketHandle.bindToDomain(domain)
+          fdPerDomain[ord(domain)] = curFd
+
+      doConnect(curFd, curAddrInfo).callback = tryNextAddrInfo
+      curAddrInfo = curAddrInfo.ai_next
+    else:
+      freeAddrInfo(addrInfo)
+      when shouldCreateFd:
+        closeUnusedFds(ord(domain))
+        retFuture.complete(curFd)
+      else:
+        retFuture.complete()
+
+  tryNextAddrInfo(nil)
+
+proc dial*(address: string, port: Port,
+           protocol: Protocol = IPPROTO_TCP): Future[AsyncFD] =
+  ## Establishes connection to the specified ``address``:``port`` pair via the
+  ## specified protocol. The procedure iterates through possible
+  ## resolutions of the ``address`` until it succeeds, meaning that it
+  ## seamlessly works with both IPv4 and IPv6.
+  ## Returns the async file descriptor, registered in the dispatcher of
+  ## the current thread, ready to send or receive data.
+  let retFuture = newFuture[AsyncFD]("dial")
+  result = retFuture
+  let sockType = protocol.toSockType()
+
+  let aiList = getAddrInfo(address, port, Domain.AF_UNSPEC, sockType, protocol)
+  asyncAddrInfoLoop(aiList, noFD, protocol)
+
+proc connect*(socket: AsyncFD, address: string, port: Port,
+              domain = Domain.AF_INET): Future[void] =
+  let retFuture = newFuture[void]("connect")
+  result = retFuture
+
+  when defined(windows):
+    verifyPresence(socket)
+  else:
+    assert getSockDomain(socket.SocketHandle) == domain
+
+  let aiList = getAddrInfo(address, port, domain)
+  when defined(windows):
+    socket.SocketHandle.bindToDomain(domain)
+  asyncAddrInfoLoop(aiList, socket)
 
 proc sleepAsync*(ms: int | float): Future[void] =
   ## Suspends the execution of the current async procedure for the next
@@ -1638,7 +1847,7 @@ proc recvLine*(socket: AsyncFD): Future[string] {.async, deprecated.} =
       return
     add(result, c)
 
-proc callSoon(cbproc: proc ()) =
+proc callSoon*(cbproc: proc ()) =
   ## Schedule `cbproc` to be called as soon as possible.
   ## The callback is called when control returns to the event loop.
   getGlobalDispatcher().callbacks.addLast(cbproc)
diff --git a/lib/pure/asyncfutures.nim b/lib/pure/asyncfutures.nim
index df0e7c17e..5037c8a24 100644
--- a/lib/pure/asyncfutures.nim
+++ b/lib/pure/asyncfutures.nim
@@ -123,11 +123,17 @@ proc add(callbacks: var CallbackList, function: CallbackFunc) =
     callbacks.function = function
     assert callbacks.next == nil
   else:
-    let newNext = new(ref CallbackList)
-    newNext.function = callbacks.function
-    newNext.next = callbacks.next
-    callbacks.next = newNext
-    callbacks.function = function
+    let newCallback = new(ref CallbackList)
+    newCallback.function = function
+    newCallback.next = nil
+
+    if callbacks.next == nil:
+      callbacks.next = newCallback
+    else:
+      var last = callbacks.next
+      while last.next != nil:
+        last = last.next
+      last.next = newCallback
 
 proc complete*[T](future: Future[T], val: T) =
   ## Completes ``future`` with value ``val``.
@@ -339,7 +345,8 @@ proc asyncCheck*[T](future: Future[T]) =
   ## Sets a callback on ``future`` which raises an exception if the future
   ## finished with an error.
   ##
-  ## This should be used instead of ``discard`` to discard void futures.
+  ## This should be used instead of ``discard`` to discard void futures,
+  ## or use ``waitFor`` if you need to wait for the future's completion.
   assert(not future.isNil, "Future is nil")
   future.callback =
     proc () =
@@ -368,8 +375,9 @@ proc `or`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] =
   ## complete.
   var retFuture = newFuture[void]("asyncdispatch.`or`")
   proc cb[X](fut: Future[X]) =
-    if fut.failed: retFuture.fail(fut.error)
-    if not retFuture.finished: retFuture.complete()
+    if not retFuture.finished:
+      if fut.failed: retFuture.fail(fut.error)
+      else: retFuture.complete()
   fut1.callback = cb[T]
   fut2.callback = cb[Y]
   return retFuture
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index 71a1600dc..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:
@@ -599,7 +599,7 @@ proc listen*(socket: AsyncSocket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].}
   ## ``Backlog`` specifies the maximum length of the
   ## queue of pending connections.
   ##
-  ## Raises an EOS error upon failure.
+  ## Raises an OSError error upon failure.
   if listen(socket.fd, backlog) < 0'i32: raiseOSError(osLastError())
 
 proc bindAddr*(socket: AsyncSocket, port = Port(0), address = "") {.
diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim
index 101146ace..869abc9cc 100644
--- a/lib/pure/cgi.nim
+++ b/lib/pure/cgi.nim
@@ -147,6 +147,12 @@ proc readData*(allowedMethods: set[RequestMethod] =
   for name, value in decodeData(allowedMethods):
     result[name.string] = value.string
 
+proc readData*(data: string): StringTableRef =
+  ## Read CGI data from a string.
+  result = newStringTable()
+  for name, value in decodeData(data):
+    result[name.string] = value.string
+
 proc validateData*(data: StringTableRef, validKeys: varargs[string]) =
   ## validates data; raises `ECgi` if this fails. This checks that each variable
   ## name of the CGI `data` occurs in the `validKeys` array.
diff --git a/lib/pure/collections/LockFreeHash.nim b/lib/pure/collections/LockFreeHash.nim
index 954d62491..28fa2a81b 100644
--- a/lib/pure/collections/LockFreeHash.nim
+++ b/lib/pure/collections/LockFreeHash.nim
@@ -49,13 +49,11 @@ when sizeof(int) == 4: # 32bit
     Raw = range[0..1073741823]
     ## The range of uint values that can be stored directly in a value slot
     ## when on a 32 bit platform
-  {.deprecated: [TRaw: Raw].}
 elif sizeof(int) == 8: # 64bit
   type
     Raw = range[0'i64..4611686018427387903'i64]
     ## The range of uint values that can be stored directly in a value slot
     ## when on a 64 bit platform
-  {.deprecated: [TRaw: Raw].}
 else:
   {.error: "unsupported platform".}
 
@@ -74,7 +72,6 @@ type
     copyDone: int
     next: PConcTable[K,V]
     data: EntryArr
-{.deprecated: [TEntry: Entry, TEntryArr: EntryArr].}
 
 proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
   expVal: int, match: bool): int
@@ -544,7 +541,6 @@ when not defined(testing) and isMainModule:
     Data = tuple[k: string,v: TestObj]
     PDataArr = array[0..numTests-1, Data]
     Dict = PConcTable[string,TestObj]
-  {.deprecated: [TTestObj: TestObj, TData: Data].}
 
   var
     thr: array[0..numThreads-1, Thread[Dict]]
diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim
index c94e08098..32e0299ba 100644
--- a/lib/pure/collections/critbits.nim
+++ b/lib/pure/collections/critbits.nim
@@ -33,8 +33,6 @@ type
     root: Node[T]
     count: int
 
-{.deprecated: [TCritBitTree: CritBitTree].}
-
 proc len*[T](c: CritBitTree[T]): int =
   ## returns the number of elements in `c` in O(1).
   result = c.count
diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim
index 545958977..def96b8f7 100644
--- a/lib/pure/collections/intsets.nim
+++ b/lib/pure/collections/intsets.nim
@@ -44,8 +44,6 @@ type
     data: TrunkSeq
     a: array[0..33, int] # profiling shows that 34 elements are enough
 
-{.deprecated: [TIntSet: IntSet, TTrunk: Trunk, TTrunkSeq: TrunkSeq].}
-
 proc mustRehash(length, counter: int): bool {.inline.} =
   assert(length > counter)
   result = (length * 2 < counter * 3) or (length - counter < 4)
diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim
index e69acc8d9..15ce5d074 100644
--- a/lib/pure/collections/lists.nim
+++ b/lib/pure/collections/lists.nim
@@ -45,15 +45,6 @@ type
 
   SomeLinkedNode*[T] = SinglyLinkedNode[T] | DoublyLinkedNode[T]
 
-{.deprecated: [TDoublyLinkedNode: DoublyLinkedNodeObj,
-    PDoublyLinkedNode: DoublyLinkedNode,
-    TSinglyLinkedNode: SinglyLinkedNodeObj,
-    PSinglyLinkedNode: SinglyLinkedNode,
-    TDoublyLinkedList: DoublyLinkedList,
-    TSinglyLinkedRing: SinglyLinkedRing,
-    TDoublyLinkedRing: DoublyLinkedRing,
-    TSinglyLinkedList: SinglyLinkedList].}
-
 proc initSinglyLinkedList*[T](): SinglyLinkedList[T] =
   ## creates a new singly linked list that is empty.
   discard
@@ -149,11 +140,26 @@ proc contains*[T](L: SomeLinkedCollection[T], value: T): bool {.inline.} =
   ## exist, true otherwise.
   result = find(L, value) != nil
 
+proc append*[T](L: var SinglyLinkedList[T],
+                n: SinglyLinkedNode[T]) {.inline.} =
+  ## appends a node `n` to `L`. Efficiency: O(1).
+  n.next = nil
+  if L.tail != nil:
+    assert(L.tail.next == nil)
+    L.tail.next = n
+  L.tail = n
+  if L.head == nil: L.head = n
+
+proc append*[T](L: var SinglyLinkedList[T], value: T) {.inline.} =
+  ## appends a value to `L`. Efficiency: O(1).
+  append(L, newSinglyLinkedNode(value))
+
 proc prepend*[T](L: var SinglyLinkedList[T],
                  n: SinglyLinkedNode[T]) {.inline.} =
   ## prepends a node to `L`. Efficiency: O(1).
   n.next = L.head
   L.head = n
+  if L.tail == nil: L.tail = n
 
 proc prepend*[T](L: var SinglyLinkedList[T], value: T) {.inline.} =
   ## prepends a node to `L`. Efficiency: O(1).
diff --git a/lib/pure/collections/queues.nim b/lib/pure/collections/queues.nim
index ce792d6da..9a1d169fb 100644
--- a/lib/pure/collections/queues.nim
+++ b/lib/pure/collections/queues.nim
@@ -46,8 +46,6 @@ type
     data: seq[T]
     rd, wr, count, mask: int
 
-{.deprecated: [TQueue: Queue].}
-
 proc initQueue*[T](initialSize: int = 4): Queue[T] =
   ## Create a new queue.
   ## Optionally, the initial capacity can be reserved via `initialSize` as a
diff --git a/lib/pure/collections/rtarrays.nim b/lib/pure/collections/rtarrays.nim
index 3849117a0..90dbf0049 100644
--- a/lib/pure/collections/rtarrays.nim
+++ b/lib/pure/collections/rtarrays.nim
@@ -19,7 +19,6 @@ type
     L: Natural
     spart: seq[T]
     apart: array[ArrayPartSize, T]
-  UncheckedArray* {.unchecked.}[T] = array[0, T]
 
 template usesSeqPart(x): untyped = x.L > ArrayPartSize
 
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index 2e21786bb..39ba6df49 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -115,7 +115,7 @@ proc repeat*[T](x: T, n: Natural): seq[T] =
   for i in 0 ..< n:
     result[i] = x
 
-proc deduplicate*[T](s: openArray[T]): seq[T] =
+proc deduplicate*[T](s: openArray[T], isSorted: bool = false): seq[T] =
   ## Returns a new sequence without duplicates.
   ##
   ## Example:
@@ -129,8 +129,17 @@ proc deduplicate*[T](s: openArray[T]): seq[T] =
   ##   assert unique1 == @[1, 3, 4, 2, 8]
   ##   assert unique2 == @["a", "c", "d"]
   result = @[]
-  for itm in items(s):
-    if not result.contains(itm): result.add(itm)
+  if s.len > 0:
+    if isSorted:
+      var prev = s[0]
+      result.add(prev)
+      for i in 1..s.high:
+        if s[i] != prev:
+          prev = s[i]
+          result.add(prev)
+    else:
+      for itm in items(s):
+        if not result.contains(itm): result.add(itm)
 
 proc zip*[S, T](s1: openArray[S], s2: openArray[T]): seq[tuple[a: S, b: T]] =
   ## Returns a new sequence with a combination of the two input containers.
@@ -504,36 +513,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.
   ##
@@ -673,10 +722,16 @@ template mapIt*(s: typed, op: untyped): untyped =
   ##     nums = @[1, 2, 3, 4]
   ##     strings = nums.mapIt($(4 * it))
   ##   assert strings == @["4", "8", "12", "16"]
-  type outType = type((
-    block:
-      var it{.inject.}: type(items(s));
-      op))
+  when defined(nimHasTypeof):
+    type outType = typeof((
+      block:
+        var it{.inject.}: typeof(items(s), typeOfIter);
+        op), typeOfProc)
+  else:
+    type outType = type((
+      block:
+        var it{.inject.}: type(items(s));
+        op))
   when compiles(s.len):
     block: # using a block avoids https://github.com/nim-lang/Nim/issues/8580
 
@@ -781,6 +836,7 @@ macro mapLiterals*(constructor, op: untyped;
 
 when isMainModule:
   import strutils
+  from algorithm import sorted
 
   # helper for testing double substitution side effects which are handled
   # by `evalOnceAs`
@@ -856,10 +912,18 @@ when isMainModule:
       unique2 = deduplicate(dup2)
       unique3 = deduplicate(dup3)
       unique4 = deduplicate(dup4)
+      unique5 = deduplicate(dup1.sorted, true)
+      unique6 = deduplicate(dup2, true)
+      unique7 = deduplicate(dup3.sorted, true)
+      unique8 = deduplicate(dup4, true)
     assert unique1 == @[1, 3, 4, 2, 8]
     assert unique2 == @["a", "c", "d"]
     assert unique3 == @[1, 3, 4, 2, 8]
     assert unique4 == @["a", "c", "d"]
+    assert unique5 == @[1, 2, 3, 4, 8]
+    assert unique6 == @["a", "c", "d"]
+    assert unique7 == @[1, 2, 3, 4, 8]
+    assert unique8 == @["a", "c", "d"]
 
   block: # zip test
     let
@@ -1027,12 +1091,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
@@ -1135,5 +1259,13 @@ when isMainModule:
       A, B
     doAssert mapIt(X, $it) == @["A", "B"]
 
+  block:
+    # bug #9093
+    let inp = "a:b,c:d"
+
+    let outp = inp.split(",").mapIt(it.split(":"))
+    doAssert outp == @[@["a", "b"], @["c", "d"]]
+
+
   when not defined(testing):
     echo "Finished doc tests"
diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim
index 7355aae02..1273cbc33 100644
--- a/lib/pure/collections/sets.nim
+++ b/lib/pure/collections/sets.nim
@@ -39,8 +39,6 @@ type
     data: KeyValuePairSeq[A]
     counter: int
 
-{.deprecated: [TSet: HashSet].}
-
 template default[T](t: typedesc[T]): T =
   ## Used by clear methods to get a default value.
   var v: T
@@ -631,8 +629,6 @@ type
     data: OrderedKeyValuePairSeq[A]
     counter, first, last: int
 
-{.deprecated: [TOrderedSet: OrderedSet].}
-
 proc clear*[A](s: var OrderedSet[A]) =
   ## Clears the OrderedSet back to an empty state, without shrinking
   ## any of the existing storage. O(n) where n is the size of the hash bucket.
diff --git a/lib/pure/collections/sharedstrings.nim b/lib/pure/collections/sharedstrings.nim
index 7e9de4b73..b283cd4b1 100644
--- a/lib/pure/collections/sharedstrings.nim
+++ b/lib/pure/collections/sharedstrings.nim
@@ -12,6 +12,8 @@
 type
   UncheckedCharArray = UncheckedArray[char]
 
+import system/helpers2
+
 type
   Buffer = ptr object
     refcount: int
@@ -49,11 +51,11 @@ proc len*(s: SharedString): int = s.len
 
 proc `[]`*(s: SharedString; i: Natural): char =
   if i < s.len: result = s.buffer.data[i+s.first]
-  else: raise newException(IndexError, "index out of bounds")
+  else: raise newException(IndexError, formatErrorIndexBound(i, s.len-1))
 
 proc `[]=`*(s: var SharedString; i: Natural; value: char) =
   if i < s.len: s.buffer.data[i+s.first] = value
-  else: raise newException(IndexError, "index out of bounds")
+  else: raise newException(IndexError, formatErrorIndexBound(i, s.len-1))
 
 proc `[]`*(s: SharedString; ab: HSlice[int, int]): SharedString =
   #incRef(src.buffer)
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index 9fdae33ed..f46a368b1 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -125,8 +125,6 @@ type
     counter: int
   TableRef*[A,B] = ref Table[A, B]
 
-{.deprecated: [TTable: Table, PTable: TableRef].}
-
 template maxHash(t): untyped = high(t.data)
 template dataLen(t): untyped = len(t.data)
 
@@ -520,8 +518,6 @@ type
     counter, first, last: int
   OrderedTableRef*[A, B] = ref OrderedTable[A, B]
 
-{.deprecated: [TOrderedTable: OrderedTable, POrderedTable: OrderedTableRef].}
-
 proc len*[A, B](t: OrderedTable[A, B]): int {.inline.} =
   ## returns the number of keys in ``t``.
   result = t.counter
@@ -795,7 +791,7 @@ proc getOrDefault*[A, B](t: OrderedTableRef[A, B], key: A): B =
   getOrDefault(t[], key)
 
 proc getOrDefault*[A, B](t: OrderedTableRef[A, B], key: A, default: B): B =
-  ## retrieves the value at ``t[key]`` iff ``key`` is in ``t``. Otherwise, 
+  ## retrieves the value at ``t[key]`` iff ``key`` is in ``t``. Otherwise,
   ## ``default`` is returned.
   getOrDefault(t[], key, default)
 
@@ -892,8 +888,6 @@ type
     counter: int
   CountTableRef*[A] = ref CountTable[A]
 
-{.deprecated: [TCountTable: CountTable, PCountTable: CountTableRef].}
-
 proc len*[A](t: CountTable[A]): int =
   ## returns the number of keys in ``t``.
   result = t.counter
diff --git a/lib/pure/colors.nim b/lib/pure/colors.nim
index 843f29a63..b58166b05 100644
--- a/lib/pure/colors.nim
+++ b/lib/pure/colors.nim
@@ -377,7 +377,7 @@ proc colorNameCmp(x: tuple[name: string, col: Color], y: string): int =
 
 proc parseColor*(name: string): Color =
   ## parses `name` to a color value. If no valid color could be
-  ## parsed ``EInvalidValue`` is raised. Case insensitive.
+  ## parsed ``ValueError`` is raised. Case insensitive.
   if name[0] == '#':
     result = Color(parseHexInt(name))
   else:
diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim
index ba5c571ce..69d9c0f7f 100644
--- a/lib/pure/complex.nim
+++ b/lib/pure/complex.nim
@@ -9,78 +9,109 @@
 
 
 
-## This module implements complex numbers.
-{.push checks:off, line_dir:off, stack_trace:off, debugger:off.}
-# the user does not want to trace a part
-# of the standard library!
 
 
-import
-  math
+## This module implements complex numbers.
+## Complex numbers are currently implemented as generic on a 64-bit or 32-bit float.
+
+{.push checks: off, line_dir: off, stack_trace: off, debugger: off.}
+# the user does not want to trace a part of the standard library!
 
-const
-  EPS = 1.0e-7 ## Epsilon used for float comparisons.
+import math
 
 type
-  Complex* = tuple[re, im: float]
-    ## a complex number, consisting of a real and an imaginary part
-
-const
-  im*: Complex = (re: 0.0, im: 1.0)
-    ## The imaginary unit. √-1.
+  Complex*[T: SomeFloat] = object
+    re*, im*: T
+    ## A complex number, consisting of a real and an imaginary part.
+  Complex64* = Complex[float64]
+    ## Alias for a pair of 64-bit floats.
+  Complex32* = Complex[float32]
+    ## Alias for a pair of 32-bit floats.
+
+proc complex*[T: SomeFloat](re: T; im: T = 0.0): Complex[T] =
+  result.re = re
+  result.im = im
+
+proc complex32*(re: float32; im: float32 = 0.0): Complex[float32] =
+  result.re = re
+  result.im = im
+
+proc complex64*(re: float64; im: float64 = 0.0): Complex[float64] =
+  result.re = re
+  result.im = im
+
+template im*(arg: typedesc[float32]): Complex32 = complex[float32](0, 1)
+template im*(arg: typedesc[float64]): Complex64 = complex[float64](0, 1)
+template im*(arg : float32): Complex32 = complex[float32](0, arg)
+template im*(arg : float64): Complex64 = complex[float64](0, arg)
+
+proc abs*[T](z: Complex[T]): T =
+  ## Return the distance from (0,0) to ``z``.
+  result = hypot(z.re, z.im)
+
+proc abs2*[T](z: Complex[T]): T =
+  ## Return the squared distance from (0,0) to ``z``.
+  result = z.re*z.re + z.im*z.im
+
+proc conjugate*[T](z: Complex[T]): Complex[T] =
+  ## Conjugate of complex number ``z``.
+  result.re = z.re
+  result.im = -z.im
 
-proc toComplex*(x: SomeInteger): Complex =
-  ## Convert some integer ``x`` to a complex number.
-  result.re = x
-  result.im = 0
+proc inv*[T](z: Complex[T]): Complex[T] =
+  ## Multiplicative inverse of complex number ``z``.
+  conjugate(z) / abs2(z)
 
-proc `==` *(x, y: Complex): bool =
-  ## Compare two complex numbers `x` and `y` for equality.
+proc `==` *[T](x, y: Complex[T]): bool =
+  ## Compare two complex numbers ``x`` and ``y`` for equality.
   result = x.re == y.re and x.im == y.im
 
-proc `=~` *(x, y: Complex): bool =
-  ## Compare two complex numbers `x` and `y` approximately.
-  result = abs(x.re-y.re)<EPS and abs(x.im-y.im)<EPS
-
-proc `+` *(x, y: Complex): Complex =
-  ## Add two complex numbers.
-  result.re = x.re + y.re
-  result.im = x.im + y.im
+proc `+` *[T](x: T, y: Complex[T]): Complex[T] =
+  ## Add a real number to a complex number.
+  result.re = x + y.re
+  result.im = y.im
 
-proc `+` *(x: Complex, y: float): Complex =
-  ## Add complex `x` to float `y`.
+proc `+` *[T](x: Complex[T], y: T): Complex[T] =
+  ## Add a complex number to a real number.
   result.re = x.re + y
   result.im = x.im
 
-proc `+` *(x: float, y: Complex): Complex =
-  ## Add float `x` to complex `y`.
-  result.re = x + y.re
-  result.im = y.im
-
+proc `+` *[T](x, y: Complex[T]): Complex[T] =
+  ## Add two complex numbers.
+  result.re = x.re + y.re
+  result.im = x.im + y.im
 
-proc `-` *(z: Complex): Complex =
+proc `-` *[T](z: Complex[T]): Complex[T] =
   ## Unary minus for complex numbers.
   result.re = -z.re
   result.im = -z.im
 
-proc `-` *(x, y: Complex): Complex =
+proc `-` *[T](x: T, y: Complex[T]): Complex[T] =
+  ## Subtract a complex number from a real number.
+  x + (-y)
+
+proc `-` *[T](x: Complex[T], y: T): Complex[T] =
+  ## Subtract a real number from a complex number.
+  result.re = x.re - y
+  result.im = x.im
+
+proc `-` *[T](x, y: Complex[T]): Complex[T] =
   ## Subtract two complex numbers.
   result.re = x.re - y.re
   result.im = x.im - y.im
 
-proc `-` *(x: Complex, y: float): Complex =
-  ## Subtracts float `y` from complex `x`.
-  result = x + (-y)
-
-proc `-` *(x: float, y: Complex): Complex =
-  ## Subtracts complex `y` from float `x`.
-  result = x + (-y)
+proc `/` *[T](x: Complex[T], y: T): Complex[T] =
+  ## Divide complex number ``x`` by real number ``y``.
+  result.re = x.re / y
+  result.im = x.im / y
 
+proc `/` *[T](x: T, y: Complex[T]): Complex[T] =
+  ## Divide real number ``x`` by complex number ``y``.
+  result = x * inv(y)
 
-proc `/` *(x, y: Complex): Complex =
-  ## Divide `x` by `y`.
-  var
-    r, den: float
+proc `/` *[T](x, y: Complex[T]): Complex[T] =
+  ## Divide ``x`` by ``y``.
+  var r, den: T
   if abs(y.re) < abs(y.im):
     r = y.re / y.im
     den = y.im + r * y.re
@@ -92,101 +123,46 @@ proc `/` *(x, y: Complex): Complex =
     result.re = (x.re + r * x.im) / den
     result.im = (x.im - r * x.re) / den
 
-proc `/` *(x : Complex, y: float ): Complex =
-  ## Divide complex `x` by float `y`.
-  result.re = x.re/y
-  result.im = x.im/y
-
-proc `/` *(x : float, y: Complex ): Complex =
-  ## Divide float `x` by complex `y`.
-  var num : Complex = (x, 0.0)
-  result = num/y
-
-
-proc `*` *(x, y: Complex): Complex =
-  ## Multiply `x` with `y`.
-  result.re = x.re * y.re - x.im * y.im
-  result.im = x.im * y.re + x.re * y.im
-
-proc `*` *(x: float, y: Complex): Complex =
-  ## Multiply float `x` with complex `y`.
+proc `*` *[T](x: T, y: Complex[T]): Complex[T] =
+  ## Multiply a real number and a complex number.
   result.re = x * y.re
   result.im = x * y.im
 
-proc `*` *(x: Complex, y: float): Complex =
-  ## Multiply complex `x` with float `y`.
+proc `*` *[T](x: Complex[T], y: T): Complex[T] =
+  ## Multiply a complex number with a real number.
   result.re = x.re * y
   result.im = x.im * y
 
+proc `*` *[T](x, y: Complex[T]): Complex[T] =
+  ## Multiply ``x`` with ``y``.
+  result.re = x.re * y.re - x.im * y.im
+  result.im = x.im * y.re + x.re * y.im
 
-proc `+=` *(x: var Complex, y: Complex) =
-  ## Add `y` to `x`.
+
+proc `+=` *[T](x: var Complex[T], y: Complex[T]) =
+  ## Add ``y`` to ``x``.
   x.re += y.re
   x.im += y.im
 
-proc `+=` *(x: var Complex, y: float) =
-  ## Add `y` to the complex number `x`.
-  x.re += y
-
-proc `-=` *(x: var Complex, y: Complex) =
-  ## Subtract `y` from `x`.
+proc `-=` *[T](x: var Complex[T], y: Complex[T]) =
+  ## Subtract ``y`` from ``x``.
   x.re -= y.re
   x.im -= y.im
 
-proc `-=` *(x: var Complex, y: float) =
-  ## Subtract `y` from the complex number `x`.
-  x.re -= y
-
-proc `*=` *(x: var Complex, y: Complex) =
-  ## Multiply `y` to `x`.
+proc `*=` *[T](x: var Complex[T], y: Complex[T]) =
+  ## Multiply ``y`` to ``x``.
   let im = x.im * y.re + x.re * y.im
   x.re = x.re * y.re - x.im * y.im
   x.im = im
 
-proc `*=` *(x: var Complex, y: float) =
-  ## Multiply `y` to the complex number `x`.
-  x.re *= y
-  x.im *= y
-
-proc `/=` *(x: var Complex, y: Complex) =
-  ## Divide `x` by `y` in place.
+proc `/=` *[T](x: var Complex[T], y: Complex[T]) =
+  ## Divide ``x`` by ``y`` in place.
   x = x / y
 
-proc `/=` *(x : var Complex, y: float) =
-  ## Divide complex `x` by float `y` in place.
-  x.re /= y
-  x.im /= y
-
-
-proc abs*(z: Complex): float =
-  ## Return the distance from (0,0) to `z`.
 
-  # optimized by checking special cases (sqrt is expensive)
-  var x, y, temp: float
-
-  x = abs(z.re)
-  y = abs(z.im)
-  if x == 0.0:
-    result = y
-  elif y == 0.0:
-    result = x
-  elif x > y:
-    temp = y / x
-    result = x * sqrt(1.0 + temp * temp)
-  else:
-    temp = x / y
-    result = y * sqrt(1.0 + temp * temp)
-
-
-proc conjugate*(z: Complex): Complex =
-  ## Conjugate of complex number `z`.
-  result.re = z.re
-  result.im = -z.im
-
-
-proc sqrt*(z: Complex): Complex =
-  ## Square root for a complex number `z`.
-  var x, y, w, r: float
+proc sqrt*[T](z: Complex[T]): Complex[T] =
+  ## Square root for a complex number ``z``.
+  var x, y, w, r: T
 
   if z.re == 0.0 and z.im == 0.0:
     result = z
@@ -199,247 +175,283 @@ proc sqrt*(z: Complex): Complex =
     else:
       r = x / y
       w = sqrt(y) * sqrt(0.5 * (r + sqrt(1.0 + r * r)))
+
     if z.re >= 0.0:
       result.re = w
       result.im = z.im / (w * 2.0)
     else:
-      if z.im >= 0.0: result.im = w
-      else:           result.im = -w
+      result.im = if z.im >= 0.0: w else: -w
       result.re = z.im / (result.im + result.im)
 
+proc exp*[T](z: Complex[T]): Complex[T] =
+  ## ``e`` raised to the power ``z``.
+  var
+    rho = exp(z.re)
+    theta = z.im
+  result.re = rho * cos(theta)
+  result.im = rho * sin(theta)
 
-proc exp*(z: Complex): Complex =
-  ## e raised to the power `z`.
-  var rho   = exp(z.re)
-  var theta = z.im
-  result.re = rho*cos(theta)
-  result.im = rho*sin(theta)
-
-
-proc ln*(z: Complex): Complex =
-  ## Returns the natural log of `z`.
+proc ln*[T](z: Complex[T]): Complex[T] =
+  ## Returns the natural log of ``z``.
   result.re = ln(abs(z))
-  result.im = arctan2(z.im,z.re)
-
-proc log10*(z: Complex): Complex =
-  ## Returns the log base 10 of `z`.
-  result = ln(z)/ln(10.0)
+  result.im = arctan2(z.im, z.re)
 
-proc log2*(z: Complex): Complex =
-  ## Returns the log base 2 of `z`.
-  result = ln(z)/ln(2.0)
+proc log10*[T](z: Complex[T]): Complex[T] =
+  ## Returns the log base 10 of ``z``.
+  result = ln(z) / ln(10.0)
 
+proc log2*[T](z: Complex[T]): Complex[T] =
+  ## Returns the log base 2 of ``z``.
+  result = ln(z) / ln(2.0)
 
-proc pow*(x, y: Complex): Complex =
-  ## `x` raised to the power `y`.
-  if x.re == 0.0  and  x.im == 0.0:
-    if y.re == 0.0  and  y.im == 0.0:
+proc pow*[T](x, y: Complex[T]): Complex[T] =
+  ## ``x`` raised to the power ``y``.
+  if x.re == 0.0 and x.im == 0.0:
+    if y.re == 0.0 and y.im == 0.0:
       result.re = 1.0
       result.im = 0.0
     else:
       result.re = 0.0
       result.im = 0.0
-  elif y.re == 1.0  and  y.im == 0.0:
+  elif y.re == 1.0 and y.im == 0.0:
     result = x
-  elif y.re == -1.0  and  y.im == 0.0:
-    result = 1.0/x
+  elif y.re == -1.0 and y.im == 0.0:
+    result = T(1.0) / x
   else:
-    var rho   = sqrt(x.re*x.re + x.im*x.im)
-    var theta = arctan2(x.im,x.re)
-    var s     = pow(rho,y.re) * exp(-y.im*theta)
-    var r     = y.re*theta + y.im*ln(rho)
-    result.re = s*cos(r)
-    result.im = s*sin(r)
-
-
-proc sin*(z: Complex): Complex =
-  ## Returns the sine of `z`.
-  result.re = sin(z.re)*cosh(z.im)
-  result.im = cos(z.re)*sinh(z.im)
-
-proc arcsin*(z: Complex): Complex =
-  ## Returns the inverse sine of `z`.
-  var i: Complex = (0.0,1.0)
-  result = -i*ln(i*z + sqrt(1.0-z*z))
-
-proc cos*(z: Complex): Complex =
-  ## Returns the cosine of `z`.
-  result.re = cos(z.re)*cosh(z.im)
-  result.im = -sin(z.re)*sinh(z.im)
-
-proc arccos*(z: Complex): Complex =
-  ## Returns the inverse cosine of `z`.
-  var i: Complex = (0.0,1.0)
-  result = -i*ln(z + sqrt(z*z-1.0))
-
-proc tan*(z: Complex): Complex =
-  ## Returns the tangent of `z`.
-  result = sin(z)/cos(z)
-
-proc arctan*(z: Complex): Complex =
-  ## Returns the inverse tangent of `z`.
-  var i: Complex = (0.0,1.0)
-  result = 0.5*i*(ln(1-i*z)-ln(1+i*z))
-
-proc cot*(z: Complex): Complex =
-  ## Returns the cotangent of `z`.
+    var
+      rho = abs(x)
+      theta = arctan2(x.im, x.re)
+      s = pow(rho, y.re) * exp(-y.im * theta)
+      r = y.re * theta + y.im * ln(rho)
+    result.re = s * cos(r)
+    result.im = s * sin(r)
+
+proc pow*[T](x: Complex[T], y: T): Complex[T] =
+  ## Complex number ``x`` raised to the power ``y``.
+  pow(x, complex[T](y))
+
+
+proc sin*[T](z: Complex[T]): Complex[T] =
+  ## Returns the sine of ``z``.
+  result.re = sin(z.re) * cosh(z.im)
+  result.im = cos(z.re) * sinh(z.im)
+
+proc arcsin*[T](z: Complex[T]): Complex[T] =
+  ## Returns the inverse sine of ``z``.
+  result = -im(T) * ln(im(T) * z + sqrt(T(1.0) - z*z))
+
+proc cos*[T](z: Complex[T]): Complex[T] =
+  ## Returns the cosine of ``z``.
+  result.re = cos(z.re) * cosh(z.im)
+  result.im = -sin(z.re) * sinh(z.im)
+
+proc arccos*[T](z: Complex[T]): Complex[T] =
+  ## Returns the inverse cosine of ``z``.
+  result = -im(T) * ln(z + sqrt(z*z - T(1.0)))
+
+proc tan*[T](z: Complex[T]): Complex[T] =
+  ## Returns the tangent of ``z``.
+  result = sin(z) / cos(z)
+
+proc arctan*[T](z: Complex[T]): Complex[T] =
+  ## Returns the inverse tangent of ``z``.
+  result = T(0.5)*im(T) * (ln(T(1.0) - im(T)*z) - ln(T(1.0) + im(T)*z))
+
+proc cot*[T](z: Complex[T]): Complex[T] =
+  ## Returns the cotangent of ``z``.
   result = cos(z)/sin(z)
 
-proc arccot*(z: Complex): Complex =
-  ## Returns the inverse cotangent of `z`.
-  var i: Complex = (0.0,1.0)
-  result = 0.5*i*(ln(1-i/z)-ln(1+i/z))
+proc arccot*[T](z: Complex[T]): Complex[T] =
+  ## Returns the inverse cotangent of ``z``.
+  result = T(0.5)*im(T) * (ln(T(1.0) - im(T)/z) - ln(T(1.0) + im(T)/z))
 
-proc sec*(z: Complex): Complex =
-  ## Returns the secant of `z`.
-  result = 1.0/cos(z)
+proc sec*[T](z: Complex[T]): Complex[T] =
+  ## Returns the secant of ``z``.
+  result = T(1.0) / cos(z)
 
-proc arcsec*(z: Complex): Complex =
-  ## Returns the inverse secant of `z`.
-  var i: Complex = (0.0,1.0)
-  result = -i*ln(i*sqrt(1-1/(z*z))+1/z)
+proc arcsec*[T](z: Complex[T]): Complex[T] =
+  ## Returns the inverse secant of ``z``.
+  result = -im(T) * ln(im(T) * sqrt(1.0 - 1.0/(z*z)) + T(1.0)/z)
 
-proc csc*(z: Complex): Complex =
-  ## Returns the cosecant of `z`.
-  result = 1.0/sin(z)
+proc csc*[T](z: Complex[T]): Complex[T] =
+  ## Returns the cosecant of ``z``.
+  result = T(1.0) / sin(z)
 
-proc arccsc*(z: Complex): Complex =
-  ## Returns the inverse cosecant of `z`.
-  var i: Complex = (0.0,1.0)
-  result = -i*ln(sqrt(1-1/(z*z))+i/z)
+proc arccsc*[T](z: Complex[T]): Complex[T] =
+  ## Returns the inverse cosecant of ``z``.
+  result = -im(T) * ln(sqrt(T(1.0) - T(1.0)/(z*z)) + im(T)/z)
 
+proc sinh*[T](z: Complex[T]): Complex[T] =
+  ## Returns the hyperbolic sine of ``z``.
+  result = T(0.5) * (exp(z) - exp(-z))
 
-proc sinh*(z: Complex): Complex =
-  ## Returns the hyperbolic sine of `z`.
-  result = 0.5*(exp(z)-exp(-z))
+proc arcsinh*[T](z: Complex[T]): Complex[T] =
+  ## Returns the inverse hyperbolic sine of ``z``.
+  result = ln(z + sqrt(z*z + 1.0))
 
-proc arcsinh*(z: Complex): Complex =
-  ## Returns the inverse hyperbolic sine of `z`.
-  result = ln(z+sqrt(z*z+1))
+proc cosh*[T](z: Complex[T]): Complex[T] =
+  ## Returns the hyperbolic cosine of ``z``.
+  result = T(0.5) * (exp(z) + exp(-z))
 
-proc cosh*(z: Complex): Complex =
-  ## Returns the hyperbolic cosine of `z`.
-  result = 0.5*(exp(z)+exp(-z))
+proc arccosh*[T](z: Complex[T]): Complex[T] =
+  ## Returns the inverse hyperbolic cosine of ``z``.
+  result = ln(z + sqrt(z*z - T(1.0)))
 
-proc arccosh*(z: Complex): Complex =
-  ## Returns the inverse hyperbolic cosine of `z`.
-  result = ln(z+sqrt(z*z-1))
+proc tanh*[T](z: Complex[T]): Complex[T] =
+  ## Returns the hyperbolic tangent of ``z``.
+  result = sinh(z) / cosh(z)
 
-proc tanh*(z: Complex): Complex =
-  ## Returns the hyperbolic tangent of `z`.
-  result = sinh(z)/cosh(z)
+proc arctanh*[T](z: Complex[T]): Complex[T] =
+  ## Returns the inverse hyperbolic tangent of ``z``.
+  result = T(0.5) * (ln((T(1.0)+z) / (T(1.0)-z)))
 
-proc arctanh*(z: Complex): Complex =
-  ## Returns the inverse hyperbolic tangent of `z`.
-  result = 0.5*(ln((1+z)/(1-z)))
+proc sech*[T](z: Complex[T]): Complex[T] =
+  ## Returns the hyperbolic secant of ``z``.
+  result = T(2.0) / (exp(z) + exp(-z))
 
-proc sech*(z: Complex): Complex =
-  ## Returns the hyperbolic secant of `z`.
-  result = 2/(exp(z)+exp(-z))
+proc arcsech*[T](z: Complex[T]): Complex[T] =
+  ## Returns the inverse hyperbolic secant of ``z``.
+  result = ln(1.0/z + sqrt(T(1.0)/z+T(1.0)) * sqrt(T(1.0)/z-T(1.0)))
 
-proc arcsech*(z: Complex): Complex =
-  ## Returns the inverse hyperbolic secant of `z`.
-  result = ln(1/z+sqrt(1/z+1)*sqrt(1/z-1))
+proc csch*[T](z: Complex[T]): Complex[T] =
+  ## Returns the hyperbolic cosecant of ``z``.
+  result = T(2.0) / (exp(z) - exp(-z))
 
-proc csch*(z: Complex): Complex =
-  ## Returns the hyperbolic cosecant of `z`.
-  result = 2/(exp(z)-exp(-z))
+proc arccsch*[T](z: Complex[T]): Complex[T] =
+  ## Returns the inverse hyperbolic cosecant of ``z``.
+  result = ln(T(1.0)/z + sqrt(T(1.0)/(z*z) + T(1.0)))
 
-proc arccsch*(z: Complex): Complex =
-  ## Returns the inverse hyperbolic cosecant of `z`.
-  result = ln(1/z+sqrt(1/(z*z)+1))
+proc coth*[T](z: Complex[T]): Complex[T] =
+  ## Returns the hyperbolic cotangent of ``z``.
+  result = cosh(z) / sinh(z)
 
-proc coth*(z: Complex): Complex =
-  ## Returns the hyperbolic cotangent of `z`.
-  result = cosh(z)/sinh(z)
+proc arccoth*[T](z: Complex[T]): Complex[T] =
+  ## Returns the inverse hyperbolic cotangent of ``z``.
+  result = T(0.5) * (ln(T(1.0) + T(1.0)/z) - ln(T(1.0) - T(1.0)/z))
 
-proc arccoth*(z: Complex): Complex =
-  ## Returns the inverse hyperbolic cotangent of `z`.
-  result = 0.5*(ln(1+1/z)-ln(1-1/z))
-
-proc phase*(z: Complex): float =
-  ## Returns the phase of `z`.
+proc phase*[T](z: Complex[T]): T =
+  ## Returns the phase of ``z``.
   arctan2(z.im, z.re)
 
-proc polar*(z: Complex): tuple[r, phi: float] =
-  ## Returns `z` in polar coordinates.
-  result.r = abs(z)
-  result.phi = phase(z)
+proc polar*[T](z: Complex[T]): tuple[r, phi: T] =
+  ## Returns ``z`` in polar coordinates.
+  (r: abs(z), phi: phase(z))
 
-proc rect*(r: float, phi: float): Complex =
-  ## Returns the complex number with polar coordinates `r` and `phi`.
-  result.re = r * cos(phi)
-  result.im = r * sin(phi)
+proc rect*[T](r, phi: T): Complex[T] =
+  ## Returns the complex number with polar coordinates ``r`` and ``phi``.
+  ##
+  ## | ``result.re = r * cos(phi)``
+  ## | ``result.im = r * sin(phi)``
+  complex(r * cos(phi), r * sin(phi))
 
 
 proc `$`*(z: Complex): string =
-  ## Returns `z`'s string representation as ``"(re, im)"``.
+  ## Returns ``z``'s string representation as ``"(re, im)"``.
   result = "(" & $z.re & ", " & $z.im & ")"
 
 {.pop.}
 
 
 when isMainModule:
-  var z = (0.0, 0.0)
-  var oo = (1.0,1.0)
-  var a = (1.0, 2.0)
-  var b = (-1.0, -2.0)
-  var m1 = (-1.0, 0.0)
-  var i = (0.0,1.0)
-  var one = (1.0,0.0)
-  var tt = (10.0, 20.0)
-  var ipi = (0.0, -PI)
-
-  assert( a == a )
-  assert( (a-a) == z )
-  assert( (a+b) == z )
-  assert( (a/b) == m1 )
-  assert( (1.0/a) == (0.2, -0.4) )
-  assert( (a*b) == (3.0, -4.0) )
-  assert( 10.0*a == tt )
-  assert( a*10.0 == tt )
-  assert( tt/10.0 == a )
-  assert( oo+(-1.0) == i )
-  assert( (-1.0)+oo == i )
-  assert( abs(oo) == sqrt(2.0) )
-  assert( conjugate(a) == (1.0, -2.0) )
-  assert( sqrt(m1) == i )
-  assert( exp(ipi) =~ m1 )
-
-  assert( pow(a,b) =~ (-3.72999124927876, -1.68815826725068) )
-  assert( pow(z,a) =~ (0.0, 0.0) )
-  assert( pow(z,z) =~ (1.0, 0.0) )
-  assert( pow(a,one) =~ a )
-  assert( pow(a,m1) =~ (0.2, -0.4) )
-
-  assert( ln(a) =~ (0.804718956217050, 1.107148717794090) )
-  assert( log10(a) =~ (0.349485002168009, 0.480828578784234) )
-  assert( log2(a) =~ (1.16096404744368, 1.59727796468811) )
-
-  assert( sin(a) =~ (3.16577851321617, 1.95960104142161) )
-  assert( cos(a) =~ (2.03272300701967, -3.05189779915180) )
-  assert( tan(a) =~ (0.0338128260798967, 1.0147936161466335) )
-  assert( cot(a) =~ 1.0/tan(a) )
-  assert( sec(a) =~ 1.0/cos(a) )
-  assert( csc(a) =~ 1.0/sin(a) )
-  assert( arcsin(a) =~ (0.427078586392476, 1.528570919480998) )
-  assert( arccos(a) =~ (1.14371774040242, -1.52857091948100) )
-  assert( arctan(a) =~ (1.338972522294494, 0.402359478108525) )
-
-  assert( cosh(a) =~ (-0.642148124715520, 1.068607421382778) )
-  assert( sinh(a) =~ (-0.489056259041294, 1.403119250622040) )
-  assert( tanh(a) =~ (1.1667362572409199,-0.243458201185725) )
-  assert( sech(a) =~ 1/cosh(a) )
-  assert( csch(a) =~ 1/sinh(a) )
-  assert( coth(a) =~ 1/tanh(a) )
-  assert( arccosh(a) =~ (1.528570919480998, 1.14371774040242) )
-  assert( arcsinh(a) =~ (1.469351744368185, 1.06344002357775) )
-  assert( arctanh(a) =~ (0.173286795139986, 1.17809724509617) )
-  assert( arcsech(a) =~ arccosh(1/a) )
-  assert( arccsch(a) =~ arcsinh(1/a) )
-  assert( arccoth(a) =~ arctanh(1/a) )
-
-  assert( phase(a) == 1.1071487177940904 )
+  proc `=~`[T](x, y: Complex[T]): bool =
+    result = abs(x.re-y.re) < 1e-6 and abs(x.im-y.im) < 1e-6
+
+  proc `=~`[T](x: Complex[T], y: T): bool =
+    result = abs(x.re-y) < 1e-6 and abs(x.im) < 1e-6
+
+  var
+    z: Complex64   = complex(0.0, 0.0)
+    oo: Complex64  = complex(1.0, 1.0)
+    a: Complex64   = complex(1.0, 2.0)
+    b: Complex64   = complex(-1.0, -2.0)
+    m1: Complex64  = complex(-1.0, 0.0)
+    i: Complex64   = complex(0.0, 1.0)
+    one: Complex64 = complex(1.0, 0.0)
+    tt: Complex64  = complex(10.0, 20.0)
+    ipi: Complex64 = complex(0.0, -PI)
+
+  doAssert(a/2.0 =~ complex(0.5, 1.0))
+  doAssert(a == a)
+  doAssert((a-a) == z)
+  doAssert((a+b) == z)
+  doAssert((a+b) =~ 0.0)
+  doAssert((a/b) == m1)
+  doAssert((1.0/a) == complex(0.2, -0.4))
+  doAssert((a*b) == complex(3.0, -4.0))
+  doAssert(10.0*a == tt)
+  doAssert(a*10.0 == tt)
+  doAssert(tt/10.0 == a)
+  doAssert(oo+(-1.0) == i)
+  doAssert( (-1.0)+oo == i)
+  doAssert(abs(oo) == sqrt(2.0))
+  doAssert(conjugate(a) == complex(1.0, -2.0))
+  doAssert(sqrt(m1) == i)
+  doAssert(exp(ipi) =~ m1)
+
+  doAssert(pow(a, b) =~ complex(-3.72999124927876, -1.68815826725068))
+  doAssert(pow(z, a) =~ complex(0.0, 0.0))
+  doAssert(pow(z, z) =~ complex(1.0, 0.0))
+  doAssert(pow(a, one) =~ a)
+  doAssert(pow(a, m1) =~ complex(0.2, -0.4))
+  doAssert(pow(a, 2.0) =~ complex(-3.0, 4.0))
+  doAssert(pow(a, 2) =~ complex(-3.0, 4.0))
+  doAssert(not(pow(a, 2.0) =~ a))
+
+  doAssert(ln(a) =~ complex(0.804718956217050, 1.107148717794090))
+  doAssert(log10(a) =~ complex(0.349485002168009, 0.480828578784234))
+  doAssert(log2(a) =~ complex(1.16096404744368, 1.59727796468811))
+
+  doAssert(sin(a) =~ complex(3.16577851321617, 1.95960104142161))
+  doAssert(cos(a) =~ complex(2.03272300701967, -3.05189779915180))
+  doAssert(tan(a) =~ complex(0.0338128260798967, 1.0147936161466335))
+  doAssert(cot(a) =~ 1.0 / tan(a))
+  doAssert(sec(a) =~ 1.0 / cos(a))
+  doAssert(csc(a) =~ 1.0 / sin(a))
+  doAssert(arcsin(a) =~ complex(0.427078586392476, 1.528570919480998))
+  doAssert(arccos(a) =~ complex(1.14371774040242, -1.52857091948100))
+  doAssert(arctan(a) =~ complex(1.338972522294494, 0.402359478108525))
+  doAssert(arccot(a) =~ complex(0.2318238045004031, -0.402359478108525))
+  doAssert(arcsec(a) =~ complex(1.384478272687081, 0.3965682301123288))
+  doAssert(arccsc(a) =~ complex(0.1863180541078155, -0.3965682301123291))
+
+  doAssert(cosh(a) =~ complex(-0.642148124715520, 1.068607421382778))
+  doAssert(sinh(a) =~ complex(-0.489056259041294, 1.403119250622040))
+  doAssert(tanh(a) =~ complex(1.1667362572409199, -0.243458201185725))
+  doAssert(sech(a) =~ 1.0 / cosh(a))
+  doAssert(csch(a) =~ 1.0 / sinh(a))
+  doAssert(coth(a) =~ 1.0 / tanh(a))
+  doAssert(arccosh(a) =~ complex(1.528570919480998, 1.14371774040242))
+  doAssert(arcsinh(a) =~ complex(1.469351744368185, 1.06344002357775))
+  doAssert(arctanh(a) =~ complex(0.173286795139986, 1.17809724509617))
+  doAssert(arcsech(a) =~ arccosh(1.0/a))
+  doAssert(arccsch(a) =~ arcsinh(1.0/a))
+  doAssert(arccoth(a) =~ arctanh(1.0/a))
+
+  doAssert(phase(a) == 1.1071487177940904)
   var t = polar(a)
-  assert( rect(t.r, t.phi) =~ a )
-  assert( rect(1.0, 2.0) =~ (-0.4161468365471424, 0.9092974268256817) )
+  doAssert(rect(t.r, t.phi) =~ a)
+  doAssert(rect(1.0, 2.0) =~ complex(-0.4161468365471424, 0.9092974268256817))
+
+
+  var
+    i64: Complex32 = complex(0.0f, 1.0f)
+    a64: Complex32 = 2.0f*i64 + 1.0.float32
+    b64: Complex32 = complex(-1.0'f32, -2.0'f32)
+
+  doAssert(a64 == a64)
+  doAssert(a64 == -b64)
+  doAssert(a64 + b64 =~ 0.0'f32)
+  doAssert(not(pow(a64, b64) =~ a64))
+  doAssert(pow(a64, 0.5f) =~ sqrt(a64))
+  doAssert(pow(a64, 2) =~ complex(-3.0'f32, 4.0'f32))
+  doAssert(sin(arcsin(b64)) =~ b64)
+  doAssert(cosh(arccosh(a64)) =~ a64)
+
+  doAssert(phase(a64) - 1.107149f < 1e-6)
+  var t64 = polar(a64)
+  doAssert(rect(t64.r, t64.phi) =~ a64)
+  doAssert(rect(1.0f, 2.0f) =~ complex(-0.4161468f, 0.90929742f))
+  doAssert(sizeof(a64) == 8)
+  doAssert(sizeof(a) == 16)
+
+  doAssert 123.0.im + 456.0 == complex64(456, 123)
diff --git a/lib/pure/coro.nim b/lib/pure/coro.nim
index 2fe34ed40..d6a7ceec8 100644
--- a/lib/pure/coro.nim
+++ b/lib/pure/coro.nim
@@ -6,15 +6,17 @@
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
-## Nim coroutines implementation supports several context switching methods:
-## ucontext: available on unix and alike (default)
-## setjmp:   available on unix and alike (x86/64 only)
-## Fibers:   available and required on windows.
+## Nim coroutines implementation, supports several context switching methods:
+## --------  ------------
+## ucontext  available on unix and alike (default)
+## setjmp    available on unix and alike (x86/64 only)
+## fibers    available and required on windows.
+## --------  ------------
 ##
-## -d:nimCoroutines              Required to build this module.
-## -d:nimCoroutinesUcontext      Use ucontext backend.
-## -d:nimCoroutinesSetjmp        Use setjmp backend.
-## -d:nimCoroutinesSetjmpBundled Use bundled setjmp implementation.
+## -d:nimCoroutines               Required to build this module.
+## -d:nimCoroutinesUcontext       Use ucontext backend.
+## -d:nimCoroutinesSetjmp         Use setjmp backend.
+## -d:nimCoroutinesSetjmpBundled  Use bundled setjmp implementation.
 
 when not nimCoroutines and not defined(nimdoc):
   when defined(noNimCoroutines):
@@ -105,7 +107,7 @@ elif coroBackend == CORO_BACKEND_SETJMP:
     # Use setjmp/longjmp implementation provided by the system.
     type
       JmpBuf {.importc: "jmp_buf", header: "<setjmp.h>".} = object
-    
+
     proc setjmp(ctx: var JmpBuf): int {.importc, header: "<setjmp.h>".}
     proc longjmp(ctx: JmpBuf, ret=1) {.importc, header: "<setjmp.h>".}
 
@@ -241,7 +243,7 @@ proc start*(c: proc(), stacksize: int=defaultStackSize): CoroutineRef {.discarda
   ## Schedule coroutine for execution. It does not run immediately.
   if ctx == nil:
     initialize()
-  
+
   var coro: CoroutinePtr
   when coroBackend == CORO_BACKEND_FIBERS:
     coro = cast[CoroutinePtr](alloc0(sizeof(Coroutine)))
@@ -287,7 +289,7 @@ proc run*() =
     if current.state == CORO_FINISHED:
       var next = ctx.current.prev
       if next == nil:
-        # If first coroutine ends then `prev` is nil even if more coroutines 
+        # If first coroutine ends then `prev` is nil even if more coroutines
         # are to be scheduled.
         next = ctx.current.next
       current.reference.coro = nil
diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim
index 2039a31be..e09b00221 100644
--- a/lib/pure/encodings.nim
+++ b/lib/pure/encodings.nim
@@ -213,7 +213,6 @@ when defined(windows):
         maxCharSize: int32
         defaultChar: array[0..1, char]
         leadByte: array[0..12-1, char]
-    {.deprecated: [TCpInfo: CpInfo].}
 
     proc getCPInfo(codePage: CodePage, lpCPInfo: var CpInfo): int32 {.
       stdcall, importc: "GetCPInfo", dynlib: "kernel32".}
@@ -302,7 +301,7 @@ proc getCurrentEncoding*(): string =
 
 proc open*(destEncoding = "UTF-8", srcEncoding = "CP1252"): EncodingConverter =
   ## opens a converter that can convert from `srcEncoding` to `destEncoding`.
-  ## Raises `EIO` if it cannot fulfill the request.
+  ## Raises `IOError` if it cannot fulfill the request.
   when not defined(windows):
     result = iconvOpen(destEncoding, srcEncoding)
     if result == nil:
diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim
index fbf2b8e73..2d24050f2 100644
--- a/lib/pure/htmlparser.nim
+++ b/lib/pure/htmlparser.nim
@@ -2014,7 +2014,8 @@ proc parseHtml*(s: Stream, filename: string,
   ## Parses the XML from stream `s` and returns a ``XmlNode``. Every
   ## occurred parsing error is added to the `errors` sequence.
   var x: XmlParser
-  open(x, s, filename, {reportComments, reportWhitespace})
+  open(x, s, filename, {reportComments, reportWhitespace, allowUnquotedAttribs,
+    allowEmptyAttribs})
   next(x)
   # skip the DOCTYPE:
   if x.kind == xmlSpecial: next(x)
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index 139d4bb50..b7498b1c5 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -848,8 +848,6 @@ proc newHttpClient*(userAgent = defUserAgent,
 type
   AsyncHttpClient* = HttpClientBase[AsyncSocket]
 
-{.deprecated: [PAsyncHttpClient: AsyncHttpClient].}
-
 proc newAsyncHttpClient*(userAgent = defUserAgent,
     maxRedirects = 5, sslContext = getDefaultSSL(),
     proxy: Proxy = nil): AsyncHttpClient =
@@ -1164,6 +1162,9 @@ proc requestAux(client: HttpClient | AsyncHttpClient, url: string,
   # Helper that actually makes the request. Does not handle redirects.
   let requestUrl = parseUri(url)
 
+  if requestUrl.scheme == "":
+    raise newException(ValueError, "No uri scheme supplied.")
+
   when client is AsyncHttpClient:
     if not client.parseBodyFut.isNil:
       # let the current operation finish before making another request
@@ -1207,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
 
 
@@ -1226,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 =
@@ -1264,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/includes/asynccommon.nim b/lib/pure/includes/asynccommon.nim
deleted file mode 100644
index 13887acc9..000000000
--- a/lib/pure/includes/asynccommon.nim
+++ /dev/null
@@ -1,211 +0,0 @@
-template createAsyncNativeSocketImpl(domain, sockType, protocol) =
-  let handle = newNativeSocket(domain, sockType, protocol)
-  if handle == osInvalidSocket:
-    return osInvalidSocket.AsyncFD
-  handle.setBlocking(false)
-  when defined(macosx) and not defined(nimdoc):
-    handle.setSockOptInt(SOL_SOCKET, SO_NOSIGPIPE, 1)
-  result = handle.AsyncFD
-  register(result)
-
-proc createAsyncNativeSocket*(domain: cint, sockType: cint,
-                           protocol: cint): AsyncFD =
-  createAsyncNativeSocketImpl(domain, sockType, protocol)
-
-proc createAsyncNativeSocket*(domain: Domain = Domain.AF_INET,
-                           sockType: SockType = SOCK_STREAM,
-                           protocol: Protocol = IPPROTO_TCP): AsyncFD =
-  createAsyncNativeSocketImpl(domain, sockType, protocol)
-
-proc newAsyncNativeSocket*(domain: cint, sockType: cint,
-                           protocol: cint): AsyncFD {.deprecated: "use createAsyncNativeSocket instead".} =
-  createAsyncNativeSocketImpl(domain, sockType, protocol)
-
-proc newAsyncNativeSocket*(domain: Domain = Domain.AF_INET,
-                           sockType: SockType = SOCK_STREAM,
-                           protocol: Protocol = IPPROTO_TCP): AsyncFD
-                           {.deprecated: "use createAsyncNativeSocket instead".} =
-  createAsyncNativeSocketImpl(domain, sockType, protocol)
-
-when defined(windows) or defined(nimdoc):
-  proc bindToDomain(handle: SocketHandle, domain: Domain) =
-    # Extracted into a separate proc, because connect() on Windows requires
-    # the socket to be initially bound.
-    template doBind(saddr) =
-      if bindAddr(handle, cast[ptr SockAddr](addr(saddr)),
-                  sizeof(saddr).SockLen) < 0'i32:
-        raiseOSError(osLastError())
-
-    if domain == Domain.AF_INET6:
-      var saddr: Sockaddr_in6
-      saddr.sin6_family = uint16(toInt(domain))
-      doBind(saddr)
-    else:
-      var saddr: Sockaddr_in
-      saddr.sin_family = uint16(toInt(domain))
-      doBind(saddr)
-
-  proc doConnect(socket: AsyncFD, addrInfo: ptr AddrInfo): Future[void] =
-    let retFuture = newFuture[void]("doConnect")
-    result = retFuture
-
-    var ol = PCustomOverlapped()
-    GC_ref(ol)
-    ol.data = CompletionData(fd: socket, cb:
-      proc (fd: AsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
-        if not retFuture.finished:
-          if errcode == OSErrorCode(-1):
-            retFuture.complete()
-          else:
-            retFuture.fail(newException(OSError, osErrorMsg(errcode)))
-    )
-
-    let ret = connectEx(socket.SocketHandle, addrInfo.ai_addr,
-                        cint(addrInfo.ai_addrlen), nil, 0, nil,
-                        cast[POVERLAPPED](ol))
-    if ret:
-      # Request to connect completed immediately.
-      retFuture.complete()
-      # We don't deallocate ``ol`` here because even though this completed
-      # immediately poll will still be notified about its completion and it
-      # will free ``ol``.
-    else:
-      let lastError = osLastError()
-      if lastError.int32 != ERROR_IO_PENDING:
-        # With ERROR_IO_PENDING ``ol`` will be deallocated in ``poll``,
-        # and the future will be completed/failed there, too.
-        GC_unref(ol)
-        retFuture.fail(newException(OSError, osErrorMsg(lastError)))
-else:
-  proc doConnect(socket: AsyncFD, addrInfo: ptr AddrInfo): Future[void] =
-    let retFuture = newFuture[void]("doConnect")
-    result = retFuture
-
-    proc cb(fd: AsyncFD): bool =
-      let ret = SocketHandle(fd).getSockOptInt(
-        cint(SOL_SOCKET), cint(SO_ERROR))
-      if ret == 0:
-        # We have connected.
-        retFuture.complete()
-        return true
-      elif ret == EINTR:
-        # interrupted, keep waiting
-        return false
-      else:
-        retFuture.fail(newException(OSError, osErrorMsg(OSErrorCode(ret))))
-        return true
-
-    let ret = connect(socket.SocketHandle,
-                      addrInfo.ai_addr,
-                      addrInfo.ai_addrlen.Socklen)
-    if ret == 0:
-      # Request to connect completed immediately.
-      retFuture.complete()
-    else:
-      let lastError = osLastError()
-      if lastError.int32 == EINTR or lastError.int32 == EINPROGRESS:
-        addWrite(socket, cb)
-      else:
-        retFuture.fail(newException(OSError, osErrorMsg(lastError)))
-
-template asyncAddrInfoLoop(addrInfo: ptr AddrInfo, fd: untyped,
-                           protocol: Protocol = IPPROTO_RAW) =
-  ## Iterates through the AddrInfo linked list asynchronously
-  ## until the connection can be established.
-  const shouldCreateFd = not declared(fd)
-
-  when shouldCreateFd:
-    let sockType = protocol.toSockType()
-
-    var fdPerDomain: array[low(Domain).ord..high(Domain).ord, AsyncFD]
-    for i in low(fdPerDomain)..high(fdPerDomain):
-      fdPerDomain[i] = osInvalidSocket.AsyncFD
-    template closeUnusedFds(domainToKeep = -1) {.dirty.} =
-      for i, fd in fdPerDomain:
-        if fd != osInvalidSocket.AsyncFD and i != domainToKeep:
-          fd.closeSocket()
-
-  var lastException: ref Exception
-  var curAddrInfo = addrInfo
-  var domain: Domain
-  when shouldCreateFd:
-    var curFd: AsyncFD
-  else:
-    var curFd = fd
-  proc tryNextAddrInfo(fut: Future[void]) {.gcsafe.} =
-    if fut == nil or fut.failed:
-      if fut != nil:
-        lastException = fut.readError()
-
-      while curAddrInfo != nil:
-        let domainOpt = curAddrInfo.ai_family.toKnownDomain()
-        if domainOpt.isSome:
-          domain = domainOpt.unsafeGet()
-          break
-        curAddrInfo = curAddrInfo.ai_next
-
-      if curAddrInfo == nil:
-        freeAddrInfo(addrInfo)
-        when shouldCreateFd:
-          closeUnusedFds()
-        if lastException != nil:
-          retFuture.fail(lastException)
-        else:
-          retFuture.fail(newException(
-            IOError, "Couldn't resolve address: " & address))
-        return
-
-      when shouldCreateFd:
-        curFd = fdPerDomain[ord(domain)]
-        if curFd == osInvalidSocket.AsyncFD:
-          try:
-            curFd = newAsyncNativeSocket(domain, sockType, protocol)
-          except:
-            freeAddrInfo(addrInfo)
-            closeUnusedFds()
-            raise getCurrentException()
-          when defined(windows):
-            curFd.SocketHandle.bindToDomain(domain)
-          fdPerDomain[ord(domain)] = curFd
-
-      doConnect(curFd, curAddrInfo).callback = tryNextAddrInfo
-      curAddrInfo = curAddrInfo.ai_next
-    else:
-      freeAddrInfo(addrInfo)
-      when shouldCreateFd:
-        closeUnusedFds(ord(domain))
-        retFuture.complete(curFd)
-      else:
-        retFuture.complete()
-
-  tryNextAddrInfo(nil)
-
-proc dial*(address: string, port: Port,
-           protocol: Protocol = IPPROTO_TCP): Future[AsyncFD] =
-  ## Establishes connection to the specified ``address``:``port`` pair via the
-  ## specified protocol. The procedure iterates through possible
-  ## resolutions of the ``address`` until it succeeds, meaning that it
-  ## seamlessly works with both IPv4 and IPv6.
-  ## Returns the async file descriptor, registered in the dispatcher of
-  ## the current thread, ready to send or receive data.
-  let retFuture = newFuture[AsyncFD]("dial")
-  result = retFuture
-  let sockType = protocol.toSockType()
-
-  let aiList = getAddrInfo(address, port, Domain.AF_UNSPEC, sockType, protocol)
-  asyncAddrInfoLoop(aiList, noFD, protocol)
-
-proc connect*(socket: AsyncFD, address: string, port: Port,
-              domain = Domain.AF_INET): Future[void] =
-  let retFuture = newFuture[void]("connect")
-  result = retFuture
-
-  when defined(windows):
-    verifyPresence(socket)
-  else:
-    assert getSockDomain(socket.SocketHandle) == domain
-
-  let aiList = getAddrInfo(address, port, domain)
-  when defined(windows):
-    socket.SocketHandle.bindToDomain(domain)
-  asyncAddrInfoLoop(aiList, socket)
diff --git a/lib/pure/includes/osenv.nim b/lib/pure/includes/osenv.nim
index ae62a5c4e..4acc36b93 100644
--- a/lib/pure/includes/osenv.nim
+++ b/lib/pure/includes/osenv.nim
@@ -1,7 +1,9 @@
 ## Include file that implements 'getEnv' and friends. Do not import it!
 
-when not declared(ospaths):
-  {.error: "This is an include file for ospaths.nim!".}
+when not declared(os):
+  {.error: "This is an include file for os.nim!".}
+
+from parseutils import skipIgnoreCase
 
 proc c_getenv(env: cstring): cstring {.
   importc: "getenv", header: "<stdlib.h>".}
@@ -91,7 +93,10 @@ proc findEnvVar(key: string): int =
   getEnvVarsC()
   var temp = key & '='
   for i in 0..high(environment):
-    if startsWith(environment[i], temp): return i
+    when defined(windows):
+      if skipIgnoreCase(environment[i], temp) == len(temp): return i
+    else:
+      if startsWith(environment[i], temp): return i
   return -1
 
 proc getEnv*(key: string, default = ""): TaintedString {.tags: [ReadEnvEffect].} =
diff --git a/lib/pure/includes/oserr.nim b/lib/pure/includes/oserr.nim
index 31212d0d1..abd0bf501 100644
--- a/lib/pure/includes/oserr.nim
+++ b/lib/pure/includes/oserr.nim
@@ -1,7 +1,7 @@
 ## Include file that implements 'osErrorMsg' and friends. Do not import it!
 
-when not declared(ospaths):
-  {.error: "This is an include file for ospaths.nim!".}
+when not declared(os):
+  {.error: "This is an include file for os.nim!".}
 
 when not defined(nimscript):
   var errno {.importc, header: "<errno.h>".}: cint
@@ -59,7 +59,8 @@ proc raiseOSError*(errorCode: OSErrorCode; additionalInfo = "") {.noinline.} =
   e.errorCode = errorCode.int32
   e.msg = osErrorMsg(errorCode)
   if additionalInfo.len > 0:
-    e.msg.add  "; Additional info: "
+    if e.msg[^1] != '\n': e.msg.add '\n'
+    e.msg.add  "Additional info: "
     e.msg.addQuoted additionalInfo
   if e.msg == "":
     e.msg = "unknown OS error"
diff --git a/lib/pure/ioselects/ioselectors_epoll.nim b/lib/pure/ioselects/ioselectors_epoll.nim
index 8b3f14f34..16d901ff0 100644
--- a/lib/pure/ioselects/ioselectors_epoll.nim
+++ b/lib/pure/ioselects/ioselectors_epoll.nim
@@ -383,14 +383,14 @@ proc selectInto*[T](s: Selector[T], timeout: int,
 
       if (pevents and EPOLLERR) != 0 or (pevents and EPOLLHUP) != 0:
         if (pevents and EPOLLHUP) != 0:
-          rkey.errorCode = ECONNRESET.OSErrorCode
+          rkey.errorCode = OSErrorCode ECONNRESET
         else:
           # Try reading SO_ERROR from fd.
           var error: cint
-          var size = sizeof(error).SockLen
-          if getsockopt(fdi.SocketHandle, SOL_SOCKET, SO_ERROR, addr(error),
+          var size = SockLen sizeof(error)
+          if getsockopt(SocketHandle fdi, SOL_SOCKET, SO_ERROR, addr(error),
                         addr(size)) == 0'i32:
-            rkey.errorCode = error.OSErrorCode
+            rkey.errorCode = OSErrorCode error
 
         rkey.events.incl(Event.Error)
       if (pevents and EPOLLOUT) != 0:
diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim
index f2f5cac9e..cd13deec3 100644
--- a/lib/pure/logging.nim
+++ b/lib/pure/logging.nim
@@ -80,6 +80,7 @@ type
 
   ConsoleLogger* = ref object of Logger ## logger that writes the messages to the
                                         ## console
+    useStderr*: bool ## will send logs into Stderr if set 
 
 when not defined(js):
   type
@@ -150,16 +151,20 @@ method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) =
       {.emit: "console.log(`cln`);".}
     else:
       try:
-        writeLine(stdout, ln)
-        if level in {lvlError, lvlFatal}: flushFile(stdout)
+        var handle = stdout
+        if logger.useStderr:
+          handle = stderr 
+        writeLine(handle, ln)
+        if level in {lvlError, lvlFatal}: flushFile(handle)
       except IOError:
         discard
 
-proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): ConsoleLogger =
+proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr, useStderr=false): ConsoleLogger =
   ## Creates a new console logger. This logger logs to the console.
   new result
   result.fmtStr = fmtStr
   result.levelThreshold = levelThreshold
+  result.useStderr = useStderr
 
 when not defined(js):
   method log*(logger: FileLogger, level: Level, args: varargs[string, `$`]) =
diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim
index 171b71493..6756107bb 100644
--- a/lib/pure/marshal.nim
+++ b/lib/pure/marshal.nim
@@ -254,12 +254,12 @@ proc loadAny(s: Stream, a: Any, t: var Table[BiggestInt, pointer]) =
   close(p)
 
 proc load*[T](s: Stream, data: var T) =
-  ## loads `data` from the stream `s`. Raises `EIO` in case of an error.
+  ## loads `data` from the stream `s`. Raises `IOError` in case of an error.
   var tab = initTable[BiggestInt, pointer]()
   loadAny(s, toAny(data), tab)
 
 proc store*[T](s: Stream, data: T) =
-  ## stores `data` into the stream `s`. Raises `EIO` in case of an error.
+  ## stores `data` into the stream `s`. Raises `IOError` in case of an error.
   var stored = initIntSet()
   var d: T
   shallowCopy(d, data)
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index f04cb5050..ee32772b1 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -168,16 +168,19 @@ when not defined(JS): # C
   proc sqrt*(x: float32): float32 {.importc: "sqrtf", header: "<math.h>".}
   proc sqrt*(x: float64): float64 {.importc: "sqrt", header: "<math.h>".}
     ## Computes the square root of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo sqrt(1.44) ## 1.2
   proc cbrt*(x: float32): float32 {.importc: "cbrtf", header: "<math.h>".}
   proc cbrt*(x: float64): float64 {.importc: "cbrt", header: "<math.h>".}
     ## Computes the cubic root of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo cbrt(2.197) ## 1.3
   proc ln*(x: float32): float32 {.importc: "logf", header: "<math.h>".}
   proc ln*(x: float64): float64 {.importc: "log", header: "<math.h>".}
     ## Computes the `natural logarithm <https://en.wikipedia.org/wiki/Natural_logarithm>`_ of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo ln(exp(4.0)) ## 4.0
 else: # JS
@@ -189,6 +192,7 @@ else: # JS
 
 proc log*[T: SomeFloat](x, base: T): T =
   ## Computes the logarithm of ``x`` to base ``base``.
+  ##
   ## .. code-block:: nim
   ##  echo log(9.0, 3.0) ## 2.0
   ln(x) / ln(base)
@@ -197,51 +201,60 @@ when not defined(JS): # C
   proc log10*(x: float32): float32 {.importc: "log10f", header: "<math.h>".}
   proc log10*(x: float64): float64 {.importc: "log10", header: "<math.h>".}
     ## Computes the common logarithm (base 10) of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo log10(100.0) ## 2.0
   proc exp*(x: float32): float32 {.importc: "expf", header: "<math.h>".}
   proc exp*(x: float64): float64 {.importc: "exp", header: "<math.h>".}
     ## Computes the exponential function of ``x`` (pow(E, x)).
+    ##
     ## .. code-block:: nim
     ##  echo exp(1.0) ## 2.718281828459045
     ##  echo ln(exp(4.0)) ## 4.0
   proc sin*(x: float32): float32 {.importc: "sinf", header: "<math.h>".}
   proc sin*(x: float64): float64 {.importc: "sin", header: "<math.h>".}
     ## Computes the sine of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo sin(PI / 6) ## 0.4999999999999999
     ##  echo sin(degToRad(90.0)) ## 1.0
   proc cos*(x: float32): float32 {.importc: "cosf", header: "<math.h>".}
   proc cos*(x: float64): float64 {.importc: "cos", header: "<math.h>".}
     ## Computes the cosine of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo cos(2 * PI) ## 1.0
     ##  echo cos(degToRad(60.0)) ## 0.5000000000000001
   proc tan*(x: float32): float32 {.importc: "tanf", header: "<math.h>".}
   proc tan*(x: float64): float64 {.importc: "tan", header: "<math.h>".}
     ## Computes the tangent of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo tan(degToRad(45.0)) ## 0.9999999999999999
     ##  echo tan(PI / 4) ## 0.9999999999999999
   proc sinh*(x: float32): float32 {.importc: "sinhf", header: "<math.h>".}
   proc sinh*(x: float64): float64 {.importc: "sinh", header: "<math.h>".}
     ## Computes the `hyperbolic sine <https://en.wikipedia.org/wiki/Hyperbolic_function#Definitions>`_ of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo sinh(1.0) ## 1.175201193643801
   proc cosh*(x: float32): float32 {.importc: "coshf", header: "<math.h>".}
   proc cosh*(x: float64): float64 {.importc: "cosh", header: "<math.h>".}
     ## Computes the `hyperbolic cosine <https://en.wikipedia.org/wiki/Hyperbolic_function#Definitions>`_ of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo cosh(1.0) ## 1.543080634815244
   proc tanh*(x: float32): float32 {.importc: "tanhf", header: "<math.h>".}
   proc tanh*(x: float64): float64 {.importc: "tanh", header: "<math.h>".}
     ## Computes the `hyperbolic tangent <https://en.wikipedia.org/wiki/Hyperbolic_function#Definitions>`_ of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo tanh(1.0) ## 0.7615941559557649
 
   proc arccos*(x: float32): float32 {.importc: "acosf", header: "<math.h>".}
   proc arccos*(x: float64): float64 {.importc: "acos", header: "<math.h>".}
     ## Computes the arc cosine of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo arccos(1.0) ## 0.0
   proc arcsin*(x: float32): float32 {.importc: "asinf", header: "<math.h>".}
@@ -250,6 +263,7 @@ when not defined(JS): # C
   proc arctan*(x: float32): float32 {.importc: "atanf", header: "<math.h>".}
   proc arctan*(x: float64): float64 {.importc: "atan", header: "<math.h>".}
     ## Calculate the arc tangent of ``x``.
+    ##
     ## .. code-block:: nim
     ##  echo arctan(1.0) ## 0.7853981633974483
     ##  echo radToDeg(arctan(1.0)) ## 45.0
@@ -259,6 +273,7 @@ when not defined(JS): # C
     ## `arctan2` returns the arc tangent of ``y`` / ``x``; it produces correct
     ## results even when the resulting angle is near pi/2 or -pi/2
     ## (``x`` near 0).
+    ##
     ## .. code-block:: nim
     ##  echo arctan2(1.0, 0.0) ## 1.570796326794897
     ##  echo radToDeg(arctan2(1.0, 0.0)) ## 90.0
@@ -332,6 +347,7 @@ when not defined(JS): # C
   proc hypot*(x, y: float64): float64 {.importc: "hypot", header: "<math.h>".}
     ## Computes the hypotenuse of a right-angle triangle with ``x`` and
     ## ``y`` as its base and height. Equivalent to ``sqrt(x*x + y*y)``.
+    ##
     ## .. code-block:: nim
     ##  echo hypot(4.0, 3.0) ## 5.0
   proc pow*(x, y: float32): float32 {.importc: "powf", header: "<math.h>".}
@@ -339,6 +355,7 @@ when not defined(JS): # C
     ## computes x to power raised of y.
     ##
     ## To compute power between integers, use ``^`` e.g. 2 ^ 6
+    ##
     ## .. code-block:: nim
     ##  echo pow(16.0, 0.5) ## 4.0
 
@@ -361,7 +378,7 @@ when not defined(JS): # C
       ## **Deprecated since version 0.19.0**: Use ``gamma`` instead.
     proc lgamma*(x: float32): float32 {.importc: "lgammaf", header: "<math.h>".}
     proc lgamma*(x: float64): float64 {.importc: "lgamma", header: "<math.h>".}
-      ## Computes the natural log of the gamma function for ``x``. 
+      ## Computes the natural log of the gamma function for ``x``.
 
   proc floor*(x: float32): float32 {.importc: "floorf", header: "<math.h>".}
   proc floor*(x: float64): float64 {.importc: "floor", header: "<math.h>".}
@@ -456,9 +473,14 @@ when not defined(JS): # C
     ## Computes the modulo operation for float values (the remainder of ``x`` divided by ``y``).
     ##
     ## .. code-block:: nim
-    ##  echo 2.5 mod 0.3 ## 0.1
+    ##  ( 6.5 mod  2.5) ==  1.5
+    ##  (-6.5 mod  2.5) == -1.5
+    ##  ( 6.5 mod -2.5) ==  1.5
+    ##  (-6.5 mod -2.5) == -1.5
+
 else: # JS
-  proc hypot*[T: float32|float64](x, y: T): T = return sqrt(x*x + y*y)
+  proc hypot*(x, y: float32): float32 {.importc: "Math.hypot", varargs, nodecl.}
+  proc hypot*(x, y: float64): float64 {.importc: "Math.hypot", varargs, nodecl.}
   proc pow*(x, y: float32): float32 {.importC: "Math.pow", nodecl.}
   proc pow*(x, y: float64): float64 {.importc: "Math.pow", nodecl.}
   proc floor*(x: float32): float32 {.importc: "Math.floor", nodecl.}
@@ -474,7 +496,10 @@ else: # JS
     ## Computes the modulo operation for float values (the remainder of ``x`` divided by ``y``).
     ##
     ## .. code-block:: nim
-    ##  echo 2.5 mod 0.3 ## 0.1
+    ##  ( 6.5 mod  2.5) ==  1.5
+    ##  (-6.5 mod  2.5) == -1.5
+    ##  ( 6.5 mod -2.5) ==  1.5
+    ##  (-6.5 mod -2.5) == -1.5
 
 proc round*[T: float32|float64](x: T, places: int): T {.deprecated: "use format instead".} =
   ## Decimal rounding on a binary floating point number.
@@ -498,19 +523,25 @@ proc floorDiv*[T: SomeInteger](x, y: T): T =
   ## This is different from the ``div`` operator, which is defined
   ## as ``trunc(x / y)``. That is, ``div`` rounds towards ``0`` and ``floorDiv``
   ## rounds down.
+  ##
   ## .. code-block:: nim
-  ##  echo floorDiv(13, 3) # 4
-  ##  echo floorDiv(-13, 3) # -5
+  ##  echo floorDiv( 13,  3) #  4
+  ##  echo floorDiv(-13,  3) # -5
+  ##  echo floorDiv( 13, -3) # -5
+  ##  echo floorDiv(-13, -3) #  4
   result = x div y
   let r = x mod y
   if (r > 0 and y < 0) or (r < 0 and y > 0): result.dec 1
 
 proc floorMod*[T: SomeNumber](x, y: T): T =
-  ## Floor modulus is conceptually defined as ``x - (floorDiv(x, y) * y).
+  ## Floor modulus is conceptually defined as ``x - (floorDiv(x, y) * y)``.
   ## This proc behaves the same as the ``%`` operator in Python.
+  ##
   ## .. code-block:: nim
-  ##  echo floorMod(13, 3) # 1
-  ##  echo floorMod(-13, 3) # 2
+  ##  echo floorMod( 13,  3) #  1
+  ##  echo floorMod(-13,  3) #  2
+  ##  echo floorMod( 13, -3) # -2
+  ##  echo floorMod(-13, -3) # -1
   result = x mod y
   if (result > 0 and y < 0) or (result < 0 and y > 0): result += y
 
@@ -525,6 +556,7 @@ when not defined(JS):
     ## and less than 1) and the integer value n such that ``x`` (the original
     ## float value) equals ``m * 2**n``. frexp stores n in `exponent` and returns
     ## m.
+    ##
     ## .. code-block:: nim
     ##  var x : int
     ##  echo frexp(5.0, x) # 0.625
@@ -579,6 +611,7 @@ proc splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] =
   ##
   ## Both parts have the same sign as ``x``.  Analogous to the ``modf``
   ## function in C.
+  ##
   ## .. code-block:: nim
   ##  echo splitDecimal(5.25) # (intpart: 5.0, floatpart: 0.25)
   var
@@ -594,12 +627,14 @@ proc splitDecimal*[T: float32|float64](x: T): tuple[intpart: T, floatpart: T] =
 
 proc degToRad*[T: float32|float64](d: T): T {.inline.} =
   ## Convert from degrees to radians
+  ##
   ## .. code-block:: nim
   ##  echo degToRad(180.0) # 3.141592653589793
   result = T(d) * RadPerDeg
 
 proc radToDeg*[T: float32|float64](d: T): T {.inline.} =
   ## Convert from radians to degrees
+
   ## .. code-block:: nim
   ##  echo degToRad(2 * PI) # 360.0
   result = T(d) / RadPerDeg
@@ -608,6 +643,7 @@ proc sgn*[T: SomeNumber](x: T): int {.inline.} =
   ## Sign function. Returns -1 for negative numbers and ``NegInf``, 1 for
   ## positive numbers and ``Inf``, and 0 for positive zero, negative zero and
   ## ``NaN``.
+  ##
   ## .. code-block:: nim
   ##  echo sgn(-5) # 1
   ##  echo sgn(-4.1) # -1
@@ -619,6 +655,7 @@ proc sgn*[T: SomeNumber](x: T): int {.inline.} =
 proc `^`*[T](x: T, y: Natural): T =
   ## Computes ``x`` to the power ``y``. ``x`` must be non-negative, use
   ## `pow <#pow,float,float>`_ for negative exponents.
+  ##
   ## .. code-block:: nim
   ##  echo 2 ^ 3 # 8
   when compiles(y >= T(0)):
@@ -650,6 +687,7 @@ proc gcd*[T](x, y: T): T =
 proc gcd*(x, y: SomeInteger): SomeInteger =
   ## Computes the greatest common (positive) divisor of ``x`` and ``y``.
   ## Using binary GCD (aka Stein's) algorithm.
+  ##
   ## .. code-block:: nim
   ##  echo gcd(24, 30) # 6
   when x is SomeSignedInt:
@@ -677,6 +715,7 @@ proc gcd*(x, y: SomeInteger): SomeInteger =
 
 proc lcm*[T](x, y: T): T =
   ## Computes the least common multiple of ``x`` and ``y``.
+  ##
   ## .. code-block:: nim
   ##  echo lcm(24, 30) # 120
   x div gcd(x, y) * y
diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim
index 9fccd08d4..810223d72 100644
--- a/lib/pure/memfiles.nim
+++ b/lib/pure/memfiles.nim
@@ -36,11 +36,12 @@ type
     size*: int       ## size of the memory mapped file
 
     when defined(windows):
-      fHandle: Handle
-      mapHandle: Handle
-      wasOpened: bool   ## only close if wasOpened
+      fHandle*: Handle     ## **Caution**: Windows specific public field to allow
+                           ## even more low level trickery.
+      mapHandle*: Handle   ## **Caution**: Windows specific public field.
+      wasOpened*: bool     ## **Caution**: Windows specific public field.
     else:
-      handle: cint
+      handle*: cint        ## **Caution**: Posix specific public field.
 
 proc mapMem*(m: var MemFile, mode: FileMode = fmRead,
              mappedSize = -1, offset = 0): pointer =
@@ -90,7 +91,7 @@ proc unmapMem*(f: var MemFile, p: pointer, size: int) =
 proc open*(filename: string, mode: FileMode = fmRead,
            mappedSize = -1, offset = 0, newFileSize = -1,
            allowRemap = false): MemFile =
-  ## opens a memory mapped file. If this fails, ``EOS`` is raised.
+  ## opens a memory mapped file. If this fails, ``OSError`` is raised.
   ##
   ## ``newFileSize`` can only be set if the file does not exist and is opened
   ## with write access (e.g., with fmReadWrite).
@@ -141,7 +142,7 @@ proc open*(filename: string, mode: FileMode = fmRead,
       if result.mapHandle != 0: discard closeHandle(result.mapHandle)
       raiseOSError(errCode)
       # return false
-      #raise newException(EIO, msg)
+      #raise newException(IOError, msg)
 
     template callCreateFile(winApiProc, filename): untyped =
       winApiProc(
@@ -281,6 +282,35 @@ proc flush*(f: var MemFile; attempts: Natural = 3) =
       if lastErr != EBUSY.OSErrorCode:
         raiseOSError(lastErr, "error flushing mapping")
 
+when defined(posix) or defined(nimdoc):
+  proc resize*(f: var MemFile, newFileSize: int) {.raises: [IOError, OSError].} =
+    ## resize and re-map the file underlying an ``allowRemap MemFile``.
+    ## **Note**: this assumes the entire file is mapped read-write at offset zero.
+    ## Also, the value of ``.mem`` will probably change.
+    ## **Note**: This is not (yet) avaiable on Windows.
+    when defined(posix):
+      if f.handle == -1:
+        raise newException(IOError,
+                            "Cannot resize MemFile opened with allowRemap=false")
+      if ftruncate(f.handle, newFileSize) == -1:
+        raiseOSError(osLastError())
+      when defined(linux):                          #Maybe NetBSD, too?
+        #On Linux this can be over 100 times faster than a munmap,mmap cycle.
+        proc mremap(old: pointer; oldSize,newSize: csize; flags: cint): pointer {.
+          importc: "mremap", header: "<sys/mman.h>" .}
+        let newAddr = mremap(f.mem, csize(f.size), csize(newFileSize), cint(1))
+        if newAddr == cast[pointer](MAP_FAILED):
+          raiseOSError(osLastError())
+      else:
+        if munmap(f.mem, f.size) != 0:
+          raiseOSError(osLastError())
+        let newAddr = mmap(nil, newFileSize, PROT_READ or PROT_WRITE,
+                            MAP_SHARED or MAP_POPULATE, f.handle, 0)
+        if newAddr == cast[pointer](MAP_FAILED):
+          raiseOSError(osLastError())
+      f.mem = newAddr
+      f.size = newFileSize
+
 proc close*(f: var MemFile) =
   ## closes the memory mapped file `f`. All changes are written back to the
   ## file system, if `f` was opened with write access.
@@ -465,7 +495,7 @@ proc mmsWriteData(s: Stream, buffer: pointer, bufLen: int) =
 proc newMemMapFileStream*(filename: string, mode: FileMode = fmRead, fileSize: int = -1):
   MemMapFileStream =
   ## creates a new stream from the file named `filename` with the mode `mode`.
-  ## Raises ## `EOS` if the file cannot be opened. See the `system
+  ## Raises ## `OSError` if the file cannot be opened. See the `system
   ## <system.html>`_ module for a list of available FileMode enums.
   ## ``fileSize`` can only be set if the file does not exist and is opened
   ## with write access (e.g., with fmReadWrite).
diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim
index 514b8d66a..b091f7310 100644
--- a/lib/pure/nativesockets.nim
+++ b/lib/pure/nativesockets.nim
@@ -221,7 +221,7 @@ proc close*(socket: SocketHandle) =
     discard winlean.closesocket(socket)
   else:
     discard posix.close(socket)
-  # TODO: These values should not be discarded. An EOS should be raised.
+  # TODO: These values should not be discarded. An OSError should be raised.
   # http://stackoverflow.com/questions/12463473/what-happens-if-you-call-close-on-a-bsd-socket-multiple-times
 
 proc bindAddr*(socket: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint =
@@ -594,7 +594,7 @@ proc setSockOptInt*(socket: SocketHandle, level, optname, optval: int) {.
 proc setBlocking*(s: SocketHandle, blocking: bool) =
   ## Sets blocking mode on socket.
   ##
-  ## Raises EOS on error.
+  ## Raises OSError on error.
   when useWinVersion:
     var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
     if ioctlsocket(s, FIONBIO, addr(mode)) == -1:
diff --git a/lib/pure/net.nim b/lib/pure/net.nim
index 179fccaa3..23cd96b20 100644
--- a/lib/pure/net.nim
+++ b/lib/pure/net.nim
@@ -210,7 +210,7 @@ proc newSocket*(fd: SocketHandle, domain: Domain = AF_INET,
 proc newSocket*(domain, sockType, protocol: cint, buffered = true): Socket =
   ## Creates a new socket.
   ##
-  ## If an error occurs EOS will be raised.
+  ## If an error occurs OSError will be raised.
   let fd = createNativeSocket(domain, sockType, protocol)
   if fd == osInvalidSocket:
     raiseOSError(osLastError())
@@ -221,7 +221,7 @@ proc newSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM,
                 protocol: Protocol = IPPROTO_TCP, buffered = true): Socket =
   ## Creates a new socket.
   ##
-  ## If an error occurs EOS will be raised.
+  ## If an error occurs OSError will be raised.
   let fd = createNativeSocket(domain, sockType, protocol)
   if fd == osInvalidSocket:
     raiseOSError(osLastError())
@@ -229,7 +229,7 @@ proc newSocket*(domain: Domain = AF_INET, sockType: SockType = SOCK_STREAM,
 
 proc parseIPv4Address(addressStr: string): IpAddress =
   ## Parses IPv4 adresses
-  ## Raises EInvalidValue on errors
+  ## Raises ValueError on errors
   var
     byteCount = 0
     currentByte:uint16 = 0
@@ -263,7 +263,7 @@ proc parseIPv4Address(addressStr: string): IpAddress =
 
 proc parseIPv6Address(addressStr: string): IpAddress =
   ## Parses IPv6 adresses
-  ## Raises EInvalidValue on errors
+  ## Raises ValueError on errors
   result.family = IpAddressFamily.IPv6
   if addressStr.len < 2:
     raise newException(ValueError, "Invalid IP Address")
@@ -384,7 +384,7 @@ proc parseIPv6Address(addressStr: string): IpAddress =
 
 proc parseIpAddress*(addressStr: string): IpAddress =
   ## Parses an IP address
-  ## Raises EInvalidValue on error
+  ## Raises ValueError on error
   if addressStr.len == 0:
     raise newException(ValueError, "IP Address string is empty")
   if addressStr.contains(':'):
@@ -746,7 +746,7 @@ proc listen*(socket: Socket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} =
   ## ``Backlog`` specifies the maximum length of the
   ## queue of pending connections.
   ##
-  ## Raises an EOS error upon failure.
+  ## Raises an OSError error upon failure.
   if nativesockets.listen(socket.fd, backlog) < 0'i32:
     raiseOSError(osLastError())
 
@@ -777,7 +777,7 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string,
   ## Blocks until a connection is being made from a client. When a connection
   ## is made sets ``client`` to the client socket and ``address`` to the address
   ## of the connecting client.
-  ## This function will raise EOS if an error occurs.
+  ## This function will raise OSError if an error occurs.
   ##
   ## The resulting client will inherit any properties of the server socket. For
   ## example: whether the socket is buffered or not.
@@ -983,7 +983,7 @@ when defined(ssl):
     ## Returns ``False`` whenever the socket is not yet ready for a handshake,
     ## ``True`` whenever handshake completed successfully.
     ##
-    ## A ESSL error is raised on any other errors.
+    ## A SslError error is raised on any other errors.
     ##
     ## **Note:** This procedure is deprecated since version 0.14.0.
     result = true
@@ -1011,7 +1011,7 @@ when defined(ssl):
     ## Determines whether a handshake has occurred between a client (``socket``)
     ## and the server that ``socket`` is connected to.
     ##
-    ## Throws ESSL if ``socket`` is not an SSL socket.
+    ## Throws SslError if ``socket`` is not an SSL socket.
     if socket.isSSL:
       return not socket.sslNoHandshake
     else:
@@ -1203,7 +1203,7 @@ proc recv*(socket: Socket, size: int, timeout = -1,
   ##
   ## When ``""`` is returned the socket's connection has been closed.
   ##
-  ## This function will throw an EOS exception when an error occurs.
+  ## This function will throw an OSError exception when an error occurs.
   ##
   ## A timeout may be specified in milliseconds, if enough data is not received
   ## within the time specified an ETimeout exception will be raised.
@@ -1244,7 +1244,7 @@ proc readLine*(socket: Socket, line: var TaintedString, timeout = -1,
   ##
   ## If the socket is disconnected, ``line`` will be set to ``""``.
   ##
-  ## An EOS exception will be raised in the case of a socket error.
+  ## An OSError exception will be raised in the case of a socket error.
   ##
   ## A timeout can be specified in milliseconds, if data is not received within
   ## the specified time an ETimeout exception will be raised.
@@ -1299,7 +1299,7 @@ proc recvLine*(socket: Socket, timeout = -1,
   ##
   ## If the socket is disconnected, the result will be set to ``""``.
   ##
-  ## An EOS exception will be raised in the case of a socket error.
+  ## An OSError exception will be raised in the case of a socket error.
   ##
   ## A timeout can be specified in milliseconds, if data is not received within
   ## the specified time an ETimeout exception will be raised.
@@ -1317,7 +1317,7 @@ proc recvFrom*(socket: Socket, data: var string, length: int,
   ## Receives data from ``socket``. This function should normally be used with
   ## connection-less sockets (UDP sockets).
   ##
-  ## If an error occurs an EOS exception will be raised. Otherwise the return
+  ## If an error occurs an OSError exception will be raised. Otherwise the return
   ## value will be the length of data received.
   ##
   ## **Warning:** This function does not yet have a buffered implementation,
@@ -1390,7 +1390,7 @@ template `&=`*(socket: Socket; data: typed) =
   send(socket, data)
 
 proc trySend*(socket: Socket, data: string): bool {.tags: [WriteIOEffect].} =
-  ## Safe alternative to ``send``. Does not raise an EOS when an error occurs,
+  ## Safe alternative to ``send``. Does not raise an OSError when an error occurs,
   ## and instead returns ``false`` on failure.
   result = send(socket, cstring(data), data.len) == data.len
 
diff --git a/lib/pure/options.nim b/lib/pure/options.nim
index 12e38d8b5..b827e1aa3 100644
--- a/lib/pure/options.nim
+++ b/lib/pure/options.nim
@@ -39,17 +39,18 @@
 ##
 ## .. code-block:: nim
 ##
-##   try:
-##     assert("abc".find('c').get() == 2)  # Immediately extract the value
-##   except UnpackError:  # If there is no value
-##     assert false  # This will not be reached, because the value is present
-##
+##    let found = "abc".find('c')
+##    assert found.isSome and found.get() == 2
+##   
 ## The ``get`` operation demonstrated above returns the underlying value, or
-## raises ``UnpackError`` if there is no value. There is another option for
-## obtaining the value: ``unsafeGet``, but you must only use it when you are
-## absolutely sure the value is present (e.g. after checking ``isSome``). If
-## you do not care about the tiny overhead that ``get`` causes, you should
-## simply never use ``unsafeGet``.
+## raises ``UnpackError`` if there is no value. Note that ``UnpackError`` inherits
+## from ``system.Defect``, and should therefore never be catched. Instead, rely on
+## checking if the option contains a value with ``isSome`` and ``isNone``.
+##
+## There is another option for obtaining the value: ``unsafeGet``, but you must
+## only use it when you are absolutely sure the value is present (e.g. after
+## checking ``isSome``). If you do not care about the tiny overhead that ``get``
+## causes, you should simply never use ``unsafeGet``.
 ##
 ## How to deal with an absence of a value:
 ##
@@ -61,12 +62,7 @@
 ##   assert(result == none(int))
 ##   # It has no value:
 ##   assert(result.isNone)
-##
-##   try:
-##     echo result.get()
-##     assert(false)  # This will not be reached
-##   except UnpackError:  # Because an exception is raised
-##     discard
+
 import typetraits
 
 type
@@ -81,7 +77,7 @@ type
       val: T
       has: bool
 
-  UnpackError* = ref object of ValueError
+  UnpackError* = object of Defect
 
 proc some*[T](val: T): Option[T] =
   ## Returns a ``Option`` that has this value.
@@ -129,7 +125,7 @@ proc get*[T](self: Option[T]): T =
   ## Returns contents of the Option. If it is none, then an exception is
   ## thrown.
   if self.isNone:
-    raise UnpackError(msg: "Can't obtain a value from a `none`")
+    raise newException(UnpackError, "Can't obtain a value from a `none`")
   self.val
 
 proc get*[T](self: Option[T], otherwise: T): T =
@@ -143,7 +139,7 @@ proc get*[T](self: var Option[T]): var T =
   ## Returns contents of the Option. If it is none, then an exception is
   ## thrown.
   if self.isNone:
-    raise UnpackError(msg: "Can't obtain a value from a `none`")
+    raise newException(UnpackError, "Can't obtain a value from a `none`")
   return self.val
 
 proc map*[T](self: Option[T], callback: proc (input: T)) =
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 9d74158fe..31610a59e 100644
--- a/lib/pure/os.nim
+++ b/lib/pure/os.nim
@@ -17,33 +17,701 @@
 include "system/inclrtl"
 
 import
-  strutils, times
+  strutils
 
-when defined(windows):
-  import winlean
+when defined(nimscript):
+  discard
+elif defined(windows):
+  import winlean, times
 elif defined(posix):
-  import posix
+  import posix, times
 
   proc toTime(ts: Timespec): times.Time {.inline.} =
     result = initTime(ts.tv_sec.int64, ts.tv_nsec.int)
-
 else:
   {.error: "OS module not ported to your operating system!".}
 
-import ospaths
-export ospaths
+when defined(nimscript) and defined(nimErrorProcCanHaveBody):
+  {.pragma: noNimScript, error: "this proc is not available on the NimScript target".}
+else:
+  {.pragma: noNimScript.}
+
+type
+  ReadEnvEffect* = object of ReadIOEffect   ## effect that denotes a read
+                                            ## from an environment variable
+  WriteEnvEffect* = object of WriteIOEffect ## effect that denotes a write
+                                            ## to an environment variable
+
+  ReadDirEffect* = object of ReadIOEffect   ## effect that denotes a read
+                                            ## operation from the directory
+                                            ## structure
+  WriteDirEffect* = object of WriteIOEffect ## effect that denotes a write
+                                            ## operation to
+                                            ## the directory structure
+
+  OSErrorCode* = distinct int32 ## Specifies an OS Error Code.
+
+const
+  doslikeFileSystem* = defined(windows) or defined(OS2) or defined(DOS)
+
+when defined(Nimdoc): # only for proper documentation:
+  const
+    CurDir* = '.'
+      ## The constant string used by the operating system to refer to the
+      ## current directory.
+      ##
+      ## For example: '.' for POSIX or ':' for the classic Macintosh.
+
+    ParDir* = ".."
+      ## The constant string used by the operating system to refer to the
+      ## parent directory.
+      ##
+      ## For example: ".." for POSIX or "::" for the classic Macintosh.
+
+    DirSep* = '/'
+      ## The character used by the operating system to separate pathname
+      ## components, for example, '/' for POSIX or ':' for the classic
+      ## Macintosh.
+
+    AltSep* = '/'
+      ## An alternative character used by the operating system to separate
+      ## pathname components, or the same as `DirSep` if only one separator
+      ## character exists. This is set to '/' on Windows systems
+      ## where `DirSep` is a backslash.
+
+    PathSep* = ':'
+      ## The character conventionally used by the operating system to separate
+      ## search patch components (as in PATH), such as ':' for POSIX
+      ## or ';' for Windows.
+
+    FileSystemCaseSensitive* = true
+      ## true if the file system is case sensitive, false otherwise. Used by
+      ## `cmpPaths` to compare filenames properly.
+
+    ExeExt* = ""
+      ## The file extension of native executables. For example:
+      ## "" for POSIX, "exe" on Windows.
+
+    ScriptExt* = ""
+      ## The file extension of a script file. For example: "" for POSIX,
+      ## "bat" on Windows.
+
+    DynlibFormat* = "lib$1.so"
+      ## The format string to turn a filename into a `DLL`:idx: file (also
+      ## called `shared object`:idx: on some operating systems).
+
+elif defined(macos):
+  const
+    CurDir* = ':'
+    ParDir* = "::"
+    DirSep* = ':'
+    AltSep* = Dirsep
+    PathSep* = ','
+    FileSystemCaseSensitive* = false
+    ExeExt* = ""
+    ScriptExt* = ""
+    DynlibFormat* = "$1.dylib"
+
+  #  MacOS paths
+  #  ===========
+  #  MacOS directory separator is a colon ":" which is the only character not
+  #  allowed in filenames.
+  #
+  #  A path containing no colon or which begins with a colon is a partial
+  #  path.
+  #  E.g. ":kalle:petter" ":kalle" "kalle"
+  #
+  #  All other paths are full (absolute) paths. E.g. "HD:kalle:" "HD:"
+  #  When generating paths, one is safe if one ensures that all partial paths
+  #  begin with a colon, and all full paths end with a colon.
+  #  In full paths the first name (e g HD above) is the name of a mounted
+  #  volume.
+  #  These names are not unique, because, for instance, two diskettes with the
+  #  same names could be inserted. This means that paths on MacOS are not
+  #  waterproof. In case of equal names the first volume found will do.
+  #  Two colons "::" are the relative path to the parent. Three is to the
+  #  grandparent etc.
+elif doslikeFileSystem:
+  const
+    CurDir* = '.'
+    ParDir* = ".."
+    DirSep* = '\\' # seperator within paths
+    AltSep* = '/'
+    PathSep* = ';' # seperator between paths
+    FileSystemCaseSensitive* = false
+    ExeExt* = "exe"
+    ScriptExt* = "bat"
+    DynlibFormat* = "$1.dll"
+elif defined(PalmOS) or defined(MorphOS):
+  const
+    DirSep* = '/'
+    AltSep* = Dirsep
+    PathSep* = ';'
+    ParDir* = ".."
+    FileSystemCaseSensitive* = false
+    ExeExt* = ""
+    ScriptExt* = ""
+    DynlibFormat* = "$1.prc"
+elif defined(RISCOS):
+  const
+    DirSep* = '.'
+    AltSep* = '.'
+    ParDir* = ".." # is this correct?
+    PathSep* = ','
+    FileSystemCaseSensitive* = true
+    ExeExt* = ""
+    ScriptExt* = ""
+    DynlibFormat* = "lib$1.so"
+else: # UNIX-like operating system
+  const
+    CurDir* = '.'
+    ParDir* = ".."
+    DirSep* = '/'
+    AltSep* = DirSep
+    PathSep* = ':'
+    FileSystemCaseSensitive* = when defined(macosx): false else: true
+    ExeExt* = ""
+    ScriptExt* = ""
+    DynlibFormat* = when defined(macosx): "lib$1.dylib" else: "lib$1.so"
+
+const
+  ExtSep* = '.'
+    ## The character which separates the base filename from the extension;
+    ## for example, the '.' in ``os.nim``.
+
+proc normalizePathEnd(path: var string, trailingSep = false) =
+  ## ensures ``path`` has exactly 0 or 1 trailing `DirSep`, depending on
+  ## ``trailingSep``, and taking care of edge cases: it preservers whether
+  ## a path is absolute or relative, and makes sure trailing sep is `DirSep`,
+  ## not `AltSep`.
+  if path.len == 0: return
+  var i = path.len
+  while i >= 1 and path[i-1] in {DirSep, AltSep}: dec(i)
+  if trailingSep:
+    # foo// => foo
+    path.setLen(i)
+    # foo => foo/
+    path.add DirSep
+  elif i>0:
+    # foo// => foo
+    path.setLen(i)
+  else:
+    # // => / (empty case was already taken care of)
+    path = $DirSep
+
+proc normalizePathEnd(path: string, trailingSep = false): string =
+  result = path
+  result.normalizePathEnd(trailingSep)
+
+proc joinPath*(head, tail: string): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Joins two directory names to one.
+  ##
+  ## For example on Unix:
+  ##
+  ## .. code-block:: nim
+  ##   joinPath("usr", "lib")
+  ##
+  ## results in:
+  ##
+  ## .. code-block:: nim
+  ##   "usr/lib"
+  ##
+  ## If head is the empty string, tail is returned. If tail is the empty
+  ## string, head is returned with a trailing path separator. If tail starts
+  ## with a path separator it will be removed when concatenated to head. Other
+  ## path separators not located on boundaries won't be modified. More
+  ## examples on Unix:
+  ##
+  ## .. code-block:: nim
+  ##   assert joinPath("usr", "") == "usr/"
+  ##   assert joinPath("", "lib") == "lib"
+  ##   assert joinPath("", "/lib") == "/lib"
+  ##   assert joinPath("usr/", "/lib") == "usr/lib"
+  if len(head) == 0:
+    result = tail
+  elif head[len(head)-1] in {DirSep, AltSep}:
+    if tail.len > 0 and tail[0] in {DirSep, AltSep}:
+      result = head & substr(tail, 1)
+    else:
+      result = head & tail
+  else:
+    if tail.len > 0 and tail[0] in {DirSep, AltSep}:
+      result = head & tail
+    else:
+      result = head & DirSep & tail
+
+proc joinPath*(parts: varargs[string]): string {.noSideEffect,
+  rtl, extern: "nos$1OpenArray".} =
+  ## The same as `joinPath(head, tail)`, but works with any number of
+  ## directory parts. You need to pass at least one element or the proc
+  ## will assert in debug builds and crash on release builds.
+  result = parts[0]
+  for i in 1..high(parts):
+    result = joinPath(result, parts[i])
+
+proc `/` * (head, tail: string): string {.noSideEffect.} =
+  ## The same as ``joinPath(head, tail)``
+  ##
+  ## Here are some examples for Unix:
+  ##
+  ## .. code-block:: nim
+  ##   assert "usr" / "" == "usr/"
+  ##   assert "" / "lib" == "lib"
+  ##   assert "" / "/lib" == "/lib"
+  ##   assert "usr/" / "/lib" == "usr/lib"
+  return joinPath(head, tail)
+
+proc splitPath*(path: string): tuple[head, tail: string] {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Splits a directory into (head, tail), so that
+  ## ``head / tail == path`` (except for edge cases like "/usr").
+  ##
+  ## Examples:
+  ##
+  ## .. code-block:: nim
+  ##   splitPath("usr/local/bin") -> ("usr/local", "bin")
+  ##   splitPath("usr/local/bin/") -> ("usr/local/bin", "")
+  ##   splitPath("bin") -> ("", "bin")
+  ##   splitPath("/bin") -> ("", "bin")
+  ##   splitPath("") -> ("", "")
+  var sepPos = -1
+  for i in countdown(len(path)-1, 0):
+    if path[i] in {DirSep, AltSep}:
+      sepPos = i
+      break
+  if sepPos >= 0:
+    result.head = substr(path, 0, sepPos-1)
+    result.tail = substr(path, sepPos+1)
+  else:
+    result.head = ""
+    result.tail = path
+
+proc parentDirPos(path: string): int =
+  var q = 1
+  if len(path) >= 1 and path[len(path)-1] in {DirSep, AltSep}: q = 2
+  for i in countdown(len(path)-q, 0):
+    if path[i] in {DirSep, AltSep}: return i
+  result = -1
+
+proc parentDir*(path: string): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Returns the parent directory of `path`.
+  ##
+  ## This is the same as ``splitPath(path).head`` when ``path`` doesn't end
+  ## in a dir separator.
+  ## The remainder can be obtained with ``lastPathPart(path)``
+  runnableExamples:
+    doAssert parentDir("") == ""
+    when defined(posix):
+      doAssert parentDir("/usr/local/bin") == "/usr/local"
+      doAssert parentDir("foo/bar/") == "foo"
+
+  let sepPos = parentDirPos(path)
+  if sepPos >= 0:
+    result = substr(path, 0, sepPos-1)
+  else:
+    result = ""
+
+proc tailDir*(path: string): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Returns the tail part of `path`..
+  ##
+  ## | Example: ``tailDir("/usr/local/bin") == "local/bin"``.
+  ## | Example: ``tailDir("usr/local/bin/") == "local/bin"``.
+  ## | Example: ``tailDir("bin") == ""``.
+  var q = 1
+  if len(path) >= 1 and path[len(path)-1] in {DirSep, AltSep}: q = 2
+  for i in 0..len(path)-q:
+    if path[i] in {DirSep, AltSep}:
+      return substr(path, i+1)
+  result = ""
+
+proc isRootDir*(path: string): bool {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Checks whether a given `path` is a root directory
+  result = parentDirPos(path) < 0
+
+iterator parentDirs*(path: string, fromRoot=false, inclusive=true): string =
+  ## Walks over all parent directories of a given `path`
+  ##
+  ## If `fromRoot` is set, the traversal will start from the file system root
+  ## diretory. If `inclusive` is set, the original argument will be included
+  ## in the traversal.
+  ##
+  ## Relative paths won't be expanded by this proc. Instead, it will traverse
+  ## only the directories appearing in the relative path.
+  if not fromRoot:
+    var current = path
+    if inclusive: yield path
+    while true:
+      if current.isRootDir: break
+      current = current.parentDir
+      yield current
+  else:
+    for i in countup(0, path.len - 2): # ignore the last /
+      # deal with non-normalized paths such as /foo//bar//baz
+      if path[i] in {DirSep, AltSep} and
+          (i == 0 or path[i-1] notin {DirSep, AltSep}):
+        yield path.substr(0, i)
+
+    if inclusive: yield path
+
+proc `/../`*(head, tail: string): string {.noSideEffect.} =
+  ## The same as ``parentDir(head) / tail`` unless there is no parent
+  ## directory. Then ``head / tail`` is performed instead.
+  let sepPos = parentDirPos(head)
+  if sepPos >= 0:
+    result = substr(head, 0, sepPos-1) / tail
+  else:
+    result = head / tail
+
+proc normExt(ext: string): string =
+  if ext == "" or ext[0] == ExtSep: result = ext # no copy needed here
+  else: result = ExtSep & ext
+
+proc searchExtPos*(path: string): int =
+  ## Returns index of the '.' char in `path` if it signifies the beginning
+  ## of extension. Returns -1 otherwise.
+  # BUGFIX: do not search until 0! .DS_Store is no file extension!
+  result = -1
+  for i in countdown(len(path)-1, 1):
+    if path[i] == ExtSep:
+      result = i
+      break
+    elif path[i] in {DirSep, AltSep}:
+      break # do not skip over path
+
+proc splitFile*(path: string): tuple[dir, name, ext: string] {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Splits a filename into (dir, filename, extension).
+  ## `dir` does not end in `DirSep`.
+  ## `extension` includes the leading dot.
+  ##
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##   var (dir, name, ext) = splitFile("usr/local/nimc.html")
+  ##   assert dir == "usr/local"
+  ##   assert name == "nimc"
+  ##   assert ext == ".html"
+  ##
+  ## If `path` has no extension, `ext` is the empty string.
+  ## If `path` has no directory component, `dir` is the empty string.
+  ## If `path` has no filename component, `name` and `ext` are empty strings.
+  if path.len == 0 or path[path.len-1] in {DirSep, AltSep}:
+    result = (path, "", "")
+  else:
+    var sepPos = -1
+    var dotPos = path.len
+    for i in countdown(len(path)-1, 0):
+      if path[i] == ExtSep:
+        if dotPos == path.len and i > 0 and
+            path[i-1] notin {DirSep, AltSep}: dotPos = i
+      elif path[i] in {DirSep, AltSep}:
+        sepPos = i
+        break
+    result.dir = substr(path, 0, sepPos-1)
+    result.name = substr(path, sepPos+1, dotPos-1)
+    result.ext = substr(path, dotPos)
+
+proc extractFilename*(path: string): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Extracts the filename of a given `path`. This is the same as
+  ## ``name & ext`` from ``splitFile(path)``. See also ``lastPathPart``.
+  runnableExamples:
+    when defined(posix):
+      doAssert extractFilename("foo/bar/") == ""
+      doAssert extractFilename("foo/bar") == "bar"
+  if path.len == 0 or path[path.len-1] in {DirSep, AltSep}:
+    result = ""
+  else:
+    result = splitPath(path).tail
+
+proc lastPathPart*(path: string): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## like ``extractFilename``, but ignores trailing dir separator; aka: `baseName`:idx:
+  ## in some other languages.
+  runnableExamples:
+    when defined(posix):
+      doAssert lastPathPart("foo/bar/") == "bar"
+  let path = path.normalizePathEnd(trailingSep = false)
+  result = extractFilename(path)
+
+proc changeFileExt*(filename, ext: string): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Changes the file extension to `ext`.
+  ##
+  ## If the `filename` has no extension, `ext` will be added.
+  ## If `ext` == "" then any extension is removed.
+  ## `Ext` should be given without the leading '.', because some
+  ## filesystems may use a different character. (Although I know
+  ## of none such beast.)
+  var extPos = searchExtPos(filename)
+  if extPos < 0: result = filename & normExt(ext)
+  else: result = substr(filename, 0, extPos-1) & normExt(ext)
+
+proc addFileExt*(filename, ext: string): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Adds the file extension `ext` to `filename`, unless
+  ## `filename` already has an extension.
+  ##
+  ## `Ext` should be given without the leading '.', because some
+  ## filesystems may use a different character.
+  ## (Although I know of none such beast.)
+  var extPos = searchExtPos(filename)
+  if extPos < 0: result = filename & normExt(ext)
+  else: result = filename
+
+proc cmpPaths*(pathA, pathB: string): int {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Compares two paths.
+  ##
+  ## On a case-sensitive filesystem this is done
+  ## case-sensitively otherwise case-insensitively. Returns:
+  ##
+  ## | 0 iff pathA == pathB
+  ## | < 0 iff pathA < pathB
+  ## | > 0 iff pathA > pathB
+  runnableExamples:
+    when defined(macosx):
+      doAssert cmpPaths("foo", "Foo") == 0
+    elif defined(posix):
+      doAssert cmpPaths("foo", "Foo") > 0
+  if FileSystemCaseSensitive:
+    result = cmp(pathA, pathB)
+  else:
+    when defined(nimscript):
+      result = cmpic(pathA, pathB)
+    elif defined(nimdoc): discard
+    else:
+      result = cmpIgnoreCase(pathA, pathB)
+
+proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1".} =
+  ## Checks whether a given `path` is absolute.
+  ##
+  ## On Windows, network paths are considered absolute too.
+  runnableExamples:
+    doAssert(not "".isAbsolute)
+    doAssert(not ".".isAbsolute)
+    when defined(posix):
+      doAssert "/".isAbsolute
+      doAssert(not "a/".isAbsolute)
+
+  if len(path) == 0: return false
+
+  when doslikeFileSystem:
+    var len = len(path)
+    result = (path[0] in {'/', '\\'}) or
+              (len > 1 and path[0] in {'a'..'z', 'A'..'Z'} and path[1] == ':')
+  elif defined(macos):
+    # according to https://perldoc.perl.org/File/Spec/Mac.html `:a` is a relative path
+    result = path[0] != ':'
+  elif defined(RISCOS):
+    result = path[0] == '$'
+  elif defined(posix):
+    result = path[0] == '/'
+
+proc unixToNativePath*(path: string, drive=""): string {.
+  noSideEffect, rtl, extern: "nos$1".} =
+  ## Converts an UNIX-like path to a native one.
+  ##
+  ## On an UNIX system this does nothing. Else it converts
+  ## '/', '.', '..' to the appropriate things.
+  ##
+  ## On systems with a concept of "drives", `drive` is used to determine
+  ## which drive label to use during absolute path conversion.
+  ## `drive` defaults to the drive of the current working directory, and is
+  ## ignored on systems that do not have a concept of "drives".
+
+  when defined(unix):
+    result = path
+  else:
+    if path.len == 0:
+        return ""
+
+    var start: int
+    if path[0] == '/':
+      # an absolute path
+      when doslikeFileSystem:
+        if drive != "":
+          result = drive & ":" & DirSep
+        else:
+          result = $DirSep
+      elif defined(macos):
+        result = "" # must not start with ':'
+      else:
+        result = $DirSep
+      start = 1
+    elif path[0] == '.' and (path.len == 1 or path[1] == '/'):
+      # current directory
+      result = $CurDir
+      start = when doslikeFileSystem: 1 else: 2
+    else:
+      result = ""
+      start = 0
+
+    var i = start
+    while i < len(path): # ../../../ --> ::::
+      if i+2 < path.len and path[i] == '.' and path[i+1] == '.' and path[i+2] == '/':
+        # parent directory
+        when defined(macos):
+          if result[high(result)] == ':':
+            add result, ':'
+          else:
+            add result, ParDir
+        else:
+          add result, ParDir & DirSep
+        inc(i, 3)
+      elif path[i] == '/':
+        add result, DirSep
+        inc(i)
+      else:
+        add result, path[i]
+        inc(i)
+
+include "includes/oserr"
+when not defined(nimscript):
+  include "includes/osenv"
+
+proc getHomeDir*(): string {.rtl, extern: "nos$1",
+  tags: [ReadEnvEffect, ReadIOEffect].} =
+  ## Returns the home directory of the current user.
+  ##
+  ## This proc is wrapped by the expandTilde proc for the convenience of
+  ## processing paths coming from user configuration files.
+  when defined(windows): return string(getEnv("USERPROFILE")) & "\\"
+  else: return string(getEnv("HOME")) & "/"
+
+proc getConfigDir*(): string {.rtl, extern: "nos$1",
+  tags: [ReadEnvEffect, ReadIOEffect].} =
+  ## Returns the config directory of the current user for applications.
+  ##
+  ## On non-Windows OSs, this proc conforms to the XDG Base Directory
+  ## spec. Thus, this proc returns the value of the XDG_CONFIG_HOME environment
+  ## variable if it is set, and returns the default configuration directory,
+  ## "~/.config/", otherwise.
+  ##
+  ## An OS-dependent trailing slash is always present at the end of the
+  ## returned string; `\` on Windows and `/` on all other OSs.
+  when defined(windows):
+    result = getEnv("APPDATA").string
+  else:
+    result = getEnv("XDG_CONFIG_HOME", getEnv("HOME").string / ".config").string
+  result.normalizePathEnd(trailingSep = true)
+
+proc getTempDir*(): string {.rtl, extern: "nos$1",
+  tags: [ReadEnvEffect, ReadIOEffect].} =
+  ## Returns the temporary directory of the current user for applications to
+  ## save temporary files in.
+  ##
+  ## **Please do not use this**: On Android, it currently
+  ## returns ``getHomeDir()``, and on other Unix based systems it can cause
+  ## security problems too. That said, you can override this implementation
+  ## by adding ``-d:tempDir=mytempname`` to your compiler invokation.
+  when defined(tempDir):
+    const tempDir {.strdefine.}: string = nil
+    return tempDir
+  elif defined(windows): return string(getEnv("TEMP")) & "\\"
+  elif defined(android): return getHomeDir()
+  else: return "/tmp/"
+
+proc expandTilde*(path: string): string {.
+  tags: [ReadEnvEffect, ReadIOEffect].} =
+  ## Expands ``~`` or a path starting with ``~/`` to a full path, replacing
+  ## ``~`` with ``getHomeDir()`` (otherwise returns ``path`` unmodified).
+  ##
+  ## Windows: this is still supported despite Windows platform not having this
+  ## convention; also, both ``~/`` and ``~\`` are handled.
+  runnableExamples:
+    doAssert expandTilde("~" / "appname.cfg") == getHomeDir() / "appname.cfg"
+  if len(path) == 0 or path[0] != '~':
+    result = path
+  elif len(path) == 1:
+    result = getHomeDir()
+  elif (path[1] in {DirSep, AltSep}):
+    result = getHomeDir() / path.substr(2)
+  else:
+    # TODO: handle `~bob` and `~bob/` which means home of bob
+    result = path
 
-proc c_rename(oldname, newname: cstring): cint {.
-  importc: "rename", header: "<stdio.h>".}
-proc c_system(cmd: cstring): cint {.
-  importc: "system", header: "<stdlib.h>".}
-proc c_strlen(a: cstring): cint {.
-  importc: "strlen", header: "<string.h>", noSideEffect.}
-proc c_free(p: pointer) {.
-  importc: "free", header: "<stdlib.h>".}
+# TODO: consider whether quoteShellPosix, quoteShellWindows, quoteShell, quoteShellCommand
+# belong in `strutils` instead; they are not specific to paths
+proc quoteShellWindows*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
+  ## Quote s, so it can be safely passed to Windows API.
+  ## Based on Python's subprocess.list2cmdline
+  ## See http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
+  let needQuote = {' ', '\t'} in s or s.len == 0
 
+  result = ""
+  var backslashBuff = ""
+  if needQuote:
+    result.add("\"")
+
+  for c in s:
+    if c == '\\':
+      backslashBuff.add(c)
+    elif c == '\"':
+      result.add(backslashBuff)
+      result.add(backslashBuff)
+      backslashBuff.setLen(0)
+      result.add("\\\"")
+    else:
+      if backslashBuff.len != 0:
+        result.add(backslashBuff)
+        backslashBuff.setLen(0)
+      result.add(c)
+
+  if needQuote:
+    result.add("\"")
+
+proc quoteShellPosix*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
+  ## Quote ``s``, so it can be safely passed to POSIX shell.
+  ## Based on Python's pipes.quote
+  const safeUnixChars = {'%', '+', '-', '.', '/', '_', ':', '=', '@',
+                         '0'..'9', 'A'..'Z', 'a'..'z'}
+  if s.len == 0:
+    return "''"
+
+  let safe = s.allCharsInSet(safeUnixChars)
+
+  if safe:
+    return s
+  else:
+    return "'" & s.replace("'", "'\"'\"'") & "'"
 
-when defined(windows):
+when defined(windows) or defined(posix) or defined(nintendoswitch):
+  proc quoteShell*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
+    ## Quote ``s``, so it can be safely passed to shell.
+    when defined(windows):
+      return quoteShellWindows(s)
+    else:
+      return quoteShellPosix(s)
+
+  proc quoteShellCommand*(args: openArray[string]): string =
+    ## Concatenates and quotes shell arguments `args`
+    runnableExamples:
+      when defined(posix):
+        assert quoteShellCommand(["aaa", "", "c d"]) == "aaa '' 'c d'"
+      when defined(windows):
+        assert quoteShellCommand(["aaa", "", "c d"]) == "aaa \"\" \"c d\""
+    # can't use `map` pending https://github.com/nim-lang/Nim/issues/8303
+    for i in 0..<args.len:
+      if i > 0: result.add " "
+      result.add quoteShell(args[i])
+
+when not defined(nimscript):
+  proc c_rename(oldname, newname: cstring): cint {.
+    importc: "rename", header: "<stdio.h>".}
+  proc c_system(cmd: cstring): cint {.
+    importc: "system", header: "<stdlib.h>".}
+  proc c_strlen(a: cstring): cint {.
+    importc: "strlen", header: "<string.h>", noSideEffect.}
+  proc c_free(p: pointer) {.
+    importc: "free", header: "<stdlib.h>".}
+
+
+when defined(windows) and not defined(nimscript):
   when useWinUnicode:
     template wrapUnary(varname, winApiProc, arg: untyped) =
       var varname = winApiProc(newWideCString(arg))
@@ -71,9 +739,10 @@ when defined(windows):
              f.cFileName[1].int == dot and f.cFileName[2].int == 0)
 
 proc existsFile*(filename: string): bool {.rtl, extern: "nos$1",
-                                          tags: [ReadDirEffect].} =
+                                          tags: [ReadDirEffect], noNimScript.} =
   ## Returns true if `filename` exists and is a regular file or symlink.
   ## (directories, device files, named pipes and sockets return false)
+  ## This proc is not available for NimScript.
   when defined(windows):
     when useWinUnicode:
       wrapUnary(a, getFileAttributesW, filename)
@@ -85,7 +754,8 @@ proc existsFile*(filename: string): bool {.rtl, extern: "nos$1",
     var res: Stat
     return stat(filename, res) >= 0'i32 and S_ISREG(res.st_mode)
 
-proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect].} =
+proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect],
+                                     noNimScript.} =
   ## Returns true iff the directory `dir` exists. If `dir` is a file, false
   ## is returned. Follows symlinks.
   when defined(windows):
@@ -100,7 +770,8 @@ proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect]
     return stat(dir, res) >= 0'i32 and S_ISDIR(res.st_mode)
 
 proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1",
-                                          tags: [ReadDirEffect].} =
+                                          tags: [ReadDirEffect],
+                                          noNimScript.} =
   ## Returns true iff the symlink `link` exists. Will return true
   ## regardless of whether the link points to a directory or file.
   when defined(windows):
@@ -114,15 +785,15 @@ proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1",
     var res: Stat
     return lstat(link, res) >= 0'i32 and S_ISLNK(res.st_mode)
 
-proc fileExists*(filename: string): bool {.inline.} =
+proc fileExists*(filename: string): bool {.inline, noNimScript.} =
   ## Synonym for existsFile
   existsFile(filename)
 
-proc dirExists*(dir: string): bool {.inline.} =
+proc dirExists*(dir: string): bool {.inline, noNimScript.} =
   ## Synonym for existsDir
   existsDir(dir)
 
-when not defined(windows):
+when not defined(windows) and not defined(nimscript):
   proc checkSymlink(path: string): bool =
     var rawInfo: Stat
     if lstat(path, rawInfo) < 0'i32: result = false
@@ -135,7 +806,7 @@ const
 
 proc findExe*(exe: string, followSymlinks: bool = true;
               extensions: openarray[string]=ExeExts): string {.
-  tags: [ReadDirEffect, ReadEnvEffect, ReadIOEffect].} =
+  tags: [ReadDirEffect, ReadEnvEffect, ReadIOEffect], noNimScript.} =
   ## Searches for `exe` in the current working directory and then
   ## in directories listed in the ``PATH`` environment variable.
   ## Returns "" if the `exe` cannot be found. `exe`
@@ -183,7 +854,11 @@ proc findExe*(exe: string, followSymlinks: bool = true;
         return x
   result = ""
 
-proc getLastModificationTime*(file: string): times.Time {.rtl, extern: "nos$1".} =
+when defined(nimscript):
+  const times = "fake const"
+  template Time(x: untyped): untyped = string
+
+proc getLastModificationTime*(file: string): times.Time {.rtl, extern: "nos$1", noNimScript.} =
   ## Returns the `file`'s last modification time.
   when defined(posix):
     var res: Stat
@@ -196,7 +871,7 @@ proc getLastModificationTime*(file: string): times.Time {.rtl, extern: "nos$1".}
     result = fromWinTime(rdFileTime(f.ftLastWriteTime))
     findClose(h)
 
-proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1".} =
+proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1", noNimScript.} =
   ## Returns the `file`'s last read or write access time.
   when defined(posix):
     var res: Stat
@@ -209,7 +884,7 @@ proc getLastAccessTime*(file: string): times.Time {.rtl, extern: "nos$1".} =
     result = fromWinTime(rdFileTime(f.ftLastAccessTime))
     findClose(h)
 
-proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1".} =
+proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1", noNimScript.} =
   ## Returns the `file`'s creation time.
   ##
   ## **Note:** Under POSIX OS's, the returned time may actually be the time at
@@ -226,7 +901,7 @@ proc getCreationTime*(file: string): times.Time {.rtl, extern: "nos$1".} =
     result = fromWinTime(rdFileTime(f.ftCreationTime))
     findClose(h)
 
-proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1".} =
+proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1", noNimScript.} =
   ## Returns true if the file `a` is newer than file `b`, i.e. if `a`'s
   ## modification time is later than `b`'s.
   when defined(posix):
@@ -238,7 +913,7 @@ proc fileNewer*(a, b: string): bool {.rtl, extern: "nos$1".} =
   else:
     result = getLastModificationTime(a) > getLastModificationTime(b)
 
-proc getCurrentDir*(): string {.rtl, extern: "nos$1", tags: [].} =
+proc getCurrentDir*(): string {.rtl, extern: "nos$1", tags: [], noNimScript.} =
   ## Returns the `current working directory`:idx:.
   when defined(windows):
     var bufsize = MAX_PATH.int32
@@ -282,7 +957,7 @@ proc getCurrentDir*(): string {.rtl, extern: "nos$1", tags: [].} =
         else:
           raiseOSError(osLastError())
 
-proc setCurrentDir*(newDir: string) {.inline, tags: [].} =
+proc setCurrentDir*(newDir: string) {.inline, tags: [], noNimScript.} =
   ## Sets the `current working directory`:idx:; `OSError` is raised if
   ## `newDir` cannot been set.
   when defined(Windows):
@@ -294,19 +969,20 @@ proc setCurrentDir*(newDir: string) {.inline, tags: [].} =
   else:
     if chdir(newDir) != 0'i32: raiseOSError(osLastError())
 
-proc absolutePath*(path: string, root = getCurrentDir()): string =
-  ## Returns the absolute path of `path`, rooted at `root` (which must be absolute)
-  ## if `path` is absolute, return it, ignoring `root`
-  runnableExamples:
-    doAssert absolutePath("a") == getCurrentDir() / "a"
-  if isAbsolute(path): path
-  else:
-    if not root.isAbsolute:
-      raise newException(ValueError, "The specified root is not absolute: " & root)
-    joinPath(root, path)
+when not defined(nimscript):
+  proc absolutePath*(path: string, root = getCurrentDir()): string {.noNimScript.} =
+    ## Returns the absolute path of `path`, rooted at `root` (which must be absolute)
+    ## if `path` is absolute, return it, ignoring `root`
+    runnableExamples:
+      doAssert absolutePath("a") == getCurrentDir() / "a"
+    if isAbsolute(path): path
+    else:
+      if not root.isAbsolute:
+        raise newException(ValueError, "The specified root is not absolute: " & root)
+      joinPath(root, path)
 
 proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
-  tags: [ReadDirEffect].} =
+  tags: [ReadDirEffect], noNimScript.} =
   ## Returns the full (`absolute`:idx:) path of an existing file `filename`,
   ## raises OSError in case of an error. Follows symlinks.
   when defined(windows):
@@ -347,7 +1023,7 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1",
       result = $r
       c_free(cast[pointer](r))
 
-proc normalizePath*(path: var string) {.rtl, extern: "nos$1", tags: [].} =
+proc normalizePath*(path: var string) {.rtl, extern: "nos$1", tags: [], noNimScript.} =
   ## Normalize a path.
   ##
   ## Consecutive directory separators are collapsed, including an initial double slash.
@@ -383,12 +1059,12 @@ proc normalizePath*(path: var string) {.rtl, extern: "nos$1", tags: [].} =
   else:
     path = "."
 
-proc normalizedPath*(path: string): string {.rtl, extern: "nos$1", tags: [].} =
+proc normalizedPath*(path: string): string {.rtl, extern: "nos$1", tags: [], noNimScript.} =
   ## Returns a normalized path for the current OS. See `<#normalizePath>`_
   result = path
   normalizePath(result)
 
-when defined(Windows):
+when defined(Windows) and not defined(nimscript):
   proc openHandle(path: string, followSymlink=true, writeAccess=false): Handle =
     var flags = FILE_FLAG_BACKUP_SEMANTICS or FILE_ATTRIBUTE_NORMAL
     if not followSymlink:
@@ -409,7 +1085,7 @@ when defined(Windows):
         )
 
 proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
-  tags: [ReadDirEffect].} =
+  tags: [ReadDirEffect], noNimScript.} =
   ## Returns true if both pathname arguments refer to the same physical
   ## file or directory. Raises an exception if any of the files does not
   ## exist or information about it can not be obtained.
@@ -449,7 +1125,7 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1",
       result = a.st_dev == b.st_dev and a.st_ino == b.st_ino
 
 proc sameFileContent*(path1, path2: string): bool {.rtl, extern: "nos$1",
-  tags: [ReadIOEffect].} =
+  tags: [ReadIOEffect], noNimScript.} =
   ## Returns true if both pathname arguments refer to files with identical
   ## binary content.
   const
@@ -492,7 +1168,7 @@ type
     fpOthersRead           ## read access for others
 
 proc getFilePermissions*(filename: string): set[FilePermission] {.
-  rtl, extern: "nos$1", tags: [ReadDirEffect].} =
+  rtl, extern: "nos$1", tags: [ReadDirEffect], noNimScript.} =
   ## retrieves file permissions for `filename`. `OSError` is raised in case of
   ## an error. On Windows, only the ``readonly`` flag is checked, every other
   ## permission is available in any case.
@@ -524,7 +1200,7 @@ proc getFilePermissions*(filename: string): set[FilePermission] {.
       result = {fpUserExec..fpOthersRead}
 
 proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {.
-  rtl, extern: "nos$1", tags: [WriteDirEffect].} =
+  rtl, extern: "nos$1", tags: [WriteDirEffect], noNimScript.} =
   ## sets the file permissions for `filename`. `OSError` is raised in case of
   ## an error. On Windows, only the ``readonly`` flag is changed, depending on
   ## ``fpUserWrite``.
@@ -560,7 +1236,7 @@ proc setFilePermissions*(filename: string, permissions: set[FilePermission]) {.
     if res2 == - 1'i32: raiseOSError(osLastError())
 
 proc copyFile*(source, dest: string) {.rtl, extern: "nos$1",
-  tags: [ReadIOEffect, WriteIOEffect].} =
+  tags: [ReadIOEffect, WriteIOEffect], noNimScript.} =
   ## Copies a file from `source` to `dest`.
   ##
   ## If this fails, `OSError` is raised. On the Windows platform this proc will
@@ -611,7 +1287,7 @@ when not declared(ENOENT) and not defined(Windows):
   else:
     var ENOENT {.importc, header: "<errno.h>".}: cint
 
-when defined(Windows):
+when defined(Windows) and not defined(nimscript):
   when useWinUnicode:
     template deleteFile(file: untyped): untyped  = deleteFileW(file)
     template setFileAttributes(file, attrs: untyped): untyped =
@@ -621,7 +1297,7 @@ when defined(Windows):
     template setFileAttributes(file, attrs: untyped): untyped =
       setFileAttributesA(file, attrs)
 
-proc tryRemoveFile*(file: string): bool {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
+proc tryRemoveFile*(file: string): bool {.rtl, extern: "nos$1", tags: [WriteDirEffect], noNimScript.} =
   ## Removes the `file`. If this fails, returns `false`. This does not fail
   ## if the file never existed in the first place.
   ## On Windows, ignores the read-only attribute.
@@ -644,7 +1320,7 @@ proc tryRemoveFile*(file: string): bool {.rtl, extern: "nos$1", tags: [WriteDirE
     if unlink(file) != 0'i32 and errno != ENOENT:
       result = false
 
-proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} =
+proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect], noNimScript.} =
   ## Removes the `file`. If this fails, `OSError` is raised. This does not fail
   ## if the file never existed in the first place.
   ## On Windows, ignores the read-only attribute.
@@ -654,7 +1330,7 @@ proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].}
     else:
       raiseOSError(osLastError(), $strerror(errno))
 
-proc tryMoveFSObject(source, dest: string): bool =
+proc tryMoveFSObject(source, dest: string): bool {.noNimScript.} =
   ## Moves a file or directory from `source` to `dest`. Returns false in case
   ## of `EXDEV` error. In case of other errors `OSError` is raised. Returns
   ## true in case of success.
@@ -675,7 +1351,7 @@ proc tryMoveFSObject(source, dest: string): bool =
   return true
 
 proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
-  tags: [ReadIOEffect, WriteIOEffect].} =
+  tags: [ReadIOEffect, WriteIOEffect], noNimScript.} =
   ## Moves a file from `source` to `dest`. If this fails, `OSError` is raised.
   ## Can be used to `rename files`:idx:
   if not tryMoveFSObject(source, dest):
@@ -689,7 +1365,7 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
         raise
 
 proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
-  tags: [ExecIOEffect].} =
+  tags: [ExecIOEffect], noNimScript.} =
   ## Executes a `shell command`:idx:.
   ##
   ## Command has the form 'program args' where args are the command
@@ -704,7 +1380,7 @@ proc execShellCmd*(command: string): int {.rtl, extern: "nos$1",
     result = c_system(command)
 
 # Templates for filtering directories and files
-when defined(windows):
+when defined(windows) and not defined(nimscript):
   template isDir(f: WIN32_FIND_DATA): bool =
     (f.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) != 0'i32
   template isFile(f: WIN32_FIND_DATA): bool =
@@ -760,7 +1436,7 @@ template walkCommon(pattern: string, filter) =
         if filter(path):
           yield path
 
-iterator walkPattern*(pattern: string): string {.tags: [ReadDirEffect].} =
+iterator walkPattern*(pattern: string): string {.tags: [ReadDirEffect], noNimScript.} =
   ## Iterate over all the files and directories that match the `pattern`.
   ## On POSIX this uses the `glob`:idx: call.
   ##
@@ -768,7 +1444,7 @@ iterator walkPattern*(pattern: string): string {.tags: [ReadDirEffect].} =
   ## notation is supported.
   walkCommon(pattern, defaultWalkFilter)
 
-iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect].} =
+iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect], noNimScript.} =
   ## Iterate over all the files that match the `pattern`. On POSIX this uses
   ## the `glob`:idx: call.
   ##
@@ -776,7 +1452,7 @@ iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect].} =
   ## notation is supported.
   walkCommon(pattern, isFile)
 
-iterator walkDirs*(pattern: string): string {.tags: [ReadDirEffect].} =
+iterator walkDirs*(pattern: string): string {.tags: [ReadDirEffect], noNimScript.} =
   ## Iterate over all the directories that match the `pattern`.
   ## On POSIX this uses the `glob`:idx: call.
   ##
@@ -791,7 +1467,7 @@ type
     pcDir,                ## path refers to a directory
     pcLinkToDir           ## path refers to a symbolic link to a directory
 
-when defined(posix):
+when defined(posix) and not defined(nimscript):
   proc getSymlinkFileKind(path: string): PathComponent =
     # Helper function.
     var s: Stat
@@ -832,7 +1508,10 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path:
     for k, v in items(staticWalkDir(dir, relative)):
       yield (k, v)
   else:
-    when defined(windows):
+    when defined(nimscript):
+      for k, v in items(staticWalkDir(dir, relative)):
+        yield (k, v)
+    elif defined(windows):
       var f: WIN32_FIND_DATA
       var h = findFirstFile(dir / "*", f)
       if h != -1:
@@ -885,11 +1564,14 @@ iterator walkDir*(dir: string; relative=false): tuple[kind: PathComponent, path:
               k = getSymlinkFileKind(y)
             yield (k, y)
 
-iterator walkDirRec*(dir: string, yieldFilter = {pcFile},
-                     followFilter = {pcDir}): string {.tags: [ReadDirEffect].} =
+iterator walkDirRec*(dir: string,
+                     yieldFilter = {pcFile}, followFilter = {pcDir},
+                     relative = false): string {.tags: [ReadDirEffect].} =
   ## Recursively walks over the directory `dir` and yields for each file
   ## or directory in `dir`.
-  ## The full path for each file or directory is returned.
+  ## If ``relative`` is true the resulting path is
+  ## shortened to be relative to ``dir``, otherwise the full path is returned.
+  ##
   ## **Warning**:
   ## Modifying the directory structure while the iterator
   ## is traversing may result in undefined behavior!
@@ -912,15 +1594,17 @@ iterator walkDirRec*(dir: string, yieldFilter = {pcFile},
   ## ``pcLinkToDir``         follow symbolic links to directories
   ## ---------------------   ---------------------------------------------
   ##
-  var stack = @[dir]
+  var stack = @[""]
   while stack.len > 0:
-    for k, p in walkDir(stack.pop()):
+    let d = stack.pop()
+    for k, p in walkDir(dir / d, relative = true):
+      let rel = d / p
       if k in {pcDir, pcLinkToDir} and k in followFilter:
-        stack.add(p)
+        stack.add rel
       if k in yieldFilter:
-        yield p
+        yield if relative: rel else: dir / rel
 
-proc rawRemoveDir(dir: string) =
+proc rawRemoveDir(dir: string) {.noNimScript.} =
   when defined(windows):
     when useWinUnicode:
       wrapUnary(res, removeDirectoryW, dir)
@@ -934,7 +1618,7 @@ proc rawRemoveDir(dir: string) =
     if rmdir(dir) != 0'i32 and errno != ENOENT: raiseOSError(osLastError())
 
 proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
-  WriteDirEffect, ReadDirEffect], benign.} =
+  WriteDirEffect, ReadDirEffect], benign, noNimScript.} =
   ## Removes the directory `dir` including all subdirectories and files
   ## in `dir` (recursively).
   ##
@@ -946,7 +1630,7 @@ proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [
     of pcDir: removeDir(path)
   rawRemoveDir(dir)
 
-proc rawCreateDir(dir: string): bool =
+proc rawCreateDir(dir: string): bool {.noNimScript.} =
   # Try to create one directory (not the whole path).
   # returns `true` for success, `false` if the path has previously existed
   #
@@ -991,7 +1675,7 @@ proc rawCreateDir(dir: string): bool =
       raiseOSError(osLastError(), dir)
 
 proc existsOrCreateDir*(dir: string): bool {.rtl, extern: "nos$1",
-  tags: [WriteDirEffect, ReadDirEffect].} =
+  tags: [WriteDirEffect, ReadDirEffect], noNimScript.} =
   ## Check if a `directory`:idx: `dir` exists, and create it otherwise.
   ##
   ## Does not create parent directories (fails if parent does not exist).
@@ -1004,7 +1688,7 @@ proc existsOrCreateDir*(dir: string): bool {.rtl, extern: "nos$1",
       raise newException(IOError, "Failed to create '" & dir & "'")
 
 proc createDir*(dir: string) {.rtl, extern: "nos$1",
-  tags: [WriteDirEffect, ReadDirEffect].} =
+  tags: [WriteDirEffect, ReadDirEffect], noNimScript.} =
   ## Creates the `directory`:idx: `dir`.
   ##
   ## The directory may contain several subdirectories that do not exist yet.
@@ -1027,7 +1711,7 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1",
     discard existsOrCreateDir(dir)
 
 proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
-  tags: [WriteIOEffect, ReadIOEffect], benign.} =
+  tags: [WriteIOEffect, ReadIOEffect], benign, noNimScript.} =
   ## Copies a directory from `source` to `dest`.
   ##
   ## If this fails, `OSError` is raised. On the Windows platform this proc will
@@ -1045,7 +1729,7 @@ proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
       copyDir(path, dest / noSource)
     else: discard
 
-proc createSymlink*(src, dest: string) =
+proc createSymlink*(src, dest: string) {.noNimScript.} =
   ## Create a symbolic link at `dest` which points to the item specified
   ## by `src`. On most operating systems, will fail if a link already exists.
   ##
@@ -1068,7 +1752,7 @@ proc createSymlink*(src, dest: string) =
     if symlink(src, dest) != 0:
       raiseOSError(osLastError())
 
-proc createHardlink*(src, dest: string) =
+proc createHardlink*(src, dest: string) {.noNimScript.} =
   ## Create a hard link at `dest` which points to the item specified
   ## by `src`.
   ##
@@ -1176,7 +1860,7 @@ proc parseCmdLine*(c: string): seq[string] {.
     add(result, a)
 
 proc copyFileWithPermissions*(source, dest: string,
-                              ignorePermissionErrors = true) =
+                              ignorePermissionErrors = true) {.noNimScript.} =
   ## Copies a file from `source` to `dest` preserving file permissions.
   ##
   ## This is a wrapper proc around `copyFile() <#copyFile>`_,
@@ -1200,7 +1884,7 @@ proc copyFileWithPermissions*(source, dest: string,
 
 proc copyDirWithPermissions*(source, dest: string,
     ignorePermissionErrors = true) {.rtl, extern: "nos$1",
-    tags: [WriteIOEffect, ReadIOEffect], benign.} =
+    tags: [WriteIOEffect, ReadIOEffect], benign, noNimScript.} =
   ## Copies a directory from `source` to `dest` preserving file permissions.
   ##
   ## If this fails, `OSError` is raised. This is a wrapper proc around `copyDir()
@@ -1231,7 +1915,7 @@ proc copyDirWithPermissions*(source, dest: string,
 
 proc inclFilePermissions*(filename: string,
                           permissions: set[FilePermission]) {.
-  rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect].} =
+  rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect], noNimScript.} =
   ## a convenience procedure for:
   ##
   ## .. code-block:: nim
@@ -1240,14 +1924,14 @@ proc inclFilePermissions*(filename: string,
 
 proc exclFilePermissions*(filename: string,
                           permissions: set[FilePermission]) {.
-  rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect].} =
+  rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect], noNimScript.} =
   ## a convenience procedure for:
   ##
   ## .. code-block:: nim
   ##   setFilePermissions(filename, getFilePermissions(filename)-permissions)
   setFilePermissions(filename, getFilePermissions(filename)-permissions)
 
-proc moveDir*(source, dest: string) {.tags: [ReadIOEffect, WriteIOEffect].} =
+proc moveDir*(source, dest: string) {.tags: [ReadIOEffect, WriteIOEffect], noNimScript.} =
   ## Moves a directory from `source` to `dest`. If this fails, `OSError` is raised.
   if not tryMoveFSObject(source, dest):
     when not defined(windows):
@@ -1255,9 +1939,7 @@ proc moveDir*(source, dest: string) {.tags: [ReadIOEffect, WriteIOEffect].} =
       copyDir(source, dest)
       removeDir(source)
 
-#include ospaths
-
-proc expandSymlink*(symlinkPath: string): string =
+proc expandSymlink*(symlinkPath: string): string {.noNimScript.} =
   ## Returns a string representing the path to which the symbolic link points.
   ##
   ## On Windows this is a noop, ``symlinkPath`` is simply returned.
@@ -1320,6 +2002,13 @@ when defined(nimdoc):
     ##   else:
     ##     # Do something else!
 
+elif defined(nintendoswitch) or defined(nimscript):
+  proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} =
+    raise newException(OSError, "paramStr is not implemented on Nintendo Switch")
+
+  proc paramCount*(): int {.tags: [ReadIOEffect].} =
+    raise newException(OSError, "paramCount is not implemented on Nintendo Switch")
+
 elif defined(windows):
   # Since we support GUI applications with Nim, we sometimes generate
   # a WinMain entry proc. But a WinMain proc has no access to the parsed
@@ -1346,13 +2035,6 @@ elif defined(windows):
     if i < ownArgv.len and i >= 0: return TaintedString(ownArgv[i])
     raise newException(IndexError, "invalid index")
 
-elif defined(nintendoswitch):
-  proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} =
-    raise newException(OSError, "paramStr is not implemented on Nintendo Switch")
-
-  proc paramCount*(): int {.tags: [ReadIOEffect].} =
-    raise newException(OSError, "paramCount is not implemented on Nintendo Switch")
-
 elif defined(genode):
   proc paramStr*(i: int): TaintedString =
     raise newException(OSError, "paramStr is not implemented on Genode")
@@ -1397,7 +2079,7 @@ when declared(paramCount) or defined(nimdoc):
     for i in 1..paramCount():
       result.add(paramStr(i))
 
-when defined(freebsd) or defined(dragonfly):
+when not defined(nimscript) and (defined(freebsd) or defined(dragonfly)):
   proc sysctl(name: ptr cint, namelen: cuint, oldp: pointer, oldplen: ptr csize,
               newp: pointer, newplen: csize): cint
        {.importc: "sysctl",header: """#include <sys/types.h>
@@ -1430,7 +2112,7 @@ when defined(freebsd) or defined(dragonfly):
         result.setLen(pathLength)
         break
 
-when defined(linux) or defined(solaris) or defined(bsd) or defined(aix):
+when not defined(nimscript) and (defined(linux) or defined(solaris) or defined(bsd) or defined(aix)):
   proc getApplAux(procPath: string): string =
     result = newString(256)
     var len = readlink(procPath, result, 256)
@@ -1439,7 +2121,7 @@ when defined(linux) or defined(solaris) or defined(bsd) or defined(aix):
       len = readlink(procPath, result, len)
     setLen(result, len)
 
-when not (defined(windows) or defined(macosx)):
+when not (defined(windows) or defined(macosx) or defined(nimscript)):
   proc getApplHeuristic(): string =
     when declared(paramStr):
       result = string(paramStr(0))
@@ -1483,7 +2165,7 @@ when defined(haiku):
     else:
       result = ""
 
-proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} =
+proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noNimScript.} =
   ## Returns the filename of the application's executable.
   ##
   ## This procedure will resolve symlinks.
@@ -1543,11 +2225,11 @@ proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} =
     if result.len == 0:
       result = getApplHeuristic()
 
-proc getAppDir*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} =
+proc getAppDir*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect], noNimScript.} =
   ## Returns the directory of the application's executable.
   result = splitFile(getAppFilename()).dir
 
-proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect].} =
+proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect], noNimScript.} =
   ## sleeps `milsecs` milliseconds.
   when defined(windows):
     winlean.sleep(int32(milsecs))
@@ -1558,7 +2240,7 @@ proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect].} =
     discard posix.nanosleep(a, b)
 
 proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1",
-  tags: [ReadIOEffect].} =
+  tags: [ReadIOEffect], noNimScript.} =
   ## returns the file size of `file` (in bytes). An ``OSError`` exception is
   ## raised in case of an error.
   when defined(windows):
@@ -1574,7 +2256,7 @@ proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1",
       close(f)
     else: raiseOSError(osLastError())
 
-when defined(Windows):
+when defined(Windows) or defined(nimscript):
   type
     DeviceId* = int32
     FileId* = int64
@@ -1654,7 +2336,7 @@ template rawToFormalFileInfo(rawInfo, path, formalInfo): untyped =
       assert(path != "") # symlinks can't occur for file handles
       formalInfo.kind = getSymlinkFileKind(path)
 
-proc getFileInfo*(handle: FileHandle): FileInfo =
+proc getFileInfo*(handle: FileHandle): FileInfo {.noNimScript.} =
   ## Retrieves file information for the file object represented by the given
   ## handle.
   ##
@@ -1675,12 +2357,12 @@ proc getFileInfo*(handle: FileHandle): FileInfo =
       raiseOSError(osLastError())
     rawToFormalFileInfo(rawInfo, "", result)
 
-proc getFileInfo*(file: File): FileInfo =
+proc getFileInfo*(file: File): FileInfo {.noNimScript.} =
   if file.isNil:
     raise newException(IOError, "File is nil")
   result = getFileInfo(file.getFileHandle())
 
-proc getFileInfo*(path: string, followSymlink = true): FileInfo =
+proc getFileInfo*(path: string, followSymlink = true): FileInfo {.noNimScript.} =
   ## Retrieves file information for the file object pointed to by `path`.
   ##
   ## Due to intrinsic differences between operating systems, the information
@@ -1714,7 +2396,7 @@ proc getFileInfo*(path: string, followSymlink = true): FileInfo =
         raiseOSError(osLastError())
     rawToFormalFileInfo(rawInfo, path, result)
 
-proc isHidden*(path: string): bool =
+proc isHidden*(path: string): bool {.noNimScript.} =
   ## Determines whether ``path`` is hidden or not, using this
   ## reference https://en.wikipedia.org/wiki/Hidden_file_and_hidden_directory
   ##
@@ -1742,9 +2424,18 @@ proc isHidden*(path: string): bool =
     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) =
+proc setLastModificationTime*(file: string, t: times.Time) {.noNimScript.} =
   ## Sets the `file`'s last modification time. `OSError` is raised in case of
   ## an error.
   when defined(posix):
@@ -1760,3 +2451,37 @@ proc setLastModificationTime*(file: string, t: times.Time) =
     let res = setFileTime(h, nil, nil, ft.addr)
     discard h.closeHandle
     if res == 0'i32: raiseOSError(osLastError())
+
+when isMainModule:
+  assert quoteShellWindows("aaa") == "aaa"
+  assert quoteShellWindows("aaa\"") == "aaa\\\""
+  assert quoteShellWindows("") == "\"\""
+
+  assert quoteShellPosix("aaa") == "aaa"
+  assert quoteShellPosix("aaa a") == "'aaa a'"
+  assert quoteShellPosix("") == "''"
+  assert quoteShellPosix("a'a") == "'a'\"'\"'a'"
+
+  when defined(posix):
+    assert quoteShell("") == "''"
+
+  block normalizePathEndTest:
+    # handle edge cases correctly: shouldn't affect whether path is
+    # absolute/relative
+    doAssert "".normalizePathEnd(true) == ""
+    doAssert "".normalizePathEnd(false) == ""
+    doAssert "/".normalizePathEnd(true) == $DirSep
+    doAssert "/".normalizePathEnd(false) == $DirSep
+
+    when defined(posix):
+      doAssert "//".normalizePathEnd(false) == "/"
+      doAssert "foo.bar//".normalizePathEnd == "foo.bar"
+      doAssert "bar//".normalizePathEnd(trailingSep = true) == "bar/"
+    when defined(Windows):
+      doAssert r"C:\foo\\".normalizePathEnd == r"C:\foo"
+      doAssert r"C:\foo".normalizePathEnd(trailingSep = true) == r"C:\foo\"
+      # this one is controversial: we could argue for returning `D:\` instead,
+      # but this is simplest.
+      doAssert r"D:\".normalizePathEnd == r"D:"
+      doAssert r"E:/".normalizePathEnd(trailingSep = true) == r"E:\"
+      doAssert "/".normalizePathEnd == r"\"
diff --git a/lib/pure/ospaths.nim b/lib/pure/ospaths.nim
deleted file mode 100644
index 7f7f9a425..000000000
--- a/lib/pure/ospaths.nim
+++ /dev/null
@@ -1,713 +0,0 @@
-#
-#
-#            Nim's Runtime Library
-#        (c) Copyright 2015 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-# Forwarded by the ``os`` module but a module in its own right for NimScript
-# support.
-
-include "system/inclrtl"
-
-import strutils
-
-type
-  ReadEnvEffect* = object of ReadIOEffect   ## effect that denotes a read
-                                            ## from an environment variable
-  WriteEnvEffect* = object of WriteIOEffect ## effect that denotes a write
-                                            ## to an environment variable
-
-  ReadDirEffect* = object of ReadIOEffect   ## effect that denotes a read
-                                            ## operation from the directory
-                                            ## structure
-  WriteDirEffect* = object of WriteIOEffect ## effect that denotes a write
-                                            ## operation to
-                                            ## the directory structure
-
-  OSErrorCode* = distinct int32 ## Specifies an OS Error Code.
-
-const
-  doslikeFileSystem* = defined(windows) or defined(OS2) or defined(DOS)
-
-when defined(Nimdoc): # only for proper documentation:
-  const
-    CurDir* = '.'
-      ## The constant string used by the operating system to refer to the
-      ## current directory.
-      ##
-      ## For example: '.' for POSIX or ':' for the classic Macintosh.
-
-    ParDir* = ".."
-      ## The constant string used by the operating system to refer to the
-      ## parent directory.
-      ##
-      ## For example: ".." for POSIX or "::" for the classic Macintosh.
-
-    DirSep* = '/'
-      ## The character used by the operating system to separate pathname
-      ## components, for example, '/' for POSIX or ':' for the classic
-      ## Macintosh.
-
-    AltSep* = '/'
-      ## An alternative character used by the operating system to separate
-      ## pathname components, or the same as `DirSep` if only one separator
-      ## character exists. This is set to '/' on Windows systems
-      ## where `DirSep` is a backslash.
-
-    PathSep* = ':'
-      ## The character conventionally used by the operating system to separate
-      ## search patch components (as in PATH), such as ':' for POSIX
-      ## or ';' for Windows.
-
-    FileSystemCaseSensitive* = true
-      ## true if the file system is case sensitive, false otherwise. Used by
-      ## `cmpPaths` to compare filenames properly.
-
-    ExeExt* = ""
-      ## The file extension of native executables. For example:
-      ## "" for POSIX, "exe" on Windows.
-
-    ScriptExt* = ""
-      ## The file extension of a script file. For example: "" for POSIX,
-      ## "bat" on Windows.
-
-    DynlibFormat* = "lib$1.so"
-      ## The format string to turn a filename into a `DLL`:idx: file (also
-      ## called `shared object`:idx: on some operating systems).
-
-elif defined(macos):
-  const
-    CurDir* = ':'
-    ParDir* = "::"
-    DirSep* = ':'
-    AltSep* = Dirsep
-    PathSep* = ','
-    FileSystemCaseSensitive* = false
-    ExeExt* = ""
-    ScriptExt* = ""
-    DynlibFormat* = "$1.dylib"
-
-  #  MacOS paths
-  #  ===========
-  #  MacOS directory separator is a colon ":" which is the only character not
-  #  allowed in filenames.
-  #
-  #  A path containing no colon or which begins with a colon is a partial
-  #  path.
-  #  E.g. ":kalle:petter" ":kalle" "kalle"
-  #
-  #  All other paths are full (absolute) paths. E.g. "HD:kalle:" "HD:"
-  #  When generating paths, one is safe if one ensures that all partial paths
-  #  begin with a colon, and all full paths end with a colon.
-  #  In full paths the first name (e g HD above) is the name of a mounted
-  #  volume.
-  #  These names are not unique, because, for instance, two diskettes with the
-  #  same names could be inserted. This means that paths on MacOS are not
-  #  waterproof. In case of equal names the first volume found will do.
-  #  Two colons "::" are the relative path to the parent. Three is to the
-  #  grandparent etc.
-elif doslikeFileSystem:
-  const
-    CurDir* = '.'
-    ParDir* = ".."
-    DirSep* = '\\' # seperator within paths
-    AltSep* = '/'
-    PathSep* = ';' # seperator between paths
-    FileSystemCaseSensitive* = false
-    ExeExt* = "exe"
-    ScriptExt* = "bat"
-    DynlibFormat* = "$1.dll"
-elif defined(PalmOS) or defined(MorphOS):
-  const
-    DirSep* = '/'
-    AltSep* = Dirsep
-    PathSep* = ';'
-    ParDir* = ".."
-    FileSystemCaseSensitive* = false
-    ExeExt* = ""
-    ScriptExt* = ""
-    DynlibFormat* = "$1.prc"
-elif defined(RISCOS):
-  const
-    DirSep* = '.'
-    AltSep* = '.'
-    ParDir* = ".." # is this correct?
-    PathSep* = ','
-    FileSystemCaseSensitive* = true
-    ExeExt* = ""
-    ScriptExt* = ""
-    DynlibFormat* = "lib$1.so"
-else: # UNIX-like operating system
-  const
-    CurDir* = '.'
-    ParDir* = ".."
-    DirSep* = '/'
-    AltSep* = DirSep
-    PathSep* = ':'
-    FileSystemCaseSensitive* = when defined(macosx): false else: true
-    ExeExt* = ""
-    ScriptExt* = ""
-    DynlibFormat* = when defined(macosx): "lib$1.dylib" else: "lib$1.so"
-
-const
-  ExtSep* = '.'
-    ## The character which separates the base filename from the extension;
-    ## for example, the '.' in ``os.nim``.
-
-proc normalizePathEnd(path: var string, trailingSep = false) =
-  ## ensures ``path`` has exactly 0 or 1 trailing `DirSep`, depending on
-  ## ``trailingSep``, and taking care of edge cases: it preservers whether
-  ## a path is absolute or relative, and makes sure trailing sep is `DirSep`,
-  ## not `AltSep`.
-  if path.len == 0: return
-  var i = path.len
-  while i >= 1 and path[i-1] in {DirSep, AltSep}: dec(i)
-  if trailingSep:
-    # foo// => foo
-    path.setLen(i)
-    # foo => foo/
-    path.add DirSep
-  elif i>0:
-    # foo// => foo
-    path.setLen(i)
-  else:
-    # // => / (empty case was already taken care of)
-    path = $DirSep
-
-proc normalizePathEnd(path: string, trailingSep = false): string =
-  result = path
-  result.normalizePathEnd(trailingSep)
-
-proc joinPath*(head, tail: string): string {.
-  noSideEffect, rtl, extern: "nos$1".} =
-  ## Joins two directory names to one.
-  ##
-  ## For example on Unix:
-  ##
-  ## .. code-block:: nim
-  ##   joinPath("usr", "lib")
-  ##
-  ## results in:
-  ##
-  ## .. code-block:: nim
-  ##   "usr/lib"
-  ##
-  ## If head is the empty string, tail is returned. If tail is the empty
-  ## string, head is returned with a trailing path separator. If tail starts
-  ## with a path separator it will be removed when concatenated to head. Other
-  ## path separators not located on boundaries won't be modified. More
-  ## examples on Unix:
-  ##
-  ## .. code-block:: nim
-  ##   assert joinPath("usr", "") == "usr/"
-  ##   assert joinPath("", "lib") == "lib"
-  ##   assert joinPath("", "/lib") == "/lib"
-  ##   assert joinPath("usr/", "/lib") == "usr/lib"
-  if len(head) == 0:
-    result = tail
-  elif head[len(head)-1] in {DirSep, AltSep}:
-    if tail.len > 0 and tail[0] in {DirSep, AltSep}:
-      result = head & substr(tail, 1)
-    else:
-      result = head & tail
-  else:
-    if tail.len > 0 and tail[0] in {DirSep, AltSep}:
-      result = head & tail
-    else:
-      result = head & DirSep & tail
-
-proc joinPath*(parts: varargs[string]): string {.noSideEffect,
-  rtl, extern: "nos$1OpenArray".} =
-  ## The same as `joinPath(head, tail)`, but works with any number of
-  ## directory parts. You need to pass at least one element or the proc
-  ## will assert in debug builds and crash on release builds.
-  result = parts[0]
-  for i in 1..high(parts):
-    result = joinPath(result, parts[i])
-
-proc `/` * (head, tail: string): string {.noSideEffect.} =
-  ## The same as ``joinPath(head, tail)``
-  ##
-  ## Here are some examples for Unix:
-  ##
-  ## .. code-block:: nim
-  ##   assert "usr" / "" == "usr/"
-  ##   assert "" / "lib" == "lib"
-  ##   assert "" / "/lib" == "/lib"
-  ##   assert "usr/" / "/lib" == "usr/lib"
-  return joinPath(head, tail)
-
-proc splitPath*(path: string): tuple[head, tail: string] {.
-  noSideEffect, rtl, extern: "nos$1".} =
-  ## Splits a directory into (head, tail), so that
-  ## ``head / tail == path`` (except for edge cases like "/usr").
-  ##
-  ## Examples:
-  ##
-  ## .. code-block:: nim
-  ##   splitPath("usr/local/bin") -> ("usr/local", "bin")
-  ##   splitPath("usr/local/bin/") -> ("usr/local/bin", "")
-  ##   splitPath("bin") -> ("", "bin")
-  ##   splitPath("/bin") -> ("", "bin")
-  ##   splitPath("") -> ("", "")
-  var sepPos = -1
-  for i in countdown(len(path)-1, 0):
-    if path[i] in {DirSep, AltSep}:
-      sepPos = i
-      break
-  if sepPos >= 0:
-    result.head = substr(path, 0, sepPos-1)
-    result.tail = substr(path, sepPos+1)
-  else:
-    result.head = ""
-    result.tail = path
-
-proc parentDirPos(path: string): int =
-  var q = 1
-  if len(path) >= 1 and path[len(path)-1] in {DirSep, AltSep}: q = 2
-  for i in countdown(len(path)-q, 0):
-    if path[i] in {DirSep, AltSep}: return i
-  result = -1
-
-proc parentDir*(path: string): string {.
-  noSideEffect, rtl, extern: "nos$1".} =
-  ## Returns the parent directory of `path`.
-  ##
-  ## This is the same as ``splitPath(path).head`` when ``path`` doesn't end
-  ## in a dir separator.
-  ## The remainder can be obtained with ``lastPathPart(path)``
-  runnableExamples:
-    doAssert parentDir("") == ""
-    when defined(posix):
-      doAssert parentDir("/usr/local/bin") == "/usr/local"
-      doAssert parentDir("foo/bar/") == "foo"
-
-  let sepPos = parentDirPos(path)
-  if sepPos >= 0:
-    result = substr(path, 0, sepPos-1)
-  else:
-    result = ""
-
-proc tailDir*(path: string): string {.
-  noSideEffect, rtl, extern: "nos$1".} =
-  ## Returns the tail part of `path`..
-  ##
-  ## | Example: ``tailDir("/usr/local/bin") == "local/bin"``.
-  ## | Example: ``tailDir("usr/local/bin/") == "local/bin"``.
-  ## | Example: ``tailDir("bin") == ""``.
-  var q = 1
-  if len(path) >= 1 and path[len(path)-1] in {DirSep, AltSep}: q = 2
-  for i in 0..len(path)-q:
-    if path[i] in {DirSep, AltSep}:
-      return substr(path, i+1)
-  result = ""
-
-proc isRootDir*(path: string): bool {.
-  noSideEffect, rtl, extern: "nos$1".} =
-  ## Checks whether a given `path` is a root directory
-  result = parentDirPos(path) < 0
-
-iterator parentDirs*(path: string, fromRoot=false, inclusive=true): string =
-  ## Walks over all parent directories of a given `path`
-  ##
-  ## If `fromRoot` is set, the traversal will start from the file system root
-  ## diretory. If `inclusive` is set, the original argument will be included
-  ## in the traversal.
-  ##
-  ## Relative paths won't be expanded by this proc. Instead, it will traverse
-  ## only the directories appearing in the relative path.
-  if not fromRoot:
-    var current = path
-    if inclusive: yield path
-    while true:
-      if current.isRootDir: break
-      current = current.parentDir
-      yield current
-  else:
-    for i in countup(0, path.len - 2): # ignore the last /
-      # deal with non-normalized paths such as /foo//bar//baz
-      if path[i] in {DirSep, AltSep} and
-          (i == 0 or path[i-1] notin {DirSep, AltSep}):
-        yield path.substr(0, i)
-
-    if inclusive: yield path
-
-proc `/../`*(head, tail: string): string {.noSideEffect.} =
-  ## The same as ``parentDir(head) / tail`` unless there is no parent
-  ## directory. Then ``head / tail`` is performed instead.
-  let sepPos = parentDirPos(head)
-  if sepPos >= 0:
-    result = substr(head, 0, sepPos-1) / tail
-  else:
-    result = head / tail
-
-proc normExt(ext: string): string =
-  if ext == "" or ext[0] == ExtSep: result = ext # no copy needed here
-  else: result = ExtSep & ext
-
-proc searchExtPos*(path: string): int =
-  ## Returns index of the '.' char in `path` if it signifies the beginning
-  ## of extension. Returns -1 otherwise.
-  # BUGFIX: do not search until 0! .DS_Store is no file extension!
-  result = -1
-  for i in countdown(len(path)-1, 1):
-    if path[i] == ExtSep:
-      result = i
-      break
-    elif path[i] in {DirSep, AltSep}:
-      break # do not skip over path
-
-proc splitFile*(path: string): tuple[dir, name, ext: string] {.
-  noSideEffect, rtl, extern: "nos$1".} =
-  ## Splits a filename into (dir, filename, extension).
-  ## `dir` does not end in `DirSep`.
-  ## `extension` includes the leading dot.
-  ##
-  ## Example:
-  ##
-  ## .. code-block:: nim
-  ##   var (dir, name, ext) = splitFile("usr/local/nimc.html")
-  ##   assert dir == "usr/local"
-  ##   assert name == "nimc"
-  ##   assert ext == ".html"
-  ##
-  ## If `path` has no extension, `ext` is the empty string.
-  ## If `path` has no directory component, `dir` is the empty string.
-  ## If `path` has no filename component, `name` and `ext` are empty strings.
-  if path.len == 0 or path[path.len-1] in {DirSep, AltSep}:
-    result = (path, "", "")
-  else:
-    var sepPos = -1
-    var dotPos = path.len
-    for i in countdown(len(path)-1, 0):
-      if path[i] == ExtSep:
-        if dotPos == path.len and i > 0 and
-            path[i-1] notin {DirSep, AltSep}: dotPos = i
-      elif path[i] in {DirSep, AltSep}:
-        sepPos = i
-        break
-    result.dir = substr(path, 0, sepPos-1)
-    result.name = substr(path, sepPos+1, dotPos-1)
-    result.ext = substr(path, dotPos)
-
-proc extractFilename*(path: string): string {.
-  noSideEffect, rtl, extern: "nos$1".} =
-  ## Extracts the filename of a given `path`. This is the same as
-  ## ``name & ext`` from ``splitFile(path)``. See also ``lastPathPart``.
-  runnableExamples:
-    when defined(posix):
-      doAssert extractFilename("foo/bar/") == ""
-      doAssert extractFilename("foo/bar") == "bar"
-  if path.len == 0 or path[path.len-1] in {DirSep, AltSep}:
-    result = ""
-  else:
-    result = splitPath(path).tail
-
-proc lastPathPart*(path: string): string {.
-  noSideEffect, rtl, extern: "nos$1".} =
-  ## like ``extractFilename``, but ignores trailing dir separator; aka: `baseName`:idx:
-  ## in some other languages.
-  runnableExamples:
-    when defined(posix):
-      doAssert lastPathPart("foo/bar/") == "bar"
-  let path = path.normalizePathEnd(trailingSep = false)
-  result = extractFilename(path)
-
-proc changeFileExt*(filename, ext: string): string {.
-  noSideEffect, rtl, extern: "nos$1".} =
-  ## Changes the file extension to `ext`.
-  ##
-  ## If the `filename` has no extension, `ext` will be added.
-  ## If `ext` == "" then any extension is removed.
-  ## `Ext` should be given without the leading '.', because some
-  ## filesystems may use a different character. (Although I know
-  ## of none such beast.)
-  var extPos = searchExtPos(filename)
-  if extPos < 0: result = filename & normExt(ext)
-  else: result = substr(filename, 0, extPos-1) & normExt(ext)
-
-proc addFileExt*(filename, ext: string): string {.
-  noSideEffect, rtl, extern: "nos$1".} =
-  ## Adds the file extension `ext` to `filename`, unless
-  ## `filename` already has an extension.
-  ##
-  ## `Ext` should be given without the leading '.', because some
-  ## filesystems may use a different character.
-  ## (Although I know of none such beast.)
-  var extPos = searchExtPos(filename)
-  if extPos < 0: result = filename & normExt(ext)
-  else: result = filename
-
-proc cmpPaths*(pathA, pathB: string): int {.
-  noSideEffect, rtl, extern: "nos$1".} =
-  ## Compares two paths.
-  ##
-  ## On a case-sensitive filesystem this is done
-  ## case-sensitively otherwise case-insensitively. Returns:
-  ##
-  ## | 0 iff pathA == pathB
-  ## | < 0 iff pathA < pathB
-  ## | > 0 iff pathA > pathB
-  runnableExamples:
-    when defined(macosx):
-      doAssert cmpPaths("foo", "Foo") == 0
-    elif defined(posix):
-      doAssert cmpPaths("foo", "Foo") > 0
-  if FileSystemCaseSensitive:
-    result = cmp(pathA, pathB)
-  else:
-    when defined(nimscript):
-      result = cmpic(pathA, pathB)
-    elif defined(nimdoc): discard
-    else:
-      result = cmpIgnoreCase(pathA, pathB)
-
-proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1".} =
-  ## Checks whether a given `path` is absolute.
-  ##
-  ## On Windows, network paths are considered absolute too.
-  runnableExamples:
-    doAssert(not "".isAbsolute)
-    doAssert(not ".".isAbsolute)
-    when defined(posix):
-      doAssert "/".isAbsolute
-      doAssert(not "a/".isAbsolute)
-
-  if len(path) == 0: return false
-
-  when doslikeFileSystem:
-    var len = len(path)
-    result = (path[0] in {'/', '\\'}) or
-              (len > 1 and path[0] in {'a'..'z', 'A'..'Z'} and path[1] == ':')
-  elif defined(macos):
-    # according to https://perldoc.perl.org/File/Spec/Mac.html `:a` is a relative path
-    result = path[0] != ':'
-  elif defined(RISCOS):
-    result = path[0] == '$'
-  elif defined(posix):
-    result = path[0] == '/'
-
-proc unixToNativePath*(path: string, drive=""): string {.
-  noSideEffect, rtl, extern: "nos$1".} =
-  ## Converts an UNIX-like path to a native one.
-  ##
-  ## On an UNIX system this does nothing. Else it converts
-  ## '/', '.', '..' to the appropriate things.
-  ##
-  ## On systems with a concept of "drives", `drive` is used to determine
-  ## which drive label to use during absolute path conversion.
-  ## `drive` defaults to the drive of the current working directory, and is
-  ## ignored on systems that do not have a concept of "drives".
-
-  when defined(unix):
-    result = path
-  else:
-    if path.len == 0:
-        return ""
-
-    var start: int
-    if path[0] == '/':
-      # an absolute path
-      when doslikeFileSystem:
-        if drive != "":
-          result = drive & ":" & DirSep
-        else:
-          result = $DirSep
-      elif defined(macos):
-        result = "" # must not start with ':'
-      else:
-        result = $DirSep
-      start = 1
-    elif path[0] == '.' and (path.len == 1 or path[1] == '/'):
-      # current directory
-      result = $CurDir
-      start = when doslikeFileSystem: 1 else: 2
-    else:
-      result = ""
-      start = 0
-
-    var i = start
-    while i < len(path): # ../../../ --> ::::
-      if i+2 < path.len and path[i] == '.' and path[i+1] == '.' and path[i+2] == '/':
-        # parent directory
-        when defined(macos):
-          if result[high(result)] == ':':
-            add result, ':'
-          else:
-            add result, ParDir
-        else:
-          add result, ParDir & DirSep
-        inc(i, 3)
-      elif path[i] == '/':
-        add result, DirSep
-        inc(i)
-      else:
-        add result, path[i]
-        inc(i)
-
-include "includes/oserr"
-when not defined(nimscript):
-  include "includes/osenv"
-
-proc getHomeDir*(): string {.rtl, extern: "nos$1",
-  tags: [ReadEnvEffect, ReadIOEffect].} =
-  ## Returns the home directory of the current user.
-  ##
-  ## This proc is wrapped by the expandTilde proc for the convenience of
-  ## processing paths coming from user configuration files.
-  when defined(windows): return string(getEnv("USERPROFILE")) & "\\"
-  else: return string(getEnv("HOME")) & "/"
-
-proc getConfigDir*(): string {.rtl, extern: "nos$1",
-  tags: [ReadEnvEffect, ReadIOEffect].} =
-  ## Returns the config directory of the current user for applications.
-  ##
-  ## On non-Windows OSs, this proc conforms to the XDG Base Directory
-  ## spec. Thus, this proc returns the value of the XDG_CONFIG_HOME environment
-  ## variable if it is set, and returns the default configuration directory,
-  ## "~/.config/", otherwise.
-  ##
-  ## An OS-dependent trailing slash is always present at the end of the
-  ## returned string; `\` on Windows and `/` on all other OSs.
-  when defined(windows):
-    result = getEnv("APPDATA").string
-  else:
-    result = getEnv("XDG_CONFIG_HOME", getEnv("HOME").string / ".config").string
-  result.normalizePathEnd(trailingSep = true)
-
-proc getTempDir*(): string {.rtl, extern: "nos$1",
-  tags: [ReadEnvEffect, ReadIOEffect].} =
-  ## Returns the temporary directory of the current user for applications to
-  ## save temporary files in.
-  ##
-  ## **Please do not use this**: On Android, it currently
-  ## returns ``getHomeDir()``, and on other Unix based systems it can cause
-  ## security problems too. That said, you can override this implementation
-  ## by adding ``-d:tempDir=mytempname`` to your compiler invokation.
-  when defined(tempDir):
-    const tempDir {.strdefine.}: string = nil
-    return tempDir
-  elif defined(windows): return string(getEnv("TEMP")) & "\\"
-  elif defined(android): return getHomeDir()
-  else: return "/tmp/"
-
-proc expandTilde*(path: string): string {.
-  tags: [ReadEnvEffect, ReadIOEffect].} =
-  ## Expands ``~`` or a path starting with ``~/`` to a full path, replacing
-  ## ``~`` with ``getHomeDir()`` (otherwise returns ``path`` unmodified).
-  ##
-  ## Windows: this is still supported despite Windows platform not having this
-  ## convention; also, both ``~/`` and ``~\`` are handled.
-  runnableExamples:
-    doAssert expandTilde("~" / "appname.cfg") == getHomeDir() / "appname.cfg"
-  if len(path) == 0 or path[0] != '~':
-    result = path
-  elif len(path) == 1:
-    result = getHomeDir()
-  elif (path[1] in {DirSep, AltSep}):
-    result = getHomeDir() / path.substr(2)
-  else:
-    # TODO: handle `~bob` and `~bob/` which means home of bob
-    result = path
-
-# TODO: consider whether quoteShellPosix, quoteShellWindows, quoteShell, quoteShellCommand
-# belong in `strutils` instead; they are not specific to paths
-proc quoteShellWindows*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
-  ## Quote s, so it can be safely passed to Windows API.
-  ## Based on Python's subprocess.list2cmdline
-  ## See http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
-  let needQuote = {' ', '\t'} in s or s.len == 0
-
-  result = ""
-  var backslashBuff = ""
-  if needQuote:
-    result.add("\"")
-
-  for c in s:
-    if c == '\\':
-      backslashBuff.add(c)
-    elif c == '\"':
-      result.add(backslashBuff)
-      result.add(backslashBuff)
-      backslashBuff.setLen(0)
-      result.add("\\\"")
-    else:
-      if backslashBuff.len != 0:
-        result.add(backslashBuff)
-        backslashBuff.setLen(0)
-      result.add(c)
-
-  if needQuote:
-    result.add("\"")
-
-proc quoteShellPosix*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
-  ## Quote ``s``, so it can be safely passed to POSIX shell.
-  ## Based on Python's pipes.quote
-  const safeUnixChars = {'%', '+', '-', '.', '/', '_', ':', '=', '@',
-                         '0'..'9', 'A'..'Z', 'a'..'z'}
-  if s.len == 0:
-    return "''"
-
-  let safe = s.allCharsInSet(safeUnixChars)
-
-  if safe:
-    return s
-  else:
-    return "'" & s.replace("'", "'\"'\"'") & "'"
-
-when defined(windows) or defined(posix) or defined(nintendoswitch):
-  proc quoteShell*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
-    ## Quote ``s``, so it can be safely passed to shell.
-    when defined(windows):
-      return quoteShellWindows(s)
-    else:
-      return quoteShellPosix(s)
-
-  proc quoteShellCommand*(args: openArray[string]): string =
-    ## Concatenates and quotes shell arguments `args`
-    runnableExamples:
-      when defined(posix):
-        assert quoteShellCommand(["aaa", "", "c d"]) == "aaa '' 'c d'"
-      when defined(windows):
-        assert quoteShellCommand(["aaa", "", "c d"]) == "aaa \"\" \"c d\""
-    # can't use `map` pending https://github.com/nim-lang/Nim/issues/8303
-    for i in 0..<args.len:
-      if i > 0: result.add " "
-      result.add quoteShell(args[i])
-
-when isMainModule:
-  assert quoteShellWindows("aaa") == "aaa"
-  assert quoteShellWindows("aaa\"") == "aaa\\\""
-  assert quoteShellWindows("") == "\"\""
-
-  assert quoteShellPosix("aaa") == "aaa"
-  assert quoteShellPosix("aaa a") == "'aaa a'"
-  assert quoteShellPosix("") == "''"
-  assert quoteShellPosix("a'a") == "'a'\"'\"'a'"
-
-  when defined(posix):
-    assert quoteShell("") == "''"
-
-  block normalizePathEndTest:
-    # handle edge cases correctly: shouldn't affect whether path is
-    # absolute/relative
-    doAssert "".normalizePathEnd(true) == ""
-    doAssert "".normalizePathEnd(false) == ""
-    doAssert "/".normalizePathEnd(true) == $DirSep
-    doAssert "/".normalizePathEnd(false) == $DirSep
-
-    when defined(posix):
-      doAssert "//".normalizePathEnd(false) == "/"
-      doAssert "foo.bar//".normalizePathEnd == "foo.bar"
-      doAssert "bar//".normalizePathEnd(trailingSep = true) == "bar/"
-    when defined(Windows):
-      doAssert r"C:\foo\\".normalizePathEnd == r"C:\foo"
-      doAssert r"C:\foo".normalizePathEnd(trailingSep = true) == r"C:\foo\"
-      # this one is controversial: we could argue for returning `D:\` instead,
-      # but this is simplest.
-      doAssert r"D:\".normalizePathEnd == r"D:"
-      doAssert r"E:/".normalizePathEnd(trailingSep = true) == r"E:\"
-      doAssert "/".normalizePathEnd == r"\"
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index e487a8975..b2239b9c5 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -15,7 +15,6 @@ include "system/inclrtl"
 import
   strutils, os, strtabs, streams, cpuinfo
 
-from ospaths import quoteShell, quoteShellWindows, quoteShellPosix
 export quoteShell, quoteShellWindows, quoteShellPosix
 
 when defined(windows):
@@ -65,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,
@@ -121,7 +121,7 @@ proc startProcess*(command: string,
   ## invocation if possible as it leads to non portable software.
   ##
   ## Return value: The newly created process object. Nil is never returned,
-  ## but ``EOS`` is raised in case of an error.
+  ## but ``OSError`` is raised in case of an error.
 
 proc startCmd*(command: string, options: set[ProcessOption] = {
                poStdErrToStdOut, poUsePath}): Process {.
@@ -155,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,
@@ -350,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
@@ -1324,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:
@@ -1334,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/parseopt.nim b/lib/pure/parseopt.nim
index c91134738..fe3d3186f 100644
--- a/lib/pure/parseopt.nim
+++ b/lib/pure/parseopt.nim
@@ -44,9 +44,9 @@ type
     cmdShortOption            ## a short option ``-c`` detected
   OptParser* =
       object of RootObj ## this object implements the command line parser
-    cmd*: string              #  cmd,pos exported so caller can catch "--" as..
     pos*: int                 # ..empty key or subcmd cmdArg & handle specially
     inShortState: bool
+    allowWhitespaceAfterColon: bool
     shortNoVal: set[char]
     longNoVal: seq[string]
     cmds: seq[string]
@@ -95,7 +95,8 @@ when declared(os.paramCount):
   # access the command line arguments then!
 
   proc initOptParser*(cmdline = "", shortNoVal: set[char]={},
-                      longNoVal: seq[string] = @[]): OptParser =
+                      longNoVal: seq[string] = @[];
+                      allowWhitespaceAfterColon = true): OptParser =
     ## inits the option parser. If ``cmdline == ""``, the real command line
     ## (as provided by the ``OS`` module) is taken.  If ``shortNoVal`` is
     ## provided command users do not need to delimit short option keys and
@@ -108,23 +109,21 @@ when declared(os.paramCount):
     result.inShortState = false
     result.shortNoVal = shortNoVal
     result.longNoVal = longNoVal
+    result.allowWhitespaceAfterColon = allowWhitespaceAfterColon
     if cmdline != "":
-      result.cmd = cmdline
       result.cmds = parseCmdLine(cmdline)
     else:
-      result.cmd = ""
       result.cmds = newSeq[string](paramCount())
       for i in countup(1, paramCount()):
         result.cmds[i-1] = paramStr(i).string
-        result.cmd.add quote(result.cmds[i-1])
-        result.cmd.add ' '
 
     result.kind = cmdEnd
     result.key = TaintedString""
     result.val = TaintedString""
 
   proc initOptParser*(cmdline: seq[TaintedString], shortNoVal: set[char]={},
-                      longNoVal: seq[string] = @[]): OptParser =
+                      longNoVal: seq[string] = @[];
+                      allowWhitespaceAfterColon = true): OptParser =
     ## inits the option parser. If ``cmdline.len == 0``, the real command line
     ## (as provided by the ``OS`` module) is taken. ``shortNoVal`` and
     ## ``longNoVal`` behavior is the same as for ``initOptParser(string,...)``.
@@ -133,19 +132,15 @@ when declared(os.paramCount):
     result.inShortState = false
     result.shortNoVal = shortNoVal
     result.longNoVal = longNoVal
-    result.cmd = ""
+    result.allowWhitespaceAfterColon = allowWhitespaceAfterColon
     if cmdline.len != 0:
       result.cmds = newSeq[string](cmdline.len)
       for i in 0..<cmdline.len:
         result.cmds[i] = cmdline[i].string
-        result.cmd.add quote(cmdline[i].string)
-        result.cmd.add ' '
     else:
       result.cmds = newSeq[string](paramCount())
       for i in countup(1, paramCount()):
         result.cmds[i-1] = paramStr(i).string
-        result.cmd.add quote(result.cmds[i-1])
-        result.cmd.add ' '
     result.kind = cmdEnd
     result.key = TaintedString""
     result.val = TaintedString""
@@ -210,7 +205,7 @@ proc next*(p: var OptParser) {.rtl, extern: "npo$1".} =
         inc(i)
         while i < p.cmds[p.idx].len and p.cmds[p.idx][i] in {'\t', ' '}: inc(i)
         # if we're at the end, use the next command line option:
-        if i >= p.cmds[p.idx].len and p.idx < p.cmds.len:
+        if i >= p.cmds[p.idx].len and p.idx < p.cmds.len and p.allowWhitespaceAfterColon:
           inc p.idx
           i = 0
         p.val = TaintedString p.cmds[p.idx].substr(i)
diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim
index 9aef43c1b..20f02e815 100644
--- a/lib/pure/parsesql.nim
+++ b/lib/pure/parsesql.nim
@@ -566,10 +566,6 @@ type
   SqlParser* = object of SqlLexer ## SQL parser object
     tok: Token
 
-
-{.deprecated: [EInvalidSql: SqlParseError, PSqlNode: SqlNode,
-    TSqlNode: SqlNodeObj, TSqlParser: SqlParser, TSqlNodeKind: SqlNodeKind].}
-
 proc newNode*(k: SqlNodeKind): SqlNode =
   new(result)
   result.kind = k
@@ -591,6 +587,7 @@ proc len*(n: SqlNode): int =
     result = n.sons.len
 
 proc `[]`*(n: SqlNode; i: int): SqlNode = n.sons[i]
+proc `[]`*(n: SqlNode; i: BackwardsIndex): SqlNode = n.sons[n.len - int(i)]
 
 proc add*(father, n: SqlNode) =
   add(father.sons, n)
@@ -674,7 +671,7 @@ proc getPrecedence(p: SqlParser): int =
     result = 5
   elif isOpr(p, "=") or isOpr(p, "<") or isOpr(p, ">") or isOpr(p, ">=") or
        isOpr(p, "<=") or isOpr(p, "<>") or isOpr(p, "!=") or isKeyw(p, "is") or
-       isKeyw(p, "like"):
+       isKeyw(p, "like") or isKeyw(p, "in"):
     result = 4
   elif isKeyw(p, "and"):
     result = 3
@@ -717,7 +714,10 @@ proc identOrLiteral(p: var SqlParser): SqlNode =
   of tkParLe:
     getTok(p)
     result = newNode(nkPrGroup)
-    result.add(parseExpr(p))
+    while true:
+      result.add(parseExpr(p))
+      if p.tok.kind != tkComma: break
+      getTok(p)
     eat(p, tkParRi)
   else:
     if p.tok.literal == "*":
@@ -1465,6 +1465,22 @@ proc `$`*(n: SqlNode): string =
   ## an alias for `renderSQL`.
   renderSQL(n)
 
+proc treeReprAux(s: SqlNode, level: int, result: var string) =
+  result.add('\n')
+  for i in 0 ..< level: result.add("  ")
+
+  result.add($s.kind)
+  if s.kind in LiteralNodes:
+    result.add(' ')
+    result.add(s.strVal)
+  else:
+    for son in s.sons:
+      treeReprAux(son, level + 1, result)
+
+proc treeRepr*(s: SqlNode): string =
+  result = newStringOfCap(128)
+  treeReprAux(s, 0, result)
+
 when not defined(js):
   import streams
 
diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim
index e633d8cf7..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:
@@ -267,7 +267,7 @@ proc parseBiggestInt*(s: string, number: var BiggestInt, start = 0): int {.
   rtl, extern: "npuParseBiggestInt", noSideEffect.} =
   ## parses an integer starting at `start` and stores the value into `number`.
   ## Result is the number of processed chars or 0 if there is no integer.
-  ## `EOverflow` is raised if an overflow occurs.
+  ## `OverflowError` is raised if an overflow occurs.
   var res: BiggestInt
   # use 'res' for exception safety (don't write to 'number' in case of an
   # overflow exception):
@@ -278,7 +278,7 @@ proc parseInt*(s: string, number: var int, start = 0): int {.
   rtl, extern: "npuParseInt", noSideEffect.} =
   ## parses an integer starting at `start` and stores the value into `number`.
   ## Result is the number of processed chars or 0 if there is no integer.
-  ## `EOverflow` is raised if an overflow occurs.
+  ## `OverflowError` is raised if an overflow occurs.
   var res: BiggestInt
   result = parseBiggestInt(s, res, start)
   if (sizeof(int) <= 4) and
@@ -289,7 +289,7 @@ proc parseInt*(s: string, number: var int, start = 0): int {.
 
 proc parseSaturatedNatural*(s: string, b: var int, start = 0): int =
   ## parses a natural number into ``b``. This cannot raise an overflow
-  ## error. Instead of an ``Overflow`` exception ``high(int)`` is returned.
+  ## error. ``high(int)`` is returned for an overflow.
   ## The number of processed character is returned.
   ## This is usually what you really want to use instead of `parseInt`:idx:.
   ## Example:
diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim
index d8d5a7a2d..0967f7983 100644
--- a/lib/pure/parsexml.nim
+++ b/lib/pure/parsexml.nim
@@ -180,6 +180,7 @@ type
     errEqExpected,           ## ``=`` expected
     errQuoteExpected,        ## ``"`` or ``'`` expected
     errEndOfCommentExpected  ## ``-->`` expected
+    errAttributeValueExpected ## non-empty attribute value expected
 
   ParserState = enum
     stateStart, stateNormal, stateAttr, stateEmptyElementTag, stateError
@@ -187,6 +188,8 @@ type
   XmlParseOption* = enum  ## options for the XML parser
     reportWhitespace,      ## report whitespace
     reportComments         ## report comments
+    allowUnquotedAttribs   ## allow unquoted attribute values (for HTML)
+    allowEmptyAttribs      ## allow empty attributes (without explicit value)
 
   XmlParser* = object of BaseLexer ## the parser object.
     a, b, c: string
@@ -207,7 +210,8 @@ const
     "'>' expected",
     "'=' expected",
     "'\"' or \"'\" expected",
-    "'-->' expected"
+    "'-->' expected",
+    "attribute value expected"
   ]
 
 proc open*(my: var XmlParser, input: Stream, filename: string,
@@ -618,10 +622,15 @@ proc parseAttribute(my: var XmlParser) =
   if my.a.len == 0:
     markError(my, errGtExpected)
     return
+
+  let startPos = my.bufpos
   parseWhitespace(my, skip=true)
   if my.buf[my.bufpos] != '=':
-    markError(my, errEqExpected)
+    if allowEmptyAttribs notin my.options or
+        (my.buf[my.bufpos] != '>' and my.bufpos == startPos):
+      markError(my, errEqExpected)
     return
+
   inc(my.bufpos)
   parseWhitespace(my, skip=true)
 
@@ -669,6 +678,21 @@ proc parseAttribute(my: var XmlParser) =
             pendingSpace = false
           add(my.b, buf[pos])
           inc(pos)
+  elif allowUnquotedAttribs in my.options:
+    const disallowedChars = {'"', '\'', '`', '=', '<', '>', ' ',
+                             '\0', '\t', '\L', '\F', '\f'}
+    let startPos = pos
+    while (let c = buf[pos]; c notin disallowedChars):
+      if c == '&':
+        my.bufpos = pos
+        parseEntity(my, my.b)
+        my.kind = xmlAttribute # parseEntity overwrites my.kind!
+        pos = my.bufpos
+      else:
+        add(my.b, c)
+        inc(pos)
+    if pos == startPos:
+      markError(my, errAttributeValueExpected)
   else:
     markError(my, errQuoteExpected)
     # error corrections: guess what was meant
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index 3ee82917d..957091918 100644
--- a/lib/pure/pegs.nim
+++ b/lib/pure/pegs.nim
@@ -90,19 +90,19 @@ proc kind*(p: Peg): PegKind = p.kind
   ## Returns the *PegKind* of a given *Peg* object.
 
 proc term*(p: Peg): string = p.term
-  ## Returns the *string* representation of a given *Peg* variant object 
+  ## Returns the *string* representation of a given *Peg* variant object
   ## where present.
 
 proc ch*(p: Peg): char = p.ch
-  ## Returns the *char* representation of a given *Peg* variant object 
+  ## Returns the *char* representation of a given *Peg* variant object
   ## where present.
 
 proc charChoice*(p: Peg): ref set[char] = p.charChoice
-  ## Returns the *charChoice* field of a given *Peg* variant object 
+  ## Returns the *charChoice* field of a given *Peg* variant object
   ## where present.
 
 proc nt*(p: Peg): NonTerminal = p.nt
-  ## Returns the *NonTerminal* object of a given *Peg* variant object 
+  ## Returns the *NonTerminal* object of a given *Peg* variant object
   ## where present.
 
 proc index*(p: Peg): range[0..MaxSubpatterns] = p.index
@@ -137,7 +137,7 @@ proc flags*(nt: NonTerminal): set[NonTerminalFlag] = nt.flags
 
 proc rule*(nt: NonTerminal): Peg = nt.rule
   ## Gets the *Peg* object representing the rule definition of the parent *Peg*
-  ## object variant of a given *NonTerminal*. 
+  ## object variant of a given *NonTerminal*.
 
 proc term*(t: string): Peg {.nosideEffect, rtl, extern: "npegs$1Str".} =
   ## constructs a PEG from a terminal string
@@ -553,8 +553,6 @@ type
     ml: int
     origStart: int
 
-{.deprecated: [TCaptures: Captures].}
-
 proc bounds*(c: Captures,
              i: range[0..MaxSubpatterns-1]): tuple[first, last: int] =
   ## returns the bounds ``[first..last]`` of the `i`'th capture.
@@ -885,7 +883,7 @@ proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int
 macro mkHandlerTplts(handlers: untyped): untyped =
   # Transforms the handler spec in *handlers* into handler templates.
   # The AST structure of *handlers[0]*:
-  # 
+  #
   # .. code-block::
   # StmtList
   #   Call
@@ -1009,7 +1007,7 @@ template eventParser*(pegAst, handlers: untyped): (proc(s: string): int) =
   ##            echo opStack
   ##
   ##  let pLen = parseArithExpr(txt)
-  ## 
+  ##
   ## The *handlers* parameter consists of code blocks for *PegKinds*,
   ## which define the grammar elements of interest. Each block can contain
   ## handler code to be executed when the parser enters and leaves text
@@ -1342,7 +1340,7 @@ when not defined(js):
                       subs: varargs[tuple[pattern: Peg, repl: string]]) {.
                       rtl, extern: "npegs$1".} =
     ## reads in the file `infile`, performs a parallel replacement (calls
-    ## `parallelReplace`) and writes back to `outfile`. Raises ``EIO`` if an
+    ## `parallelReplace`) and writes back to `outfile`. Raises ``IOError`` if an
     ## error occurs. This is supposed to be used for quick scripting.
     ##
     ## **Note**: this proc does not exist while using the JS backend.
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/smtp.nim b/lib/pure/smtp.nim
index d9b863a52..5f4b09f80 100644
--- a/lib/pure/smtp.nim
+++ b/lib/pure/smtp.nim
@@ -71,7 +71,12 @@ when not defined(ssl):
   type PSSLContext = ref object
   let defaultSSLContext: PSSLContext = nil
 else:
-  let defaultSSLContext = newContext(verifyMode = CVerifyNone)
+  var defaultSSLContext {.threadvar.}: SSLContext
+
+  proc getSSLContext(): SSLContext =
+    if defaultSSLContext == nil:
+      defaultSSLContext = newContext(verifyMode = CVerifyNone)
+    result = defaultSSLContext
 
 proc createMessage*(mSubject, mBody: string, mTo, mCc: seq[string],
                 otherHeaders: openarray[tuple[name, value: string]]): Message =
@@ -109,20 +114,22 @@ proc `$`*(msg: Message): string =
   result.add(msg.msgBody)
 
 proc newSmtp*(useSsl = false, debug=false,
-              sslContext = defaultSslContext): Smtp =
+              sslContext: SSLContext = nil): Smtp =
   ## Creates a new ``Smtp`` instance.
   new result
   result.debug = debug
-
   result.sock = newSocket()
   if useSsl:
     when compiledWithSsl:
-      sslContext.wrapSocket(result.sock)
+      if sslContext == nil:
+        getSSLContext().wrapSocket(result.sock)
+      else:
+        sslContext.wrapSocket(result.sock)
     else:
       {.error: "SMTP module compiled without SSL support".}
 
 proc newAsyncSmtp*(useSsl = false, debug=false,
-                   sslContext = defaultSslContext): AsyncSmtp =
+                   sslContext: SSLContext = nil): AsyncSmtp =
   ## Creates a new ``AsyncSmtp`` instance.
   new result
   result.debug = debug
@@ -130,7 +137,10 @@ proc newAsyncSmtp*(useSsl = false, debug=false,
   result.sock = newAsyncSocket()
   if useSsl:
     when compiledWithSsl:
-      sslContext.wrapSocket(result.sock)
+      if sslContext == nil:
+        getSSLContext().wrapSocket(result.sock)
+      else:
+        sslContext.wrapSocket(result.sock)
     else:
       {.error: "SMTP module compiled without SSL support".}
 
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index 9950c5877..b0ac62525 100644
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -157,112 +157,112 @@ proc peek[T](s: Stream, result: var T) =
     raise newEIO("cannot read from stream")
 
 proc readChar*(s: Stream): char =
-  ## reads a char from the stream `s`. Raises `EIO` if an error occurred.
+  ## reads a char from the stream `s`. Raises `IOError` if an error occurred.
   ## Returns '\\0' as an EOF marker.
   if readData(s, addr(result), sizeof(result)) != 1: result = '\0'
 
 proc peekChar*(s: Stream): char =
-  ## peeks a char from the stream `s`. Raises `EIO` if an error occurred.
+  ## peeks a char from the stream `s`. Raises `IOError` if an error occurred.
   ## Returns '\\0' as an EOF marker.
   if peekData(s, addr(result), sizeof(result)) != 1: result = '\0'
 
 proc readBool*(s: Stream): bool =
-  ## reads a bool from the stream `s`. Raises `EIO` if an error occurred.
+  ## reads a bool from the stream `s`. Raises `IOError` if an error occurred.
   read(s, result)
 
 proc peekBool*(s: Stream): bool =
-  ## peeks a bool from the stream `s`. Raises `EIO` if an error occurred.
+  ## peeks a bool from the stream `s`. Raises `IOError` if an error occurred.
   peek(s, result)
 
 proc readInt8*(s: Stream): int8 =
-  ## reads an int8 from the stream `s`. Raises `EIO` if an error occurred.
+  ## reads an int8 from the stream `s`. Raises `IOError` if an error occurred.
   read(s, result)
 
 proc peekInt8*(s: Stream): int8 =
-  ## peeks an int8 from the stream `s`. Raises `EIO` if an error occurred.
+  ## peeks an int8 from the stream `s`. Raises `IOError` if an error occurred.
   peek(s, result)
 
 proc readInt16*(s: Stream): int16 =
-  ## reads an int16 from the stream `s`. Raises `EIO` if an error occurred.
+  ## reads an int16 from the stream `s`. Raises `IOError` if an error occurred.
   read(s, result)
 
 proc peekInt16*(s: Stream): int16 =
-  ## peeks an int16 from the stream `s`. Raises `EIO` if an error occurred.
+  ## peeks an int16 from the stream `s`. Raises `IOError` if an error occurred.
   peek(s, result)
 
 proc readInt32*(s: Stream): int32 =
-  ## reads an int32 from the stream `s`. Raises `EIO` if an error occurred.
+  ## reads an int32 from the stream `s`. Raises `IOError` if an error occurred.
   read(s, result)
 
 proc peekInt32*(s: Stream): int32 =
-  ## peeks an int32 from the stream `s`. Raises `EIO` if an error occurred.
+  ## peeks an int32 from the stream `s`. Raises `IOError` if an error occurred.
   peek(s, result)
 
 proc readInt64*(s: Stream): int64 =
-  ## reads an int64 from the stream `s`. Raises `EIO` if an error occurred.
+  ## reads an int64 from the stream `s`. Raises `IOError` if an error occurred.
   read(s, result)
 
 proc peekInt64*(s: Stream): int64 =
-  ## peeks an int64 from the stream `s`. Raises `EIO` if an error occurred.
+  ## peeks an int64 from the stream `s`. Raises `IOError` if an error occurred.
   peek(s, result)
 
 proc readUint8*(s: Stream): uint8 =
-  ## reads an uint8 from the stream `s`. Raises `EIO` if an error occurred.
+  ## reads an uint8 from the stream `s`. Raises `IOError` if an error occurred.
   read(s, result)
 
 proc peekUint8*(s: Stream): uint8 =
-  ## peeks an uint8 from the stream `s`. Raises `EIO` if an error occurred.
+  ## peeks an uint8 from the stream `s`. Raises `IOError` if an error occurred.
   peek(s, result)
 
 proc readUint16*(s: Stream): uint16 =
-  ## reads an uint16 from the stream `s`. Raises `EIO` if an error occurred.
+  ## reads an uint16 from the stream `s`. Raises `IOError` if an error occurred.
   read(s, result)
 
 proc peekUint16*(s: Stream): uint16 =
-  ## peeks an uint16 from the stream `s`. Raises `EIO` if an error occurred.
+  ## peeks an uint16 from the stream `s`. Raises `IOError` if an error occurred.
   peek(s, result)
 
 proc readUint32*(s: Stream): uint32 =
-  ## reads an uint32 from the stream `s`. Raises `EIO` if an error occurred.
+  ## reads an uint32 from the stream `s`. Raises `IOError` if an error occurred.
   read(s, result)
 
 proc peekUint32*(s: Stream): uint32 =
-  ## peeks an uint32 from the stream `s`. Raises `EIO` if an error occurred.
+  ## peeks an uint32 from the stream `s`. Raises `IOError` if an error occurred.
   peek(s, result)
 
 proc readUint64*(s: Stream): uint64 =
-  ## reads an uint64 from the stream `s`. Raises `EIO` if an error occurred.
+  ## reads an uint64 from the stream `s`. Raises `IOError` if an error occurred.
   read(s, result)
 
 proc peekUint64*(s: Stream): uint64 =
-  ## peeks an uint64 from the stream `s`. Raises `EIO` if an error occurred.
+  ## peeks an uint64 from the stream `s`. Raises `IOError` if an error occurred.
   peek(s, result)
 
 proc readFloat32*(s: Stream): float32 =
-  ## reads a float32 from the stream `s`. Raises `EIO` if an error occurred.
+  ## reads a float32 from the stream `s`. Raises `IOError` if an error occurred.
   read(s, result)
 
 proc peekFloat32*(s: Stream): float32 =
-  ## peeks a float32 from the stream `s`. Raises `EIO` if an error occurred.
+  ## peeks a float32 from the stream `s`. Raises `IOError` if an error occurred.
   peek(s, result)
 
 proc readFloat64*(s: Stream): float64 =
-  ## reads a float64 from the stream `s`. Raises `EIO` if an error occurred.
+  ## reads a float64 from the stream `s`. Raises `IOError` if an error occurred.
   read(s, result)
 
 proc peekFloat64*(s: Stream): float64 =
-  ## peeks a float64 from the stream `s`. Raises `EIO` if an error occurred.
+  ## peeks a float64 from the stream `s`. Raises `IOError` if an error occurred.
   peek(s, result)
 
 proc readStr*(s: Stream, length: int): TaintedString =
-  ## reads a string of length `length` from the stream `s`. Raises `EIO` if
+  ## reads a string of length `length` from the stream `s`. Raises `IOError` if
   ## an error occurred.
   result = newString(length).TaintedString
   var L = readData(s, cstring(result), length)
   if L != length: setLen(result.string, L)
 
 proc peekStr*(s: Stream, length: int): TaintedString =
-  ## peeks a string of length `length` from the stream `s`. Raises `EIO` if
+  ## peeks a string of length `length` from the stream `s`. Raises `IOError` if
   ## an error occurred.
   result = newString(length).TaintedString
   var L = peekData(s, cstring(result), length)
@@ -301,7 +301,7 @@ proc peekLine*(s: Stream, line: var TaintedString): bool =
 
 proc readLine*(s: Stream): TaintedString =
   ## Reads a line from a stream `s`. Note: This is not very efficient. Raises
-  ## `EIO` if an error occurred.
+  ## `IOError` if an error occurred.
   result = TaintedString""
   if s.atEnd:
     raise newEIO("cannot read from stream")
@@ -317,7 +317,7 @@ proc readLine*(s: Stream): TaintedString =
 
 proc peekLine*(s: Stream): TaintedString =
   ## Peeks a line from a stream `s`. Note: This is not very efficient. Raises
-  ## `EIO` if an error occurred.
+  ## `IOError` if an error occurred.
   let pos = getPosition(s)
   defer: setPosition(s, pos)
   result = readLine(s)
diff --git a/lib/pure/strscans.nim b/lib/pure/strscans.nim
index 77763ff43..c1c535e55 100644
--- a/lib/pure/strscans.nim
+++ b/lib/pure/strscans.nim
@@ -129,7 +129,7 @@ to use prefix instead of postfix operators.
 ``+E``           One or more
 ``?E``           Zero or One
 ``E{n,m}``       From ``n`` up to ``m`` times ``E``
-``~Ε``           Not predicate
+``~E``           Not predicate
 ``a ^* b``       Shortcut for ``?(a *(b a))``. Usually used for separators.
 ``a ^* b``       Shortcut for ``?(a +(b a))``. Usually used for separators.
 ``'a'``          Matches a single character
@@ -456,10 +456,11 @@ macro scanf*(input: string; pattern: static[string]; results: varargs[typed]): b
 
 template atom*(input: string; idx: int; c: char): bool =
   ## Used in scanp for the matching of atoms (usually chars).
-  idx < input.len and input[idx] == c
+  ## EOF is matched as ``'\0'``.
+  (idx < input.len and input[idx] == c) or (idx == input.len and c == '\0')
 
 template atom*(input: string; idx: int; s: set[char]): bool =
-  idx < input.len and input[idx] in s
+  (idx < input.len and input[idx] in s) or (idx == input.len and '\0' in s)
 
 template hasNxt*(input: string; idx: int): bool = idx < input.len
 
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 82c6dc8b9..4d0fe800e 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -149,8 +149,8 @@ proc isAlphaAscii*(s: string): bool {.noSideEffect, procvar,
   ## in `s`.
   runnableExamples:
     doAssert isAlphaAscii("fooBar") == true
-    doAssert isAlphaAscii("fooBar1") == false 
-    doAssert isAlphaAscii("foo Bar") == false 
+    doAssert isAlphaAscii("fooBar1") == false
+    doAssert isAlphaAscii("foo Bar") == false
   isImpl isAlphaAscii
 
 proc isAlphaNumeric*(s: string): bool {.noSideEffect, procvar,
@@ -164,7 +164,7 @@ proc isAlphaNumeric*(s: string): bool {.noSideEffect, procvar,
   ## in `s`.
   runnableExamples:
     doAssert isAlphaNumeric("fooBar") == true
-    doAssert isAlphaNumeric("fooBar") == true 
+    doAssert isAlphaNumeric("fooBar") == true
     doAssert isAlphaNumeric("foo Bar") == false
   isImpl isAlphaNumeric
 
@@ -179,7 +179,7 @@ proc isDigit*(s: string): bool {.noSideEffect, procvar,
   ## in `s`.
   runnableExamples:
     doAssert isDigit("1908") == true
-    doAssert isDigit("fooBar1") == false 
+    doAssert isDigit("fooBar1") == false
   isImpl isDigit
 
 proc isSpaceAscii*(s: string): bool {.noSideEffect, procvar,
@@ -191,7 +191,7 @@ proc isSpaceAscii*(s: string): bool {.noSideEffect, procvar,
   ## characters and there is at least one character in `s`.
   runnableExamples:
     doAssert isSpaceAscii("   ") == true
-    doAssert isSpaceAscii("") == false 
+    doAssert isSpaceAscii("") == false
   isImpl isSpaceAscii
 
 template isCaseImpl(s, charProc, skipNonAlpha) =
@@ -420,7 +420,7 @@ proc toOctal*(c: char): string {.noSideEffect, rtl, extern: "nsuToOctal".} =
   ## The resulting string may not have a leading zero. Its length is always
   ## exactly 3.
   runnableExamples:
-    doAssert toOctal('!') == "041" 
+    doAssert toOctal('!') == "041"
   result = newString(3)
   var val = ord(c)
   for i in countdown(2, 0):
@@ -909,7 +909,7 @@ proc toHex*(x: BiggestInt, len: Positive): string {.noSideEffect,
 proc toHex*[T: SomeInteger](x: T): string =
   ## Shortcut for ``toHex(x, T.sizeOf * 2)``
   runnableExamples:
-    doAssert toHex(1984) == "00000000000007C0"
+    doAssert toHex(1984'i64) == "00000000000007C0"
   toHex(BiggestInt(x), T.sizeOf * 2)
 
 proc toHex*(s: string): string {.noSideEffect, rtl.} =
@@ -933,7 +933,7 @@ proc intToStr*(x: int, minchars: Positive = 1): string {.noSideEffect,
   ## achieved by adding leading zeros.
   runnableExamples:
     doAssert intToStr(1984) == "1984"
-    doAssert intToStr(1984, 6) == "001984" 
+    doAssert intToStr(1984, 6) == "001984"
   result = $abs(x)
   for i in 1 .. minchars - len(result):
     result = '0' & result
@@ -1211,7 +1211,8 @@ proc wordWrap*(s: string, maxLineWidth = 80,
                splitLongWords = true,
                seps: set[char] = Whitespace,
                newLine = "\n"): string {.
-               noSideEffect, rtl, extern: "nsuWordWrap".} =
+               noSideEffect, rtl, extern: "nsuWordWrap",
+               deprecated: "use wrapWords in std/wordwrap instead".} =
   ## Word wraps `s`.
   result = newStringOfCap(s.len + s.len shr 6)
   var spaceLeft = maxLineWidth
@@ -1262,6 +1263,7 @@ proc indent*(s: string, count: Natural, padding: string = " "): string
 proc unindent*(s: string, count: Natural, padding: string = " "): string
     {.noSideEffect, rtl, extern: "nsuUnindent".} =
   ## Unindents each line in ``s`` by ``count`` amount of ``padding``.
+  ## Sometimes called `dedent`:idx:
   ##
   ## **Note:** This does not preserve the new line characters used in ``s``.
   runnableExamples:
@@ -1525,6 +1527,8 @@ proc rfind*(s, sub: string, start: int = -1): int {.noSideEffect.} =
   ## backwards to 0.
   ##
   ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
+  if sub.len == 0:
+    return -1
   let realStart = if start == -1: s.len else: start
   for i in countdown(realStart-sub.len, 0):
     for j in 0..sub.len-1:
@@ -1632,11 +1636,7 @@ proc replace*(s, sub: string, by = ""): string {.noSideEffect,
   result = ""
   let subLen = sub.len
   if subLen == 0:
-    for c in s:
-      add result, by
-      add result, c
-    add result, by
-    return
+    result = s
   elif subLen == 1:
     # when the pattern is a single char, we use a faster
     # char-based search that doesn't need a skip table:
@@ -1691,21 +1691,22 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
   initSkipTable(a, sub)
   var i = 0
   let last = s.high
-  let sublen = max(sub.len, 1)
-  while true:
-    var j = find(a, s, sub, i, last)
-    if j < 0: break
-    # word boundary?
-    if (j == 0 or s[j-1] notin wordChars) and
-        (j+sub.len >= s.len or s[j+sub.len] notin wordChars):
-      add result, substr(s, i, j - 1)
-      add result, by
-      i = j + sublen
-    else:
-      add result, substr(s, i, j)
-      i = j + 1
-  # copy the rest:
-  add result, substr(s, i)
+  let sublen = sub.len
+  if sublen > 0:
+    while true:
+      var j = find(a, s, sub, i, last)
+      if j < 0: break
+      # word boundary?
+      if (j == 0 or s[j-1] notin wordChars) and
+          (j+sub.len >= s.len or s[j+sub.len] notin wordChars):
+        add result, substr(s, i, j - 1)
+        add result, by
+        i = j + sublen
+      else:
+        add result, substr(s, i, j)
+        i = j + 1
+    # copy the rest:
+    add result, substr(s, i)
 
 proc multiReplace*(s: string, replacements: varargs[(string, string)]): string {.noSideEffect.} =
   ## Same as replace, but specialized for doing multiple replacements in a single
@@ -1722,15 +1723,18 @@ proc multiReplace*(s: string, replacements: varargs[(string, string)]): string {
   result = newStringOfCap(s.len)
   var i = 0
   var fastChk: set[char] = {}
-  for tup in replacements: fastChk.incl(tup[0][0]) # Include first character of all replacements
+  for sub, by in replacements.items:
+    if sub.len > 0:
+      # Include first character of all replacements
+      fastChk.incl sub[0]
   while i < s.len:
     block sIteration:
       # Assume most chars in s are not candidates for any replacement operation
       if s[i] in fastChk:
-        for tup in replacements:
-          if s.continuesWith(tup[0], i):
-            add result, tup[1]
-            inc(i, tup[0].len)
+        for sub, by in replacements.items:
+          if sub.len > 0 and s.continuesWith(sub, i):
+            add result, by
+            inc(i, sub.len)
             break sIteration
       # No matching replacement found
       # copy current character from s
@@ -1983,8 +1987,6 @@ type
     ffDecimal,         ## use decimal floating point notation
     ffScientific       ## use scientific notation (using ``e`` character)
 
-{.deprecated: [TFloatFormat: FloatFormatMode].}
-
 proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault,
                          precision: range[-1..32] = 16;
                          decimalSep = '.'): string {.
@@ -2510,6 +2512,7 @@ proc stripLineEnd*(s: var string) =
   ## Returns ``s`` stripped from one of these suffixes:
   ## ``\r, \n, \r\n, \f, \v`` (at most once instance).
   ## For example, can be useful in conjunction with ``osproc.execCmdEx``.
+  ## aka: `chomp`:idx:
   runnableExamples:
     var s = "foo\n\n"
     s.stripLineEnd
@@ -2612,7 +2615,7 @@ when isMainModule:
     doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz  abc"
 
     doAssert "-lda-ldz -ld abc".replaceWord("") == "-lda-ldz -ld abc"
-    doAssert "oo".replace("", "abc") == "abcoabcoabc"
+    doAssert "oo".replace("", "abc") == "oo"
 
     type MyEnum = enum enA, enB, enC, enuD, enE
     doAssert parseEnum[MyEnum]("enu_D") == enuD
diff --git a/lib/pure/subexes.nim b/lib/pure/subexes.nim
index 8149c72cc..638e71f04 100644
--- a/lib/pure/subexes.nim
+++ b/lib/pure/subexes.nim
@@ -17,7 +17,7 @@
 
 from strutils import parseInt, cmpIgnoreStyle, Digits
 include "system/inclrtl"
-
+import system/helpers2
 
 proc findNormalized(x: string, inArray: openarray[string]): int =
   var i = 0
@@ -85,7 +85,7 @@ proc getFormatArg(p: var FormatParser, a: openArray[string]): int =
     result = parseInt(a[result])-1
   else:
     raiseInvalidFormat("'#', '$', number or identifier expected")
-  if result >=% a.len: raiseInvalidFormat("index out of bounds: " & $result)
+  if result >=% a.len: raiseInvalidFormat(formatErrorIndexBound(result, a.len))
   p.i = i
 
 proc scanDollar(p: var FormatParser, a: openarray[string], s: var string) {.
@@ -300,8 +300,6 @@ proc scanDollar(p: var FormatParser, a: openarray[string], s: var string) =
 type
   Subex* = distinct string ## string that contains a substitution expression
 
-{.deprecated: [TSubex: Subex].}
-
 proc subex*(s: string): Subex =
   ## constructs a *substitution expression* from `s`. Currently this performs
   ## no syntax checking but this may change in later versions.
diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim
index 8ded552d9..53c31e8c9 100644
--- a/lib/pure/sugar.nim
+++ b/lib/pure/sugar.nim
@@ -125,6 +125,8 @@ macro `->`*(p, b: untyped): untyped =
 type ListComprehension = object
 var lc*: ListComprehension
 
+template `|`*(lc: ListComprehension, comp: untyped): untyped = lc
+
 macro `[]`*(lc: ListComprehension, comp, typ: untyped): untyped =
   ## List comprehension, returns a sequence. `comp` is the actual list
   ## comprehension, for example ``x | (x <- 1..10, x mod 2 == 0)``. `typ` is
@@ -140,8 +142,7 @@ macro `[]`*(lc: ListComprehension, comp, typ: untyped): untyped =
 
   expectLen(comp, 3)
   expectKind(comp, nnkInfix)
-  expectKind(comp[0], nnkIdent)
-  assert($comp[0].ident == "|")
+  assert($comp[0] == "|")
 
   result = newCall(
     newDotExpr(
diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim
index 974dc839d..35dc2483c 100644
--- a/lib/pure/terminal.nim
+++ b/lib/pure/terminal.nim
@@ -481,9 +481,6 @@ type
     styleHidden,         ## hidden text
     styleStrikethrough   ## strikethrough
 
-{.deprecated: [TStyle: Style].}
-{.deprecated: [styleUnknown: styleItalic].}
-
 when not defined(windows):
   var
     gFG {.threadvar.}: int
@@ -556,9 +553,6 @@ type
     bg8Bit,                ## 256-color (not supported, see ``enableTrueColors`` instead.)
     bgDefault              ## default terminal background color
 
-{.deprecated: [TForegroundColor: ForegroundColor,
-               TBackgroundColor: BackgroundColor].}
-
 when defined(windows):
   var defaultForegroundColor, defaultBackgroundColor: int16 = 0xFFFF'i16 # Default to an invalid value 0xFFFF
 
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 62284c6cb..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>".}
@@ -298,9 +300,6 @@ type
   TimeIntervalParts* = array[TimeUnit, int] # Array of Duration parts starts
   TimesMutableTypes = DateTime | Time | Duration | TimeInterval
 
-{.deprecated: [TMonth: Month, TWeekDay: WeekDay, TTime: Time,
-    TTimeInterval: TimeInterval, TTimeInfo: DateTime, TimeInfo: DateTime].}
-
 const
   secondsInMin = 60
   secondsInHour = 60*60
@@ -748,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
@@ -843,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()
@@ -1050,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)
@@ -1064,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
@@ -1144,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,
@@ -1385,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
@@ -1400,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()
@@ -1549,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
 
 #
@@ -1813,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: '-'
@@ -2026,9 +2019,9 @@ proc parsePattern(input: string, pattern: FormatPattern, i: var int,
       var offset = 0
       case pattern
       of z:
-        offset = takeInt(1..2) * -3600
+        offset = takeInt(1..2) * 3600
       of zz:
-        offset = takeInt(2..2) * -3600
+        offset = takeInt(2..2) * 3600
       of zzz:
         offset.inc takeInt(2..2) * 3600
         if input[i] != ':':
@@ -2346,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
@@ -2508,4 +2509,4 @@ proc zoneInfoFromUtc*(zone: Timezone, time: Time): ZonedTime
 proc zoneInfoFromTz*(zone: Timezone, adjTime: Time): ZonedTime
     {.deprecated: "Use zonedTimeFromAdjTime instead".} =
   ## **Deprecated since v0.19.0:** use the ``zonedTimeFromAdjTime`` instead.
-  zone.zonedTimeFromAdjTime(adjTime)
\ No newline at end of file
+  zone.zonedTimeFromAdjTime(adjTime)
diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim
index 0107e2715..712cc46c8 100644
--- a/lib/pure/unicode.nim
+++ b/lib/pure/unicode.nim
@@ -18,8 +18,6 @@ type
   Rune* = distinct RuneImpl   ## type that can hold any Unicode character
   Rune16* = distinct int16 ## 16 bit Unicode character
 
-{.deprecated: [TRune: Rune, TRune16: Rune16].}
-
 proc `<=%`*(a, b: Rune): bool = return int(a) <=% int(b)
 proc `<%`*(a, b: Rune): bool = return int(a) <% int(b)
 proc `==`*(a, b: Rune): bool = return int(a) == int(b)
@@ -213,6 +211,10 @@ proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} =
   result = ""
   fastToUTF8Copy(c, result, 0, false)
 
+proc add*(s: var string; c: Rune) =
+  let pos = s.len
+  fastToUTF8Copy(c, s, pos, false)
+
 proc `$`*(rune: Rune): string =
   ## Converts a Rune to a string
   rune.toUTF8
@@ -220,7 +222,8 @@ proc `$`*(rune: Rune): string =
 proc `$`*(runes: seq[Rune]): string =
   ## Converts a sequence of Runes to a string
   result = ""
-  for rune in runes: result.add(rune.toUTF8)
+  for rune in runes:
+    result.add rune
 
 proc runeOffset*(s: string, pos:Natural, start: Natural = 0): int =
   ## Returns the byte position of unicode character
@@ -228,7 +231,7 @@ proc runeOffset*(s: string, pos:Natural, start: Natural = 0): int =
   ## returns the special value -1 if it runs out of the string
   ##
   ## Beware: This can lead to unoptimized code and slow execution!
-  ## Most problems are solve more efficient by using an iterator
+  ## Most problems can be solved more efficiently by using an iterator
   ## or conversion to a seq of Rune.
   var
     i = 0
@@ -244,7 +247,7 @@ proc runeAtPos*(s: string, pos: int): Rune =
   ## Returns the unicode character at position pos
   ##
   ## Beware: This can lead to unoptimized code and slow execution!
-  ## Most problems are solve more efficient by using an iterator
+  ## Most problems can be solved more efficiently by using an iterator
   ## or conversion to a seq of Rune.
   fastRuneAt(s, runeOffset(s, pos), result, false)
 
@@ -252,7 +255,7 @@ proc runeStrAtPos*(s: string, pos: Natural): string =
   ## Returns the unicode character at position pos as UTF8 String
   ##
   ## Beware: This can lead to unoptimized code and slow execution!
-  ## Most problems are solve more efficient by using an iterator
+  ## Most problems can be solved more efficiently by using an iterator
   ## or conversion to a seq of Rune.
   let o = runeOffset(s, pos)
   s[o.. (o+runeLenAt(s, o)-1)]
@@ -266,7 +269,7 @@ proc runeReverseOffset*(s: string, rev:Positive): (int, int) =
   ## satisfy the request.
   ##
   ## Beware: This can lead to unoptimized code and slow execution!
-  ## Most problems are solve more efficient by using an iterator
+  ## Most problems can be solved more efficiently by using an iterator
   ## or conversion to a seq of Rune.
   var
     a = rev.int
@@ -1938,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,
@@ -1963,12 +1966,12 @@ proc align*(s: string, count: Natural, padding = ' '.Rune): string {.
   ## returned unchanged. If you need to left align a string use the `alignLeft
   ## proc <#alignLeft>`_.
   runnableExamples:
-     assert align("abc", 4) == " abc"
-     assert align("a", 0) == "a"
-     assert align("1232", 6) == "  1232"
-     assert align("1232", 6, '#'.Rune) == "##1232"
-     assert align("Åge", 5) == "  Åge"
-     assert align("×", 4, '_'.Rune) == "___×"
+    assert align("abc", 4) == " abc"
+    assert align("a", 0) == "a"
+    assert align("1232", 6) == "  1232"
+    assert align("1232", 6, '#'.Rune) == "##1232"
+    assert align("Åge", 5) == "  Åge"
+    assert align("×", 4, '_'.Rune) == "___×"
 
   let sLen = s.runeLen
   if sLen < count:
@@ -2158,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/pure/unittest.nim b/lib/pure/unittest.nim
index 757bf4745..837072be2 100644
--- a/lib/pure/unittest.nim
+++ b/lib/pure/unittest.nim
@@ -145,8 +145,6 @@ type
     testStartTime: float
     testStackTrace: string
 
-{.deprecated: [TTestStatus: TestStatus, TOutputLevel: OutputLevel]}
-
 var
   abortOnError* {.threadvar.}: bool ## Set to true in order to quit
                                     ## immediately on fail. Default is false,
diff --git a/lib/std/diff.nim b/lib/std/diff.nim
new file mode 100644
index 000000000..bffce2803
--- /dev/null
+++ b/lib/std/diff.nim
@@ -0,0 +1,387 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2018 Nim contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements an algorithm to compute the
+## `diff`:idx: between two sequences of lines.
+
+# code owner: Arne Döring
+#
+# This is based on C# code written by Matthias Hertel, http://www.mathertel.de
+#
+# This Class implements the Difference Algorithm published in
+# "An O(ND) Difference Algorithm and its Variations" by Eugene Myers
+# Algorithmica Vol. 1 No. 2, 1986, p 251.
+
+import tables, strutils
+
+type
+  Item* = object    ## An Item in the list of differences.
+    startA*: int    ## Start Line number in Data A.
+    startB*: int    ## Start Line number in Data B.
+    deletedA*: int  ## Number of changes in Data A.
+    insertedB*: int ## Number of changes in Data B.
+
+  DiffData = object ## Data on one input file being compared.
+    data: seq[int] ## Buffer of numbers that will be compared.
+    modified: seq[bool] ## Array of booleans that flag for modified
+                        ## data. This is the result of the diff.
+                        ## This means deletedA in the first Data or
+                        ## inserted in the second Data.
+
+  Smsrd = object
+    x, y: int
+
+# template to avoid a seq copy. Required until ``sink`` parameters are ready.
+template newDiffData(initData: seq[int]; L: int): DiffData =
+  DiffData(
+    data: initData,
+    modified: newSeq[bool](L + 2)
+  )
+
+proc len(d: DiffData): int {.inline.} = d.data.len
+
+proc diffCodes(aText: string; h: var Table[string, int]): DiffData =
+  ## This function converts all textlines of the text into unique numbers for every unique textline
+  ## so further work can work only with simple numbers.
+  ## ``aText`` the input text
+  ## ``h`` This extern initialized hashtable is used for storing all ever used textlines.
+  ## ``trimSpace`` ignore leading and trailing space characters
+  ## Returns a array of integers.
+  var lastUsedCode = h.len
+  result.data = newSeq[int]()
+  for s in aText.splitLines:
+    if h.contains s:
+      result.data.add h[s]
+    else:
+      inc lastUsedCode
+      h[s] = lastUsedCode
+      result.data.add lastUsedCode
+  result.modified = newSeq[bool](result.data.len + 2)
+
+proc optimize(data: var DiffData) =
+  ## If a sequence of modified lines starts with a line that contains the same content
+  ## as the line that appends the changes, the difference sequence is modified so that the
+  ## appended line and not the starting line is marked as modified.
+  ## This leads to more readable diff sequences when comparing text files.
+  var startPos = 0
+  while startPos < data.len:
+    while startPos < data.len and not data.modified[startPos]:
+      inc startPos
+    var endPos = startPos
+    while endPos < data.len and data.modified[endPos]:
+      inc endPos
+
+    if endPos < data.len and data.data[startPos] == data.data[endPos]:
+      data.modified[startPos] = false
+      data.modified[endPos] = true
+    else:
+      startPos = endPos
+
+proc sms(dataA: var DiffData; lowerA, upperA: int; dataB: DiffData; lowerB, upperB: int;
+         downVector, upVector: var openArray[int]): Smsrd =
+  ## This is the algorithm to find the Shortest Middle Snake (sms).
+  ## ``dataA`` sequence A
+  ## ``lowerA`` lower bound of the actual range in dataA
+  ## ``upperA`` upper bound of the actual range in dataA (exclusive)
+  ## ``dataB`` sequence B
+  ## ``lowerB`` lower bound of the actual range in dataB
+  ## ``upperB`` upper bound of the actual range in dataB (exclusive)
+  ## ``downVector`` a vector for the (0,0) to (x,y) search. Passed as a parameter for speed reasons.
+  ## ``upVector`` a vector for the (u,v) to (N,M) search. Passed as a parameter for speed reasons.
+  ## Returns a MiddleSnakeData record containing x,y and u,v.
+
+  let max = dataA.len + dataB.len + 1
+
+  let downK = lowerA - lowerB # the k-line to start the forward search
+  let upK = upperA - upperB # the k-line to start the reverse search
+
+  let delta = (upperA - lowerA) - (upperB - lowerB)
+  let oddDelta = (delta and 1) != 0
+
+  # The vectors in the publication accepts negative indexes. the vectors implemented here are 0-based
+  # and are access using a specific offset: upOffset upVector and downOffset for downVector
+  let downOffset = max - downK
+  let upOffset = max - upK
+
+  let maxD = ((upperA - lowerA + upperB - lowerB) div 2) + 1
+
+  downVector[downOffset + downK + 1] = lowerA
+  upVector[upOffset + upK - 1] = upperA
+
+  for D in 0 .. maxD:
+    # Extend the forward path.
+    for k in countUp(downK - D, downK + D, 2):
+      # find the only or better starting point
+      var x: int
+      if k == downK - D:
+        x = downVector[downOffset + k + 1] # down
+      else:
+        x = downVector[downOffset + k - 1] + 1 # a step to the right
+        if k < downK + D and downVector[downOffset + k + 1] >= x:
+          x = downVector[downOffset + k + 1] # down
+
+      var y = x - k
+
+      # find the end of the furthest reaching forward D-path in diagonal k.
+      while x < upperA and y < upperB and dataA.data[x] == dataB.data[y]:
+        inc x
+        inc y
+
+      downVector[downOffset + k] = x
+
+      # overlap ?
+      if oddDelta and upK - D < k and k < upK + D:
+        if upVector[upOffset + k] <= downVector[downOffset + k]:
+          return Smsrd(x: downVector[downOffset + k],
+                       y: downVector[downOffset + k] - k)
+
+    # Extend the reverse path.
+    for k in countUp(upK - D, upK + D, 2):
+      # find the only or better starting point
+      var x: int
+      if k == upK + D:
+        x = upVector[upOffset + k - 1] # up
+      else:
+        x = upVector[upOffset + k + 1] - 1 # left
+        if k > upK - D and upVector[upOffset + k - 1] < x:
+          x = upVector[upOffset + k - 1] # up
+
+      var y = x - k
+      while x > lowerA and y > lowerB and dataA.data[x - 1] == dataB.data[y - 1]:
+        dec x
+        dec y
+
+      upVector[upOffset + k] = x
+
+      # overlap ?
+      if not oddDelta and downK-D <= k and k <= downK+D:
+        if upVector[upOffset + k] <= downVector[downOffset + k]:
+          return Smsrd(x: downVector[downOffset + k],
+                       y: downVector[downOffset + k] - k)
+
+  assert false, "the algorithm should never come here."
+
+proc lcs(dataA: var DiffData; lowerA, upperA: int; dataB: var DiffData; lowerB, upperB: int;
+         downVector, upVector: var openArray[int]) =
+  ## This is the divide-and-conquer implementation of the longes common-subsequence (lcs)
+  ## algorithm.
+  ## The published algorithm passes recursively parts of the A and B sequences.
+  ## To avoid copying these arrays the lower and upper bounds are passed while the sequences stay constant.
+  ## ``dataA`` sequence A
+  ## ``lowerA`` lower bound of the actual range in dataA
+  ## ``upperA`` upper bound of the actual range in dataA (exclusive)
+  ## ``dataB`` sequence B
+  ## ``lowerB`` lower bound of the actual range in dataB
+  ## ``upperB`` upper bound of the actual range in dataB (exclusive)
+  ## ``downVector`` a vector for the (0,0) to (x,y) search. Passed as a parameter for speed reasons.
+  ## ``upVector`` a vector for the (u,v) to (N,M) search. Passed as a parameter for speed reasons.
+
+  # make mutable copy:
+  var lowerA = lowerA
+  var lowerB = lowerB
+  var upperA = upperA
+  var upperB = upperB
+
+  # Fast walkthrough equal lines at the start
+  while lowerA < upperA and lowerB < upperB and dataA.data[lowerA] == dataB.data[lowerB]:
+    inc lowerA
+    inc lowerB
+
+  # Fast walkthrough equal lines at the end
+  while lowerA < upperA and lowerB < upperB and dataA.data[upperA - 1] == dataB.data[upperB - 1]:
+    dec upperA
+    dec upperB
+
+  if lowerA == upperA:
+    # mark as inserted lines.
+    while lowerB < upperB:
+      dataB.modified[lowerB] = true
+      inc lowerB
+
+  elif lowerB == upperB:
+    # mark as deleted lines.
+    while lowerA < upperA:
+      dataA.modified[lowerA] = true
+      inc lowerA
+
+  else:
+    # Find the middle snakea and length of an optimal path for A and B
+    let smsrd = sms(dataA, lowerA, upperA, dataB, lowerB, upperB, downVector, upVector)
+    # Debug.Write(2, "MiddleSnakeData", String.Format("{0},{1}", smsrd.x, smsrd.y))
+
+    # The path is from LowerX to (x,y) and (x,y) to UpperX
+    lcs(dataA, lowerA, smsrd.x, dataB, lowerB, smsrd.y, downVector, upVector)
+    lcs(dataA, smsrd.x, upperA, dataB, smsrd.y, upperB, downVector, upVector)  # 2002.09.20: no need for 2 points
+
+proc createDiffs(dataA, dataB: DiffData): seq[Item] =
+  ## Scan the tables of which lines are inserted and deleted,
+  ## producing an edit script in forward order.
+  var startA = 0
+  var startB = 0
+  var lineA = 0
+  var lineB = 0
+  while lineA < dataA.len or lineB < dataB.len:
+    if lineA < dataA.len and not dataA.modified[lineA] and
+       lineB < dataB.len and not dataB.modified[lineB]:
+      # equal lines
+      inc lineA
+      inc lineB
+    else:
+      # maybe deleted and/or inserted lines
+      startA = lineA
+      startB = lineB
+
+      while lineA < dataA.len and (lineB >= dataB.len or dataA.modified[lineA]):
+        inc lineA
+
+      while lineB < dataB.len and (lineA >= dataA.len or dataB.modified[lineB]):
+        inc lineB
+
+      if (startA < lineA) or (startB < lineB):
+        result.add Item(startA: startA,
+                        startB: startB,
+                        deletedA: lineA - startA,
+                        insertedB: lineB - startB)
+
+
+proc diffInt*(arrayA, arrayB: openArray[int]): seq[Item] =
+  ## Find the difference in 2 arrays of integers.
+  ## ``arrayA`` A-version of the numbers (usualy the old one)
+  ## ``arrayB`` B-version of the numbers (usualy the new one)
+  ## Returns a array of Items that describe the differences.
+
+  # The A-Version of the data (original data) to be compared.
+  var dataA = newDiffData(@arrayA, arrayA.len)
+
+  # The B-Version of the data (modified data) to be compared.
+  var dataB = newDiffData(@arrayB, arrayB.len)
+
+  let max = dataA.len + dataB.len + 1
+  ## vector for the (0,0) to (x,y) search
+  var downVector = newSeq[int](2 * max + 2)
+  ## vector for the (u,v) to (N,M) search
+  var upVector = newSeq[int](2 * max + 2)
+
+  lcs(dataA, 0, dataA.len, dataB, 0, dataB.len, downVector, upVector)
+  result = createDiffs(dataA, dataB)
+
+proc diffText*(textA, textB: string): seq[Item] =
+  ## Find the difference in 2 text documents, comparing by textlines.
+  ## The algorithm itself is comparing 2 arrays of numbers so when comparing 2 text documents
+  ## each line is converted into a (hash) number. This hash-value is computed by storing all
+  ## textlines into a common hashtable so i can find dublicates in there, and generating a
+  ## new number each time a new textline is inserted.
+  ## ``TextA`` A-version of the text (usualy the old one)
+  ## ``TextB`` B-version of the text (usualy the new one)
+  ## ``trimSpace`` When set to true, all leading and trailing whitespace characters are stripped out before the comparation is done.
+  ## ``ignoreSpace`` When set to true, all whitespace characters are converted to a single space character before the comparation is done.
+  ## ``ignoreCase`` When set to true, all characters are converted to their lowercase equivivalence before the comparation is done.
+  ## Returns a seq of Items that describe the differences.
+
+  # prepare the input-text and convert to comparable numbers.
+  var h = initTable[string, int]()  # TextA.len + TextB.len  <- probably wrong initial size
+  # The A-Version of the data (original data) to be compared.
+  var dataA = diffCodes(textA, h)
+
+  # The B-Version of the data (modified data) to be compared.
+  var dataB = diffCodes(textB, h)
+
+  h.clear # free up hashtable memory (maybe)
+
+  let max = dataA.len + dataB.len + 1
+  ## vector for the (0,0) to (x,y) search
+  var downVector = newSeq[int](2 * max + 2)
+  ## vector for the (u,v) to (N,M) search
+  var upVector = newSeq[int](2 * max + 2)
+
+  lcs(dataA, 0, dataA.len, dataB, 0, dataB.len, downVector, upVector)
+
+  optimize(dataA)
+  optimize(dataB)
+  result = createDiffs(dataA, dataB)
+
+when isMainModule:
+
+  proc testHelper(f: seq[Item]): string =
+    for it in f:
+      result.add(
+        $it.deletedA & "." & $it.insertedB & "." & $it.startA & "." & $it.startB & "*"
+      )
+
+  proc main() =
+    var a, b: string
+
+    stdout.writeLine("Diff Self Test...")
+
+    # test all changes
+    a = "a,b,c,d,e,f,g,h,i,j,k,l".replace(',', '\n')
+    b = "0,1,2,3,4,5,6,7,8,9".replace(',', '\n')
+    assert(testHelper(diffText(a, b)) ==
+      "12.10.0.0*",
+      "all-changes test failed.")
+    stdout.writeLine("all-changes test passed.")
+    # test all same
+    a = "a,b,c,d,e,f,g,h,i,j,k,l".replace(',', '\n')
+    b = a
+    assert(testHelper(diffText(a, b)) ==
+      "",
+      "all-same test failed.")
+    stdout.writeLine("all-same test passed.")
+
+    # test snake
+    a = "a,b,c,d,e,f".replace(',', '\n')
+    b = "b,c,d,e,f,x".replace(',', '\n')
+    assert(testHelper(diffText(a, b)) ==
+      "1.0.0.0*0.1.6.5*",
+      "snake test failed.")
+    stdout.writeLine("snake test passed.")
+
+    # 2002.09.20 - repro
+    a = "c1,a,c2,b,c,d,e,g,h,i,j,c3,k,l".replace(',', '\n')
+    b = "C1,a,C2,b,c,d,e,I1,e,g,h,i,j,C3,k,I2,l".replace(',', '\n')
+    assert(testHelper(diffText(a, b)) ==
+      "1.1.0.0*1.1.2.2*0.2.7.7*1.1.11.13*0.1.13.15*",
+      "repro20020920 test failed.")
+    stdout.writeLine("repro20020920 test passed.")
+
+    # 2003.02.07 - repro
+    a = "F".replace(',', '\n')
+    b = "0,F,1,2,3,4,5,6,7".replace(',', '\n')
+    assert(testHelper(diffText(a, b)) ==
+      "0.1.0.0*0.7.1.2*",
+      "repro20030207 test failed.")
+    stdout.writeLine("repro20030207 test passed.")
+
+    # Muegel - repro
+    a = "HELLO\nWORLD"
+    b = "\n\nhello\n\n\n\nworld\n"
+    assert(testHelper(diffText(a, b)) ==
+      "2.8.0.0*",
+      "repro20030409 test failed.")
+    stdout.writeLine("repro20030409 test passed.")
+
+    # test some differences
+    a = "a,b,-,c,d,e,f,f".replace(',', '\n')
+    b = "a,b,x,c,e,f".replace(',', '\n')
+    assert(testHelper(diffText(a, b)) ==
+      "1.1.2.2*1.0.4.4*1.0.7.6*",
+      "some-changes test failed.")
+    stdout.writeLine("some-changes test passed.")
+
+    # test one change within long chain of repeats
+    a = "a,a,a,a,a,a,a,a,a,a".replace(',', '\n')
+    b = "a,a,a,a,-,a,a,a,a,a".replace(',', '\n')
+    assert(testHelper(diffText(a, b)) ==
+      "0.1.4.4*1.0.9.10*",
+      "long chain of repeats test failed.")
+
+    stdout.writeLine("End.")
+    stdout.flushFile
+
+  main()
diff --git a/lib/pure/editdistance.nim b/lib/std/editdistance.nim
index 40beb7d93..40beb7d93 100644
--- a/lib/pure/editdistance.nim
+++ b/lib/std/editdistance.nim
diff --git a/lib/std/wordwrap.nim b/lib/std/wordwrap.nim
new file mode 100644
index 000000000..c7898b339
--- /dev/null
+++ b/lib/std/wordwrap.nim
@@ -0,0 +1,90 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2018 Nim contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains an algorithm to wordwrap a Unicode string.
+
+import strutils, unicode
+
+proc olen(s: string): int =
+  var i = 0
+  result = 0
+  while i < s.len:
+    inc result
+    let L = graphemeLen(s, i)
+    inc i, L
+
+proc wrapWords*(s: string, maxLineWidth = 80,
+               splitLongWords = true,
+               seps: set[char] = Whitespace,
+               newLine = "\n"): string {.noSideEffect.} =
+  ## Word wraps `s`.
+  result = newStringOfCap(s.len + s.len shr 6)
+  var spaceLeft = maxLineWidth
+  var lastSep = ""
+  for word, isSep in tokenize(s, seps):
+    let wlen = olen(word)
+    if isSep:
+      lastSep = word
+      spaceLeft = spaceLeft - wlen
+    elif wlen > spaceLeft:
+      if splitLongWords and wlen > maxLineWidth:
+        var i = 0
+        while i < word.len:
+          if spaceLeft <= 0:
+            spaceLeft = maxLineWidth
+            result.add newLine
+          dec spaceLeft
+          let L = graphemeLen(word, i)
+          for j in 0 ..< L: result.add word[i+j]
+          inc i, L
+      else:
+        spaceLeft = maxLineWidth - wlen
+        result.add(newLine)
+        result.add(word)
+    else:
+      spaceLeft = spaceLeft - wlen
+      result.add(lastSep)
+      result.add(word)
+      lastSep.setLen(0)
+
+when isMainModule:
+
+  when true:
+    let
+      inp = """ this is a long text --  muchlongerthan10chars and here
+                 it goes"""
+      outp = " this is a\nlong text\n--\nmuchlongerthan10chars\nand here\nit goes"
+    doAssert wrapWords(inp, 10, false) == outp
+
+    let
+      longInp = """ThisIsOneVeryLongStringWhichWeWillSplitIntoEightSeparatePartsNow"""
+      longOutp = "ThisIsOn\neVeryLon\ngStringW\nhichWeWi\nllSplitI\nntoEight\nSeparate\nPartsNow"
+    doAssert wrapWords(longInp, 8, true) == longOutp
+
+  # test we don't break Umlauts into invalid bytes:
+  let fies = "äöüöäöüöäöüöäöüööäöüöäößßßßüöäößßßßßß"
+  let fiesRes = "ä\nö\nü\nö\nä\nö\nü\nö\nä\nö\nü\nö\nä\nö\nü\nö\nö\nä\nö\nü\nö\nä\nö\nß\nß\nß\nß\nü\nö\nä\nö\nß\nß\nß\nß\nß\nß"
+  doAssert wrapWords(fies, 1, true) == fiesRes
+
+  let longlongword = """abc uitdaeröägfßhydüäpydqfü,träpydqgpmüdträpydföägpydörztdüöäfguiaeowäzjdtrüöäp psnrtuiydrözenrüöäpyfdqazpesnrtulocjtüö
+äzydgyqgfqfgprtnwjlcydkqgfüöezmäzydydqüüöäpdtrnvwfhgckdumböäpydfgtdgfhtdrntdrntydfogiayqfguiatrnydrntüöärtniaoeydfgaoeiqfglwcßqfgxvlcwgtfhiaoen
+rsüöäapmböäptdrniaoydfglckqfhouenrtsüöäptrniaoeyqfgulocfqclgwxßqflgcwßqfxglcwrniatrnmüböäpmöäbpümöäbpüöämpbaoestnriaesnrtdiaesrtdniaesdrtnaetdr
+iaoenvlcyfglwckßqfgvwkßqgfvlwkßqfgvlwckßqvlwkgfUIαοιαοιαχολωχσωχνωκψρχκψρτιεαοσηζϵηζιοεννκεωνιαλωσωκνκψρκγτφγτχκγτεκργτιχνκιωχσιλωσλωχξλξλξωχωχ
+ξχλωωχαοεοιαεοαεοιαεοαεοιαοεσναοεκνρκψγκψφϵιηαααοε"""
+  let longlongwordRes = """
+abc uitdaeröägfßhydüäpydqfü,träpydqgpmüdträpydföägpydörztdüöäfguiaeowäzjdtrüöäp
+psnrtuiydrözenrüöäpyfdqazpesnrtulocjtüöäzydgyqgfqfgprtnwjlcydkqgfüöezmäzydydqüü
+öäpdtrnvwfhgckdumböäpydfgtdgfhtdrntdrntydfogiayqfguiatrnydrntüöärtniaoeydfgaoeiq
+fglwcßqfgxvlcwgtfhiaoenrsüöäapmböäptdrniaoydfglckqfhouenrtsüöäptrniaoeyqfgulocf
+qclgwxßqflgcwßqfxglcwrniatrnmüböäpmöäbpümöäbpüöämpbaoestnriaesnrtdiaesrtdniaesdr
+tnaetdriaoenvlcyfglwckßqfgvwkßqgfvlwkßqfgvlwckßqvlwkgfUIαοιαοιαχολωχσωχνωκψρχκψ
+ρτιεαοσηζϵηζιοεννκεωνιαλωσωκνκψρκγτφγτχκγτεκργτιχνκιωχσιλωσλωχξλξλξωχωχ
+ξχλωωχαοεοιαεοαεοιαεοαεοιαοεσναοεκνρκψγκψφϵιηαααοε"""
+  doAssert wrapWords(longlongword) == longlongwordRes
+
diff --git a/lib/system.nim b/lib/system.nim
index 469f5cebe..ea767e27a 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -106,8 +106,6 @@ type
   SomeNumber* = SomeInteger|SomeFloat
     ## type class matching all number types
 
-{.deprecated: [SomeReal: SomeFloat].}
-
 proc defined*(x: untyped): bool {.magic: "Defined", noSideEffect, compileTime.}
   ## Special compile-time procedure that checks whether `x` is
   ## defined.
@@ -180,6 +178,15 @@ else:
     ## Cannot be overloaded.
     discard
 
+when defined(nimHasTypeof):
+  type
+    TypeOfMode* = enum ## Possible modes of `typeof`.
+      typeOfProc,      ## Prefer the interpretation that means `x` is a proc call.
+      typeOfIter       ## Prefer the interpretation that means `x` is an iterator call.
+  proc typeof*(x: untyped; mode = typeOfIter): typeDesc {.magic: "TypeOf", noSideEffect, compileTime.} =
+    ## Builtin 'typeof' operation for accessing the type of an expression. Since version 0.20.0.
+    discard
+
 proc `not`*(x: bool): bool {.magic: "Not", noSideEffect.}
   ## Boolean not; returns true iff ``x == false``.
 
@@ -194,23 +201,6 @@ proc `or`*(x, y: bool): bool {.magic: "Or", noSideEffect.}
 proc `xor`*(x, y: bool): bool {.magic: "Xor", noSideEffect.}
   ## Boolean `exclusive or`; returns true iff ``x != y``.
 
-proc new*[T](a: var ref T) {.magic: "New", noSideEffect.}
-  ## creates a new object of type ``T`` and returns a safe (traced)
-  ## reference to it in ``a``.
-
-proc new*(T: typedesc): auto =
-  ## creates a new object of type ``T`` and returns a safe (traced)
-  ## reference to it as result value.
-  ##
-  ## When ``T`` is a ref type then the resulting type will be ``T``,
-  ## otherwise it will be ``ref T``.
-  when (T is ref):
-    var r: T
-  else:
-    var r: ref T
-  new(r)
-  return r
-
 const ThisIsSystem = true
 
 proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.}
@@ -383,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".} =
@@ -563,7 +553,7 @@ type
       trace: string
     else:
       trace: seq[StackTraceEntry]
-    raise_id: uint # set when exception is raised
+    raiseId: uint # set when exception is raised
     up: ref Exception # used for stacking exceptions. Not exported!
 
   Defect* = object of Exception ## \
@@ -992,10 +982,13 @@ proc `div`*(x, y: int32): int32 {.magic: "DivI", noSideEffect.}
   ## ``trunc(x/y)``.
   ##
   ## .. code-block:: Nim
-  ##   1 div 2 == 0
-  ##   2 div 2 == 1
-  ##   3 div 2 == 1
-  ##   7 div 5 == 1
+  ##   ( 1 div  2) ==  0
+  ##   ( 2 div  2) ==  1
+  ##   ( 3 div  2) ==  1
+  ##   ( 7 div  3) ==  2
+  ##   (-7 div  3) == -2
+  ##   ( 7 div -3) == -2
+  ##   (-7 div -3) ==  2
 
 when defined(nimnomagic64):
   proc `div`*(x, y: int64): int64 {.magic: "DivI", noSideEffect.}
@@ -1011,7 +1004,10 @@ proc `mod`*(x, y: int32): int32 {.magic: "ModI", noSideEffect.}
   ## ``x - (x div y) * y``.
   ##
   ## .. code-block:: Nim
-  ##   (7 mod 5) == 2
+  ##   ( 7 mod  5) ==  2
+  ##   (-7 mod  5) == -2
+  ##   ( 7 mod -5) ==  2
+  ##   (-7 mod -5) == -2
 
 when defined(nimnomagic64):
   proc `mod`*(x, y: int64): int64 {.magic: "ModI", noSideEffect.}
@@ -1316,6 +1312,23 @@ proc `is`*[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.}
 template `isnot`*(x, y: untyped): untyped = not (x is y)
   ## Negated version of `is`. Equivalent to ``not(x is y)``.
 
+proc new*[T](a: var ref T) {.magic: "New", noSideEffect.}
+  ## creates a new object of type ``T`` and returns a safe (traced)
+  ## reference to it in ``a``.
+
+proc new*(t: typedesc): auto =
+  ## creates a new object of type ``T`` and returns a safe (traced)
+  ## reference to it as result value.
+  ##
+  ## When ``T`` is a ref type then the resulting type will be ``T``,
+  ## otherwise it will be ``ref T``.
+  when (t is ref):
+    var r: t
+  else:
+    var r: ref t
+  new(r)
+  return r
+
 proc `of`*[T, S](x: typeDesc[T], y: typeDesc[S]): bool {.magic: "Of", noSideEffect.}
 proc `of`*[T, S](x: T, y: typeDesc[S]): bool {.magic: "Of", noSideEffect.}
 proc `of`*[T, S](x: T, y: S): bool {.magic: "Of", noSideEffect.}
@@ -1777,35 +1790,35 @@ type # these work for most platforms:
 proc toFloat*(i: int): float {.
   magic: "ToFloat", noSideEffect, importc: "toFloat".}
   ## converts an integer `i` into a ``float``. If the conversion
-  ## fails, `EInvalidValue` is raised. However, on most platforms the
+  ## fails, `ValueError` is raised. However, on most platforms the
   ## conversion cannot fail.
 
 proc toBiggestFloat*(i: BiggestInt): BiggestFloat {.
   magic: "ToBiggestFloat", noSideEffect, importc: "toBiggestFloat".}
   ## converts an biggestint `i` into a ``biggestfloat``. If the conversion
-  ## fails, `EInvalidValue` is raised. However, on most platforms the
+  ## fails, `ValueError` is raised. However, on most platforms the
   ## conversion cannot fail.
 
 proc toInt*(f: float): int {.
   magic: "ToInt", noSideEffect, importc: "toInt".}
   ## converts a floating point number `f` into an ``int``. Conversion
   ## rounds `f` if it does not contain an integer value. If the conversion
-  ## fails (because `f` is infinite for example), `EInvalidValue` is raised.
+  ## fails (because `f` is infinite for example), `ValueError` is raised.
 
 proc toBiggestInt*(f: BiggestFloat): BiggestInt {.
   magic: "ToBiggestInt", noSideEffect, importc: "toBiggestInt".}
   ## converts a biggestfloat `f` into a ``biggestint``. Conversion
   ## rounds `f` if it does not contain an integer value. If the conversion
-  ## fails (because `f` is infinite for example), `EInvalidValue` is raised.
+  ## fails (because `f` is infinite for example), `ValueError` is raised.
 
-proc addQuitProc*(QuitProc: proc() {.noconv.}) {.
+proc addQuitProc*(quitProc: proc() {.noconv.}) {.
   importc: "atexit", header: "<stdlib.h>".}
   ## Adds/registers a quit procedure.
   ##
   ## Each call to ``addQuitProc`` registers another quit procedure. Up to 30
   ## procedures can be registered. They are executed on a last-in, first-out
   ## basis (that is, the last function registered is the first to be executed).
-  ## ``addQuitProc`` raises an EOutOfIndex exception if ``QuitProc`` cannot be
+  ## ``addQuitProc`` raises an EOutOfIndex exception if ``quitProc`` cannot be
   ## registered.
 
 # Support for addQuitProc() is done by Ansi C's facilities here.
@@ -2026,11 +2039,11 @@ proc getRefcount*[T](x: seq[T]): int {.importc: "getRefcount", noSideEffect,
 
 
 const
-  Inf* {.magic: "Inf".} = 1.0 / 0.0
+  Inf* = 0x7FF0000000000000'f64
     ## contains the IEEE floating point value of positive infinity.
-  NegInf* {.magic: "NegInf".} = -Inf
+  NegInf* = 0xFFF0000000000000'f64
     ## contains the IEEE floating point value of negative infinity.
-  NaN* {.magic: "NaN".} = 0.0 / 0.0
+  NaN* = 0x7FF7FFFFFFFFFFFF'f64
     ## contains an IEEE floating point value of *Not A Number*. Note
     ## that you cannot compare a floating point value to this value
     ## and expect a reasonable result - use the `classify` procedure
@@ -2041,7 +2054,7 @@ const
   NimMinor* {.intdefine.}: int = 19
     ## is the minor number of Nim's version.
 
-  NimPatch* {.intdefine.}: int = 1
+  NimPatch* {.intdefine.}: int = 9
     ## is the patch number of Nim's version.
 
   NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
@@ -2075,6 +2088,8 @@ when not defined(nimscript) and hasAlloc:
       ## returns the number of bytes on the shared heap that are owned by the
       ## process. This is only available when threads are enabled.
 
+proc `|`*(a, b: typedesc): typedesc = discard
+
 when sizeof(int) <= 2:
   type IntLikeForCount = int|int8|int16|char|bool|uint8|enum
 else:
@@ -2177,10 +2192,14 @@ else:
         inc(res)
 
 
-iterator `||`*[S, T](a: S, b: T, annotation=""): T {.
+iterator `||`*[S, T](a: S, b: T, annotation: static string = "parallel for"): T {.
   inline, magic: "OmpParFor", sideEffect.} =
-  ## parallel loop iterator. Same as `..` but the loop may run in parallel.
+  ## OpenMP parallel loop iterator. Same as `..` but the loop may run in parallel.
   ## `annotation` is an additional annotation for the code generator to use.
+  ## The default annotation is `parallel for`.
+  ## Please refer to the `OpenMP Syntax Reference<https://www.openmp.org/wp-content/uploads/OpenMP-4.5-1115-CPP-web.pdf>`_
+  ## for further information.
+  ##
   ## Note that the compiler maps that to
   ## the ``#pragma omp parallel for`` construct of `OpenMP`:idx: and as
   ## such isn't aware of the parallelism in your code! Be careful! Later
@@ -2232,10 +2251,10 @@ proc min*(x, y: float): float {.magic: "MinF64", noSideEffect.} =
 proc max*(x, y: float): float {.magic: "MaxF64", noSideEffect.} =
   if y <= x: x else: y
 
-proc min*[T](x, y: T): T =
+proc min*[T](x, y: T): T {.inline.}=
   if x <= y: x else: y
 
-proc max*[T](x, y: T): T =
+proc max*[T](x, y: T): T {.inline.}=
   if y <= x: x else: y
 {.pop.}
 
@@ -2503,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:
@@ -2621,6 +2641,16 @@ proc `<`*[T: tuple](x, y: T): bool =
     if c > 0: return false
   return false
 
+proc compiles*(x: untyped): bool {.magic: "Compiles", noSideEffect, compileTime.} =
+  ## Special compile-time procedure that checks whether `x` can be compiled
+  ## without any semantic error.
+  ## This can be used to check whether a type supports some operation:
+  ##
+  ## .. code-block:: Nim
+  ##   when compiles(3 + 4):
+  ##     echo "'+' for integers is available"
+  discard
+
 proc `$`*[T: tuple|object](x: T): string =
   ## generic ``$`` operator for tuples that is lifted from the components
   ## of `x`. Example:
@@ -2963,7 +2993,7 @@ when defined(nimnomagic64):
     ## returns the absolute value of `x`. If `x` is ``low(x)`` (that
     ## is -MININT for its type), an overflow exception is thrown (if overflow
     ## checking is turned on).
-    if x < 0: -x else: x
+    result = if x < 0: -x else: x
 else:
   proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.} =
     ## returns the absolute value of `x`. If `x` is ``low(x)`` (that
@@ -2973,8 +3003,8 @@ else:
 {.pop.}
 
 when not defined(JS):
-  proc likely_proc(val: bool): bool {.importc: "likely", nodecl, nosideeffect.}
-  proc unlikely_proc(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.}
+  proc likelyProc(val: bool): bool {.importc: "likely", nodecl, nosideeffect.}
+  proc unlikelyProc(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.}
 
 template likely*(val: bool): bool =
   ## Hints the optimizer that `val` is likely going to be true.
@@ -2998,7 +3028,7 @@ template likely*(val: bool): bool =
     when defined(JS):
       val
     else:
-      likely_proc(val)
+      likelyProc(val)
 
 template unlikely*(val: bool): bool =
   ## Hints the optimizer that `val` is likely going to be false.
@@ -3022,7 +3052,7 @@ template unlikely*(val: bool): bool =
     when defined(JS):
       val
     else:
-      unlikely_proc(val)
+      unlikelyProc(val)
 
 type
   FileSeekPos* = enum ## Position relative to which seek should happen
@@ -3431,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
 
@@ -3466,7 +3497,7 @@ when not defined(JS): #and not defined(nimscript):
     iterator lines*(filename: string): TaintedString {.tags: [ReadIOEffect].} =
       ## Iterates over any line in the file named `filename`.
       ##
-      ## If the file does not exist `EIO` is raised. The trailing newline
+      ## If the file does not exist `IOError` is raised. The trailing newline
       ## character(s) are removed from the iterated lines. Example:
       ##
       ## .. code-block:: nim
@@ -3988,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
@@ -3998,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
@@ -4008,8 +4042,6 @@ type
   NimNode* {.magic: "PNimrodNode".} = ref NimNodeObj
     ## represents a Nim AST node. Macros operate on this type.
 
-{.deprecated: [PNimrodNode: NimNode].}
-
 when false:
   template eval*(blk: typed): typed =
     ## executes a block of code at compile time just as if it was a macro
@@ -4032,16 +4064,6 @@ when hasAlloc:
       x[j+i] = item[j]
       inc(j)
 
-proc compiles*(x: untyped): bool {.magic: "Compiles", noSideEffect, compileTime.} =
-  ## Special compile-time procedure that checks whether `x` can be compiled
-  ## without any semantic error.
-  ## This can be used to check whether a type supports some operation:
-  ##
-  ## .. code-block:: Nim
-  ##   when compiles(3 + 4):
-  ##     echo "'+' for integers is available"
-  discard
-
 when declared(initDebugger):
   initDebugger()
 
@@ -4189,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/ansi_c.nim b/lib/system/ansi_c.nim
index 67e42c0af..38910dbd6 100644
--- a/lib/system/ansi_c.nim
+++ b/lib/system/ansi_c.nim
@@ -50,7 +50,8 @@ when defined(windows):
     SIGTERM = cint(15)
 elif defined(macosx) or defined(linux) or defined(freebsd) or
      defined(openbsd) or defined(netbsd) or defined(solaris) or
-     defined(dragonfly) or defined(nintendoswitch) or defined(genode):
+     defined(dragonfly) or defined(nintendoswitch) or defined(genode) or
+     defined(aix):
   const
     SIGABRT = cint(6)
     SIGFPE = cint(8)
diff --git a/lib/system/atomics.nim b/lib/system/atomics.nim
index 56ebde823..b41b4009a 100644
--- a/lib/system/atomics.nim
+++ b/lib/system/atomics.nim
@@ -40,7 +40,6 @@ when someGcc and hasThreadSupport:
   type
     AtomType* = SomeNumber|pointer|ptr|char|bool
       ## Type Class representing valid types for use with atomic procs
-  {.deprecated: [TAtomType: AtomType].}
 
   proc atomicLoadN*[T: AtomType](p: ptr T, mem: AtomMemModel): T {.
     importc: "__atomic_load_n", nodecl.}
diff --git a/lib/system/cellsets.nim b/lib/system/cellsets.nim
index f26cb86ab..d56de06bb 100644
--- a/lib/system/cellsets.nim
+++ b/lib/system/cellsets.nim
@@ -39,8 +39,7 @@ type
   CellSeq {.final, pure.} = object
     len, cap: int
     d: PCellArray
-{.deprecated: [TCell: Cell, TBitIndex: BitIndex, TPageDesc: PageDesc,
-              TRefCount: RefCount, TCellSet: CellSet, TCellSeq: CellSeq].}
+
 # ------------------- cell seq handling ---------------------------------------
 
 proc contains(s: CellSeq, c: PCell): bool {.inline.} =
diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim
index d3651f659..6f4e8ce37 100644
--- a/lib/system/chcks.nim
+++ b/lib/system/chcks.nim
@@ -8,6 +8,7 @@
 #
 
 # Implementation of some runtime checks.
+import system/helpers2
 
 proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} =
   when hostOS == "standalone":
@@ -15,6 +16,12 @@ proc raiseRangeError(val: BiggestInt) {.compilerproc, noinline.} =
   else:
     sysFatal(RangeError, "value out of range: ", $val)
 
+proc raiseIndexError3(i, a, b: int) {.compilerproc, noinline.} =
+  sysFatal(IndexError, formatErrorIndexBound(i, a, b))
+
+proc raiseIndexError2(i, n: int) {.compilerproc, noinline.} =
+  sysFatal(IndexError, formatErrorIndexBound(i, n))
+
 proc raiseIndexError() {.compilerproc, noinline.} =
   sysFatal(IndexError, "index out of bounds")
 
@@ -25,7 +32,7 @@ proc chckIndx(i, a, b: int): int =
   if i >= a and i <= b:
     return i
   else:
-    raiseIndexError()
+    raiseIndexError3(i, a, b)
 
 proc chckRange(i, a, b: int): int =
   if i >= a and i <= b:
diff --git a/lib/system/debugger.nim b/lib/system/debugger.nim
index 937c0d6f0..fd0ae2399 100644
--- a/lib/system/debugger.nim
+++ b/lib/system/debugger.nim
@@ -23,7 +23,6 @@ type
                            # except for the global data description.
     f: TFrame
     slots: array[0..10_000, VarSlot]
-{.deprecated: [TVarSlot: VarSlot, TExtendedFrame: ExtendedFrame].}
 
 var
   dbgGlobalData: ExtendedFrame  # this reserves much space, but
@@ -156,7 +155,6 @@ type
     address: pointer
     typ: PNimType
     oldValue: Hash
-{.deprecated: [THash: Hash, TWatchpoint: Watchpoint].}
 
 var
   watchpoints: array[0..99, Watchpoint]
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/endb.nim b/lib/system/endb.nim
index d51ae29df..257ee3fea 100644
--- a/lib/system/endb.nim
+++ b/lib/system/endb.nim
@@ -35,8 +35,6 @@ type
     dbSkipCurrent,
     dbQuiting,    # debugger wants to quit
     dbBreakpoints # debugger is only interested in breakpoints
-{.deprecated: [TStaticStr: StaticStr, TBreakpointFilename: BreakpointFilename,
-              TDbgState: DbgState].}
 
 var
   dbgUser: StaticStr    # buffer for user input; first command is ``step_into``
diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim
index 7d5f5af7f..84a1da343 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 {.
@@ -60,7 +67,7 @@ var
     # list of exception handlers
     # a global variable for the root of all try blocks
   currException {.threadvar.}: ref Exception
-  raise_counter {.threadvar.}: uint
+  raiseCounter {.threadvar.}: uint
 
   gcFramePtr {.threadvar.}: GcFrame
 
@@ -122,12 +129,12 @@ proc popCurrentException {.compilerRtl, inl.} =
 
 proc popCurrentExceptionEx(id: uint) {.compilerRtl.} =
   # in cpp backend exceptions can pop-up in the different order they were raised, example #5628
-  if currException.raise_id == id:
+  if currException.raiseId == id:
     currException = currException.up
   else:
     var cur = currException.up
     var prev = currException
-    while cur != nil and cur.raise_id != id:
+    while cur != nil and cur.raiseId != id:
       prev = cur
       cur = cur.up
     if cur == nil:
@@ -345,10 +352,10 @@ proc raiseExceptionAux(e: ref Exception) =
       quitOrDebug()
     else:
       pushCurrentException(e)
-      raise_counter.inc
-      if raise_counter == 0:
-        raise_counter.inc # skip zero at overflow
-      e.raise_id = raise_counter
+      raiseCounter.inc
+      if raiseCounter == 0:
+        raiseCounter.inc # skip zero at overflow
+      e.raiseId = raiseCounter
       {.emit: "`e`->raise();".}
   else:
     if excHandler != nil:
@@ -381,6 +388,8 @@ proc raiseExceptionAux(e: ref Exception) =
           xadd(buf, s, s.len)
         var buf: array[0..2000, char]
         var L = 0
+        if e.trace.len != 0:
+          add(buf, $e.trace) # gc allocation
         add(buf, "Error: unhandled exception: ")
         add(buf, e.msg)
         add(buf, " [")
@@ -394,7 +403,7 @@ proc raiseExceptionAux(e: ref Exception) =
           showErrorMessage(tbuf())
           quitOrDebug()
 
-proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} =
+proc raiseExceptionEx(e: ref Exception, ename, procname, filename: cstring, line: int) {.compilerRtl.} =
   if e.name.isNil: e.name = ename
   when hasSomeStackTrace:
     if e.trace.len == 0:
@@ -403,8 +412,14 @@ proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} =
       e.trace.add reraisedFrom(reraisedFromBegin)
       auxWriteStackTrace(framePtr, e.trace)
       e.trace.add reraisedFrom(reraisedFromEnd)
+  else:
+    if procname != nil and filename != nil:
+      e.trace.add StackTraceEntry(procname: procname, filename: filename, line: line)
   raiseExceptionAux(e)
 
+proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} =
+  raiseExceptionEx(e, ename, nil, nil, 0)
+
 proc reraiseException() {.compilerRtl.} =
   if currException == nil:
     sysFatal(ReraiseError, "no exception to reraise")
@@ -439,16 +454,21 @@ when not defined(gcDestructors):
     shallowCopy(result, e.trace)
 
 when defined(nimRequiresNimFrame):
-  proc stackOverflow() {.noinline.} =
+  const nimCallDepthLimit {.intdefine.} = 2000
+
+  proc callDepthLimitReached() {.noinline.} =
     writeStackTrace()
-    showErrorMessage("Stack overflow\n")
+    showErrorMessage("Error: call depth limit reached in a debug build (" &
+        $nimCallDepthLimit & " function calls). You can change it with " &
+        "-d:nimCallDepthLimit=<int> but really try to avoid deep " &
+        "recursions instead.\n")
     quitOrDebug()
 
   proc nimFrame(s: PFrame) {.compilerRtl, inl, exportc: "nimFrame".} =
     s.calldepth = if framePtr == nil: 0 else: framePtr.calldepth+1
     s.prev = framePtr
     framePtr = s
-    if s.calldepth == 2000: stackOverflow()
+    if s.calldepth == nimCallDepthLimit: callDepthLimitReached()
 else:
   proc pushFrame(s: PFrame) {.compilerRtl, inl, exportc: "nimFrame".} =
     # XXX only for backwards compatibility
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_common.nim b/lib/system/gc_common.nim
index c9866164e..565453298 100644
--- a/lib/system/gc_common.nim
+++ b/lib/system/gc_common.nim
@@ -157,46 +157,6 @@ else:
   iterator items(first: var GcStack): ptr GcStack = yield addr(first)
   proc len(stack: var GcStack): int = 1
 
-proc stackSize(stack: ptr GcStack): int {.noinline.} =
-  when nimCoroutines:
-    var pos = stack.pos
-  else:
-    var pos {.volatile.}: pointer
-    pos = addr(pos)
-
-  if pos != nil:
-    when defined(stackIncreases):
-      result = cast[ByteAddress](pos) -% cast[ByteAddress](stack.bottom)
-    else:
-      result = cast[ByteAddress](stack.bottom) -% cast[ByteAddress](pos)
-  else:
-    result = 0
-
-proc stackSize(): int {.noinline.} =
-  for stack in gch.stack.items():
-    result = result + stack.stackSize()
-
-when nimCoroutines:
-  proc setPosition(stack: ptr GcStack, position: pointer) =
-    stack.pos = position
-    stack.maxStackSize = max(stack.maxStackSize, stack.stackSize())
-
-  proc setPosition(stack: var GcStack, position: pointer) =
-    setPosition(addr(stack), position)
-
-  proc getActiveStack(gch: var GcHeap): ptr GcStack =
-    return gch.activeStack
-
-  proc isActiveStack(stack: ptr GcStack): bool =
-    return gch.activeStack == stack
-else:
-  # Stack positions do not need to be tracked if coroutines are not used.
-  proc setPosition(stack: ptr GcStack, position: pointer) = discard
-  proc setPosition(stack: var GcStack, position: pointer) = discard
-  # There is just one stack - main stack of the thread. It is active always.
-  proc getActiveStack(gch: var GcHeap): ptr GcStack = addr(gch.stack)
-  proc isActiveStack(stack: ptr GcStack): bool = true
-
 when declared(threadType):
   proc setupForeignThreadGc*() {.gcsafe.} =
     ## Call this if you registered a callback that will be run from a thread not
@@ -246,6 +206,46 @@ elif defined(hppa) or defined(hp9000) or defined(hp9000s300) or
 else:
   const stackIncreases = false
 
+proc stackSize(stack: ptr GcStack): int {.noinline.} =
+  when nimCoroutines:
+    var pos = stack.pos
+  else:
+    var pos {.volatile.}: pointer
+    pos = addr(pos)
+
+  if pos != nil:
+    when stackIncreases:
+      result = cast[ByteAddress](pos) -% cast[ByteAddress](stack.bottom)
+    else:
+      result = cast[ByteAddress](stack.bottom) -% cast[ByteAddress](pos)
+  else:
+    result = 0
+
+proc stackSize(): int {.noinline.} =
+  for stack in gch.stack.items():
+    result = result + stack.stackSize()
+
+when nimCoroutines:
+  proc setPosition(stack: ptr GcStack, position: pointer) =
+    stack.pos = position
+    stack.maxStackSize = max(stack.maxStackSize, stack.stackSize())
+
+  proc setPosition(stack: var GcStack, position: pointer) =
+    setPosition(addr(stack), position)
+
+  proc getActiveStack(gch: var GcHeap): ptr GcStack =
+    return gch.activeStack
+
+  proc isActiveStack(stack: ptr GcStack): bool =
+    return gch.activeStack == stack
+else:
+  # Stack positions do not need to be tracked if coroutines are not used.
+  proc setPosition(stack: ptr GcStack, position: pointer) = discard
+  proc setPosition(stack: var GcStack, position: pointer) = discard
+  # There is just one stack - main stack of the thread. It is active always.
+  proc getActiveStack(gch: var GcHeap): ptr GcStack = addr(gch.stack)
+  proc isActiveStack(stack: ptr GcStack): bool = true
+
 {.push stack_trace: off.}
 when nimCoroutines:
   proc GC_addStack(bottom: pointer) {.cdecl, exportc.} =
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/helpers2.nim b/lib/system/helpers2.nim
new file mode 100644
index 000000000..1c9e7c068
--- /dev/null
+++ b/lib/system/helpers2.nim
@@ -0,0 +1,5 @@
+template formatErrorIndexBound*[T](i, a, b: T): string =
+  "index out of bounds: (a:" & $a & ") <= (i:" & $i & ") <= (b:" & $b & ") "
+
+template formatErrorIndexBound*[T](i, n: T): string =
+  "index out of bounds: (i:" & $i & ") <= (n:" & $n & ") "
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
index 836ac198d..8be19e5b8 100644
--- a/lib/system/jssys.nim
+++ b/lib/system/jssys.nim
@@ -228,6 +228,7 @@ proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} =
 
 proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
   asm """
+  if (`s` === null) return "";
   var len = `s`.length;
   var asciiPart = new Array(len);
   var fcc = String.fromCharCode;
@@ -330,6 +331,8 @@ proc cmp(x, y: string): int =
 proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerProc.} =
   asm """
     if (`a` == `b`) return true;
+    if (`a` === null && `b`.length == 0) return true;
+    if (`b` === null && `a`.length == 0) return true;
     if ((!`a`) || (!`b`)) return false;
     var alen = `a`.length;
     if (alen != `b`.length) return false;
@@ -516,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 9a7af0a28..89bc11d2c 100644
--- a/lib/system/mmdisp.nim
+++ b/lib/system/mmdisp.nim
@@ -37,7 +37,6 @@ type
   ByteArray = UncheckedArray[byte]
   PByte = ptr ByteArray
   PString = ptr string
-{.deprecated: [TByteArray: ByteArray].}
 
 # Page size of the system; in most cases 4096 bytes. For exotic OS or
 # CPU this needs to be changed:
@@ -171,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
@@ -327,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
@@ -417,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
@@ -474,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/nimscript.nim b/lib/system/nimscript.nim
index 0adc7a83c..fc4b574e4 100644
--- a/lib/system/nimscript.nim
+++ b/lib/system/nimscript.nim
@@ -32,7 +32,7 @@ proc listFiles*(dir: string): seq[string] =
   ## Lists all the files (non-recursively) in the directory `dir`.
   builtin
 
-proc removeDir(dir: string){.
+proc removeDir(dir: string) {.
   tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin
 proc removeFile(dir: string) {.
   tags: [ReadIOEffect, WriteIOEffect], raises: [OSError].} = builtin
diff --git a/lib/system/profiler.nim b/lib/system/profiler.nim
index 7146500d9..ffd6fd0c5 100644
--- a/lib/system/profiler.nim
+++ b/lib/system/profiler.nim
@@ -23,7 +23,6 @@ type
     lines*: array[0..MaxTraceLen-1, cstring]
     files*: array[0..MaxTraceLen-1, cstring]
   ProfilerHook* = proc (st: StackTrace) {.nimcall.}
-{.deprecated: [TStackTrace: StackTrace, TProfilerHook: ProfilerHook].}
 
 proc `[]`*(st: StackTrace, i: int): cstring = st.lines[i]
 
diff --git a/lib/system/repr.nim b/lib/system/repr.nim
index ce7c349bd..ff8f92404 100644
--- a/lib/system/repr.nim
+++ b/lib/system/repr.nim
@@ -127,7 +127,6 @@ type
       marked: CellSet
     recdepth: int       # do not recurse endlessly
     indent: int         # indentation
-{.deprecated: [TReprClosure: ReprClosure].}
 
 when not defined(useNimRtl):
   proc initReprClosure(cl: var ReprClosure) =
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/lib/system/sets.nim b/lib/system/sets.nim
index 53d222468..a5f6c5de9 100644
--- a/lib/system/sets.nim
+++ b/lib/system/sets.nim
@@ -11,7 +11,6 @@
 
 type
   NimSet = array[0..4*2048-1, uint8]
-{.deprecated: [TNimSet: NimSet].}
 
 proc countBits32(n: int32): int {.compilerproc.} =
   var v = n
diff --git a/lib/system/syslocks.nim b/lib/system/syslocks.nim
index 6569f4f9f..fa4164b95 100644
--- a/lib/system/syslocks.nim
+++ b/lib/system/syslocks.nim
@@ -26,8 +26,6 @@ when defined(Windows):
 
     SysCond = Handle
 
-  {.deprecated: [THandle: Handle, TSysLock: SysLock, TSysCond: SysCond].}
-
   proc initSysLock(L: var SysLock) {.importc: "InitializeCriticalSection",
                                      header: "<windows.h>".}
     ## Initializes the lock `L`.
diff --git a/lib/system/threads.nim b/lib/system/threads.nim
index aaf0164fd..f89de4376 100644
--- a/lib/system/threads.nim
+++ b/lib/system/threads.nim
@@ -57,7 +57,6 @@ when defined(windows):
   type
     SysThread* = Handle
     WinThreadProc = proc (x: pointer): int32 {.stdcall.}
-  {.deprecated: [TSysThread: SysThread].}
 
   proc createThread(lpThreadAttributes: pointer, dwStackSize: int32,
                      lpStartAddress: WinThreadProc,
@@ -198,8 +197,6 @@ else:
     Timespec {.importc: "struct timespec", header: "<time.h>".} = object
       tv_sec: Time
       tv_nsec: clong
-  {.deprecated: [TSysThread: SysThread, Tpthread_attr: PThreadAttr,
-                Ttimespec: Timespec, TThreadVarSlot: ThreadVarSlot].}
 
   proc pthread_attr_init(a1: var PthreadAttr) {.
     importc, header: pthreadh.}
@@ -277,7 +274,6 @@ type
       stackSize: int
     else:
       nil
-{.deprecated: [TThreadLocalStorage: ThreadLocalStorage, TGcThread: GcThread].}
 
 when not defined(useNimRtl):
   when not useStackMaskHack:
@@ -382,8 +378,6 @@ type
       dataFn: proc (m: TArg) {.nimcall, gcsafe.}
       data: TArg
 
-{.deprecated: [TThread: Thread].}
-
 var
   threadDestructionHandlers {.rtlThreadVar.}: seq[proc () {.closure, gcsafe.}]
 
diff --git a/lib/system/timers.nim b/lib/system/timers.nim
index f2ebad2c1..dd8350e2d 100644
--- a/lib/system/timers.nim
+++ b/lib/system/timers.nim
@@ -13,7 +13,6 @@
 type
   Ticks = distinct int64
   Nanos = int64
-{.deprecated: [TTicks: Ticks, TNanos: Nanos].}
 
 when defined(windows):
 
@@ -38,7 +37,6 @@ elif defined(macosx):
         importc: "mach_timebase_info_data_t",
         header: "<mach/mach_time.h>".} = object
       numer, denom: int32
-  {.deprecated: [TMachTimebaseInfoData: MachTimebaseInfoData].}
 
   proc mach_absolute_time(): int64 {.importc, header: "<mach/mach.h>".}
   proc mach_timebase_info(info: var MachTimebaseInfoData) {.importc,
@@ -61,7 +59,6 @@ elif defined(posixRealtime):
                final, pure.} = object ## struct timespec
       tv_sec: int  ## Seconds.
       tv_nsec: int ## Nanoseconds.
-  {.deprecated: [TClockid: Clockid, TTimeSpec: TimeSpec].}
 
   var
     CLOCK_REALTIME {.importc: "CLOCK_REALTIME", header: "<time.h>".}: Clockid
@@ -89,7 +86,7 @@ else:
                final, pure.} = object ## struct timeval
       tv_sec: Time  ## Seconds.
       tv_usec: clong ## Microseconds.
-  {.deprecated: [Ttimeval: Timeval].}
+
   proc posix_gettimeofday(tp: var Timeval, unused: pointer = nil) {.
     importc: "gettimeofday", header: "<sys/time.h>".}
 
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index beb60332b..3e37b824c 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -22,10 +22,8 @@ const
 
 when useWinUnicode:
   type WinChar* = Utf16Char
-  {.deprecated: [TWinChar: WinChar].}
 else:
   type WinChar* = char
-  {.deprecated: [TWinChar: WinChar].}
 
 type
   Handle* = int
@@ -96,10 +94,6 @@ type
     dwPlatformId*: DWORD
     szCSDVersion*: array[0..127, WinChar]
 
-{.deprecated: [THandle: Handle, TSECURITY_ATTRIBUTES: SECURITY_ATTRIBUTES,
-    TSTARTUPINFO: STARTUPINFO, TPROCESS_INFORMATION: PROCESS_INFORMATION,
-    TFILETIME: FILETIME, TBY_HANDLE_FILE_INFORMATION: BY_HANDLE_FILE_INFORMATION].}
-
 const
   STARTF_USESHOWWINDOW* = 1'i32
   STARTF_USESTDHANDLES* = 256'i32
@@ -327,7 +321,6 @@ type
     dwReserved1: int32
     cFileName*: array[0..(MAX_PATH) - 1, WinChar]
     cAlternateFileName*: array[0..13, WinChar]
-{.deprecated: [TWIN32_FIND_DATA: WIN32_FIND_DATA].}
 
 when useWinUnicode:
   proc findFirstFileW*(lpFileName: WideCString,
@@ -453,7 +446,6 @@ proc wsaGetLastError*(): cint {.importc: "WSAGetLastError", dynlib: ws2dll.}
 
 type
   SocketHandle* = distinct int
-{.deprecated: [TSocketHandle: SocketHandle].}
 
 type
   WSAData* {.importc: "WSADATA", header: "winsock2.h".} = object
@@ -538,11 +530,6 @@ type
     ai_next*: ptr AddrInfo ## Pointer to next in list.
 
   SockLen* = cuint
-{.deprecated: [TSockaddr_in: Sockaddr_in, TAddrinfo: AddrInfo,
-    TSockAddr: SockAddr, TSockLen: SockLen, TTimeval: Timeval,
-    TWSADATA: WSADATA, Thostent: Hostent, TServent: Servent,
-    TInAddr: InAddr, Tin6_addr: In6_addr, Tsockaddr_in6: Sockaddr_in6,
-    Tsockaddr_in6_old: Sockaddr_in6_old].}
 
 
 var
@@ -668,7 +655,6 @@ const
 type
   WOHandleArray* = array[0..MAXIMUM_WAIT_OBJECTS - 1, Handle]
   PWOHandleArray* = ptr WOHandleArray
-{.deprecated: [TWOHandleArray: WOHandleArray].}
 
 proc waitForMultipleObjects*(nCount: DWORD, lpHandles: PWOHandleArray,
                              bWaitAll: WINBOOL, dwMilliseconds: DWORD): DWORD{.
@@ -798,7 +784,6 @@ type
     D2*: int16
     D3*: int16
     D4*: array[0..7, int8]
-{.deprecated: [TOVERLAPPED: OVERLAPPED, TGUID: GUID].}
 
 const
   ERROR_IO_PENDING* = 997 # a.k.a WSA_IO_PENDING
@@ -1101,7 +1086,7 @@ proc ConvertThreadToFiber*(param: pointer): pointer {.stdcall, discardable, dynl
 proc ConvertThreadToFiberEx*(param: pointer, flags: int32): pointer {.stdcall, discardable, dynlib: "kernel32", importc.}
 proc DeleteFiber*(fiber: pointer): void {.stdcall, discardable, dynlib: "kernel32", importc.}
 proc SwitchToFiber*(fiber: pointer): void {.stdcall, discardable, dynlib: "kernel32", importc.}
-proc GetCurrentFiber*(): pointer {.stdcall, importc, header: "Windows.h".}
+proc GetCurrentFiber*(): pointer {.stdcall, importc, header: "windows.h".}
 
 proc toFILETIME*(t: int64): FILETIME =
   ## Convert the Windows file time timestamp ``t`` to ``FILETIME``.
diff --git a/lib/wrappers/odbcsql.nim b/lib/wrappers/odbcsql.nim
index 43d1c504d..3b022290b 100644
--- a/lib/wrappers/odbcsql.nim
+++ b/lib/wrappers/odbcsql.nim
@@ -60,17 +60,6 @@ type
   PSQLDOUBLE* = ptr TSqlDouble
   PSQLFLOAT* = ptr TSqlFloat
   PSQLHANDLE* = ptr SqlHandle
-{.deprecated: [
-    # TSqlChar: TSqlChar, # Name conflict if we drop`T`
-    # TSqlSmallInt: TSqlSmallInt, # Name conflict if we drop`T`
-    TSqlUSmallInt: SqlUSmallInt, TSqlHandle: SqlHandle, TSqlHEnv: SqlHEnv,
-    TSqlHDBC: SqlHDBC, TSqlHStmt: SqlHStmt, TSqlHDesc: SqlHDesc,
-    # TSqlInteger: TSqlInteger, # Name conflict if we drop `T`
-    TSqlUInteger: SqlUInteger, TSqlPointer: SqlPointer,
-    # TSqlReal: TSqlReal, # Name conflict if we drop`T`
-    # TSqlDouble: TSqlDouble, # Name conflict if we drop`T`
-    # TSqlFloat: TSqlFloat, # Name conflict if we drop `T`
-    TSqlHWND: SqlHWND].}
 
 const                         # SQL data type codes
   SQL_UNKNOWN_TYPE* = 0
diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim
index e1d36e461..2f072d5c7 100644
--- a/lib/wrappers/openssl.nim
+++ b/lib/wrappers/openssl.nim
@@ -38,7 +38,7 @@ when useWinVersion:
 
   from winlean import SocketHandle
 else:
-  const versions = "(.1.1|.38|.39|.41|.43|.44|.45|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|)"
+  const versions = "(.1.1|.38|.39|.41|.43|.44|.45|.46|.10|.1.0.2|.1.0.1|.1.0.0|.0.9.9|.0.9.8|)"
 
   when defined(macosx):
     const
@@ -83,8 +83,6 @@ type
 
   pem_password_cb* = proc(buf: cstring, size, rwflag: cint, userdata: pointer): cint {.cdecl.}
 
-{.deprecated: [PSSL: SslPtr, PSSL_CTX: SslCtx, PBIO: BIO].}
-
 const
   SSL_SENT_SHUTDOWN* = 1
   SSL_RECEIVED_SHUTDOWN* = 2
diff --git a/lib/wrappers/pcre.nim b/lib/wrappers/pcre.nim
index e9e11960c..c4bb24cfd 100644
--- a/lib/wrappers/pcre.nim
+++ b/lib/wrappers/pcre.nim
@@ -466,14 +466,6 @@ proc study*(code: ptr Pcre,
 {.pop.}
 
 
-{.deprecated: [MAJOR: PCRE_MAJOR, MINOR: PCRE_MINOR,
-               PRERELEASE: PCRE_PRERELEASE, DATE: PCRE_DATE].}
-
-{.deprecated: [TPcre: Pcre, TJitStack: JitStack].}
 type
   PPcre* {.deprecated.} = ptr Pcre
   PJitStack* {.deprecated.} = ptr JitStack
-
-{.deprecated: [TExtra: ExtraData].}
-{.deprecated: [TCalloutBlock: CalloutBlock].}
-{.deprecated: [TJitCallback: JitCallback].}
diff --git a/lib/wrappers/postgres.nim b/lib/wrappers/postgres.nim
index 7cb816f68..f38712c0e 100644
--- a/lib/wrappers/postgres.nim
+++ b/lib/wrappers/postgres.nim
@@ -152,10 +152,6 @@ type
     length*: int32
     isint*: int32
     p*: pointer
-{.deprecated: [TSockAddr: SockAddr, TPGresAttDesc: PgresAttDesc,
-      TPGresAttValue: PgresAttValue, TExecStatusType: ExecStatusType,
-      TPGlobjfuncs: Pglobjfuncs, TConnStatusType: ConnStatusType, TPGconn: Pgconn,
-      TPGresult: PGresult].}
 
 proc pqconnectStart*(conninfo: cstring): PPGconn{.cdecl, dynlib: dllName,
     importc: "PQconnectStart".}
diff --git a/lib/wrappers/sqlite3.nim b/lib/wrappers/sqlite3.nim
index 0276a0a65..e4bf2e67b 100644
--- a/lib/wrappers/sqlite3.nim
+++ b/lib/wrappers/sqlite3.nim
@@ -121,12 +121,6 @@ type
                                   para4: int32, para5: pointer): int32{.cdecl.}
   Collation_needed_func* = proc (para1: pointer, para2: PSqlite3, eTextRep: int32,
                                   para4: cstring){.cdecl.}
-{.deprecated: [TSqlite3: Sqlite3, TContext: Context, Tvalue: Value,
-    Tcallback: Callback, Tcreate_function_step_func: Create_function_step_func,
-    Tcreate_function_func_func: Create_function_func_func,
-    Tcreate_function_final_func: Create_function_final_func,
-    Tresult_func: Result_func, Tcreate_collation_func: Create_collation_func,
-    Tcollation_needed_func: Collation_needed_func].}
 
 const
   SQLITE_STATIC* = nil
diff --git a/lib/wrappers/tinyc.nim b/lib/wrappers/tinyc.nim
index f2ce92d36..f29758f13 100644
--- a/lib/wrappers/tinyc.nim
+++ b/lib/wrappers/tinyc.nim
@@ -12,7 +12,6 @@ type
   PccState* = ptr CcState
 
   ErrorFunc* = proc (opaque: pointer, msg: cstring) {.cdecl.}
-{.deprecated: [TccState: CcState, TErrorFunc: ErrorFunc].}
 
 proc openCCState*(): PccState {.importc: "tcc_new", cdecl.}
   ## create a new TCC compilation context
diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html
index e7f9cd508..2c89acce4 100644
--- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html
+++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html
@@ -16,7 +16,7 @@
 <link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
 
 <!-- CSS -->
-<title>Module utils</title>
+<title>utils</title>
 <style type="text/css" >
 /*
 Stylesheet for use with Docutils/rst2html.
@@ -1219,7 +1219,7 @@ function main() {
 <body onload="main()">
 <div class="document" id="documentId">
   <div class="container">
-    <h1 class="title">Module utils</h1>
+    <h1 class="title">utils</h1>
     <div class="row">
   <div class="three columns">
   <div id="global-links">
@@ -1255,6 +1255,16 @@ function main() {
 
   </ul>
 </li>
+<li>
+  <a class="reference reference-toplevel" href="#18" id="68">Templates</a>
+  <ul class="simple simple-toc-section">
+      <li><a class="reference" href="#aEnum.t%2C"
+    title="aEnum(): untyped"><wbr />a<wbr />Enum<span class="attachedType" style="visibility:hidden"></span></a></li>
+  <li><a class="reference" href="#bEnum.t%2C"
+    title="bEnum(): untyped"><wbr />b<wbr />Enum<span class="attachedType" style="visibility:hidden"></span></a></li>
+
+  </ul>
+</li>
 
 </ul>
 
@@ -1285,6 +1295,23 @@ constructor.
 </dd>
 
 </dl></div>
+<div class="section" id="18">
+<h1><a class="toc-backref" href="#18">Templates</a></h1>
+<dl class="item">
+<a id="aEnum.t,"></a>
+<dt><pre><span class="Keyword">template</span> <span class="Identifier">aEnum</span><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
+<dd>
+
+
+</dd>
+<a id="bEnum.t,"></a>
+<dt><pre><span class="Keyword">template</span> <span class="Identifier">bEnum</span><span class="Other">(</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">untyped</span></pre></dt>
+<dd>
+
+
+</dd>
+
+</dl></div>
 
   </div>
 </div>
diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html
index 1d09d809c..2e23a64d5 100644
--- a/nimdoc/testproject/expected/testproject.html
+++ b/nimdoc/testproject/expected/testproject.html
@@ -16,7 +16,7 @@
 <link href='https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600' rel='stylesheet' type='text/css'/>
 
 <!-- CSS -->
-<title>Module testproject</title>
+<title>testproject</title>
 <style type="text/css" >
 /*
 Stylesheet for use with Docutils/rst2html.
@@ -1219,7 +1219,7 @@ function main() {
 <body onload="main()">
 <div class="document" id="documentId">
   <div class="container">
-    <h1 class="title">Module testproject</h1>
+    <h1 class="title">testproject</h1>
     <div class="row">
   <div class="three columns">
   <div id="global-links">
@@ -1245,6 +1245,18 @@ function main() {
   </ul>
 </li>
 <li>
+  <a class="reference reference-toplevel" href="#7" id="57">Types</a>
+  <ul class="simple simple-toc-section">
+      <li><a class="reference" href="#A"
+    title="A {.inject.} = enum
+  aA"><wbr />A<span class="attachedType" style="visibility:hidden"></span></a></li>
+  <li><a class="reference" href="#B"
+    title="B {.inject.} = enum
+  bB"><wbr />B<span class="attachedType" style="visibility:hidden"></span></a></li>
+
+  </ul>
+</li>
+<li>
   <a class="reference reference-toplevel" href="#8" id="58">Vars</a>
   <ul class="simple simple-toc-section">
       <li><a class="reference" href="#aVariable"
@@ -1257,6 +1269,16 @@ function main() {
   <ul class="simple simple-toc-section">
       <li><a class="reference" href="#bar%2CT%2CT"
     title="bar[T](a, b: T): T"><wbr />bar<span class="attachedType" style="visibility:hidden"></span></a></li>
+  <li><a class="reference" href="#isValid%2CT"
+    title="isValid[T](x: T): bool"><wbr />is<wbr />Valid<span class="attachedType" style="visibility:hidden"></span></a></li>
+
+  </ul>
+</li>
+<li>
+  <a class="reference reference-toplevel" href="#13" id="63">Funcs</a>
+  <ul class="simple simple-toc-section">
+      <li><a class="reference" href="#someFunc%2C"
+    title="someFunc()"><wbr />some<wbr />Func<span class="attachedType" style="visibility:hidden"></span></a></li>
 
   </ul>
 </li>
@@ -1294,6 +1316,25 @@ function main() {
 <dl class="item">
 <a class="reference external" href="subdir/subdir_b/utils.html">subdir/subdir_b/utils</a>
 </dl></div>
+<div class="section" id="7">
+<h1><a class="toc-backref" href="#7">Types</a></h1>
+<dl class="item">
+<a id="A"></a>
+<dt><pre><a href="testproject.html#A"><span class="Identifier">A</span></a> <span><span class="Other">{</span><span class="Other pragmadots">...</span><span class="Other">}</span></span><span class="pragmawrap"><span class="Other">{.</span><span class="pragma"><span class="Identifier">inject</span></span><span class="Other">.}</span></span> <span class="Other">=</span> <span class="Keyword">enum</span>
+  <span class="Identifier">aA</span></pre></dt>
+<dd>
+The enum A.
+
+</dd>
+<a id="B"></a>
+<dt><pre><a href="testproject.html#B"><span class="Identifier">B</span></a> <span><span class="Other">{</span><span class="Other pragmadots">...</span><span class="Other">}</span></span><span class="pragmawrap"><span class="Other">{.</span><span class="pragma"><span class="Identifier">inject</span></span><span class="Other">.}</span></span> <span class="Other">=</span> <span class="Keyword">enum</span>
+  <span class="Identifier">bB</span></pre></dt>
+<dd>
+The enum B.
+
+</dd>
+
+</dl></div>
 <div class="section" id="8">
 <h1><a class="toc-backref" href="#8">Vars</a></h1>
 <dl class="item">
@@ -1314,6 +1355,23 @@ function main() {
 
 
 </dd>
+<a id="isValid,T"></a>
+<dt><pre><span class="Keyword">proc</span> <span class="Identifier">isValid</span><span class="Other">[</span><span class="Identifier">T</span><span class="Other">]</span><span class="Other">(</span><span class="Identifier">x</span><span class="Other">:</span> <span class="Identifier">T</span><span class="Other">)</span><span class="Other">:</span> <span class="Identifier">bool</span></pre></dt>
+<dd>
+
+
+</dd>
+
+</dl></div>
+<div class="section" id="13">
+<h1><a class="toc-backref" href="#13">Funcs</a></h1>
+<dl class="item">
+<a id="someFunc,"></a>
+<dt><pre><span class="Keyword">func</span> <span class="Identifier">someFunc</span><span class="Other">(</span><span class="Other">)</span> <span><span class="Other">{</span><span class="Other pragmadots">...</span><span class="Other">}</span></span><span class="pragmawrap"><span class="Other">{.</span><span class="pragma"><span class="Identifier">raises</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span><span class="Other">,</span> <span class="Identifier">tags</span><span class="Other">:</span> <span class="Other">[</span><span class="Other">]</span></span><span class="Other">.}</span></span></pre></dt>
+<dd>
+My someFunc.
+
+</dd>
 
 </dl></div>
 <div class="section" id="17">
diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html
index 865e5a28e..652077be8 100644
--- a/nimdoc/testproject/expected/theindex.html
+++ b/nimdoc/testproject/expected/theindex.html
@@ -1221,16 +1221,32 @@ function main() {
   <div class="container">
     <h1 class="title">Index</h1>
     Modules: <a href="subdir/subdir_b/utils.html">subdir/subdir_b/utils</a>, <a href="testproject.html">testproject</a>.<br/><p /><h2>API symbols</h2>
-<dl><dt><a name="aVariable" href="#aVariable"><span>aVariable:</span></a></dt><dd><ul class="simple">
+<dl><dt><a name="A" href="#A"><span>A:</span></a></dt><dd><ul class="simple">
+<li><a class="reference external"
+          data-doc-search-tag="testproject: A" href="testproject.html#A">testproject: A</a></li>
+          </ul></dd>
+<dt><a name="aEnum" href="#aEnum"><span>aEnum:</span></a></dt><dd><ul class="simple">
+<li><a class="reference external"
+          data-doc-search-tag="utils: aEnum(): untyped" href="subdir/subdir_b/utils.html#aEnum.t%2C">utils: aEnum(): untyped</a></li>
+          </ul></dd>
+<dt><a name="aVariable" href="#aVariable"><span>aVariable:</span></a></dt><dd><ul class="simple">
 <li><a class="reference external"
           data-doc-search-tag="testproject: aVariable" href="testproject.html#aVariable">testproject: aVariable</a></li>
           </ul></dd>
+<dt><a name="B" href="#B"><span>B:</span></a></dt><dd><ul class="simple">
+<li><a class="reference external"
+          data-doc-search-tag="testproject: B" href="testproject.html#B">testproject: B</a></li>
+          </ul></dd>
 <dt><a name="bar" href="#bar"><span>bar:</span></a></dt><dd><ul class="simple">
 <li><a class="reference external"
           data-doc-search-tag="testproject: bar[T](a, b: T): T" href="testproject.html#bar%2CT%2CT">testproject: bar[T](a, b: T): T</a></li>
           <li><a class="reference external"
           data-doc-search-tag="testproject: bar(): untyped" href="testproject.html#bar.m%2C">testproject: bar(): untyped</a></li>
           </ul></dd>
+<dt><a name="bEnum" href="#bEnum"><span>bEnum:</span></a></dt><dd><ul class="simple">
+<li><a class="reference external"
+          data-doc-search-tag="utils: bEnum(): untyped" href="subdir/subdir_b/utils.html#bEnum.t%2C">utils: bEnum(): untyped</a></li>
+          </ul></dd>
 <dt><a name="enumValueA" href="#enumValueA"><span>enumValueA:</span></a></dt><dd><ul class="simple">
 <li><a class="reference external"
           data-doc-search-tag="SomeType.enumValueA" href="subdir/subdir_b/utils.html#enumValueA">SomeType.enumValueA</a></li>
@@ -1247,6 +1263,14 @@ function main() {
 <li><a class="reference external"
           data-doc-search-tag="testproject: foo(a, b: SomeType)" href="testproject.html#foo.t%2CSomeType%2CSomeType">testproject: foo(a, b: SomeType)</a></li>
           </ul></dd>
+<dt><a name="isValid" href="#isValid"><span>isValid:</span></a></dt><dd><ul class="simple">
+<li><a class="reference external"
+          data-doc-search-tag="testproject: isValid[T](x: T): bool" href="testproject.html#isValid%2CT">testproject: isValid[T](x: T): bool</a></li>
+          </ul></dd>
+<dt><a name="someFunc" href="#someFunc"><span>someFunc:</span></a></dt><dd><ul class="simple">
+<li><a class="reference external"
+          data-doc-search-tag="testproject: someFunc()" href="testproject.html#someFunc%2C">testproject: someFunc()</a></li>
+          </ul></dd>
 <dt><a name="SomeType" href="#SomeType"><span>SomeType:</span></a></dt><dd><ul class="simple">
 <li><a class="reference external"
           data-doc-search-tag="utils: SomeType" href="subdir/subdir_b/utils.html#SomeType">utils: SomeType</a></li>
diff --git a/nimdoc/testproject/subdir/subdir_b/utils.nim b/nimdoc/testproject/subdir/subdir_b/utils.nim
index d7d82b3cd..e2ec80dc2 100644
--- a/nimdoc/testproject/subdir/subdir_b/utils.nim
+++ b/nimdoc/testproject/subdir/subdir_b/utils.nim
@@ -8,3 +8,19 @@ type
 proc someType*(): SomeType =
   ## constructor.
   SomeType(2)
+
+# bug #9235
+
+template aEnum*(): untyped =
+  type
+    A* {.inject.} = enum ## The enum A.
+      aA
+
+template bEnum*(): untyped =
+  type
+    B* {.inject.} = enum ## The enum B.
+      bB
+
+  func someFunc*() =
+    ## My someFunc.
+    discard
diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim
index 327466014..d6fac4751 100644
--- a/nimdoc/testproject/testproject.nim
+++ b/nimdoc/testproject/testproject.nim
@@ -22,3 +22,9 @@ macro bar*(): untyped =
   result = newStmtList()
 
 var aVariable*: array[1,int]
+
+aEnum()
+bEnum()
+
+# bug #9432
+proc isValid*[T](x: T): bool = x.len > 0
diff --git a/nimpretty/nimpretty.nim b/nimpretty/nimpretty.nim
index fb2b8637f..628bc163e 100644
--- a/nimpretty/nimpretty.nim
+++ b/nimpretty/nimpretty.nim
@@ -12,7 +12,8 @@
 when not defined(nimpretty):
   {.error: "This needs to be compiled with --define:nimPretty".}
 
-import ../compiler / [idents, msgs, ast, syntaxes, renderer, options, pathutils]
+import ../compiler / [idents, msgs, ast, syntaxes, renderer, options,
+  pathutils, layouter]
 
 import parseopt, strutils, os
 
@@ -26,6 +27,7 @@ Usage:
 Options:
   --backup:on|off     create a backup file before overwritting (default: ON)
   --output:file       set the output file (default: overwrite the .nim file)
+  --indent:N          set the number of spaces that is used for indentation
   --version           show the version
   --help              show this help
 """
@@ -40,12 +42,20 @@ proc writeVersion() =
   stdout.flushFile()
   quit(0)
 
-proc prettyPrint(infile, outfile: string) =
+type
+  PrettyOptions = object
+    indWidth: int
+
+proc prettyPrint(infile, outfile: string, opt: PrettyOptions) =
   var conf = newConfigRef()
   let fileIdx = fileInfoIdx(conf, AbsoluteFile infile)
   conf.outFile = AbsoluteFile outfile
   when defined(nimpretty2):
-    discard parseFile(fileIdx, newIdentCache(), conf)
+    var p: TParsers
+    p.parser.em.indWidth = opt.indWidth
+    if setupParsers(p, fileIdx, newIdentCache(), conf):
+      discard parseAll(p)
+      closeParsers(p)
   else:
     let tree = parseFile(fileIdx, newIdentCache(), conf)
     renderModule(tree, infile, outfile, {}, fileIdx, conf)
@@ -53,6 +63,7 @@ proc prettyPrint(infile, outfile: string) =
 proc main =
   var infile, outfile: string
   var backup = true
+  var opt: PrettyOptions
   for kind, key, val in getopt():
     case kind
     of cmdArgument:
@@ -63,6 +74,7 @@ proc main =
       of "version", "v": writeVersion()
       of "backup": backup = parseBool(val)
       of "output", "o": outfile = val
+      of "indent": opt.indWidth = parseInt(val)
       else: writeHelp()
     of cmdEnd: assert(false) # cannot happen
   if infile.len == 0:
@@ -70,6 +82,6 @@ proc main =
   if backup:
     os.copyFile(source=infile, dest=changeFileExt(infile, ".nim.backup"))
   if outfile.len == 0: outfile = infile
-  prettyPrint(infile, outfile)
+  prettyPrint(infile, outfile, opt)
 
 main()
diff --git a/nimpretty/tester.nim b/nimpretty/tester.nim
index c4e364752..041e7edd8 100644
--- a/nimpretty/tester.nim
+++ b/nimpretty/tester.nim
@@ -15,13 +15,15 @@ when defined(develop):
 else:
   const nimp = "nimpretty"
 
-proc test(infile, outfile: string) =
-  if execShellCmd("$# -o:$# --backup:off $#" % [nimp, outfile, infile]) != 0:
-    quit("FAILURE")
+proc test(infile, ext: string) =
+  if execShellCmd("$# -o:$# --backup:off $#" % [nimp, infile.changeFileExt(ext), infile]) != 0:
+    echo "FAILURE: nimpretty cannot prettify ", infile
+    failures += 1
+    return
   let nimFile = splitFile(infile).name
   let expected = dir / "expected" / nimFile & ".nim"
-  let produced = dir / nimFile & ".pretty"
-  if strip(readFile(expected)) != strip(readFile(produced)):
+  let produced = dir / nimFile.changeFileExt(ext)
+  if readFile(expected) != readFile(produced):
     echo "FAILURE: files differ: ", nimFile
     discard execShellCmd("diff -uNdr " & expected & " " & produced)
     failures += 1
@@ -29,8 +31,12 @@ proc test(infile, outfile: string) =
     echo "SUCCESS: files identical: ", nimFile
 
 for t in walkFiles(dir / "*.nim"):
-  let res = t.changeFileExt("pretty")
-  test(t, res)
-  removeFile(res)
+  test(t, "pretty")
+  # also test that pretty(pretty(x)) == pretty(x)
+  test(t.changeFileExt("pretty"), "pretty2")
+
+  removeFile(t.changeFileExt("pretty"))
+  removeFile(t.changeFileExt("pretty2"))
+
 
 if failures > 0: quit($failures & " failures occurred.")
diff --git a/nimpretty/tests/exhaustive.nim b/nimpretty/tests/exhaustive.nim
index ab58b7da4..9a0f9a49b 100644
--- a/nimpretty/tests/exhaustive.nim
+++ b/nimpretty/tests/exhaustive.nim
@@ -329,3 +329,34 @@ proc getKeyAndData(cursor: int, op: int):
 #!nimpretty on
 
 const test = r"C:\Users\-\Desktop\test.txt"
+
+proc abcdef*[T:not (tuple|object|string|cstring|char|ref|ptr|array|seq|distinct)]() =
+  # bug #9504
+  type T2 = a.type
+  discard
+
+proc fun() =
+  #[
+  this one here
+  ]#
+  discard
+
+proc fun2() =
+  ##[
+  foobar
+  ]##
+  discard
+
+#[
+foobar
+]#
+
+proc fun3() =
+  discard
+
+##[
+foobar
+]##
+
+# bug #9673
+discard `* `(1, 2)
diff --git a/nimpretty/tests/expected/exhaustive.nim b/nimpretty/tests/expected/exhaustive.nim
index b114e9b8c..8ea7ca4dd 100644
--- a/nimpretty/tests/expected/exhaustive.nim
+++ b/nimpretty/tests/expected/exhaustive.nim
@@ -338,3 +338,34 @@ proc getKeyAndData(cursor: int; op: int):
 #!nimpretty on
 
 const test = r"C:\Users\-\Desktop\test.txt"
+
+proc abcdef*[T: not (tuple|object|string|cstring|char|ref|ptr|array|seq|distinct)]() =
+  # bug #9504
+  type T2 = a.type
+  discard
+
+proc fun() =
+  #[
+  this one here
+  ]#
+  discard
+
+proc fun2() =
+  ##[
+  foobar
+  ]##
+  discard
+
+#[
+foobar
+]#
+
+proc fun3() =
+  discard
+
+##[
+foobar
+]##
+
+# bug #9673
+discard `*`(1, 2)
diff --git a/nimpretty/tests/expected/simple.nim b/nimpretty/tests/expected/simple.nim
index 75f570bac..5126658ea 100644
--- a/nimpretty/tests/expected/simple.nim
+++ b/nimpretty/tests/expected/simple.nim
@@ -1,4 +1,13 @@
 
 var x: int = 2
 
-echo x                        # bug #9144
+echo x
+# bug #9144
+
+proc a() =
+  while true:
+    discard
+    # comment 1
+
+  # comment 2
+  discard
diff --git a/nimpretty/tests/expected/simple2.nim b/nimpretty/tests/expected/simple2.nim
index 8d60c4067..909ac48c3 100644
--- a/nimpretty/tests/expected/simple2.nim
+++ b/nimpretty/tests/expected/simple2.nim
@@ -1,3 +1,22 @@
+# comment here
 var x: int = 2
 
 echo x
+
+proc fun*() =
+  echo "ok"
+  ## doc comment
+  # regular comment
+
+proc funB() =
+  echo "ok1"
+  # echo "ok2"
+
+fun()
+
+#[
+bug #9483
+]#
+
+proc funE() =
+  echo "ok1"
diff --git a/nimpretty/tests/expected/simple3.nim b/nimpretty/tests/expected/simple3.nim
new file mode 100644
index 000000000..7f17e0fc6
--- /dev/null
+++ b/nimpretty/tests/expected/simple3.nim
@@ -0,0 +1,16 @@
+
+#[
+foo bar
+]#
+
+
+
+proc fun() =
+  echo "ok1"
+
+proc fun2(a = "fooo" & "bar" & "bar" & "bar" & "bar" & (
+    "bar" & "bar" & "bar") & "bar" & "bar" & "bar" & "bar" & "bar" & "bar" &
+    "bar" & "bar" & "bar"): auto =
+  discard
+
+fun2()
diff --git a/nimpretty/tests/simple.nim b/nimpretty/tests/simple.nim
index 9e3c52f9b..5126658ea 100644
--- a/nimpretty/tests/simple.nim
+++ b/nimpretty/tests/simple.nim
@@ -3,3 +3,11 @@ var x: int = 2
 
 echo x
 # bug #9144
+
+proc a() =
+  while true:
+    discard
+    # comment 1
+
+  # comment 2
+  discard
diff --git a/nimpretty/tests/simple2.nim b/nimpretty/tests/simple2.nim
index 8d60c4067..4ef2ddd70 100644
--- a/nimpretty/tests/simple2.nim
+++ b/nimpretty/tests/simple2.nim
@@ -1,3 +1,22 @@
+# comment here
 var x: int = 2
 
 echo x
+
+proc fun*()=
+  echo "ok"
+  ## doc comment
+  # regular comment
+
+proc funB() =
+  echo "ok1"
+  # echo "ok2"
+
+fun()
+
+#[
+bug #9483
+]#
+
+proc funE() =
+  echo "ok1"
diff --git a/nimpretty/tests/simple3.nim b/nimpretty/tests/simple3.nim
new file mode 100644
index 000000000..bd60ddf39
--- /dev/null
+++ b/nimpretty/tests/simple3.nim
@@ -0,0 +1,14 @@
+
+#[
+foo bar
+]#
+
+
+
+proc fun() =
+  echo "ok1"
+
+proc fun2(a = "fooo" & "bar" & "bar" & "bar" & "bar" & ("bar" & "bar" & "bar") & "bar" & "bar" & "bar" & "bar" & "bar" & "bar" & "bar" & "bar" & "bar"): auto =
+  discard
+
+fun2()
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/nimsuggest/nimsuggest.nim.cfg b/nimsuggest/nimsuggest.nim.cfg
index 820db0dba..394449740 100644
--- a/nimsuggest/nimsuggest.nim.cfg
+++ b/nimsuggest/nimsuggest.nim.cfg
@@ -22,5 +22,3 @@ define:nimcore
 #define:noDocgen
 --path:"$nim"
 --threads:on
---noNimblePath
---path:"../compiler"
diff --git a/readme.txt b/readme.txt
deleted file mode 100644
index 8c6f25b29..000000000
--- a/readme.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-This package contains the Nim compiler, Nim's stdlib, tools and
-documentation.
-
-Nim is a compiled, garbage-collected systems programming language which has
-an excellent productivity/performance ratio. Nim's design focuses on
-efficiency, expressiveness, elegance (in the order of priority).
-
-Read install.txt for instructions of how to build and install it.
-
-The compiler and the standard library are licensed under the MIT license,
-except for some modules where the documentation suggests otherwise. This means
-that you can use any license for your own programs developed with Nim,
-allowing you to create commercial applications.
-
-Read copying.txt for more details.
-
-Copyright (c) 2006-2018 Andreas Rumpf.
-All rights reserved.
diff --git a/testament/backend.nim b/testament/backend.nim
index 385f1171c..c2658d6a0 100644
--- a/testament/backend.nim
+++ b/testament/backend.nim
@@ -20,14 +20,11 @@ var
   thisCommit: CommitId
   thisBranch: string
 
-{.experimental.}
-proc `()`(cmd: string{lit}): string = cmd.execProcess.string.strip
-
 proc getMachine*(): MachineId =
-  var name = "hostname"()
+  var name = execProcess("hostname").string.strip
   if name.len == 0:
-    name = when defined(posix): getenv"HOSTNAME".string
-           else: getenv"COMPUTERNAME".string
+    name = when defined(posix): getenv("HOSTNAME").string
+           else: getenv("COMPUTERNAME").string
   if name.len == 0:
     quit "cannot determine the machine name"
 
@@ -35,8 +32,8 @@ proc getMachine*(): MachineId =
 
 proc getCommit(): CommitId =
   const commLen = "commit ".len
-  let hash = "git log -n 1"()[commLen..commLen+10]
-  thisBranch = "git symbolic-ref --short HEAD"()
+  let hash = execProcess("git log -n 1").string.strip[commLen..commLen+10]
+  thisBranch = execProcess("git symbolic-ref --short HEAD").string.strip
   if hash.len == 0 or thisBranch.len == 0: quit "cannot determine git HEAD"
   result = CommitId(hash)
 
@@ -45,8 +42,7 @@ var
   currentCategory: string
   entries: int
 
-proc writeTestResult*(name, category, target,
-                      action, result, expected, given: string) =
+proc writeTestResult*(name, category, target, action, result, expected, given: string) =
   createDir("testresults")
   if currentCategory != category:
     if currentCategory.len > 0:
diff --git a/testament/categories.nim b/testament/categories.nim
index 429330677..a72602217 100644
--- a/testament/categories.nim
+++ b/testament/categories.nim
@@ -10,6 +10,36 @@
 ## Include for the tester that contains test suites that test special features
 ## of the compiler.
 
+const
+  specialCategories = [
+    "assert",
+    "async",
+    "debugger",
+    "dll",
+    "examples",
+    "flags",
+    "gc",
+    "io",
+    "js",
+    "lib",
+    "longgc",
+    "manyloc",
+    "nimble-all",
+    "nimble-core",
+    "nimble-extra",
+    "niminaction",
+    "rodfiles",
+    "threads",
+    "untestable",
+    "stdlib",
+    "testdata",
+    "nimcache",
+    "coroutines",
+    "osproc",
+    "shouldfail",
+    "dir with space"
+  ]
+
 # included from tester.nim
 # ---------------- ROD file tests ---------------------------------------------
 
@@ -27,7 +57,7 @@ proc delNimCache(filename, options: string) =
 proc runRodFiles(r: var TResults, cat: Category, options: string) =
   template test(filename: string, clearCacheFirst=false) =
     if clearCacheFirst: delNimCache(filename, options)
-    testSpec r, makeTest(rodfilesDir / filename, options, cat, actionRun)
+    testSpec r, makeTest(rodfilesDir / filename, options, cat)
 
 
   # test basic recompilation scheme:
@@ -97,11 +127,12 @@ 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)
-
+  var test1 = makeTest("lib/nimrtl.nim", options & " --app:lib -d:createNimRtl --threads:on", cat)
+  test1.spec.action = actionCompile
+  testSpec c, test1
+  var test2 = makeTest("tests/dll/server.nim", options & " --app:lib -d:useNimRtl --threads:on" & rpath, cat)
+  test2.spec.action = actionCompile
+  testSpec c, test2
 
   when defined(Windows):
     # windows looks in the dir of the exe (yay!):
@@ -121,7 +152,7 @@ proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) =
     safeCopyFile("lib" / nimrtlDll, "tests/dll" / nimrtlDll)
 
   testSpec r, makeTest("tests/dll/client.nim", options & " -d:useNimRtl --threads:on" & rpath,
-                       cat, actionRun)
+                       cat)
 
 proc dllTests(r: var TResults, cat: Category, options: string) =
   # dummy compile result:
@@ -139,32 +170,32 @@ proc dllTests(r: var TResults, cat: Category, options: string) =
 proc gcTests(r: var TResults, cat: Category, options: string) =
   template testWithNone(filename: untyped) =
     testSpec r, makeTest("tests/gc" / filename, options &
-                  " --gc:none", cat, actionRun)
+                  " --gc:none", cat)
     testSpec r, makeTest("tests/gc" / filename, options &
-                  " -d:release --gc:none", cat, actionRun)
+                  " -d:release --gc:none", cat)
 
   template testWithoutMs(filename: untyped) =
-    testSpec r, makeTest("tests/gc" / filename, options, cat, actionRun)
+    testSpec r, makeTest("tests/gc" / filename, options, cat)
     testSpec r, makeTest("tests/gc" / filename, options &
-                  " -d:release", cat, actionRun)
+                  " -d:release", cat)
     testSpec r, makeTest("tests/gc" / filename, options &
-                  " -d:release -d:useRealtimeGC", cat, actionRun)
+                  " -d:release -d:useRealtimeGC", cat)
 
   template testWithoutBoehm(filename: untyped) =
     testWithoutMs filename
     testSpec r, makeTest("tests/gc" / filename, options &
-                  " --gc:markAndSweep", cat, actionRun)
+                  " --gc:markAndSweep", cat)
     testSpec r, makeTest("tests/gc" / filename, options &
-                  " -d:release --gc:markAndSweep", cat, actionRun)
+                  " -d:release --gc:markAndSweep", cat)
   template test(filename: untyped) =
     testWithoutBoehm filename
     when not defined(windows) and not defined(android):
       # AR: cannot find any boehm.dll on the net, right now, so disabled
       # for windows:
       testSpec r, makeTest("tests/gc" / filename, options &
-                    " --gc:boehm", cat, actionRun)
+                    " --gc:boehm", cat)
       testSpec r, makeTest("tests/gc" / filename, options &
-                    " -d:release --gc:boehm", cat, actionRun)
+                    " -d:release --gc:boehm", cat)
 
   testWithoutBoehm "foreign_thr"
   test "gcemscripten"
@@ -197,17 +228,18 @@ proc longGCTests(r: var TResults, cat: Category, options: string) =
 
   var c = initResults()
   # According to ioTests, this should compile the file
-  testNoSpec c, makeTest("tests/realtimeGC/shared", options, cat, actionCompile)
-  testC r, makeTest("tests/realtimeGC/cmain", cOptions, cat, actionRun)
-  testSpec r, makeTest("tests/realtimeGC/nmain", options & "--threads: on", cat, actionRun)
+  testSpec c, makeTest("tests/realtimeGC/shared", options, cat)
+  #        ^- why is this not appended to r? Should this be discarded?
+  testC r, makeTest("tests/realtimeGC/cmain", cOptions, cat), actionRun
+  testSpec r, makeTest("tests/realtimeGC/nmain", options & "--threads: on", cat)
 
 # ------------------------- threading tests -----------------------------------
 
 proc threadTests(r: var TResults, cat: Category, options: string) =
   template test(filename: untyped) =
-    testSpec r, makeTest(filename, options, cat, actionRun)
-    testSpec r, makeTest(filename, options & " -d:release", cat, actionRun)
-    testSpec r, makeTest(filename, options & " --tlsEmulation:on", cat, actionRun)
+    testSpec r, makeTest(filename, options, cat)
+    testSpec r, makeTest(filename, options & " -d:release", cat)
+    testSpec r, makeTest(filename, options & " --tlsEmulation:on", cat)
   for t in os.walkFiles("tests/threads/t*.nim"):
     test(t)
 
@@ -230,23 +262,22 @@ proc asyncTests(r: var TResults, cat: Category, options: string) =
 # ------------------------- debugger tests ------------------------------------
 
 proc debuggerTests(r: var TResults, cat: Category, options: string) =
-  testNoSpec r, makeTest("tools/nimgrep", options & " --debugger:on", cat)
+  var t = makeTest("tools/nimgrep", options & " --debugger:on", cat)
+  t.spec.action = actionCompile
+  testSpec r, t
 
 # ------------------------- JS tests ------------------------------------------
 
 proc jsTests(r: var TResults, cat: Category, options: string) =
   template test(filename: untyped) =
-    testSpec r, makeTest(filename, options & " -d:nodejs", cat,
-                         actionRun), targetJS
-    testSpec r, makeTest(filename, options & " -d:nodejs -d:release", cat,
-                         actionRun), targetJS
+    testSpec r, makeTest(filename, options & " -d:nodejs", cat), {targetJS}
+    testSpec r, makeTest(filename, options & " -d:nodejs -d:release", cat), {targetJS}
 
   for t in os.walkFiles("tests/js/t*.nim"):
     test(t)
   for testfile in ["exception/texceptions", "exception/texcpt1",
                    "exception/texcsub", "exception/tfinally",
                    "exception/tfinally2", "exception/tfinally3",
-                   "exception/tunhandledexc",
                    "actiontable/tactiontable", "method/tmultimjs",
                    "varres/tvarres0", "varres/tvarres3", "varres/tvarres4",
                    "varres/tvartup", "misc/tints", "misc/tunsignedinc",
@@ -261,14 +292,14 @@ proc jsTests(r: var TResults, cat: Category, options: string) =
 proc testNimInAction(r: var TResults, cat: Category, options: string) =
   let options = options & " --nilseqs:on"
 
-  template test(filename: untyped, action: untyped) =
-    testSpec r, makeTest(filename, options, cat, action)
+  template test(filename: untyped) =
+    testSpec r, makeTest(filename, options, cat)
 
   template testJS(filename: untyped) =
-    testSpec r, makeTest(filename, options, cat, actionCompile), targetJS
+    testSpec r, makeTest(filename, options, cat), {targetJS}
 
   template testCPP(filename: untyped) =
-    testSpec r, makeTest(filename, options, cat, actionCompile), targetCPP
+    testSpec r, makeTest(filename, options, cat), {targetCPP}
 
   let tests = [
     "niminaction/Chapter1/various1",
@@ -299,43 +330,44 @@ 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"
+    "51afdfa84b3ca3d810809d6c4e5037ba",
+    "30f07e4cd5eaec981f67868d4e91cfcf",
+    "d14e7c032de36d219c9548066a97e846",
+    "b335635562ff26ec0301bdd86356ac0c",
+    "6c4add749fbf50860e2f523f548e6b0e",
+    "76de5833a7cc46f96b006ce51179aeb1",
+    "705eff79844e219b47366bd431658961",
+    "a1e87b881c5eb161553d119be8b52f64",
+    "2d706a6ec68d2973ec7e733e6d5dce50",
+    "c11a013db35e798f44077bc0763cc86d",
+    "3e32e2c5e9a24bd13375e1cd0467079c",
+    "a5452722b2841f0c1db030cf17708955",
+    "dc6c45eb59f8814aaaf7aabdb8962294",
+    "69d208d281a2e7bffd3eaf4bab2309b1",
+    "ec05666cfb60211bedc5e81d4c1caf3d",
+    "da520038c153f4054cb8cc5faa617714",
+    "59906c8cd819cae67476baa90a36b8c1",
+    "9a8fe78c588d08018843b64b57409a02",
+    "8b5d28e985c0542163927d253a3e4fc9",
+    "783299b98179cc725f9c46b5e3b5381f",
+    "1a2b3fba1187c68d6a9bfa66854f3318",
+    "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:
-    test "tests/" & testfile & ".nim", actionCompile
-
+    test "tests/" & testfile & ".nim"
   let jsFile = "tests/niminaction/Chapter8/canvas/canvas_test.nim"
   testJS jsFile
-
   let cppFile = "tests/niminaction/Chapter8/sfml/sfml_test.nim"
   testCPP cppFile
 
-
-
-
 # ------------------------- manyloc -------------------------------------------
-#proc runSpecialTests(r: var TResults, options: string) =
-#  for t in ["lib/packages/docutils/highlite"]:
-#    testSpec(r, t, options)
 
 proc findMainFile(dir: string): string =
   # finds the file belonging to ".nim.cfg"; if there is no such file
@@ -359,27 +391,32 @@ proc manyLoc(r: var TResults, cat: Category, options: string) =
       if dir.endsWith"named_argument_bug": continue
       let mainfile = findMainFile(dir)
       if mainfile != "":
-        testNoSpec r, makeTest(mainfile, options, cat)
+        var test = makeTest(mainfile, options, cat)
+        test.spec.action = actionCompile
+        testSpec r, test
 
 proc compileExample(r: var TResults, pattern, options: string, cat: Category) =
   for test in os.walkFiles(pattern):
-    testNoSpec r, makeTest(test, options, cat)
+    var test = makeTest(test, options, cat)
+    test.spec.action = actionCompile
+    testSpec r, test
 
 proc testStdlib(r: var TResults, pattern, options: string, cat: Category) =
-  for test in os.walkFiles(pattern):
-    let name = extractFilename(test)
+  for testFile in os.walkFiles(pattern):
+    let name = extractFilename(testFile)
     if name notin disabledFiles:
-      let contents = readFile(test).string
-      if contents.contains("when isMainModule"):
-        testSpec r, makeTest(test, options, cat, actionRunNoSpec)
-      else:
-        testNoSpec r, makeTest(test, options, cat, actionCompile)
+      let contents = readFile(testFile).string
+      var testObj = makeTest(testFile, options, cat)
+      if "when isMainModule" notin contents:
+        testObj.spec.action = actionCompile
+      testSpec r, testObj
 
 # ----------------------------- nimble ----------------------------------------
-type PackageFilter = enum
-  pfCoreOnly
-  pfExtraOnly
-  pfAll
+type
+  PackageFilter = enum
+    pfCoreOnly
+    pfExtraOnly
+    pfAll
 
 var nimbleDir = getEnv("NIMBLE_DIR").string
 if nimbleDir.len == 0: nimbleDir = getHomeDir() / ".nimble"
@@ -409,7 +446,6 @@ proc getPackageDir(package: string): string =
 
 iterator listPackages(filter: PackageFilter): tuple[name, url: string] =
   let packageList = parseFile(packageIndex)
-
   for package in packageList.items():
     let
       name = package["name"].str
@@ -463,24 +499,99 @@ proc testNimblePackages(r: var TResults, cat: Category, filter: PackageFilter) =
 
 # ----------------------------------------------------------------------------
 
-const AdditionalCategories = ["debugger", "examples", "lib"]
+const AdditionalCategories = ["debugger", "examples", "lib", "megatest"]
 
 proc `&.?`(a, b: string): string =
   # candidate for the stdlib?
   result = if b.startswith(a): b else: a & b
 
-#proc `&?.`(a, b: string): string = # not used
-  # candidate for the stdlib?
-  #result = if a.endswith(b): a else: a & b
-
 proc processSingleTest(r: var TResults, cat: Category, options, test: string) =
   let test = "tests" & DirSep &.? cat.string / test
   let target = if cat.string.normalize == "js": targetJS else: targetC
+  if existsFile(test):
+    testSpec r, makeTest(test, options, cat), {target}
+  else:
+    echo "[Warning] - ", test, " test does not exist"
+
+proc isJoinableSpec(spec: TSpec): bool =
+  result = not spec.sortoutput and
+    spec.action == actionRun and
+    not fileExists(spec.file.changeFileExt("cfg")) and
+    not fileExists(parentDir(spec.file) / "nim.cfg") and
+    spec.cmd.len == 0 and
+    spec.err != reDisabled and
+    not spec.unjoinable and
+    spec.exitCode == 0 and
+    spec.input.len == 0 and
+    spec.nimout.len == 0 and
+    spec.outputCheck != ocSubstr and
+    spec.ccodeCheck.len == 0 and
+    (spec.targets == {} or spec.targets == {targetC})
+
+proc norm(s: var string) =
+  while true:
+    let tmp = s.replace("\n\n", "\n")
+    if tmp == s: break
+    s = tmp
+  s = s.strip
+
+proc runJoinedTest(r: var TResults, cat: Category, testsDir: string) =
+  ## returs a list of tests that have problems
+  var specs: seq[TSpec] = @[]
+
+  for kind, dir in walkDir(testsDir):
+    assert testsDir.startsWith(testsDir)
+    let cat = dir[testsDir.len .. ^1]
+    if kind == pcDir and cat notin specialCategories:
+      for file in os.walkFiles(testsDir / cat / "t*.nim"):
+        let spec = parseSpec(file)
+        if isJoinableSpec(spec):
+          specs.add spec
+
+  echo "joinable specs: ", specs.len
+
+  var megatest: string
+  for runSpec in specs:
+    megatest.add "import r\""
+    megatest.add runSpec.file
+    megatest.add "\"\n"
+
+  writeFile("megatest.nim", megatest)
+
+  const args = ["c", "-d:testing", "--listCmd", "megatest.nim"]
+  var (buf, exitCode) = execCmdEx2(command = "nim", args = args, options = {poStdErrToStdOut, poUsePath}, input = "")
+  if exitCode != 0:
+    echo buf
+    quit("megatest compilation failed")
+
+  (buf, exitCode) = execCmdEx("./megatest")
+  if exitCode != 0:
+    echo buf
+    quit("megatest execution failed")
+
+  norm buf
+  writeFile("outputGotten.txt", buf)
+  var outputExpected = ""
+  for i, runSpec in specs:
+    outputExpected.add runSpec.output.strip
+    outputExpected.add '\n'
+  norm outputExpected
+
+  if buf != outputExpected:
+    writeFile("outputExpected.txt", outputExpected)
+    discard execShellCmd("diff -uNdr outputExpected.txt outputGotten.txt")
+    echo "output different!"
+    quit 1
+  else:
+    echo "output OK"
+    removeFile("outputGotten.txt")
+    removeFile("megatest.nim")
+  #testSpec r, makeTest("megatest", options, cat)
 
-  if existsFile(test): testSpec r, makeTest(test, options, cat), target
-  else: echo "[Warning] - ", test, " test does not exist"
+# ---------------------------------------------------------------------------
 
-proc processCategory(r: var TResults, cat: Category, options: string) =
+proc processCategory(r: var TResults, cat: Category, options, testsDir: string,
+                     runJoinableTests: bool) =
   case cat.string.normalize
   of "rodfiles":
     when false:
@@ -529,10 +640,17 @@ proc processCategory(r: var TResults, cat: Category, options: string) =
   of "untestable":
     # We can't test it because it depends on a third party.
     discard # TODO: Move untestable tests to someplace else, i.e. nimble repo.
+  of "megatest":
+    runJoinedTest(r, cat, testsDir)
   else:
     var testsRun = 0
     for name in os.walkFiles("tests" & DirSep &.? cat.string / "t*.nim"):
-      testSpec r, makeTest(name, options, cat)
+      var test = makeTest(name, options, cat)
+      if runJoinableTests or not isJoinableSpec(test.spec) or cat.string in specialCategories:
+        discard "run the test"
+      else:
+        test.spec.err = reJoined
+      testSpec r, test
       inc testsRun
     if testsRun == 0:
       echo "[Warning] - Invalid category specified \"", cat.string, "\", no tests were run"
diff --git a/testament/specs.nim b/testament/specs.nim
index c51a3343e..df12db543 100644
--- a/testament/specs.nim
+++ b/testament/specs.nim
@@ -9,21 +9,22 @@
 
 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"
-
 type
   TTestAction* = enum
-    actionCompile = "compile"
     actionRun = "run"
+    actionCompile = "compile"
     actionReject = "reject"
-    actionRunNoSpec = "runNoSpec"
+
+  TOutputCheck* = enum
+    ocIgnore = "ignore"
+    ocEqual  = "equal"
+    ocSubstr = "substr"
+
   TResultEnum* = enum
     reNimcCrash,     # nim compiler seems to have crashed
     reMsgsDiffer,       # error messages differ
@@ -37,8 +38,11 @@ type
     reExeNotFound,
     reInstallFailed     # package installation failed
     reBuildFailed       # package building failed
-    reIgnored,          # test is ignored
+    reDisabled,         # test is disabled
+    reJoined,           # test is disabled because it was joined into the megatest
     reSuccess           # test was successful
+    reInvalidSpec       # test had problems to parse the spec
+
   TTarget* = enum
     targetC = "C"
     targetCpp = "C++"
@@ -48,7 +52,10 @@ type
   TSpec* = object
     action*: TTestAction
     file*, cmd*: string
-    outp*: string
+    input*: string
+    outputCheck*: TOutputCheck
+    sortoutput*: bool
+    output*: string
     line*, column*: int
     tfile*: string
     tline*, tcolumn*: int
@@ -57,9 +64,16 @@ type
     ccodeCheck*: string
     maxCodeSize*: int
     err*: TResultEnum
-    substr*, sortoutput*: bool
     targets*: set[TTarget]
     nimout*: string
+    parseErrors*: string # when the spec definition is invalid, this is not empty.
+    unjoinable*: bool
+
+proc getCmd*(s: TSpec): string =
+  if s.cmd.len == 0:
+    result = compilerPrefix & " $target --hints:on -d:testing --nimblePath:tests/deps $options $file"
+  else:
+    result = s.cmd
 
 const
   targetToExt*: array[TTarget, string] = ["c", "cpp", "m", "js"]
@@ -88,33 +102,6 @@ proc extractSpec(filename: string): string =
 when not defined(nimhygiene):
   {.pragma: inject.}
 
-template parseSpecAux(fillResult: untyped) =
-  var ss = newStringStream(extractSpec(filename))
-  var p {.inject.}: CfgParser
-  open(p, ss, filename, 1)
-  while true:
-    var e {.inject.} = next(p)
-    case e.kind
-    of cfgEof: break
-    of cfgSectionStart, cfgOption, cfgError:
-      echo ignoreMsg(p, e)
-    of cfgKeyValuePair:
-      fillResult
-  close(p)
-
-proc specDefaults*(result: var TSpec) =
-  result.msg = ""
-  result.outp = ""
-  result.nimout = ""
-  result.ccodeCheck = ""
-  result.cmd = cmdTemplate()
-  result.line = 0
-  result.column = 0
-  result.tfile = ""
-  result.tline = 0
-  result.tcolumn = 0
-  result.maxCodeSize = 0
-
 proc parseTargets*(value: string): set[TTarget] =
   for v in value.normalize.splitWhitespace:
     case v
@@ -124,79 +111,134 @@ proc parseTargets*(value: string): set[TTarget] =
     of "js": result.incl(targetJS)
     else: echo "target ignored: " & v
 
+proc addLine*(self: var string; a: string) =
+  self.add a
+  self.add "\n"
+
+proc addLine*(self: var string; a,b: string) =
+  self.add a
+  self.add b
+  self.add "\n"
+
 proc parseSpec*(filename: string): TSpec =
-  specDefaults(result)
   result.file = filename
-  parseSpecAux:
-    case normalize(e.key)
-    of "action":
-      case e.value.normalize
-      of "compile": result.action = actionCompile
-      of "run": result.action = actionRun
-      of "reject": result.action = actionReject
-      else: echo ignoreMsg(p, e)
-    of "file": result.file = e.value
-    of "line": discard parseInt(e.value, result.line)
-    of "column": discard parseInt(e.value, result.column)
-    of "tfile": result.tfile = e.value
-    of "tline": discard parseInt(e.value, result.tline)
-    of "tcolumn": discard parseInt(e.value, result.tcolumn)
-    of "output":
-      result.action = actionRun
-      result.outp = e.value
-    of "outputsub":
-      result.action = actionRun
-      result.outp = e.value
-      result.substr = true
-    of "sortoutput":
-      result.sortoutput = parseCfgBool(e.value)
-    of "exitcode":
-      discard parseInt(e.value, result.exitCode)
-      result.action = actionRun
-    of "msg":
-      result.msg = e.value
-      if result.action != actionRun:
-        result.action = actionCompile
-    of "errormsg", "errmsg":
-      result.msg = e.value
-      result.action = actionReject
-    of "nimout":
-      result.nimout = e.value
-    of "disabled":
-      case e.value.normalize
-      of "y", "yes", "true", "1", "on": result.err = reIgnored
-      of "n", "no", "false", "0", "off": discard
-      of "win", "windows":
-        when defined(windows): result.err = reIgnored
-      of "linux":
-        when defined(linux): result.err = reIgnored
-      of "bsd":
-        when defined(bsd): result.err = reIgnored
-      of "macosx":
-        when defined(macosx): result.err = reIgnored
-      of "unix":
-        when defined(unix): result.err = reIgnored
-      of "posix":
-        when defined(posix): result.err = reIgnored
-      of "travis":
-        if isTravis: result.err = reIgnored
-      of "appveyor":
-        if isAppVeyor: result.err = reIgnored
-      else:
-        raise newException(ValueError, "cannot interpret as a bool: " & e.value)
-    of "cmd":
-      if e.value.startsWith("nim "):
-        result.cmd = compilerPrefix & e.value[4..^1]
+  let specStr = extractSpec(filename)
+  var ss = newStringStream(specStr)
+  var p: CfgParser
+  open(p, ss, filename, 1)
+  while true:
+    var e = next(p)
+    case e.kind
+    of cfgKeyValuePair:
+      case normalize(e.key)
+      of "action":
+        case e.value.normalize
+        of "compile":
+          result.action = actionCompile
+        of "run":
+          result.action = actionRun
+        of "reject":
+          result.action = actionReject
+        else:
+          result.parseErrors.addLine "cannot interpret as action: ", e.value
+      of "file":
+        if result.msg.len == 0 and result.nimout.len == 0:
+          result.parseErrors.addLine "errormsg or msg needs to be specified before file"
+        result.file = e.value
+      of "line":
+        if result.msg.len == 0 and result.nimout.len == 0:
+          result.parseErrors.addLine "errormsg, msg or nimout needs to be specified before line"
+        discard parseInt(e.value, result.line)
+      of "column":
+        if result.msg.len == 0 and result.nimout.len == 0:
+          result.parseErrors.addLine "errormsg or msg needs to be specified before column"
+        discard parseInt(e.value, result.column)
+      of "tfile":
+        result.tfile = e.value
+      of "tline":
+        discard parseInt(e.value, result.tline)
+      of "tcolumn":
+        discard parseInt(e.value, result.tcolumn)
+      of "output":
+        result.outputCheck = ocEqual
+        result.output = strip(e.value)
+      of "input":
+        result.input = e.value
+      of "outputsub":
+        result.outputCheck = ocSubstr
+        result.output = strip(e.value)
+      of "sortoutput":
+        try:
+          result.sortoutput  = parseCfgBool(e.value)
+        except:
+          result.parseErrors.addLine getCurrentExceptionMsg()
+      of "exitcode":
+        discard parseInt(e.value, result.exitCode)
+        result.action = actionRun
+      of "msg":
+        result.msg = e.value
+        if result.action != actionRun:
+          result.action = actionCompile
+      of "errormsg", "errmsg":
+        result.msg = e.value
+        result.action = actionReject
+      of "nimout":
+        result.nimout = e.value
+      of "joinable":
+        result.unjoinable = not parseCfgBool(e.value)
+      of "disabled":
+        case e.value.normalize
+        of "y", "yes", "true", "1", "on": result.err = reDisabled
+        of "n", "no", "false", "0", "off": discard
+        of "win", "windows":
+          when defined(windows): result.err = reDisabled
+        of "linux":
+          when defined(linux): result.err = reDisabled
+        of "bsd":
+          when defined(bsd): result.err = reDisabled
+        of "macosx":
+          when defined(macosx): result.err = reDisabled
+        of "unix":
+          when defined(unix): result.err = reDisabled
+        of "posix":
+          when defined(posix): result.err = reDisabled
+        of "travis":
+          if isTravis: result.err = reDisabled
+        of "appveyor":
+          if isAppVeyor: result.err = reDisabled
+        else:
+          result.parseErrors.addLine "cannot interpret as a bool: ", e.value
+      of "cmd":
+        if e.value.startsWith("nim "):
+          result.cmd = compilerPrefix & e.value[3..^1]
+        else:
+          result.cmd = e.value
+      of "ccodecheck":
+        result.ccodeCheck = e.value
+      of "maxcodesize":
+        discard parseInt(e.value, result.maxCodeSize)
+      of "target", "targets":
+        for v in e.value.normalize.splitWhitespace:
+          case v
+          of "c":
+            result.targets.incl(targetC)
+          of "cpp", "c++":
+            result.targets.incl(targetCpp)
+          of "objc":
+            result.targets.incl(targetObjC)
+          of "js":
+            result.targets.incl(targetJS)
+          else:
+            result.parseErrors.addLine "cannot interpret as a target: ", e.value
       else:
-        result.cmd = e.value
-    of "ccodecheck": result.ccodeCheck = e.value
-    of "maxcodesize": discard parseInt(e.value, result.maxCodeSize)
-    of "target", "targets":
-      for v in e.value.normalize.splitWhitespace:
-        case v
-        of "c": result.targets.incl(targetC)
-        of "cpp", "c++": result.targets.incl(targetCpp)
-        of "objc": result.targets.incl(targetObjC)
-        of "js": result.targets.incl(targetJS)
-        else: echo ignoreMsg(p, e)
-    else: echo ignoreMsg(p, e)
+        result.parseErrors.addLine "invalid key for test spec: ", e.key
+
+    of cfgSectionStart:
+      result.parseErrors.addLine "section ignored: ", e.section
+    of cfgOption:
+      result.parseErrors.addLine "command ignored: ", e.key & ": " & e.value
+    of cfgError:
+      result.parseErrors.addLine e.msg
+    of cfgEof:
+      break
+  close(p)
diff --git a/testament/tester.nim b/testament/tester.nim
index c48e4441d..6d9e05aa9 100644
--- a/testament/tester.nim
+++ b/testament/tester.nim
@@ -14,6 +14,9 @@ import
   marshal, backend, parseopt, specs, htmlgen, browsers, terminal,
   algorithm, compiler/nodejs, times, sets, md5
 
+var useColors = true
+var backendLogging = true
+
 const
   resultsFile = "testresults.html"
   #jsonFile = "testresults.json" # not used
@@ -25,6 +28,7 @@ Command:
   c|cat|category <category>   run all the tests of a certain category
   r|run <test>                run single test file
   html                        generate $1 from the database
+  stats                       generate statistics about test cases
 Arguments:
   arguments are passed to the compiler
 Options:
@@ -32,6 +36,9 @@ 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.
+  --backendLogging:on|off   Disable or enable backend logging. By default turned on.
 """ % resultsFile
 
 type
@@ -44,7 +51,7 @@ type
     name: string
     cat: Category
     options: string
-    action: TTestAction
+    spec: TSpec
     startTime: float
 
 # ----------------------------------------------------------------------------
@@ -74,6 +81,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
@@ -82,7 +116,7 @@ proc nimcacheDir(filename, options: string, target: TTarget): string =
 proc callCompiler(cmdTemplate, filename, options: string,
                   target: TTarget, extraOptions=""): TSpec =
   let nimcache = nimcacheDir(filename, options, target)
-  let options = options & " " & ("--nimCache:" & nimcache).quoteShell & extraOptions
+  let options = options & " " & quoteShell("--nimCache:" & nimcache) & extraOptions
   let c = parseCmdLine(cmdTemplate % ["target", targetToCmd[target],
                        "options", options, "file", filename.quoteShell,
                        "filedir", filename.getFileDir()])
@@ -107,7 +141,7 @@ proc callCompiler(cmdTemplate, filename, options: string,
   close(p)
   result.msg = ""
   result.file = ""
-  result.outp = ""
+  result.output = ""
   result.line = 0
   result.column = 0
   result.tfile = ""
@@ -139,7 +173,7 @@ proc callCCompiler(cmdTemplate, filename, options: string,
   result.nimout = ""
   result.msg = ""
   result.file = ""
-  result.outp = ""
+  result.output = ""
   result.line = -1
   while outp.readLine(x.TaintedString) or running(p):
     result.nimout.add(x & "\n")
@@ -153,11 +187,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,33 +221,36 @@ 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)
-  backend.writeTestResult(name = name,
-                          category = test.cat.string,
-                          target = $target,
-                          action = $test.action,
-                          result = $success,
-                          expected = expected,
-                          given = given)
+  let durationStr = duration.formatFloat(ffDecimal, precision = 8).align(11)
+  if backendLogging:
+    backend.writeTestResult(name = name,
+                            category = test.cat.string,
+                            target = $target,
+                            action = $test.spec.action,
+                            result = $success,
+                            expected = expected,
+                            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)"
-  elif success == reIgnored:
-    styledEcho styleDim, fgYellow, "SKIP: ", styleBright, fgCyan, name
+    maybeStyledEcho fgGreen, "PASS: ", fgCyan, alignLeft(name, 60), fgBlue, " (", durationStr, " secs)"
+  elif success == reDisabled:
+    maybeStyledEcho styleDim, fgYellow, "SKIP: ", styleBright, fgCyan, name
+  elif success == reJoined:
+    maybeStyledEcho styleDim, fgYellow, "JOINED: ", 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"
-
-  if existsEnv("APPVEYOR"):
+    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 backendLogging and existsEnv("APPVEYOR"):
     let (outcome, msg) =
       if success == reSuccess:
         ("Passed", "")
-      elif success == reIgnored:
+      elif success in {reDisabled, reJoined}:
         ("Skipped", "")
       else:
         ("Failed", "Failure: " & $success & "\nExpected:\n" & expected & "\n\n" & "Gotten:\n" & given)
@@ -268,15 +324,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
-
-proc makeDeterministic(s: string): string =
-  var x = splitLines(s)
-  sort(x, system.cmp)
-  result = join(x, "\n")
+  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 compilerOutputTests(test: TTest, target: TTarget, given: var TSpec,
                          expected: TSpec; r: var TResults) =
@@ -295,118 +351,103 @@ proc compilerOutputTests(test: TTest, target: TTarget, given: var TSpec,
   if given.err == reSuccess: inc(r.passed)
   r.addResult(test, target, expectedmsg, givenmsg, given.err)
 
-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)
-    if test.action == actionRun and expected.action == actionCompile:
-      expected.action = actionRun
-  else:
-    specDefaults expected
-    expected.action = actionRunNoSpec
-
-  if expected.err == reIgnored:
-    r.addResult(test, target, "", "", reIgnored)
+proc testSpec(r: var TResults, test: TTest, targets: set[TTarget] = {}) =
+  var expected = test.spec
+  if expected.parseErrors.len > 0:
+    # targetC is a lie, but parameter is required
+    r.addResult(test, targetC, "", expected.parseErrors, reInvalidSpec)
+    inc(r.total)
+    return
+  if expected.err in {reDisabled, reJoined}:
+    # targetC is a lie, but parameter is required
+    r.addResult(test, targetC, "", "", expected.err)
     inc(r.skipped)
     inc(r.total)
     return
-
-  if getEnv("NIM_COMPILE_TO_CPP", "false").string == "true" and target == targetC and expected.targets == {}:
-    expected.targets.incl(targetCpp)
-  elif expected.targets == {}:
-    expected.targets.incl(target)
-
+  expected.targets.incl targets
+  # still no target specified at all
+  if expected.targets == {}:
+    if getEnv("NIM_COMPILE_TO_CPP", "false").string == "true":
+      expected.targets = {targetCpp}
+    else:
+      expected.targets = {targetC}
   for target in expected.targets:
     inc(r.total)
-    if target notin targets:
-      r.addResult(test, target, "", "", reIgnored)
-      inc(r.skipped)
-      continue
-
     case expected.action
     of actionCompile:
-      var given = callCompiler(expected.cmd, test.name, test.options, target,
+      var given = callCompiler(expected.getCmd, test.name, test.options, target,
         extraOptions=" --stdout --hint[Path]:off --hint[Processing]:off")
       compilerOutputTests(test, target, given, expected, r)
-    of actionRun, actionRunNoSpec:
+    of actionRun:
       # In this branch of code "early return" pattern is clearer than deep
       # nested conditionals - the empty rows in between to clarify the "danger"
-      var given = callCompiler(expected.cmd, test.name, test.options,
+      var given = callCompiler(expected.getCmd, test.name, test.options,
                                target)
-
       if given.err != reSuccess:
         r.addResult(test, target, "", given.msg, given.err)
         continue
-
       let isJsTarget = target == targetJS
       var exeFile: string
       if isJsTarget:
-        let (_, file, _) = splitFile(tname)
-        exeFile = nimcacheDir(test.name, test.options, target) / file & ".js"
+        let file = test.name.lastPathPart.changeFileExt("js")
+        exeFile = nimcacheDir(test.name, test.options, target) / file
       else:
-        exeFile = changeFileExt(tname, ExeExt)
+        exeFile = changeFileExt(test.name, ExeExt)
 
       if not existsFile(exeFile):
-        r.addResult(test, target, expected.outp, "executable not found", reExeNotFound)
+        r.addResult(test, target, expected.output, "executable not found", reExeNotFound)
         continue
 
       let nodejs = if isJsTarget: findNodeJs() else: ""
       if isJsTarget and nodejs == "":
-        r.addResult(test, target, expected.outp, "nodejs binary not in PATH",
+        r.addResult(test, target, expected.output, "nodejs binary not in PATH",
                     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.
       if exitCode != 0: exitCode = 1
-
-      let bufB = if expected.sortoutput: makeDeterministic(strip(buf.string))
-                 else: strip(buf.string)
-      let expectedOut = strip(expected.outp)
-
+      let bufB =
+        if expected.sortoutput:
+          var x = splitLines(strip(buf.string))
+          sort(x, system.cmp)
+          join(x, "\n")
+        else:
+          strip(buf.string)
       if exitCode != expected.exitCode:
         r.addResult(test, target, "exitcode: " & $expected.exitCode,
                           "exitcode: " & $exitCode & "\n\nOutput:\n" &
                           bufB, reExitCodesDiffer)
         continue
-
-      if bufB != expectedOut and expected.action != actionRunNoSpec:
-        if not (expected.substr and expectedOut in bufB):
-          given.err = reOutputsDiffer
-          r.addResult(test, target, expected.outp, bufB, reOutputsDiffer)
-          continue
-
+      if (expected.outputCheck == ocEqual and expected.output != bufB) or
+         (expected.outputCheck == ocSubstr and expected.output notin bufB):
+        given.err = reOutputsDiffer
+        r.addResult(test, target, expected.output, bufB, reOutputsDiffer)
+        continue
       compilerOutputTests(test, target, given, expected, r)
       continue
-
     of actionReject:
-      var given = callCompiler(expected.cmd, test.name, test.options,
+      var given = callCompiler(expected.getCmd, test.name, test.options,
                                target)
       cmpMsgs(r, expected, given, test, target)
       continue
 
-proc testNoSpec(r: var TResults, test: TTest, target = targetC) =
-  # does not extract the spec because the file is not supposed to have any
-  #let tname = test.name.addFileExt(".nim")
-  inc(r.total)
-  let given = callCompiler(cmdTemplate(), test.name, test.options, target)
-  r.addResult(test, target, "", given.msg, given.err)
-  if given.err == reSuccess: inc(r.passed)
-
-proc testC(r: var TResults, test: TTest) =
+proc testC(r: var TResults, test: TTest, action: TTestAction) =
   # 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)
-  var given = callCCompiler(cmdTemplate(), test.name & ".c", test.options, targetC)
+  maybeStyledEcho "Processing ", fgCyan, extractFilename(tname)
+  var given = callCCompiler(getCmd(TSpec()), test.name & ".c", test.options, targetC)
   if given.err != reSuccess:
     r.addResult(test, targetC, "", given.msg, given.err)
-  elif test.action == actionRun:
+  elif action == actionRun:
     let exeFile = changeFileExt(test.name, ExeExt)
     var (_, exitCode) = execCmdEx(exeFile, options = {poStdErrToStdOut, poUsePath})
     if exitCode != 0: given.err = reExitCodesDiffer
@@ -417,7 +458,6 @@ proc testExec(r: var TResults, test: TTest) =
   inc(r.total)
   let (outp, errC) = execCmdEx(test.options.strip())
   var given: TSpec
-  specDefaults(given)
   if errC == 0:
     given.err = reSuccess
   else:
@@ -427,16 +467,17 @@ proc testExec(r: var TResults, test: TTest) =
   if given.err == reSuccess: inc(r.passed)
   r.addResult(test, targetC, "", given.msg, given.err)
 
-proc makeTest(test, options: string, cat: Category, action = actionCompile,
-              env: string = ""): TTest =
-  # start with 'actionCompile', will be overwritten in the spec:
-  result = TTest(cat: cat, name: test, options: options,
-                 action: action, startTime: epochTime())
+proc makeTest(test, options: string, cat: Category): TTest =
+  result.cat = cat
+  result.name = test
+  result.options = options
+  result.spec = parseSpec(addFileExt(test, ".nim"))
+  result.startTime = epochTime()
 
 when defined(windows):
   const
     # array of modules disabled from compilation test of stdlib.
-    disabledFiles = ["coro.nim", "fsmonitor.nim"]
+    disabledFiles = ["coro.nim"]
 else:
   const
     # array of modules disabled from compilation test of stdlib.
@@ -444,10 +485,7 @@ else:
 
 include categories
 
-# proc runCaasTests(r: var TResults) =
-#   for test, output, status, mode in caasTestsRunner():
-#     r.addResult(test, "", output & "-> " & $mode,
-#                 if status: reSuccess else: reOutputsDiffer)
+const testsDir = "tests" & DirSep
 
 proc main() =
   os.putenv "NIMTEST_COLOR", "never"
@@ -456,7 +494,6 @@ proc main() =
   backend.open()
   var optPrintResults = false
   var optFailing = false
-
   var targetsStr = ""
 
   var p = initOptParser()
@@ -469,16 +506,38 @@ proc main() =
     of "targets":
       targetsStr = p.val.string
       targets = parseTargets(targetsStr)
-    of "nim": compilerPrefix = p.val.string & " "
-    else: quit Usage
+    of "nim":
+      compilerPrefix = addFileExt(p.val.string, ExeExt)
+    of "directory":
+      setCurrentDir(p.val.string)
+    of "colors":
+      case p.val.string:
+      of "on":
+        useColors = true
+      of "off":
+        useColors = false
+      else:
+        quit Usage
+    of "backendlogging":
+      case p.val.string:
+      of "on":
+        backendLogging = true
+      of "off":
+        backendLogging = false
+      else:
+        quit Usage
+    else:
+      quit Usage
     p.next()
-  if p.kind != cmdArgument: quit Usage
+  if p.kind != cmdArgument:
+    quit Usage
   var action = p.key.string.normalize
   p.next()
   var r = initResults()
   case action
   of "all":
-    let testsDir = "tests" & DirSep
+    #processCategory(r, Category"megatest", p.cmdLineRest.string, testsDir, runJoinableTests = false)
+
     var myself = quoteShell(findExe("testament" / "tester"))
     if targetsStr.len > 0:
       myself &= " " & quoteShell("--targets:" & targetsStr)
@@ -491,14 +550,21 @@ proc main() =
       assert testsDir.startsWith(testsDir)
       let cat = dir[testsDir.len .. ^1]
       if kind == pcDir and cat notin ["testdata", "nimcache"]:
-        cmds.add(myself & " cat " & quoteShell(cat) & rest)
+        cmds.add(myself & " pcat " & quoteShell(cat) & rest)
     for cat in AdditionalCategories:
-      cmds.add(myself & " cat " & quoteShell(cat) & rest)
+      cmds.add(myself & " pcat " & quoteShell(cat) & rest)
     quit osproc.execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath, poParentStreams})
   of "c", "cat", "category":
     var cat = Category(p.key)
     p.next
-    processCategory(r, cat, p.cmdLineRest.string)
+    processCategory(r, cat, p.cmdLineRest.string, testsDir, runJoinableTests = true)
+  of "pcat":
+    # 'pcat' is used for running a category in parallel. Currently the only
+    # difference is that we don't want to run joinable tests here as they
+    # are covered by the 'megatest' category.
+    var cat = Category(p.key)
+    p.next
+    processCategory(r, cat, p.cmdLineRest.string, testsDir, runJoinableTests = false)
   of "r", "run":
     let (dir, file) = splitPath(p.key.string)
     let (_, subdir) = splitPath(dir)
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..89482e673
--- /dev/null
+++ b/testament/tests/shouldfail/tcolumn.nim
@@ -0,0 +1,8 @@
+discard """
+errormsg: "undeclared identifier: 'undeclared'"
+line: 8
+column: 7
+"""
+
+# 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..dbbdf5021
--- /dev/null
+++ b/testament/tests/shouldfail/terrormsg.nim
@@ -0,0 +1,8 @@
+discard """
+errormsg: "wrong error message"
+line: 8
+column: 6
+"""
+
+# 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..a6c2ad359
--- /dev/null
+++ b/testament/tests/shouldfail/tfile.nim
@@ -0,0 +1,6 @@
+discard """
+errmsg: "undeclared identifier: 'undefined'"
+file: "notthisfile.nim"
+"""
+
+echo undefined
diff --git a/testament/tests/shouldfail/tline.nim b/testament/tests/shouldfail/tline.nim
new file mode 100644
index 000000000..f7a09875c
--- /dev/null
+++ b/testament/tests/shouldfail/tline.nim
@@ -0,0 +1,8 @@
+discard """
+errormsg: "undeclared identifier: 'undeclared'"
+line: 9
+column: 6
+"""
+
+# 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/ambsym/tambsym.nim b/tests/ambsym/tambsym.nim
index d9115e16d..bd0f41717 100644
--- a/tests/ambsym/tambsym.nim
+++ b/tests/ambsym/tambsym.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "ambiguous identifier"
   file: "tambsym.nim"
   line: 11
-  errormsg: "ambiguous identifier"
 """
 # Test ambiguous symbols
 
@@ -11,5 +11,3 @@ var
   v: TExport #ERROR_MSG ambiguous identifier
 
 v = y
-
-
diff --git a/tests/ambsym/tambsym2.nim b/tests/ambsym/tambsym2.nim
index 8e288e73a..747f1a086 100644
--- a/tests/ambsym/tambsym2.nim
+++ b/tests/ambsym/tambsym2.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tambsym2.nim"
   output: "7"
 """
 # Test overloading of procs with locals
@@ -20,5 +19,3 @@ m.len = 7
 m.data = "1234"
 
 x(m, 5) #OUT 7
-
-
diff --git a/tests/ambsym/tambsym3.nim b/tests/ambsym/tambsym3.nim
index b25dadfd6..0558517bd 100644
--- a/tests/ambsym/tambsym3.nim
+++ b/tests/ambsym/tambsym3.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "ambiguous identifier"
   file: "tambsym3.nim"
   line: 11
-  errormsg: "ambiguous identifier"
 """
 # Test ambiguous symbols
 
@@ -11,5 +11,3 @@ var
   v = mDec #ERROR_MSG ambiguous identifier
 
 writeLine(stdout, ord(v))
-
-
diff --git a/tests/ambsym/tambsys.nim b/tests/ambsym/tambsys.nim
index 67522d7c9..aa740c38f 100644
--- a/tests/ambsym/tambsys.nim
+++ b/tests/ambsym/tambsys.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tambsys.nim"
   output: ""
 """
 # Test ambiguous symbols
@@ -9,5 +8,3 @@ import mambsys1, mambsys2
 var
   v: mambsys1.TExport
 mambsys2.foo(3) #OUT
-
-
diff --git a/tests/array/tarray.nim b/tests/array/tarray.nim
index 4a31a4d6d..2a371b788 100644
--- a/tests/array/tarray.nim
+++ b/tests/array/tarray.nim
@@ -1,7 +1,5 @@
 discard """
-  file: "tarray.nim"
-  output:
-'''
+output: '''
 [4, 5, 6]
 
 [16, 25, 36]
@@ -30,6 +28,7 @@ dflfdjkl__abcdefgasfsgdfgsgdfggsdfasdfsafewfkljdsfajsdf
 kgdchlfniambejop
 fjpmholcibdgeakn
 '''
+joinable: false
 """
 
 block tarray:
@@ -358,7 +357,7 @@ block troofregression:
   echo testStr[testStr.len - 8 .. testStr.len - 1] & "__" & testStr[0 .. testStr.len - pred(rot)]
 
   var
-    instructions = readFile(getAppDir() / "troofregression2.txt").split(',')
+    instructions = readFile(parentDir(currentSourcePath) / "troofregression2.txt").split(',')
     programs = "abcdefghijklmnop"
 
   proc dance(dancers: string): string =
@@ -400,7 +399,7 @@ block troofregression:
 
 block tunchecked:
   {.boundchecks: on.}
-  type Unchecked {.unchecked.} = array[0, char]
+  type Unchecked = UncheckedArray[char]
 
   var x = cast[ptr Unchecked](alloc(100))
   x[5] = 'x'
diff --git a/tests/array/tarraycons.nim b/tests/array/tarraycons.nim
index 9f09fd405..b6ebe55c8 100644
--- a/tests/array/tarraycons.nim
+++ b/tests/array/tarraycons.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "invalid order in array constructor"
   file: "tarraycons.nim"
   line: 14
-  errormsg: "invalid order in array constructor"
 """
 
 type
@@ -19,6 +19,3 @@ const
   ]
 
 echo myMapping[eC][1]
-
-
-
diff --git a/tests/array/tarraycons_ptr_generic2.nim b/tests/array/tarraycons_ptr_generic2.nim
index fce7af669..f6ed32b58 100644
--- a/tests/array/tarraycons_ptr_generic2.nim
+++ b/tests/array/tarraycons_ptr_generic2.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "type mismatch: got <ptr Hard[system.string]> but expected 'Book[system.string]'"
   file: "tarraycons_ptr_generic2.nim"
   line: 17
-  errormsg: "type mismatch: got <ptr Hard[system.string]> but expected 'Book[system.string]'"
 """
 
 type
diff --git a/tests/assert/tassert.nim b/tests/assert/tassert.nim
index b5f2fb715..99929f080 100644
--- a/tests/assert/tassert.nim
+++ b/tests/assert/tassert.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tassert.nim"
   outputsub: "assertion failure!this shall be always written"
   exitcode: "1"
 """
@@ -19,5 +18,3 @@ finally:
   system.write(stdout, "this shall be always written")
 
 assert(false) #OUT assertion failure!this shall be always written
-
-
diff --git a/tests/assert/testhelper.nim b/tests/assert/testhelper.nim
index 754d562ec..2e5ede990 100644
--- a/tests/assert/testhelper.nim
+++ b/tests/assert/testhelper.nim
@@ -1,5 +1,5 @@
 from strutils import endsWith, split
-from ospaths import isAbsolute
+from os import isAbsolute
 
 proc checkMsg*(msg, expectedEnd, name: string)=
   let filePrefix = msg.split(' ', maxSplit = 1)[0]
diff --git a/tests/assign/tassign.nim b/tests/assign/tassign.nim
index cb03b5004..b421802ae 100644
--- a/tests/assign/tassign.nim
+++ b/tests/assign/tassign.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tassign.nim"
   output:
 '''
 TEMP=C:\Programs\xyz\bin
diff --git a/tests/assign/tvariantasgn.nim b/tests/assign/tvariantasgn.nim
index 46cc23dd1..2278957ac 100644
--- a/tests/assign/tvariantasgn.nim
+++ b/tests/assign/tvariantasgn.nim
@@ -1,7 +1,7 @@
 discard """
-  file: "tvariantasgn.nim"
   output: "came here"
 """
+
 #BUG
 type
   TAnyKind = enum
@@ -26,5 +26,3 @@ nr.intVal = 78
 # s = nr # works
 nr = s # fails!
 echo "came here"
-
-
diff --git a/tests/async/t7192.nim b/tests/async/t7192.nim
new file mode 100644
index 000000000..9ac0e07c0
--- /dev/null
+++ b/tests/async/t7192.nim
@@ -0,0 +1,14 @@
+discard """
+output: '''
+testCallback()
+'''
+"""
+
+import asyncdispatch
+
+proc testCallback() =
+  echo "testCallback()"
+
+when true:
+  callSoon(testCallback)
+  poll()
diff --git a/tests/async/t7758.nim b/tests/async/t7758.nim
index 102a4ce4c..ce4df1fc9 100644
--- a/tests/async/t7758.nim
+++ b/tests/async/t7758.nim
@@ -1,7 +1,3 @@
-discard """
-  file: "t7758.nim"
-  exitcode: 0
-"""
 import asyncdispatch
 
 proc task() {.async.} =
@@ -16,4 +12,4 @@ proc main() =
 
   doAssert counter <= 4
 
-for i in 0 .. 10: main()
\ No newline at end of file
+for i in 0 .. 10: main()
diff --git a/tests/async/t8982.nim b/tests/async/t8982.nim
new file mode 100644
index 000000000..5face7edf
--- /dev/null
+++ b/tests/async/t8982.nim
@@ -0,0 +1,33 @@
+discard """
+output: '''
+timeout
+runForever should throw ValueError, this is expected
+'''
+"""
+
+
+import asyncdispatch
+
+proc failingAwaitable(p: int) {.async.} =
+  await sleepAsync(500)
+  if p > 0:
+    raise newException(Exception, "my exception")
+
+proc main() {.async.} =
+  let fut = failingAwaitable(1)
+  try:
+    await fut or sleepAsync(100)
+    if fut.finished:
+      echo "finished"
+    else:
+      echo "timeout"
+  except:
+    echo "failed"
+
+
+# Previously this would raise "An attempt was made to complete a Future more than once."
+try:
+  asyncCheck main()
+  runForever()
+except ValueError:
+  echo "runForever should throw ValueError, this is expected"
diff --git a/tests/async/tasyncRecvLine.nim b/tests/async/tasyncRecvLine.nim
index 679831b27..a13a171c3 100644
--- a/tests/async/tasyncRecvLine.nim
+++ b/tests/async/tasyncRecvLine.nim
@@ -1,6 +1,5 @@
 discard """
-  file: "tasyncRecvLine.nim"
-  output: '''
+output: '''
 Hello World
 Hello World
 '''
diff --git a/tests/async/tasync_gcunsafe.nim b/tests/async/tasync_gcunsafe.nim
index f4e2cdcf2..55b66aaef 100644
--- a/tests/async/tasync_gcunsafe.nim
+++ b/tests/async/tasync_gcunsafe.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "'anotherGCSafeAsyncProcIter' is not GC-safe as it calls 'asyncGCUnsafeProc'"
   cmd: "nim c --threads:on $file"
   file: "asyncmacro.nim"
-  errormsg: "'anotherGCSafeAsyncProcIter' is not GC-safe as it calls 'asyncGCUnsafeProc'"
 """
 
 assert compileOption("threads"), "this test will not do anything useful without --threads:on"
diff --git a/tests/async/tasyncall.nim b/tests/async/tasyncall.nim
index 775dd0c6f..3c318dbf7 100644
--- a/tests/async/tasyncall.nim
+++ b/tests/async/tasyncall.nim
@@ -1,8 +1,7 @@
 discard """
-  file: "tasyncall.nim"
   exitcode: 0
 """
-import times, sequtils, unittest
+import times, sequtils
 import asyncdispatch
 
 const
diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim
index e7a2ec1d9..fcb48a1f5 100644
--- a/tests/async/tasyncawait.nim
+++ b/tests/async/tasyncawait.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tasyncawait.nim"
   output: "5000"
 """
 import asyncdispatch, nativesockets, net, strutils, os
diff --git a/tests/async/tasyncconnect.nim b/tests/async/tasyncconnect.nim
index 3dac379b2..f63a87990 100644
--- a/tests/async/tasyncconnect.nim
+++ b/tests/async/tasyncconnect.nim
@@ -1,7 +1,6 @@
 discard """
-  file: "tasyncconnect.nim"
-  exitcode: 1
   outputsub: "Error: unhandled exception: Connection refused"
+  exitcode: 1
 """
 
 import
diff --git a/tests/async/tasyncdial.nim b/tests/async/tasyncdial.nim
index fa81235fe..815520294 100644
--- a/tests/async/tasyncdial.nim
+++ b/tests/async/tasyncdial.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tasyncdial.nim"
   output: '''
 OK AF_INET
 OK AF_INET6
diff --git a/tests/async/tasyncexceptions.nim b/tests/async/tasyncexceptions.nim
index 7aa1d7fb0..de61c099d 100644
--- a/tests/async/tasyncexceptions.nim
+++ b/tests/async/tasyncexceptions.nim
@@ -1,7 +1,6 @@
 discard """
-  file: "tasyncexceptions.nim"
-  exitcode: 1
   outputsub: "Error: unhandled exception: foobar"
+  exitcode: 1
 """
 import asyncdispatch
 
@@ -28,7 +27,7 @@ proc serve() {.async.} =
     var fut = await accept()
     await processClient(fut)
 
-when isMainModule:
+when true:
   proc main =
     var fut = serve()
     fut.callback =
diff --git a/tests/async/tasyncfile.nim b/tests/async/tasyncfile.nim
index c7b71a2f7..d95850c31 100644
--- a/tests/async/tasyncfile.nim
+++ b/tests/async/tasyncfile.nim
@@ -1,10 +1,9 @@
 discard """
-  output: '''13
+output: '''
+13
 hello humans!
 13
 '''
-  file: "tasyncfile.nim"
-  exitcode: 0
 """
 import asyncfile, asyncdispatch, os
 
@@ -54,8 +53,7 @@ proc main() {.async.} =
 
   # Issue #7347
   block:
-    let appDir = getAppDir()
-    var file = openAsync(appDir & DirSep & "hello.txt")
+    var file = openAsync( parentDir(currentSourcePath) / "hello.txt")
     echo file.getFileSize()
     echo await file.readAll()
     echo file.getFilePos()
diff --git a/tests/async/tasyncrecursion.nim b/tests/async/tasyncrecursion.nim
index 1aeebe9b4..7c12dbb0e 100644
--- a/tests/async/tasyncrecursion.nim
+++ b/tests/async/tasyncrecursion.nim
@@ -1,6 +1,5 @@
 discard """
-  file: "tasyncrecursion.nim"
-  output: "50005000"
+output: "50005000"
 """
 import asyncdispatch
 
@@ -16,7 +15,7 @@ proc asyncRecursionTest*(): Future[int] {.async.} =
     inc(result, await asyncRecursionCycle(i))
     inc(i)
 
-when isMainModule:
+when true:
   setGlobalDispatcher(newDispatcher())
   var i = waitFor asyncRecursionTest()
   echo i
diff --git a/tests/async/tasyncsend4757.nim b/tests/async/tasyncsend4757.nim
index 752bb3e75..a87c5df95 100644
--- a/tests/async/tasyncsend4757.nim
+++ b/tests/async/tasyncsend4757.nim
@@ -1,6 +1,5 @@
 discard """
-  file: "tasyncsend4754.nim"
-  output: "Finished"
+output: "Finished"
 """
 
 import asyncdispatch, asyncnet
diff --git a/tests/async/tasyncssl.nim b/tests/async/tasyncssl.nim
index 0607cf3c6..88a5eb32e 100644
--- a/tests/async/tasyncssl.nim
+++ b/tests/async/tasyncssl.nim
@@ -1,8 +1,13 @@
 discard """
-  file: "tasyncssl.nim"
   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):
@@ -62,5 +67,3 @@ when defined(ssl):
 
   assert msgCount == swarmSize * messagesToSend
   echo msgCount
-
-
diff --git a/tests/async/tasynctry.nim b/tests/async/tasynctry.nim
index 0fe9efdc1..b13c57951 100644
--- a/tests/async/tasynctry.nim
+++ b/tests/async/tasynctry.nim
@@ -1,7 +1,5 @@
 discard """
-  file: "tasynctry.nim"
-  exitcode: 0
-  output: '''
+output: '''
 Generic except: Test
 Specific except
 Multiple idents in except
diff --git a/tests/async/tawaitsemantics.nim b/tests/async/tawaitsemantics.nim
index 98fb5dfd5..67903cc5e 100644
--- a/tests/async/tawaitsemantics.nim
+++ b/tests/async/tawaitsemantics.nim
@@ -1,7 +1,5 @@
 discard """
-  file: "tawaitsemantics.nim"
-  exitcode: 0
-  output: '''
+output: '''
 Error can be caught using yield
 Infix `or` raises
 Infix `and` raises
diff --git a/tests/async/tcallbacks.nim b/tests/async/tcallbacks.nim
index 8c08032cd..bd82d5824 100644
--- a/tests/async/tcallbacks.nim
+++ b/tests/async/tcallbacks.nim
@@ -1,8 +1,9 @@
 discard """
   exitcode: 0
-  output: '''3
-2
+  output: '''
 1
+2
+3
 5
 '''
 """
diff --git a/tests/async/tfuturestream.nim b/tests/async/tfuturestream.nim
index 69ad80f47..b5772d5ac 100644
--- a/tests/async/tfuturestream.nim
+++ b/tests/async/tfuturestream.nim
@@ -1,7 +1,5 @@
 discard """
-  file: "tfuturestream.nim"
-  exitcode: 0
-  output: '''
+output: '''
 0
 1
 2
@@ -70,4 +68,4 @@ waitFor testCompletion()
 
 #   echo("Finished")
 
-# waitFor omega()
\ No newline at end of file
+# waitFor omega()
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/async/tioselectors.nim b/tests/async/tioselectors.nim
index 7a8986644..be6d3a167 100644
--- a/tests/async/tioselectors.nim
+++ b/tests/async/tioselectors.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tioselectors.nim"
   output: "All tests passed!"
 """
 import selectors
diff --git a/tests/async/tnewasyncudp.nim b/tests/async/tnewasyncudp.nim
index b442c0524..7dbd5a3d0 100644
--- a/tests/async/tnewasyncudp.nim
+++ b/tests/async/tnewasyncudp.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tnewasyncudp.nim"
   output: "5000"
 """
 import asyncdispatch, nativesockets, net, strutils, os
diff --git a/tests/async/tpendingcheck.nim b/tests/async/tpendingcheck.nim
index 825acb613..a5537d8cb 100644
--- a/tests/async/tpendingcheck.nim
+++ b/tests/async/tpendingcheck.nim
@@ -1,6 +1,4 @@
 discard """
-  file: "tpendingcheck.nim"
-  exitcode: 0
   output: ""
 """
 
@@ -18,4 +16,3 @@ while not f.finished:
 f.read
 
 doAssert(not hasPendingOperations())
-
diff --git a/tests/async/twinasyncrw.nim b/tests/async/twinasyncrw.nim
index 94193e921..64c5d6c26 100644
--- a/tests/async/twinasyncrw.nim
+++ b/tests/async/twinasyncrw.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "twinasyncrw.nim"
   output: "5000"
 """
 when defined(windows):
diff --git a/tests/benchmark.nim b/tests/benchmark.nim
deleted file mode 100644
index 69c9a3927..000000000
--- a/tests/benchmark.nim
+++ /dev/null
@@ -1,47 +0,0 @@
-#
-#
-#            Nim Benchmark tool
-#        (c) Copyright 2012 Dominik Picheta
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## This program runs benchmarks
-import osproc, os, times, json
-
-type
-  TBenchResult = tuple[file: string, success: bool, time: float]
-
-proc compileBench(file: string) =
-  ## Compiles ``file``.
-  doAssert(execCmdEx("nim c -d:release " & file).exitCode == QuitSuccess)
-
-proc runBench(file: string): TBenchResult =
-  ## Runs ``file`` and returns info on how long it took to run.
-  var start = epochTime()
-  if execCmdEx(file.addFileExt(ExeExt)).exitCode == QuitSuccess:
-    var t = epochTime() - start
-    result = (file, true, t)
-  else: result = (file, false, -1.0)
-
-proc genOutput(benches: seq[TBenchResult]): PJsonNode =
-  result = newJObject()
-  for i in benches:
-    if i.success:
-      result[i.file.extractFilename] = newJFloat(i.time)
-    else:
-      result[i.file.extractFilename] = newJNull()
-
-proc doBench(): seq[TBenchResult] =
-  result = @[]
-  for i in walkFiles("tests/benchmarks/*.nim"):
-    echo(i.extractFilename)
-    compileBench(i)
-    result.add(runBench(i))
-
-when isMainModule:
-  var b = doBench()
-  var output = genOutput(b)
-  writeFile("benchmarkResults.json", pretty(output))
-
diff --git a/tests/benchmarks/fannkuch.nim b/tests/benchmarks/fannkuch.nim
deleted file mode 100644
index 55405b3c9..000000000
--- a/tests/benchmarks/fannkuch.nim
+++ /dev/null
@@ -1,69 +0,0 @@
-import os
-import strutils
-
-proc fannkuch (n: int): int =
-    var
-        count: seq[int]
-        maxFlips = 0
-        m        = n-1
-        r        = n
-        check    = 0
-        perm1: seq[int]
-        perm:  seq[int]
-
-    newSeq (count, n+1)
-    newSeq (perm1, n)
-    newSeq (perm, n)
-    for i in 0 .. n-1:
-        count[i] = i+1
-        perm1[i] = i
-        perm[i]  = i
-    count[n] = n+1
-
-    while True:
-        if check < 30:
-            for i in items (perm1):
-                write (stdout, $(i+1))
-            echo ("")
-            inc (check)
-
-        while r != 1:
-            count[r-1] = r
-            dec (r)
-
-        if perm1[0] != 0 and perm1[m] != m:
-            # perm = perm1
-            # The above line is between 3 and 4 times slower than the loop below!
-            for i in 0 .. n-1:
-                perm[i] = perm1[i]
-            var flipsCount = 0
-            var k = perm[0]
-            while k != 0:
-                for i in 0 .. (k div 2):
-                    swap (perm[i], perm[k-i])
-                inc (flipsCount)
-                k = perm[0]
-
-            if flipsCount > maxFlips:
-                maxFlips = flipsCount
-
-        block makePerm:
-            while r != n:
-                var tmp = perm1[0]
-                # # perm1.delete (0)
-                # # perm1.insert (tmp, r)
-                # # The above is about twice as slow as the following:
-                # moveMem (addr (perm1[0]), addr (perm1[1]), r * sizeof (int))
-                # The call to moveMem is about 50% slower than the loop below!
-                for i in 0 .. r-1:
-                    perm1[i] = perm1[i+1]
-                perm1[r] = tmp
-
-                dec (count[r])
-                if count[r] > 0:
-                    break makePerm
-                inc (r)
-            return maxFlips
-
-var n = 10
-echo ("Pfannkuchen(" & $n & ") = " & $fannkuch (n))
diff --git a/tests/benchmarks/quicksort.nim b/tests/benchmarks/quicksort.nim
deleted file mode 100644
index 6a1222b9a..000000000
--- a/tests/benchmarks/quicksort.nim
+++ /dev/null
@@ -1,54 +0,0 @@
-import os
-import strutils
-
-# Generate some pseudo-random data
-var seed: tuple[s1, s2, s3: int32] = (2'i32, 8'i32, 16'i32)
-
-proc random(): int32 =
-    seed = (((((((seed[0] and 0x0007_FFFF'i32) shl 13'i32) xor seed[0]) shr
-               19'i32) and 0x0000_1FFF'i32) xor
-             ((seed[0] and 0x000F_FFFE'i32) shl 12'i32)),
-
-            ((((((seed[1] and 0x3FFF_FFFF'i32) shl  2'i32) xor seed[1]) shr
-               25'i32) and 0x0000_007F'i32) xor
-             ((seed[1] and 0x0FFF_FFF8'i32) shl  4'i32)),
-
-            ((((((seed[2] and 0x1FFF_FFFF'i32) shl  3'i32) xor seed[2]) shr
-               11'i32) and 0x001F_FFFF'i32) xor
-             ((seed[2] and 0x0000_7FF0'i32) shl 17'i32)))
-    return seed[0] xor seed[1] xor seed[2]
-
-var n = 9999999
-
-var data: seq[int32]
-newSeq (data, n)
-for i in 0 .. data.high():
-    data[i] = random()
-
-
-proc `$` (d: seq[int32]): string =
-    result = "[ "
-    for i in items (d):
-        result.addSep (", ", 2)
-        result.add ($(i and 0xFFFF_FFFF'i64))
-    result.add (" ]")
-
-# Sort the data
-proc sort (start, stop: int) =
-    if stop <= start+1:
-        return
-
-    var j = start
-    for i in start..stop-2:
-        if data[i] <% data[stop-1]:
-            swap (data[i], data[j])
-            inc (j)
-    swap (data[j], data[stop-1])
-
-    sort (start, j)
-    sort (j+1, stop)
-
-sort (0, data.len)
-echo (data[n div 2 - 1] and 0xFFFF_FFFF'i64, ", ",
-      data[n div 2] and 0xFFFF_FFFF'i64, ", ",
-      data[n div 2 + 1] and 0xFFFF_FFFF'i64)
diff --git a/tests/bind/tbind.nim b/tests/bind/tbind.nim
index 6fcf95433..49c37ae2e 100644
--- a/tests/bind/tbind.nim
+++ b/tests/bind/tbind.nim
@@ -1,7 +1,5 @@
 discard """
-  file: "tbind.nim"
-  output:
-'''
+output: '''
 3
 1
 1
diff --git a/tests/bind/tbind2.nim b/tests/bind/tbind2.nim
index 799b14381..fc2eeda1a 100644
--- a/tests/bind/tbind2.nim
+++ b/tests/bind/tbind2.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "ambiguous call"
   file: "tbind2.nim"
   line: 12
-  errormsg: "ambiguous call"
 """
 # Test the new ``bind`` keyword for templates
 
@@ -12,6 +12,3 @@ template tempBind(x, y): untyped =
   (bind p1(x, y))  #ERROR_MSG ambiguous call
 
 echo tempBind(1'i8, 2'i8)
-
-
-
diff --git a/tests/bind/tdatabind.nim b/tests/bind/tdatabind.nim
index 124faee6f..f6455749c 100644
--- a/tests/bind/tdatabind.nim
+++ b/tests/bind/tdatabind.nim
@@ -74,7 +74,7 @@ proc propertyBind*[T](p1: var TProperty[T], p2: var TProperty[T]) =
 proc `->`[T](p1: var TProperty[T], p2: var TProperty[T]) =
   propertyBind(p2,p1)
 
-when isMainModule:
+when true:
   # Initial value testing
   var myProp = newProperty(5)
 
diff --git a/tests/bind/tinvalidbindtypedesc.nim b/tests/bind/tinvalidbindtypedesc.nim
index ecdd12603..4bcd4e39d 100644
--- a/tests/bind/tinvalidbindtypedesc.nim
+++ b/tests/bind/tinvalidbindtypedesc.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 10
   errormsg: "type mismatch: got <type float, string>"
+  line: 10
 """
 
 proc foo(T: typedesc; some: T) =
@@ -8,4 +8,3 @@ proc foo(T: typedesc; some: T) =
 
 foo int, 4
 foo float, "bad"
-
diff --git a/tests/bind/tnicerrorforsymchoice.nim b/tests/bind/tnicerrorforsymchoice.nim
index 8c3a99c97..f16b323de 100644
--- a/tests/bind/tnicerrorforsymchoice.nim
+++ b/tests/bind/tnicerrorforsymchoice.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 18
   errormsg: "type mismatch: got <proc (s: TScgi: ScgiState or AsyncScgiState) | proc (client: AsyncSocket, headers: StringTableRef, input: string){.noSideEffect, gcsafe, locks: 0.}>"
+  line: 18
 """
 
 #bug #442
diff --git a/tests/borrow/tinvalidborrow.nim b/tests/borrow/tinvalidborrow.nim
index 9ab9e8d64..89aa4e2e8 100644
--- a/tests/borrow/tinvalidborrow.nim
+++ b/tests/borrow/tinvalidborrow.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 11
   errormsg: "no symbol to borrow from found"
+  line: 11
 """
 
 # bug #516
@@ -14,4 +14,3 @@ var
   d, e: TAtom
 
 echo( $(d == e) )
-
diff --git a/tests/caas/absurd_nesting.nim b/tests/caas/absurd_nesting.nim
deleted file mode 100644
index 136d65cc7..000000000
--- a/tests/caas/absurd_nesting.nim
+++ /dev/null
@@ -1,29 +0,0 @@
-# Tries to test the full ownership path generated by idetools.
-
-proc lev1(t1: string) =
-  var temp = t1
-  for i in 0..len(temp)-1:
-    temp[i] = chr(int(temp[i]) + 1)
-
-  proc lev2(t2: string) =
-    var temp = t2
-    for i in 0..len(temp)-1:
-      temp[i] = chr(int(temp[i]) + 1)
-
-    proc lev3(t3: string) =
-      var temp = t3
-      for i in 0..len(temp)-1:
-        temp[i] = chr(int(temp[i]) + 1)
-
-      proc lev4(t4: string) =
-        var temp = t4
-        for i in 0..len(temp)-1:
-          temp[i] = chr(int(temp[i]) + 1)
-
-        echo temp & "(lev4)"
-      lev4(temp & "(lev3)")
-    lev3(temp & "(lev2)")
-  lev2(temp & "(lev1)")
-
-when isMainModule:
-  lev1("abcd")
diff --git a/tests/caas/absurd_nesting.txt b/tests/caas/absurd_nesting.txt
deleted file mode 100644
index 986e34836..000000000
--- a/tests/caas/absurd_nesting.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-absurd_nesting.nim
-
-> c --verbosity:0 --hints:on
-SuccessX
-
-> idetools --track:$TESTNIM,6,6 --def $SILENT
-skVar\tabsurd_nesting.lev1.temp\tstring
-
-> idetools --track:$TESTNIM,21,13 --def $SILENT
-skVar\tabsurd_nesting.lev1.lev2.lev3.lev4.temp\tstring
-
-> idetools --track:$TESTNIM,6,27 --def $SILENT
-skForVar\tabsurd_nesting.lev1.i\tint
-
-> idetools --track:$TESTNIM,21,33 --def $SILENT
-skForVar\tabsurd_nesting.lev1.lev1.lev3.lev4.i\tint
-
-> idetools --track:$TESTNIM,24,8 --def $SILENT
-skProc\tabsurd_nesting.lev1.lev1.lev3.lev4\tproc \(string\)
-
-> idetools --track:$TESTNIM,4,13 --def $SILENT
-skParam\tabsurd_nesting.lev1.t1\tstring
-
-> idetools --track:$TESTNIM,4,13 --def $SILENT
-skParam\tabsurd_nesting.lev1.t1\tstring
-
-> idetools --track:$TESTNIM,19,19 --def $SILENT
-skParam\tabsurd_nesting.lev1.lev2.lev3.lev4.t4\tstring
-
diff --git a/tests/caas/basic-recompile.txt b/tests/caas/basic-recompile.txt
deleted file mode 100644
index 620e0c059..000000000
--- a/tests/caas/basic-recompile.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-main.nim
-> c --verbosity:0 --hints:on
-SuccessX
-# The "Processing" string will be found always in proc mode since each
-# compilation command will generate it. We need to test it only in Caas mode to
-# verify the server is not recompiling again the file.
-CaasRun > c --verbosity:0 --hints:on
-CaasRun ! Processing
-CaasRun SuccessX
-
diff --git a/tests/caas/compile-suggest.txt b/tests/caas/compile-suggest.txt
deleted file mode 100644
index 378320014..000000000
--- a/tests/caas/compile-suggest.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-main.nim
-> c --verbosity:0 --hints:on
-SuccessX
-> idetools --trackDirty:main_dirty.nim,$TESTNIM,12,7 --suggest $SILENT
-skField\tx
-skField\ty
-
diff --git a/tests/caas/compile-then-def.txt b/tests/caas/compile-then-def.txt
deleted file mode 100644
index 72ba46b04..000000000
--- a/tests/caas/compile-then-def.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-main.nim
-> c --verbosity:0 --hints:on
-SuccessX
-
-> idetools --track:$TESTNIM,5,18 --def --verbosity:0 --hints:on
-strutils.toUpper
-! SuccessX
-
-> idetools --track:$TESTNIM,5,18 --def --verbosity:0 --hints:on
-strutils.toUpper
-! SuccessX
diff --git a/tests/caas/completion_dot_syntax.txt b/tests/caas/completion_dot_syntax.txt
deleted file mode 100644
index 4a975e5df..000000000
--- a/tests/caas/completion_dot_syntax.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-completion_dot_syntax_main.nim
-> idetools --track:$TESTNIM,24,15 --def
-def\tskProc\t$MODULE.echoRemainingDollars
-> idetools --trackDirty:completion_dot_syntax_dirty.nim,$TESTNIM,25,12 --suggest
-sug\tskProc\techoRemainingDollars
-# The suggestion should not mention the other echoRemaining* variants.
-!echoRemainingEuros
-!echoRemainingBugs
-
diff --git a/tests/caas/completion_dot_syntax_dirty.nim b/tests/caas/completion_dot_syntax_dirty.nim
deleted file mode 100644
index 6237c4e79..000000000
--- a/tests/caas/completion_dot_syntax_dirty.nim
+++ /dev/null
@@ -1,25 +0,0 @@
-import strutils
-
-# Verifies if the --suggestion switch differentiates types for dot notation.
-
-type
-  TDollar = distinct int
-  TEuro = distinct int
-
-proc echoRemainingDollars(amount: TDollar) =
-  echo "You have $1 dollars" % [$int(amount)]
-
-proc echoRemainingEuros(amount: TEuro) =
-  echo "You have $1 euros" % [$int(amount)]
-
-proc echoRemainingBugs() =
-  echo "You still have bugs"
-
-proc main =
-  var
-    d: TDollar
-    e: TEuro
-  d = TDollar(23)
-  e = TEuro(32)
-  d.echoRemainingDollars()
-  e.echoRemai
diff --git a/tests/caas/completion_dot_syntax_main.nim b/tests/caas/completion_dot_syntax_main.nim
deleted file mode 100644
index 0be8c7f4f..000000000
--- a/tests/caas/completion_dot_syntax_main.nim
+++ /dev/null
@@ -1,24 +0,0 @@
-import strutils
-
-# Verifies if the --suggestion switch differentiates types for dot notation.
-
-type
-  TDollar = distinct int
-  TEuro = distinct int
-
-proc echoRemainingDollars(amount: TDollar) =
-  echo "You have $1 dollars" % [$int(amount)]
-
-proc echoRemainingEuros(amount: TEuro) =
-  echo "You have $1 euros" % [$int(amount)]
-
-proc echoRemainingBugs() =
-  echo "You still have bugs"
-
-proc main =
-  var
-    d: TDollar
-    e: TEuro
-  d = TDollar(23)
-  e = TEuro(32)
-  d.echoRemainingDollars()
diff --git a/tests/caas/def-def-compile.txt b/tests/caas/def-def-compile.txt
deleted file mode 100644
index 21d5ea962..000000000
--- a/tests/caas/def-def-compile.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-main.nim
-> idetools --track:$TESTNIM,5,18 --def --verbosity:0 --hints:on
-strutils.toUpper
-! SuccessX
-
-> idetools --track:$TESTNIM,5,18 --def --verbosity:0 --hints:on
-strutils.toUpper
-! SuccessX
-
-> c --verbosity:0 --hints:on
-SuccessX
-
diff --git a/tests/caas/def-then-compile.txt b/tests/caas/def-then-compile.txt
deleted file mode 100644
index 2214bf02c..000000000
--- a/tests/caas/def-then-compile.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-main.nim
-> idetools --track:$TESTNIM,5,18 --def --verbosity:0 --hints:on
-strutils.toUpper
-! SuccessX
-
-> c --verbosity:0 --hints:on
-SuccessX
-
diff --git a/tests/caas/forward_declarations.nim b/tests/caas/forward_declarations.nim
deleted file mode 100644
index 177d82f20..000000000
--- a/tests/caas/forward_declarations.nim
+++ /dev/null
@@ -1,15 +0,0 @@
-# This example shows that idetools returns an empty signature for a forward
-# declared proc in proc/symproc runs, but correctly returns the full signature
-# in caas mode.
-
-proc echoHello(text: string)
-
-proc testForward() =
-  echo "T"
-  echoHello("T")
-
-proc echoHello(text: string) =
-  echo "Hello Mr." & text
-
-when isMainModule:
-  testForward()
diff --git a/tests/caas/forward_declarations.txt b/tests/caas/forward_declarations.txt
deleted file mode 100644
index b1695b9c7..000000000
--- a/tests/caas/forward_declarations.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-forward_declarations.nim
-
-> idetools --track:$TESTNIM,9,5 --def $SILENT
-skProc
-proc \(string\)
-
-> idetools --track:$TESTNIM,5,9 --def $SILENT
-skProc
-proc \(string\)
diff --git a/tests/caas/forward_usages.txt b/tests/caas/forward_usages.txt
deleted file mode 100644
index 05ef517dc..000000000
--- a/tests/caas/forward_usages.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-forward_declarations.nim
-
-> c --verbosity:0 --hints:on
-SuccessX
-
-# None of the following return three instances of the echoHello proc, the first
-# being the forward declaration, the second being the usage inside testForward,
-# and the third being the actual implementation.
-
-> idetools --track:$TESTNIM,5,5 --usages $SILENT
-skProc.*\n.*skProc.*\n.*skProc
-
-> idetools --track:$TESTNIM,9,5 --usages $SILENT
-skProc.*\n.*skProc.*\n.*skProc
-
-> idetools --track:$TESTNIM,11,5 --usages $SILENT
-skProc.*\n.*skProc.*\n.*skProc
diff --git a/tests/caas/idetools_api.nim b/tests/caas/idetools_api.nim
deleted file mode 100644
index 281e562d7..000000000
--- a/tests/caas/idetools_api.nim
+++ /dev/null
@@ -1,84 +0,0 @@
-import unicode, sequtils, macros, re
-
-proc test_enums() =
-  var o: Tfile
-  if o.open("files " & "test.txt", fmWrite):
-    o.write("test")
-    o.close()
-
-proc test_iterators(filename = "tests.nim") =
-  let
-    input = readFile(filename)
-    letters = toSeq(runes(string(input)))
-  for letter in letters: echo int(letter)
-
-const SOME_SEQUENCE = @[1, 2]
-type
-  bad_string = distinct string
-  TPerson = object of TObject
-    name*: bad_string
-    age: int
-
-proc adder(a, b: int): int =
-  result = a + b
-
-type
-  PExpr = ref object of TObject ## abstract base class for an expression
-  PLiteral = ref object of PExpr
-    x: int
-  PPlusExpr = ref object of PExpr
-    a, b: PExpr
-
-# watch out: 'eval' relies on dynamic binding
-method eval(e: PExpr): int =
-  # override this base method
-  quit "to override!"
-
-method eval(e: PLiteral): int = e.x
-method eval(e: PPlusExpr): int = eval(e.a) + eval(e.b)
-
-proc newLit(x: int): PLiteral = PLiteral(x: x)
-proc newPlus(a, b: PExpr): PPlusExpr = PPlusExpr(a: a, b: b)
-
-echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
-
-proc findVowelPosition(text: string) =
-  var found = -1
-  block loops:
-    for i, letter in pairs(text):
-      for j in ['a', 'e', 'i', 'o', 'u']:
-        if letter == j:
-          found = i
-          break loops # leave both for-loops
-  echo found
-
-findVowelPosition("Zerg") # should output 1, position of vowel.
-
-macro expect*(exceptions: varargs[expr], body: stmt): stmt {.immediate.} =
-  ## Expect docstrings
-  let exp = callsite()
-  template expectBody(errorTypes, lineInfoLit: expr,
-                      body: stmt): NimNode {.dirty.} =
-    try:
-      body
-      assert false
-    except errorTypes:
-      nil
-
-  var body = exp[exp.len - 1]
-
-  var errorTypes = newNimNode(nnkBracket)
-  for i in countup(1, exp.len - 2):
-    errorTypes.add(exp[i])
-
-  result = getAst(expectBody(errorTypes, exp.lineinfo, body))
-
-proc err =
-  raise newException(EArithmetic, "some exception")
-
-proc testMacro() =
-  expect(EArithmetic):
-    err()
-
-testMacro()
-let notAModule = re"(\w+)=(.*)"
diff --git a/tests/caas/idetools_api.txt b/tests/caas/idetools_api.txt
deleted file mode 100644
index 035590dc3..000000000
--- a/tests/caas/idetools_api.txt
+++ /dev/null
@@ -1,59 +0,0 @@
-idetools_api.nim
-> c --verbosity:0 --hints:on
-SuccessX
-> idetools --track:$TESTNIM,4,11 --def $SILENT
-def\tskType\tsystem.TFile\tTFile
-> idetools --track:$TESTNIM,5,7 --def $SILENT
-def\tskProc\tsystem.Open\tproc \(var TFile, string, TFileMode, int\): bool
-> idetools --track:$TESTNIM,5,21 --def $SILENT
-def\tskProc\tsystem.\&\tproc \(string, string\): string\{.noSideEffect.\}
-> idetools --track:$TESTNIM,5,38 --def $SILENT
-def\tskEnumField\tsystem.TFileMode.fmWrite\tTFileMode
-> idetools --track:$TESTNIM,7,6 --def $SILENT
-def\tskProc\tsystem.Close\tproc \(TFile\)
-> idetools --track:$TESTNIM,12,23 --def $SILENT
-def\tskIterator\tunicode.runes\titerator \(string\): TRune
-> idetools --track:$TESTNIM,12,15 --def $SILENT
-def\tskTemplate\tsequtils.toSeq\tproc \(expr\): expr
-> idetools --track:$TESTNIM,15,7 --def $SILENT
-
-# ProcRun mode will fail the next line, because the type is returned empty.
-def\tskConst\t$MODULE.SOME_SEQUENCE\tseq\[int\]\t
-> idetools --track:$TESTNIM,15,23 --def $SILENT
-def\tskProc\tsystem.@\tproc \(array\[IDX, T\]\): seq\[T\]\{.noSideEffect.\}
-> idetools --track:$TESTNIM,17,3 --def $SILENT
-
-# ProcRun mode will fail the next line, because the type is returned empty.
-def\tskType\t$MODULE.bad_string\tbad_string\t
-> idetools --track:$TESTNIM,11,24 --def $SILENT
-def\tskParam\t$MODULE.test_iterators.filename\tstring
-> idetools --track:$TESTNIM,6,5 --def $SILENT
-def\tskVar\t$MODULE.test_enums.o\tTFile
-> idetools --track:$TESTNIM,12,34 --def $SILENT
-def\tskLet\t$MODULE.test_iterators.input\tTaintedString
-> idetools --track:$TESTNIM,13,35 --def $SILENT
-def\tskForVar\t$MODULE.test_iterators.letter\tTRune
-> idetools --track:$TESTNIM,23,3 --def $SILENT
-def\tskResult\t$MODULE.adder.result\tint
-> idetools --track:$TESTNIM,19,6 --def $SILENT
-
-# ProcRun mode will fail the next line, because the type is returned empty.
-def\tskField\t$MODULE.TPerson.name\tbad_string\t
-
-> idetools --track:$TESTNIM,43,7 --def $SILENT
-def\tskMethod\t$MODULE.eval\tproc \(PPlusExpr\): int\t
-
-> idetools --track:$TESTNIM,47,8 --def $SILENT
-def\tskLabel\t$MODULE.findVowelPosition.loops\t\t
-# For some reason the use of the label with break displaces its position.
-> idetools --track:$TESTNIM,52,16 --def $SILENT
-def\tskLabel\t$MODULE.findVowelPosition.loops\t\t
-
-# Displaced macro usage by one character.
-> idetools --track:$TESTNIM,80,2 --def $SILENT
-def\tskMacro\t$MODULE.expect\tproc \(varargs\[expr\], stmt\): stmt\t
-
-# The syntax for extended raw string literals should not be returned as module
-# but as the proc re() inside the re module.
-> idetools --track:$TESTNIM,84,17 --def $SILENT
-!def\tskModule
diff --git a/tests/caas/imported.nim b/tests/caas/imported.nim
deleted file mode 100644
index a4bc5c0e6..000000000
--- a/tests/caas/imported.nim
+++ /dev/null
@@ -1,3 +0,0 @@
-proc `+++`*(a,b: string): string =
-  return a & "  " & b
-
diff --git a/tests/caas/issue_416_template_shift.nim b/tests/caas/issue_416_template_shift.nim
deleted file mode 100644
index d52f611d6..000000000
--- a/tests/caas/issue_416_template_shift.nim
+++ /dev/null
@@ -1,17 +0,0 @@
-import unicode, sequtils
-
-proc test() =
-  let input = readFile("weird.nim")
-  for letter in runes(string(input)):
-    echo int(letter)
-
-when 1 > 0:
-  proc failtest() =
-    let
-      input = readFile("weird.nim")
-      letters = toSeq(runes(string(input)))
-    for letter in letters:
-      echo int(letter)
-
-when isMainModule:
-  test()
diff --git a/tests/caas/issue_416_template_shift.txt b/tests/caas/issue_416_template_shift.txt
deleted file mode 100644
index e911c1360..000000000
--- a/tests/caas/issue_416_template_shift.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-issue_416_template_shift.nim
-> c --verbosity:0 --hints:on
-SuccessX
-> idetools --track:$TESTNIM,12,28 --def $SILENT
-def\tskType\tsystem.string\tstring
-> idetools --track:$TESTNIM,12,35 --def $SILENT
-def\tskLet\t$MODULE.failtest.input\tTaintedString
-
-# The following fail because they seem shifted one column to the right.
-> idetools --track:$TESTNIM,12,16 --def $SILENT
-def\tskTemplate\tsequtils.toSeq\tproc \(expr\): expr
-> idetools --track:$TESTNIM,12,22 --def $SILENT
-def\tskIterator\tunicode.runes\titerator \(string\): TRune
-
diff --git a/tests/caas/issue_452_export_shift.nim b/tests/caas/issue_452_export_shift.nim
deleted file mode 100644
index 46cff6241..000000000
--- a/tests/caas/issue_452_export_shift.nim
+++ /dev/null
@@ -1,8 +0,0 @@
-const
-  VERSION_STR1* = "0.5.0" ## Idetools shifts this one column.
-  VERSION_STR2 = "0.5.0" ## This one is ok.
-  VERSION_STR3* = "0.5.0" ## Bad.
-  VERSION_STR4 = "0.5.0" ## Ok.
-
-proc forward1*(): string = result = ""
-proc forward2(): string = result = ""
diff --git a/tests/caas/issue_452_export_shift.txt b/tests/caas/issue_452_export_shift.txt
deleted file mode 100644
index 4676ed71e..000000000
--- a/tests/caas/issue_452_export_shift.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-issue_452_export_shift.nim
-> c --verbosity:0 --hints:on
-SuccessX
-> idetools --track:$TESTNIM,2,2 --def $SILENT
-def\tskConst\t$MODULE.VERSION_STR1\tstring
-> idetools --track:$TESTNIM,3,2 --def $SILENT
-def\tskConst\t$MODULE.VERSION_STR2\tstring
-> idetools --track:$TESTNIM,7,5 --def $SILENT
-def\tskProc\t$MODULE.forward1\tproc \(\): string\t
-> idetools --track:$TESTNIM,8,5 --def $SILENT
-def\tskProc\t$MODULE.forward2\tproc \(\): string\t
diff --git a/tests/caas/issue_477_dynamic_dispatch.nim b/tests/caas/issue_477_dynamic_dispatch.nim
deleted file mode 100644
index 6e6b21ef0..000000000
--- a/tests/caas/issue_477_dynamic_dispatch.nim
+++ /dev/null
@@ -1,19 +0,0 @@
-type
-  TThing = object of TObject
-  TUnit = object of TThing
-    x: int
-
-method collide(a, b: TThing) {.inline.} =
-  quit "to override!"
-
-method collide(a: TThing, b: TUnit) {.inline.} =
-  echo "collide1"
-
-method collide(a: TUnit, b: TThing) {.inline.} =
-  echo "collide2"
-
-var
-  a, b: TUnit
-
-when isMainModule:
-  collide(a, b) # output: 2
diff --git a/tests/caas/issue_477_dynamic_dispatch.txt b/tests/caas/issue_477_dynamic_dispatch.txt
deleted file mode 100644
index 12fd750de..000000000
--- a/tests/caas/issue_477_dynamic_dispatch.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-issue_477_dynamic_dispatch.nim
-> c --run
-SuccessX
-> idetools --track:issue_477_dynamic_dispatch.nim,19,5 --def $SILENT
-def\tskMethod\tissue_477_dynamic_dispatch.collide\tproc \(TUnit, TThing\)\{.inline.\}
diff --git a/tests/caas/its_full_of_procs.nim b/tests/caas/its_full_of_procs.nim
deleted file mode 100644
index 8f8b66764..000000000
--- a/tests/caas/its_full_of_procs.nim
+++ /dev/null
@@ -1,29 +0,0 @@
-import unicode, sequtils
-
-# This example shows that idetools returns proc as signature for everything
-# which can be called. While a clever person would use the second column to
-# differentiate between procs, methods and others, why does the output contain
-# incorrect information?
-
-type
-  TThing = object of TObject
-  TUnit = object of TThing
-    x: int
-
-method collide(a, b: TThing) {.inline.} =
-  quit "to override!"
-
-method collide(a: TThing, b: TUnit) {.inline.} =
-  echo "1"
-
-method collide(a: TUnit, b: TThing) {.inline.} =
-  echo "2"
-
-var
-  a, b: TUnit
-
-let
-  input = readFile("its_full_of_procs.nim")
-  letters = toSeq(runes(string(input)))
-
-collide(a, b) # output: 2
diff --git a/tests/caas/its_full_of_procs.txt b/tests/caas/its_full_of_procs.txt
deleted file mode 100644
index 31a2d3baa..000000000
--- a/tests/caas/its_full_of_procs.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-its_full_of_procs.nim
-
-> idetools --track:$TESTNIM,26,15 --def $SILENT
-skProc
-proc \(
-
-> idetools --track:$TESTNIM,27,21 --def $SILENT
-skIterator
-iterator \(
-!proc \(
-
-> idetools --track:$TESTNIM,29,0 --def $SILENT
-skMethod
-method \(
-!proc \(
-
-> idetools --track:$TESTNIM,27,15 --def $SILENT
-skTemplate
-template \(
-!proc \(
diff --git a/tests/caas/main.nim b/tests/caas/main.nim
deleted file mode 100644
index fafeff93b..000000000
--- a/tests/caas/main.nim
+++ /dev/null
@@ -1,7 +0,0 @@
-import imported, strutils
-
-proc main =
-  var t1 = "text"
-  var t2 = t1.toUpper
-  echo(t1 +++ t2)
-
diff --git a/tests/caas/main_dirty.nim b/tests/caas/main_dirty.nim
deleted file mode 100644
index 95fb6c624..000000000
--- a/tests/caas/main_dirty.nim
+++ /dev/null
@@ -1,14 +0,0 @@
-import imported, strutils
-
-type
-  TFoo = object
-    x: int
-    y: string
-
-proc main =
-  var t1 = "text"
-  var t2 = t1.toUpper
-  var foo = TFoo(x: 10, y: "test")
-  foo.
-  echo(t1 +++ t2)
-
diff --git a/tests/caas/suggest-compile.txt b/tests/caas/suggest-compile.txt
deleted file mode 100644
index a322908ac..000000000
--- a/tests/caas/suggest-compile.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-main.nim
-# This example shows how the suggest feature can be used on a partial file
-# using the --trackDirty switch.
-> idetools --trackDirty:main_dirty.nim,$TESTNIM,12,7 --suggest $SILENT
-skField\tx
-skField\ty
-# Repeating the query in caas should work always and retrieve same output.
-CaasRun > idetools --trackDirty:main_dirty.nim,$TESTNIM,12,7 --suggest $SILENT
-CaasRun skField\tx
-CaasRun skField\ty
-> c --verbosity:0 --hints:on
-SuccessX
-
diff --git a/tests/caas/suggest-invalid-source.txt b/tests/caas/suggest-invalid-source.txt
deleted file mode 100644
index 7f8f1213d..000000000
--- a/tests/caas/suggest-invalid-source.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-main_dirty.nim
-# A variant of the suggest-compile.txt, instead of using a "base" correct
-# source, this one uses the "broken" main_dirty.nim which won't compile. The
-# test tries to stress idetools to still provide a valid answer if possible,
-# and at least provide the same output with repeated queries rather than dying
-# after the first compilation error.
-
-# The first query should work and provide valid suggestions.
-> idetools --track:$TESTNIM,12,6 --suggest $SILENT
-skField\tx
-skField\ty
-
-# Repeating the query should work too.
-> idetools --track:$TESTNIM,12,6 --suggest $SILENT
-skField\tx
-skField\ty
-
-# Expect now a compilation failure.
-> c
-!SuccessX
-invalid indentation
-
-# Repeating suggestions *after broken compilation* should work too.
-> idetools --track:$TESTNIM,12,6 --suggest $SILENT
-skField\tx
-skField\ty
diff --git a/tests/casestmt/t7699.nim b/tests/casestmt/t7699.nim
index ea08388eb..1354551c1 100644
--- a/tests/casestmt/t7699.nim
+++ b/tests/casestmt/t7699.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 13
   errormsg: "case statement cannot work on enums with holes for computed goto"
+  line: 13
 """
 
 type
diff --git a/tests/casestmt/tcaseexpr1.nim b/tests/casestmt/tcaseexpr1.nim
index 24543f1b8..4fdac8191 100644
--- a/tests/casestmt/tcaseexpr1.nim
+++ b/tests/casestmt/tcaseexpr1.nim
@@ -1,13 +1,17 @@
 discard """
-  file: "tcaseexpr1.nim"
-
-  line: 29
   errormsg: "type mismatch: got <string> but expected 'int'"
+  line: 33
+  file: "tcaseexpr1.nim"
 
-  line: 23
   errormsg: "not all cases are covered"
+  line: 27
+  file: "tcaseexpr1.nim"
 """
 
+# NOTE: This spec is wrong. Spec doesn't support multiple error
+# messages. The first one is simply overridden by the second one.
+# This just has never been noticed.
+
 type
   E = enum A, B, C
 
@@ -27,4 +31,3 @@ var t1 = case x:
 var t2 = case x:
   of A: 10
   of B, C: "23"
-
diff --git a/tests/casestmt/tcaseoverlaprange.nim b/tests/casestmt/tcaseoverlaprange.nim
index 3527c9385..e9651c69f 100644
--- a/tests/casestmt/tcaseoverlaprange.nim
+++ b/tests/casestmt/tcaseoverlaprange.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 13
   errormsg: "duplicate case label"
+  line: 13
 """
 
 type
diff --git a/tests/casestmt/tcaseoverlaprange2.nim b/tests/casestmt/tcaseoverlaprange2.nim
index 4a9479a5f..4a1cb3ea6 100644
--- a/tests/casestmt/tcaseoverlaprange2.nim
+++ b/tests/casestmt/tcaseoverlaprange2.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 13
   errormsg: "duplicate case label"
+  line: 13
 """
 
 
diff --git a/tests/casestmt/tcasestmt.nim b/tests/casestmt/tcasestmt.nim
index 333700197..465080e84 100644
--- a/tests/casestmt/tcasestmt.nim
+++ b/tests/casestmt/tcasestmt.nim
@@ -1,6 +1,5 @@
 discard """
-  file: "tcasestmt.nim"
-  output:
+output:
 '''
 Not found!
 Found!
@@ -226,4 +225,4 @@ block tcasestm:
         "invalid Y".quit(3)
         true
       else: raise newException(ValueError, "Invalid")
-  ))
\ No newline at end of file
+  ))
diff --git a/tests/casestmt/tcomputedgoto.nim b/tests/casestmt/tcomputedgoto.nim
index 58ef3caa4..f7603dac3 100644
--- a/tests/casestmt/tcomputedgoto.nim
+++ b/tests/casestmt/tcomputedgoto.nim
@@ -1,16 +1,22 @@
 discard """
   output: '''
 yeah A enumB
+uneven
 yeah A enumB
 yeah CD enumD
+uneven
 yeah CD enumE
 yeah A enumB
+uneven
 yeah CD enumE
 yeah CD enumD
+uneven
 yeah A enumB
 yeah B enumC
+uneven
 yeah A enumB
 yeah A enumB
+uneven
 yeah A enumB
 '''
 """
@@ -47,4 +53,7 @@ proc vm() =
     of enumLast: discard
     inc(pc)
 
+    if pc mod 2 == 1:
+      echo "uneven"
+
 vm()
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/t8616.nim b/tests/ccgbugs/t8616.nim
index 54068652a..5fd940d3b 100644
--- a/tests/ccgbugs/t8616.nim
+++ b/tests/ccgbugs/t8616.nim
@@ -1,4 +1,4 @@
 import pkg8616 / scheduler
 
-when isMainModule:
+when true:
   init()
diff --git a/tests/ccgbugs/t8781.nim b/tests/ccgbugs/t8781.nim
index 1fa8ec8a5..884c6962a 100644
--- a/tests/ccgbugs/t8781.nim
+++ b/tests/ccgbugs/t8781.nim
@@ -18,7 +18,7 @@ type
     of false:
         region: float
 
-when isMainModule:
+when true:
   let r = 1.5
   let a = TypeOne(animatedU: true,
                   animated: false,
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/tcgbug.nim b/tests/ccgbugs/tcgbug.nim
index ffaa91ff3..eda475d4f 100644
--- a/tests/ccgbugs/tcgbug.nim
+++ b/tests/ccgbugs/tcgbug.nim
@@ -1,6 +1,6 @@
 discard """
-  file: "tcgbug.nim"
-  output: '''success
+output: '''
+success
 M1 M2
 '''
 """
@@ -74,5 +74,5 @@ proc newMyObjectRef(kind: MyKind, val: string): MyObjectRef =
     of M2: result.b = parseFloat(val)
     of M3: result.c = val
 
- 
-echo newMyObject(M1, "2").kind, " ", newMyObjectRef(M2, "3").kind
\ No newline at end of file
+
+echo newMyObject(M1, "2").kind, " ", newMyObjectRef(M2, "3").kind
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/tconstobj.nim b/tests/ccgbugs/tconstobj.nim
deleted file mode 100644
index 51cf661ee..000000000
--- a/tests/ccgbugs/tconstobj.nim
+++ /dev/null
@@ -1,16 +0,0 @@
-discard """
-  output: '''(FirstName: "James", LastName: "Franco")'''
-"""
-
-# bug #1547
-import tables
-
-type Person* = object
-    FirstName*: string
-    LastName*: string
-
-let people = {
-    "001": Person(FirstName: "James", LastName: "Franco")
-}.toTable()
-
-echo people["001"]
diff --git a/tests/ccgbugs/tcvarargs.nim b/tests/ccgbugs/tcvarargs.nim
index ebaf83a4a..261885f4f 100644
--- a/tests/ccgbugs/tcvarargs.nim
+++ b/tests/ccgbugs/tcvarargs.nim
@@ -12,6 +12,7 @@ discard """
 
 {.emit: """
 #include <stdarg.h>
+#include <stdio.h>
 
 void foo(int n, ...) {
   NI64 k;
diff --git a/tests/ccgbugs/tgeneric_closure.nim b/tests/ccgbugs/tgeneric_closure.nim
index f9d5e7910..9f3c5b446 100644
--- a/tests/ccgbugs/tgeneric_closure.nim
+++ b/tests/ccgbugs/tgeneric_closure.nim
@@ -1,4 +1,10 @@
-
+discard """
+output: '''
+2
+2
+2
+'''
+"""
 
 # bug 2659
 
@@ -9,7 +15,7 @@ type
 proc mult(x:int, y:var int) =
   y = 2 * x
 
-when isMainModule:
+when true:
 
   var input = 1
   var output = 0
diff --git a/tests/ccgbugs/tgeneric_smallobj_asgn_opt.nim b/tests/ccgbugs/tgeneric_smallobj_asgn_opt.nim
index 919dc3fc1..3788b9985 100644
--- a/tests/ccgbugs/tgeneric_smallobj_asgn_opt.nim
+++ b/tests/ccgbugs/tgeneric_smallobj_asgn_opt.nim
@@ -1,5 +1,5 @@
 discard """
-  output: '''false'''
+  output: "done generic smallobj asgn opt"
 """
 
 # bug #5402
@@ -23,4 +23,5 @@ proc newListOfContainers[T](): ListOfContainers[T] =
   result.list = initDoublyLinkedList[Container[T]]()
 
 let q = newListOfContainers[int64]()
-echo q.contains(123)
+if not q.contains(123):
+  echo "done generic smallobj asgn opt"
diff --git a/tests/ccgbugs/tinefficient_const_table.nim b/tests/ccgbugs/tinefficient_const_table.nim
index 149b8bcff..7422d0676 100644
--- a/tests/ccgbugs/tinefficient_const_table.nim
+++ b/tests/ccgbugs/tinefficient_const_table.nim
@@ -6,9 +6,9 @@ of
 words'''
   cmd: r"nim c --hints:on $options -d:release $file"
   ccodecheck: "! @'genericSeqAssign'"
+  target: "c"
 """
 
-
 # bug #4354
 import tables
 import sets
diff --git a/tests/ccgbugs/tmarkerproc_regression.nim b/tests/ccgbugs/tmarkerproc_regression.nim
index 99b38e3ec..3b606b834 100644
--- a/tests/ccgbugs/tmarkerproc_regression.nim
+++ b/tests/ccgbugs/tmarkerproc_regression.nim
@@ -1,5 +1,5 @@
 discard """
-  output: "done"
+  output: "done markerproc regression"
 """
 
 type
@@ -42,6 +42,6 @@ proc main =
     let expected = $i & "some longer text here " & $i
     if a[i].ver.string != expected:
       quit "bug!"
-  echo "done"
+  echo "done markerproc regression"
 
 main()
diff --git a/tests/ccgbugs/tmissingbracket.nim b/tests/ccgbugs/tmissingbracket.nim
index 886884d0c..468e13366 100644
--- a/tests/ccgbugs/tmissingbracket.nim
+++ b/tests/ccgbugs/tmissingbracket.nim
@@ -1,6 +1,8 @@
 discard """
-  output: '''Subobject test called
-5'''
+output: '''
+Subobject test called
+5
+'''
 """
 
 type
@@ -38,7 +40,7 @@ type
         t:int
     SubObject* = object of TestObj
 
-method test*(t:var TestObj) =
+method test*(t:var TestObj) {.base.} =
     echo "test called"
 
 method test*(t:var SubObject) =
@@ -49,4 +51,3 @@ var a: SubObject
 
 a.test()
 echo a.t
-
diff --git a/tests/ccgbugs/tmissinginit.nim b/tests/ccgbugs/tmissinginit.nim
index b4087008a..8806a2f21 100644
--- a/tests/ccgbugs/tmissinginit.nim
+++ b/tests/ccgbugs/tmissinginit.nim
@@ -27,4 +27,4 @@ echo bug()[0]
 echo bug()[0]
 echo bug()[0]
 
-when isMainModule: test()
+test()
diff --git a/tests/ccgbugs/tmissingvolatile.nim b/tests/ccgbugs/tmissingvolatile.nim
index 4d25e5c22..60b1771dc 100644
--- a/tests/ccgbugs/tmissingvolatile.nim
+++ b/tests/ccgbugs/tmissingvolatile.nim
@@ -2,6 +2,7 @@ discard """
   output: "1"
   cmd: r"nim c --hints:on $options -d:release $file"
   ccodecheck: "'NI volatile state;'"
+  target: "C"
 """
 
 # bug #1539
diff --git a/tests/ccgbugs/tobjconstr_bad_aliasing.nim b/tests/ccgbugs/tobjconstr_bad_aliasing.nim
index ea51ecacb..9f6045364 100644
--- a/tests/ccgbugs/tobjconstr_bad_aliasing.nim
+++ b/tests/ccgbugs/tobjconstr_bad_aliasing.nim
@@ -22,5 +22,4 @@ proc dosomething(): seq[TThing] =
 
   result = @[TThing(data: 10, children: result)]
 
-when isMainModule:
-  echo($dosomething()[0])
+echo($dosomething()[0])
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/clearmsg/tconsttypemismatch.nim b/tests/clearmsg/tconsttypemismatch.nim
index edf480348..727bfbffb 100644
--- a/tests/clearmsg/tconsttypemismatch.nim
+++ b/tests/clearmsg/tconsttypemismatch.nim
@@ -1,8 +1,7 @@
 discard """
+  errormsg: "type mismatch"
   file: "tconsttypemismatch.nim"
   line: 7
-  errormsg: "type mismatch"
 """
 # bug #2252
 const foo: int = 1000 / 30
-
diff --git a/tests/clearmsg/tmacroerrorproc.nim b/tests/clearmsg/tmacroerrorproc.nim
index cd9b15e25..86726af72 100644
--- a/tests/clearmsg/tmacroerrorproc.nim
+++ b/tests/clearmsg/tmacroerrorproc.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "Expected a node of kind nnkCharLit, got nnkCommand"
   file: "tmacroerrorproc.nim"
   line: 13
-  errormsg: "Expected a node of kind nnkCharLit, got nnkCommand"
 """
 # issue #4915
 import macros
diff --git a/tests/closure/tclosure.nim b/tests/closure/tclosure.nim
index 141968462..cfef4193a 100644
--- a/tests/closure/tclosure.nim
+++ b/tests/closure/tclosure.nim
@@ -1,5 +1,5 @@
 discard """
-  file: "tclosure.nim"
+  target: "c"
   output: '''
 1 3 6 11 20 foo
 foo88
@@ -33,6 +33,7 @@ foo88
 11
 @[1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1]
 '''
+joinable: false
 """
 
 
diff --git a/tests/closure/tissues.nim b/tests/closure/tclosure_issues.nim
index d33e3b403..b2d77c571 100644
--- a/tests/closure/tissues.nim
+++ b/tests/closure/tclosure_issues.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tissues.nim"
   output: '''true'''
 """
 
diff --git a/tests/closure/texplicit_dummy_closure.nim b/tests/closure/texplicit_dummy_closure.nim
index ec608b31a..9cd8c8ca9 100644
--- a/tests/closure/texplicit_dummy_closure.nim
+++ b/tests/closure/texplicit_dummy_closure.nim
@@ -5,8 +5,8 @@ import os
 
 type
   Window = object
-    oneInstSock*: PAsyncSocket
-    IODispatcher*: PDispatcher
+    oneInstSock*: AsyncSocket
+    IODispatcher*: Dispatcher
 
 var
   win: Window
@@ -14,9 +14,9 @@ var
 proc initSocket() =
   win.oneInstSock = asyncSocket()
   #win.oneInstSock.handleAccept =
-  proc test(s: PAsyncSocket) =
-    var client: PAsyncSocket
-    proc dummy(c: PAsyncSocket) {.closure.} =
+  proc test(s: AsyncSocket) =
+    var client: AsyncSocket
+    proc dummy(c: AsyncSocket) {.closure.} =
       discard
     client.handleRead = dummy
   test(win.oneInstSock)
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/tinvalidclosure.nim b/tests/closure/tinvalidclosure.nim
index 4e5f61f06..b2d8bd28d 100644
--- a/tests/closure/tinvalidclosure.nim
+++ b/tests/closure/tinvalidclosure.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 12
   errormsg: "type mismatch: got <proc (x: int){.gcsafe, locks: 0.}>"
+  line: 12
 """
 
 proc ugh[T](x: T) {.nimcall.} =
diff --git a/tests/closure/tinvalidclosure2.nim b/tests/closure/tinvalidclosure2.nim
index 845559309..2d58f0215 100644
--- a/tests/closure/tinvalidclosure2.nim
+++ b/tests/closure/tinvalidclosure2.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 10
   errormsg: "illegal capture 'A'"
+  line: 10
 """
 
 proc outer() =
diff --git a/tests/closure/tinvalidclosure3.nim b/tests/closure/tinvalidclosure3.nim
index 31c4976f8..0cbdaf39e 100644
--- a/tests/closure/tinvalidclosure3.nim
+++ b/tests/closure/tinvalidclosure3.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 9
   errormsg: "illegal capture 'x'"
+  line: 9
 """
 
 proc outer(arg: string) =
@@ -9,4 +9,4 @@ proc outer(arg: string) =
     echo "inner", x
   inner()
 
-outer("abc")
\ No newline at end of file
+outer("abc")
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/tnested.nim b/tests/closure/tnested.nim
index f8d69011a..dbbe9ba58 100644
--- a/tests/closure/tnested.nim
+++ b/tests/closure/tnested.nim
@@ -1,6 +1,5 @@
 discard """
-  file: "tnested.nim"
-  output: '''
+output: '''
 foo88
 23 24foo 88
 foo88
diff --git a/tests/closure/ttimeinfo.nim b/tests/closure/ttimeinfo.nim
index 3138ae72e..7416c0d31 100644
--- a/tests/closure/ttimeinfo.nim
+++ b/tests/closure/ttimeinfo.nim
@@ -1,15 +1,22 @@
+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
 import times
 
 # 1
-proc f(n: int): TimeInfo =
-  TimeInfo(year: n, month: mJan, monthday: 1)
+proc f(n: int): DateTime =
+  DateTime(year: n, month: mJan, monthday: 1)
 
 echo toSeq(2000 || 2015).map(f)
 
 # 2
-echo toSeq(2000 || 2015).map(proc (n: int): TimeInfo =
-  TimeInfo(year: n, month: mJan, monthday: 1)
+echo toSeq(2000 || 2015).map(proc (n: int): DateTime =
+  DateTime(year: n, month: mJan, monthday: 1)
 )
diff --git a/tests/cnstseq/tcnstseq.nim b/tests/cnstseq/tcnstseq.nim
index e044b9f3f..5679a6e37 100644
--- a/tests/cnstseq/tcnstseq.nim
+++ b/tests/cnstseq/tcnstseq.nim
@@ -1,6 +1,5 @@
 discard """
-  file: "tcnstseq.nim"
-  output: '''
+output: '''
 AngelikaAnneAnnaAnkaAnja
 AngelikaAnneAnnaAnkaAnja
 AngelikaAnneAnnaAnkaAnja
diff --git a/tests/collections/tcollections.nim b/tests/collections/tcollections.nim
index ff6673bba..2f8cfece7 100644
--- a/tests/collections/tcollections.nim
+++ b/tests/collections/tcollections.nim
@@ -1,7 +1,5 @@
 discard """
-  file: "tcollections.nim"
-  output: '''
-'''
+  output: ""
 """
 
 import deques, sequtils
diff --git a/tests/collections/tsets.nim b/tests/collections/thashsets.nim
index cd4401511..cd4401511 100644
--- a/tests/collections/tsets.nim
+++ b/tests/collections/thashsets.nim
diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim
index 4d11f56f2..6798e5731 100644
--- a/tests/collections/ttables.nim
+++ b/tests/collections/ttables.nim
@@ -1,16 +1,16 @@
 discard """
-  file: "ttables.nim"
-  output: '''
-done
+output: '''
+done tableadds
 And we get here
 1
 2
 3
 '''
+joinable: false
 """
 import hashes, sequtils, tables
 
-
+# test should not be joined because it takes too long.
 block tableadds:
   proc main =
     var tab = newTable[string, string]()
@@ -18,7 +18,7 @@ block tableadds:
       tab.add "key", "value " & $i
 
   main()
-  echo "done"
+  echo "done tableadds"
 
 
 block tcounttable:
@@ -142,7 +142,7 @@ block tindexby:
   tbl2.add("bar", elem1)
   tbl2.add("baz", elem2)
   doAssert indexBy(@[elem1,elem2], proc(x: TElem): string = x.bar) == tbl2, "element table"
-  
+
 
 block tableconstr:
   # Test if the new table constructor syntax works:
diff --git a/tests/compilerapi/tcompilerapi.nim b/tests/compilerapi/tcompilerapi.nim
index 30007eff0..2a7db04eb 100644
--- a/tests/compilerapi/tcompilerapi.nim
+++ b/tests/compilerapi/tcompilerapi.nim
@@ -15,7 +15,7 @@ import std / [os]
 
 proc main() =
   let std = findNimStdLibCompileTime()
-  var intr = createInterpreter("myscript.nim", [std, getAppDir()])
+  var intr = createInterpreter("myscript.nim",[std, parentDir(currentSourcePath)])
   intr.implementRoutine("*", "exposed", "addFloats", proc (a: VmArgs) =
     setResult(a, getFloat(a, 0) + getFloat(a, 1) + getFloat(a, 2))
   )
@@ -51,4 +51,3 @@ block issue9180:
 
   evalString("echo 10+1")
   evalString("echo 10+2")
-
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/t3330.nim b/tests/concepts/t3330.nim
index 3d0dde5d1..a1ad96f2b 100644
--- a/tests/concepts/t3330.nim
+++ b/tests/concepts/t3330.nim
@@ -1,5 +1,6 @@
 discard """
 errormsg: "type mismatch: got <Bar[system.int]>"
+disabled: "true"
 nimout: '''
 t3330.nim(63, 4) Error: type mismatch: got <Bar[system.int]>
 but expected one of:
diff --git a/tests/concepts/tconcepts.nim b/tests/concepts/tconcepts.nim
index dec1dafe0..d0bc76c20 100644
--- a/tests/concepts/tconcepts.nim
+++ b/tests/concepts/tconcepts.nim
@@ -1,6 +1,5 @@
 discard """
-  file: "tconcepts.nim"
-  output: '''
+output: '''
 10
 20
 int
@@ -378,53 +377,53 @@ block tvectorspace:
 block tstack:
   template reject(e) =
     static: assert(not compiles(e))
-  
+
   type
     ArrayStack = object
       data: seq[int]
-  
+
   proc push(s: var ArrayStack, item: int) =
     s.data.add item
-  
+
   proc pop(s: var ArrayStack): int =
     return s.data.pop()
-  
+
   type
     Stack[T] = concept var s
       s.push(T)
       s.pop() is T
-  
+
       type ValueType = T
       const ValueTypeName = T.name.toUpperAscii
-  
+
   proc genericAlgorithm[T](s: var Stack[T], y: T) =
     static:
       echo "INFERRED ", T.name
       echo "VALUE TYPE ", s.ValueType.name
       echo "VALUE TYPE NAME ", s.ValueTypeName
-  
+
     s.push(y)
     echo s.pop
-  
+
   proc implicitGeneric(s: var Stack): auto =
     static:
       echo "IMPLICIT INFERRED ", s.T.name, " ", Stack.T.name
       echo "IMPLICIT VALUE TYPE ", s.ValueType.name, " ", Stack.ValueType.name
       echo "IMPLICIT VALUE TYPE NAME ", s.ValueTypeName, " ", Stack.ValueTypeName
-  
+
     return s.pop()
-  
+
   var s = ArrayStack(data: @[])
-  
+
   s.push 10
   s.genericAlgorithm 20
   echo s.implicitGeneric
-  
+
   reject s.genericAlgorithm "x"
   reject s.genericAlgorithm 1.0
   reject "str".implicitGeneric
   reject implicitGeneric(10)
-  
+
 
 
 import libs/[trie_database, trie]
diff --git a/tests/concepts/tissues.nim b/tests/concepts/tconcepts_issues.nim
index e145b9f37..df4037ffb 100644
--- a/tests/concepts/tissues.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/texplain.nim b/tests/concepts/texplain.nim
index 5c8e02440..ac0c972f5 100644
--- a/tests/concepts/texplain.nim
+++ b/tests/concepts/texplain.nim
@@ -63,8 +63,8 @@ texplain.nim(92, 5) NestedConcept: concept predicate failed
 
 expression: f(y)
 '''
-  line: 138
   errormsg: "type mismatch: got <MatchingType>"
+  line: 138
 """
 
 
@@ -136,4 +136,3 @@ static:
 # finally, provide multiple nested explanations for failed matching
 # of regular concepts, even when the explain pragma is not used
 f(y)
-
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/trandomvars.nim b/tests/concepts/trandomvars.nim
index db41aa901..1f04b9ecf 100644
--- a/tests/concepts/trandomvars.nim
+++ b/tests/concepts/trandomvars.nim
@@ -41,7 +41,8 @@ proc lift1[A, B](f: proc(a: A): B, r: RandomVar[A]): ClosureVar[B] =
 
   return inner
 
-when isMainModule:
+
+proc main() =
   proc sq(x: float): float = x * x
 
   let
@@ -59,3 +60,4 @@ when isMainModule:
   echo rng.sample(u)
   echo rng.sample(t)
 
+main()
diff --git a/tests/concepts/trandom_vars.nim b/tests/concepts/trandomvars2.nim
index 861e876a7..861e876a7 100644
--- a/tests/concepts/trandom_vars.nim
+++ b/tests/concepts/trandomvars2.nim
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/constr/tconstr1.nim b/tests/constr/tconstr1.nim
index b9cf5d00b..a169bf453 100644
--- a/tests/constr/tconstr1.nim
+++ b/tests/constr/tconstr1.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "type mismatch"
   file: "tconstr1.nim"
   line: 25
-  errormsg: "type mismatch"
 """
 # Test array, record constructors
 
@@ -26,5 +26,3 @@ const
   otherThings = [  # the same
     (s: "hi", x: 69, y: 45, z: 0.0, chars: {'a', 'b', 'c'}),
     (s: "hi", x: 69, y: 45, z: 1.0, chars: {'a'})]
-
-
diff --git a/tests/constr/tconstr2.nim b/tests/constr/tconstr2.nim
index b16be6c50..2557d7db9 100644
--- a/tests/constr/tconstr2.nim
+++ b/tests/constr/tconstr2.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tconstr2.nim"
   output: "69"
 """
 # Test array, record constructors
@@ -19,8 +18,5 @@ const
     (s: "hi", x: 69, y: 45, z: 0.0, chars: {'a', 'b', 'c'}),
     (s: "hi", x: 69, y: 45, z: 1.0, chars: {'a'})]
 
-write(stdout, things[0].x)
+writeLine(stdout, things[0].x)
 #OUT 69
-
-
-
diff --git a/tests/constraints/tconstraints.nim b/tests/constraints/tconstraints.nim
index 3c9fdc354..3ca01cfd5 100644
--- a/tests/constraints/tconstraints.nim
+++ b/tests/constraints/tconstraints.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 16
   errormsg: "type mismatch: got <int literal(232)>"
+  line: 16
 """
 
 proc myGenericProc[T: object|tuple|ptr|ref|distinct](x: T): string =
@@ -14,5 +14,3 @@ var
 
 assert myGenericProc(x) == "(x: 0, y: 0)"
 assert myGenericProc(232) == "232"
-
-
diff --git a/tests/constructors/t5965_1.nim b/tests/constructors/t5965_1.nim
index 9f947f859..abf07b21c 100644
--- a/tests/constructors/t5965_1.nim
+++ b/tests/constructors/t5965_1.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "incorrect object construction syntax"
   file: "t5965_1.nim"
   line: 10
-  errormsg: "incorrect object construction syntax"
 """
 
 type Foo = object
diff --git a/tests/constructors/t5965_2.nim b/tests/constructors/t5965_2.nim
index a3f7174c9..e04f1b715 100644
--- a/tests/constructors/t5965_2.nim
+++ b/tests/constructors/t5965_2.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "incorrect object construction syntax"
   file: "t5965_2.nim"
   line: 10
-  errormsg: "incorrect object construction syntax"
 """
 
 type Foo = object
diff --git a/tests/controlflow/tblock1.nim b/tests/controlflow/tblock1.nim
index e3a780dfe..70c844513 100644
--- a/tests/controlflow/tblock1.nim
+++ b/tests/controlflow/tblock1.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "undeclared identifier: \'ha\'"
   file: "tblock1.nim"
   line: 14
-  errormsg: "undeclared identifier: \'ha\'"
 """
 # check for forward label and
 # for failure when label is not declared
@@ -14,5 +14,3 @@ proc main =
   break ha #ERROR
 
 main()
-
-
diff --git a/tests/controlflow/tcontrolflow.nim b/tests/controlflow/tcontrolflow.nim
index 9019e55b2..258f3f50d 100644
--- a/tests/controlflow/tcontrolflow.nim
+++ b/tests/controlflow/tcontrolflow.nim
@@ -85,13 +85,13 @@ block tnestif:
   if x == 0:
       write(stdout, "i == 0")
       if y == 0:
-          write(stdout, x)
+          writeLine(stdout, x)
       else:
-          write(stdout, y)
+          writeLine(stdout, y)
   elif x == 1:
-      write(stdout, "i == 1")
+      writeLine(stdout, "i == 1")
   elif x == 2:
-      write(stdout, "i == 2")
+      writeLine(stdout, "i == 2")
   else:
-      write(stdout, "looks like Python")
+      writeLine(stdout, "looks like Python")
   #OUT i == 2
diff --git a/tests/controlflow/tstatret.nim b/tests/controlflow/tstatret.nim
index 04cac9966..e0f816c7d 100644
--- a/tests/controlflow/tstatret.nim
+++ b/tests/controlflow/tstatret.nim
@@ -1,12 +1,9 @@
 discard """
+  errormsg: "unreachable statement after 'return' statement or '{.noReturn.}' proc"
   file: "tstatret.nim"
   line: 9
-  errormsg: "unreachable statement after 'return'"
 """
 # no statement after return
 proc main() =
   return
   echo("huch?") #ERROR_MSG statement not allowed after
-
-
-
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
new file mode 100644
index 000000000..23c1a3d96
--- /dev/null
+++ b/tests/converter/tconverter_unique_ptr.nim
@@ -0,0 +1,152 @@
+
+discard """
+  targets: "c cpp"
+  output: ""
+"""
+
+## Bugs 9698 and 9699
+
+type
+  UniquePtr*[T] = object
+    ## non copyable pointer to object T, exclusive ownership of the object is assumed
+    val: ptr T
+
+  MyLen* = distinct int
+
+  MySeq* = object
+    ## Vectorized matrix
+    len: MyLen  # scalar size
+    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:
+    deallocShared(m.data)
+    m.data = nil
+
+proc `=`*(m: var MySeq, m2: MySeq) =
+  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[float]](allocShared(bytes))
+    copyMem(m.data, m2.data, bytes)
+
+proc `=sink`*(m: var MySeq, m2: MySeq) {.inline.} =
+  if m.data != m2.data:
+    if m.data != nil:
+      `=destroy`(m)
+    m.len = m2.len
+    m.data = m2.data
+
+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
+
+proc setTo(s: var MySeq, val: float) =
+  for i in 0..<s.len.int:
+    s.data[i] = val
+
+proc newMySeq*(size: int, initial_value = 0.0): MySeq =
+  result.len = size.MyLen
+  if size > 0:
+    result.data = cast[ptr UncheckedArray[float]](createShared(float, size))
+
+  result.setTo(initial_value)
+
+converter literalToLen*(x: int{lit}): MyLen =
+  x.MyLen
+
+
+#-------------------------------------------------------------
+# Unique pointer implementation
+#-------------------------------------------------------------
+
+proc `=destroy`*[T](p: var UniquePtr[T]) =
+  if p.val != nil:
+    `=destroy`(p.val[])
+    dealloc(p.val)
+    p.val = nil
+
+proc `=`*[T](dest: var UniquePtr[T], src: UniquePtr[T]) {.error.}
+
+proc `=sink`*[T](dest: var UniquePtr[T], src: UniquePtr[T]) {.inline.} =
+  if dest.val != nil and dest.val != src.val:
+    `=destroy`(dest)
+  dest.val = src.val
+
+proc newUniquePtr*[T](val: sink T): UniquePtr[T] =
+  result.val = cast[type(result.val)](alloc(sizeof(result.val[])))
+  reset(result.val[])
+  result.val[] = val
+
+converter convertPtrToObj*[T](p: UniquePtr[T]): var T =
+  result = p.val[]
+
+var pu = newUniquePtr(newMySeq(5, 1.0))
+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
+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/tconverter_with_constraint.nim b/tests/converter/tconverter_with_constraint.nim
index 793264434..ce5135586 100644
--- a/tests/converter/tconverter_with_constraint.nim
+++ b/tests/converter/tconverter_with_constraint.nim
@@ -1,8 +1,8 @@
 
 discard """
+  errormsg: "type mismatch: got <int>"
   file: "tconverter_with_constraint.nim"
   line: 20
-  errormsg: "type mismatch: got <int>"
 """
 
 type
@@ -10,11 +10,11 @@ type
 
 converter to_mytype(m: int{lit}): MyType =
   m.MyType
- 
+
 proc myproc(m: MyType) =
   echo m.int, ".MyType"
 
-myproc(1) # call by literal is ok 
+myproc(1) # call by literal is ok
 
 var x: int = 12
-myproc(x) # should fail
\ No newline at end of file
+myproc(x) # should fail
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 f3debf0a7..323eb055d 100644
--- a/tests/coroutines/texceptions.nim
+++ b/tests/coroutines/texceptions.nim
@@ -1,3 +1,7 @@
+discard """
+  target: "c"
+"""
+
 import coro
 var
   stackCheckValue = 1100220033
@@ -10,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)
@@ -18,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/tgc.nim b/tests/coroutines/tgc.nim
index 66a12ab9d..46f4f8e83 100644
--- a/tests/coroutines/tgc.nim
+++ b/tests/coroutines/tgc.nim
@@ -1,3 +1,7 @@
+discard """
+  target: "c"
+"""
+
 import coro
 
 var maxOccupiedMemory = 0
diff --git a/tests/coroutines/titerators.nim b/tests/coroutines/titerators.nim
index e2623ce2d..abcfbde43 100644
--- a/tests/coroutines/titerators.nim
+++ b/tests/coroutines/titerators.nim
@@ -1,3 +1,7 @@
+discard """
+  target: "c"
+"""
+
 import coro
 include system/timers
 
@@ -18,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/coroutines/twait.nim b/tests/coroutines/twait.nim
index eb2765be4..1769966ab 100644
--- a/tests/coroutines/twait.nim
+++ b/tests/coroutines/twait.nim
@@ -1,6 +1,7 @@
 discard """
   output: "Exit 1\nExit 2"
   disabled: "macosx"
+  target: "c"
 """
 import coro
 
diff --git a/tests/cpp/t6986.nim b/tests/cpp/t6986.nim
new file mode 100644
index 000000000..ffd277adb
--- /dev/null
+++ b/tests/cpp/t6986.nim
@@ -0,0 +1,16 @@
+discard """
+  targets: "cpp"
+  action: "compile"
+"""
+
+import sequtils, strutils
+
+
+let rules = toSeq(lines("input"))
+  .mapIt(it.split(" => ").mapIt(it.replace("/", "")))
+  .mapIt((it[0], it[1]))
+
+
+proc pp(s: string): auto =
+  toSeq(lines(s)).mapIt(it.split(" => ").mapIt(it.replace("/", ""))).mapIt((it[0], it[1]))
+echo pp("input")
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/tcasts.nim b/tests/cpp/tcasts.nim
index 24ebb8f62..d968d87db 100644
--- a/tests/cpp/tcasts.nim
+++ b/tests/cpp/tcasts.nim
@@ -1,6 +1,6 @@
 discard """
   cmd: "nim cpp $file"
-  output: ""
+  output: '''{"vas": "kas", "123": "123"}'''
   targets: "cpp"
 """
 
@@ -9,3 +9,13 @@ block: #5979
   var p: pointer = cast[pointer](a)
   var c = cast[char](p)
   doAssert(c == 'a')
+
+
+#----------------------------------------------------
+# bug #9739
+import tables
+
+var t = initTable[string, string]()
+discard t.hasKeyOrPut("123", "123")
+discard t.mgetOrPut("vas", "kas")
+echo t
\ No newline at end of file
diff --git a/tests/cpp/tcppraise.nim b/tests/cpp/tcppraise.nim
index f359a2e8b..84cacf7f0 100644
--- a/tests/cpp/tcppraise.nim
+++ b/tests/cpp/tcppraise.nim
@@ -35,3 +35,13 @@ try:
 except:
   echo "caught"
 
+
+# issue 5549
+
+var strs: seq[string] = @[]
+
+try:
+  discard
+finally:
+  for foobar in strs:
+    discard
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/deprecated/tnoannot.nim b/tests/deprecated/tnoannot.nim
index 9cc5c7e06..ac168952e 100644
--- a/tests/deprecated/tnoannot.nim
+++ b/tests/deprecated/tnoannot.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 7
   errormsg: "annotation to deprecated not supported here"
+  line: 7
 """
 
 var foo* {.deprecated.} = 42
diff --git a/tests/deps/jester-#head/jester/patterns.nim b/tests/deps/jester-#head/jester/patterns.nim
index 52b0d3a15..c827fbc7f 100644
--- a/tests/deps/jester-#head/jester/patterns.nim
+++ b/tests/deps/jester-#head/jester/patterns.nim
@@ -120,7 +120,7 @@ proc match*(pattern: Pattern, s: string):
   if s.len != i:
     result.matched = false
 
-when isMainModule:
+when true:
   let f = parsePattern("/show/@id/test/@show?/?")
   doAssert match(f, "/show/12/test/hallo/").matched
   doAssert match(f, "/show/2131726/test/jjjuuwąąss").matched
diff --git a/tests/deps/jester-#head/jester/private/utils.nim b/tests/deps/jester-#head/jester/private/utils.nim
index 66f0b37a6..16dce61fe 100644
--- a/tests/deps/jester-#head/jester/private/utils.nim
+++ b/tests/deps/jester-#head/jester/private/utils.nim
@@ -188,7 +188,7 @@ when not declared(normalizePath) and not declared(normalizedPath):
     result = path
     normalizePath(result)
 
-when isMainModule:
+when false:
   var r = {:}.newStringTable
   parseUrlQuery("FirstName=Mickey", r)
   echo r
diff --git a/tests/deps/zip-0.2.1/zip/zipfiles.nim b/tests/deps/zip-0.2.1/zip/zipfiles.nim
index ca1979488..274587df9 100644
--- a/tests/deps/zip-0.2.1/zip/zipfiles.nim
+++ b/tests/deps/zip-0.2.1/zip/zipfiles.nim
@@ -186,7 +186,7 @@ proc extractAll*(z: var ZipArchive, dest: string) =
       createDir(dest / file[0..file.rfind("/")])
     extractFile(z, file, dest / file)
 
-when not defined(testing) and isMainModule:
+when not defined(testing) and true:
   var zip: ZipArchive
   if not zip.open("nim-0.11.0.zip"):
     raise newException(IOError, "opening zip failed")
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/texplicit_move.nim b/tests/destructor/texplicit_move.nim
index 6735ac75d..230f0b133 100644
--- a/tests/destructor/texplicit_move.nim
+++ b/tests/destructor/texplicit_move.nim
@@ -2,7 +2,10 @@
 discard """
   output: '''3
 0
-destroyed!'''
+0
+10
+destroyed!
+'''
 """
 
 type
@@ -17,3 +20,10 @@ var
 x.f = 3
 echo move(x.f)
 echo x.f
+
+# bug #9743
+let a = create int
+a[] = 10
+var b = move a[]
+echo a[]
+echo b
diff --git a/tests/destructor/tmatrix.nim b/tests/destructor/tmatrix.nim
index a16bfa37b..b89b41a4c 100644
--- a/tests/destructor/tmatrix.nim
+++ b/tests/destructor/tmatrix.nim
@@ -52,6 +52,8 @@ proc matrix*(m, n: int, s: float): Matrix =
   for i in 0 ..< m * n:
     result.data[i] = s
 
+proc len(m: Matrix): int = m.n * m.m
+
 proc `[]`*(m: Matrix, i, j: int): float {.inline.} =
   ## Get a single element.
   m.data[i * m.n + j]
@@ -67,24 +69,26 @@ proc `[]=`*(m: var Matrix, i, j: int, s: float) =
 proc `-`*(m: sink Matrix): Matrix =
   ## Unary minus
   result = m
-  for i in 0 ..< m.m:
-    for j in 0 ..< m.n:
-      result[i, j] = -m[i, j]
+  for i in 0 ..< result.m:
+    for j in 0 ..< result.n:
+      result[i, j] = -result[i, j]
 
 proc `+`*(a: sink Matrix; b: Matrix): Matrix =
   ## ``C = A + B``
-  assert(b.m == a.m and b.n == a.n, "Matrix dimensions must agree.")
+  doAssert(b.m == a.m and b.n == a.n, "Matrix dimensions must agree.")
+  doAssert(a.len == b.len) # non destructive use before sink is ok
   result = a
-  for i in 0 ..< a.m:
-    for j in 0 ..< a.n:
-      result[i, j] = a[i, j] + b[i, j]
+  for i in 0 ..< result.m:
+    for j in 0 ..< result.n:
+      result[i, j] = result[i, j] + b[i, j]
 
 proc `-`*(a: sink Matrix; b: Matrix): Matrix =
   ## ``C = A - B``
   assert(b.m == a.m and b.n == a.n, "Matrix dimensions must agree.")
+  doAssert(a.len == b.len) # non destructive use before sink is ok
   result = a
-  for i in 0 ..< a.m:
-     for j in 0 ..< a.n:
+  for i in 0 ..< result.m:
+     for j in 0 ..< result.n:
         result[i, j] = a[i, j] - b[i, j]
 
 proc info =
diff --git a/tests/destructor/tmove_objconstr.nim b/tests/destructor/tmove_objconstr.nim
index 50aecf46d..875f78283 100644
--- a/tests/destructor/tmove_objconstr.nim
+++ b/tests/destructor/tmove_objconstr.nim
@@ -36,7 +36,7 @@ proc pointlessWrapper(s: string): Data =
 proc main =
   var x = pointlessWrapper"test"
 
-when isMainModule:
+when true:
   main()
 
 # bug #985
@@ -60,3 +60,109 @@ 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: case x:
+    of 1: 
+      let (z1, z2) = myfunc(x,y)
+      z2
+    elif x > 5: raise newException(ValueError, "new error")
+    else: newMySeq(x, 1.0), 
+   b: 0, 
+   c: block:
+        var tmp = if y > 0: move(cc) else: newMySeq(1, 3.0)
+        tmp[0] = 5
+        tmp 
+  )
+   
+
+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)
+
+seq4 = block:
+  var tmp = newMySeq(4, 1.0)
+  tmp[0] = 3.0
+  tmp
+
+doAssert seq4[0] == 3.0 
+
+import macros
+
+seq4 = 
+  if i > 0: newMySeq(2, 5.0) 
+  elif i < -100: raise newException(ValueError, "Parse Error")
+  else: newMySeq(2, 3.0)
+
+seq4 = 
+  case (char) i:
+    of 'A', {'W'..'Z'}: newMySeq(2, 5.0) 
+    of 'B': quit(-1)
+    else: 
+      let (x1, x2, x3) = myfunc2(2, 3)
+      x3
+
+
+#------------------------------------------------------------
+#-- Move into array constructor
+#------------------------------------------------------------
+
+var ii = 1
+let arr2 = [newMySeq(2, 5.0), if i > 1: newMySeq(3, 1.0) else: newMySeq(0, 0.0)]
+var seqOfSeq2 = @[newMySeq(2, 5.0), newMySeq(3, 1.0)]
diff --git a/tests/destructor/turn_destroy_into_finalizer.nim b/tests/destructor/turn_destroy_into_finalizer.nim
index f5b705593..1409c1c57 100644
--- a/tests/destructor/turn_destroy_into_finalizer.nim
+++ b/tests/destructor/turn_destroy_into_finalizer.nim
@@ -1,5 +1,6 @@
 discard """
-  output: '''true'''
+  output: "turn_destroy_into_finalizer works"
+  joinable: false
 """
 
 type
@@ -17,6 +18,9 @@ proc main =
   for i in 1..50_000:
     new(r)
     r.id = i
-  echo destroyed > 30_000
+  if destroyed > 30_000:
+    echo "turn_destroy_into_finalizer works"
+  else:
+    echo "turn_destroy_into_finalizer failed: ", destroyed
 
 main()
diff --git a/tests/destructor/tuse_result_prevents_sinks.nim b/tests/destructor/tuse_result_prevents_sinks.nim
new file mode 100644
index 000000000..4c32eac91
--- /dev/null
+++ b/tests/destructor/tuse_result_prevents_sinks.nim
@@ -0,0 +1,31 @@
+discard """
+  output: ""
+"""
+
+# bug #9594
+
+type
+  Foo = object
+    i: int
+
+proc `=`(self: var Foo; other: Foo) =
+  self.i = other.i + 1
+
+proc `=sink`(self: var Foo; other: Foo) =
+  self.i = other.i
+
+proc `=destroy`(self: var Foo) = discard
+
+proc test(): Foo =
+  result = Foo()
+  let temp = result
+  doAssert temp.i > 0
+  return result
+
+proc testB(): Foo =
+  result = Foo()
+  let temp = result
+  doAssert temp.i > 0
+
+discard test()
+discard testB()
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 f979b29c9..81e17866a 100644
--- a/tests/discard/tdiscardable.nim
+++ b/tests/discard/tdiscardable.nim
@@ -1,3 +1,13 @@
+discard """
+output: '''
+tdiscardable
+1
+1
+'''
+"""
+
+echo "tdiscardable"
+
 # Test the discardable pragma
 
 proc p(x, y: int): int {.discardable.} =
@@ -27,3 +37,11 @@ proc bar(b: int):int =
 
 echo foo(0)
 echo bar(0)
+
+# bug #9726
+
+proc foo: (proc: int) =
+  proc bar: int = 1
+  return bar
+
+discard foo()
diff --git a/tests/discard/tillegaldiscard.nim b/tests/discard/tillegaldiscard.nim
new file mode 100644
index 000000000..757f4e727
--- /dev/null
+++ b/tests/discard/tillegaldiscard.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "illegal discard"
+  line: 9
+"""
+
+proc pop[T](arg: T): T =
+  echo arg
+
+discard tillegaldiscard.pop
diff --git a/tests/discard/tneedsdiscard.nim b/tests/discard/tneedsdiscard.nim
index 8d59e7fec..7d2997b3f 100644
--- a/tests/discard/tneedsdiscard.nim
+++ b/tests/discard/tneedsdiscard.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 10
   errormsg: '''expression 'open(f, "arg.txt", fmRead, -1)' is of type 'bool' and has to be discarded; start of expression here: tneedsdiscard.nim(7, 2)'''
+  line: 10
 """
 
 proc p =
diff --git a/tests/discard/tneedsdiscard_in_for.nim b/tests/discard/tneedsdiscard_in_for.nim
index 5658f4ba2..499b06009 100644
--- a/tests/discard/tneedsdiscard_in_for.nim
+++ b/tests/discard/tneedsdiscard_in_for.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 22
   errormsg: '''expression 'premultiply(app.gradient[i])' is of type 'Rgba8' and has to be discarded'''
+  line: 22
 """
 
 # bug #9076
diff --git a/tests/distinct/tdistinct.nim b/tests/distinct/tdistinct.nim
index 52728fc2b..70e586ded 100644
--- a/tests/distinct/tdistinct.nim
+++ b/tests/distinct/tdistinct.nim
@@ -1,9 +1,11 @@
 discard """
   output: '''
+tdistinct
 25
 '''
 """
 
+echo "tdistinct"
 
 block tborrowdot:
   type
@@ -18,8 +20,6 @@ block tborrowdot:
   bb.a = 90
   bb.s = "abc"
 
-
-
 block tcurrncy:
   template Additive(typ: untyped) =
     proc `+`(x, y: typ): typ {.borrow.}
@@ -53,8 +53,6 @@ block tcurrncy:
   DefineCurrency(TEuro, int)
   echo($( 12.TDollar + 13.TDollar )) #OUT 25
 
-
-
 block tconsts:
   # bug #2641
 
diff --git a/tests/distinct/tissues.nim b/tests/distinct/tdistinct_issues.nim
index ce71344d0..ce71344d0 100644
--- a/tests/distinct/tissues.nim
+++ b/tests/distinct/tdistinct_issues.nim
diff --git a/tests/distinct/tnil.nim b/tests/distinct/tnil.nim
index 16de38f60..5bdb97f37 100644
--- a/tests/distinct/tnil.nim
+++ b/tests/distinct/tnil.nim
@@ -1,6 +1,6 @@
 discard """
-  file: "tnil.nim"
-  output: '''1
+output: '''
+1
 0
 0
 '''
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/dummy.txt b/tests/dummy.txt
new file mode 100644
index 000000000..64cd361f9
--- /dev/null
+++ b/tests/dummy.txt
@@ -0,0 +1 @@
+Just a simple text for test
\ No newline at end of file
diff --git a/tests/effects/teffects1.nim b/tests/effects/teffects1.nim
index ef76c9130..767845cb4 100644
--- a/tests/effects/teffects1.nim
+++ b/tests/effects/teffects1.nim
@@ -1,6 +1,6 @@
 discard """
-  file: "system.nim"
   errormsg: "can raise an unlisted exception: ref IOError"
+  file: "system.nim"
 """
 
 type
@@ -17,4 +17,3 @@ proc lier(): int {.raises: [IO2Error].} =
 
 proc forw: int =
   raise newException(IOError, "arg")
-
diff --git a/tests/effects/teffects2.nim b/tests/effects/teffects2.nim
index 0fa789869..e4b50aba5 100644
--- a/tests/effects/teffects2.nim
+++ b/tests/effects/teffects2.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 19
   errormsg: "can raise an unlisted exception: ref IOError"
+  line: 19
 """
 
 type
@@ -17,4 +17,3 @@ proc lier(): int {.raises: [IOError].} =
 
 proc forw: int =
   raise newException(IOError, "arg")
-
diff --git a/tests/effects/teffects3.nim b/tests/effects/teffects3.nim
index cbd11f722..ee5470c47 100644
--- a/tests/effects/teffects3.nim
+++ b/tests/effects/teffects3.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 18
   errormsg: "type mismatch"
+  line: 18
 """
 
 type
@@ -16,4 +16,3 @@ proc raiser(): int {.tags: [TObj, WriteIoEffect].} =
 
 var o: TObjB
 o.fn = raiser
-
diff --git a/tests/effects/teffects4.nim b/tests/effects/teffects4.nim
index 0025c10c5..88cc0efa9 100644
--- a/tests/effects/teffects4.nim
+++ b/tests/effects/teffects4.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 23
   errormsg: "type mismatch"
+  line: 23
 """
 
 type
@@ -21,4 +21,3 @@ proc raiser(): int =
 
 var o: TObjB
 o.fn = raiser
-
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/effects/tgcsafe.nim b/tests/effects/tgcsafe.nim
index d146794b6..ff207df59 100644
--- a/tests/effects/tgcsafe.nim
+++ b/tests/effects/tgcsafe.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 17
   errormsg: "'mainUnsafe' is not GC-safe"
+  line: 17
   cmd: "nim $target --hints:on --threads:on $options $file"
 """
 
diff --git a/tests/effects/tsidee1.nim b/tests/effects/tsidee1.nim
index e486d32e7..ca6816561 100644
--- a/tests/effects/tsidee1.nim
+++ b/tests/effects/tsidee1.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "\'SideEffectLyer\' can have side effects"
   file: "tsidee1.nim"
   line: 12
-  errormsg: "\'SideEffectLyer\' can have side effects"
 """
 
 var
@@ -13,6 +13,3 @@ proc SideEffectLyer(x, y: int): int {.noSideEffect.} = #ERROR_MSG 'SideEffectLye
   return x + y + dontcare(x)
 
 echo SideEffectLyer(1, 3)
-
-
-
diff --git a/tests/effects/tsidee2.nim b/tests/effects/tsidee2.nim
index 5ed541300..b2e5f3379 100644
--- a/tests/effects/tsidee2.nim
+++ b/tests/effects/tsidee2.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tsidee2.nim"
   output: "5"
 """
 
@@ -12,6 +11,3 @@ proc SideEffectLyer(x, y: int): int {.noSideEffect.} =
   return x + y + dontcare(x)
 
 echo SideEffectLyer(1, 3) #OUT 5
-
-
-
diff --git a/tests/effects/tsidee3.nim b/tests/effects/tsidee3.nim
index e15fbc3d1..c3801ba28 100644
--- a/tests/effects/tsidee3.nim
+++ b/tests/effects/tsidee3.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tsidee3.nim"
   output: "5"
 """
 
@@ -12,6 +11,3 @@ proc noSideEffect(x, y: int, p: proc (a: int): int {.noSideEffect.}): int {.noSi
   return x + y + dontcare(x)
 
 echo noSideEffect(1, 3, dontcare) #OUT 5
-
-
-
diff --git a/tests/effects/tsidee4.nim b/tests/effects/tsidee4.nim
index ecc79580c..d6c192cbf 100644
--- a/tests/effects/tsidee4.nim
+++ b/tests/effects/tsidee4.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "'noSideEffect' can have side effects"
   file: "tsidee4.nim"
   line: 12
-  errormsg: "'noSideEffect' can have side effects"
 """
 
 var
@@ -13,5 +13,3 @@ proc noSideEffect(x, y: int, p: proc (a: int): int {.noSideEffect.}): int {.noSi
   return x + y + dontcare(x)
 
 echo noSideEffect(1, 3, dontcare) #ERROR_MSG type mismatch
-
-
diff --git a/tests/enum/tenumitems.nim b/tests/enum/tenumitems.nim
index 6d13dd162..76f368f8a 100644
--- a/tests/enum/tenumitems.nim
+++ b/tests/enum/tenumitems.nim
@@ -1,9 +1,7 @@
 discard """
-  line: 7
   errormsg: "attempting to call routine: 'items'"
+  line: 7
 """
 
 type a = enum b,c,d
 a.items()
-
-
diff --git a/tests/errmsgs/t6483.nim b/tests/errmsgs/t6483.nim
index 59ea6d7e2..0e977b36d 100644
--- a/tests/errmsgs/t6483.nim
+++ b/tests/errmsgs/t6483.nim
@@ -16,7 +16,7 @@ type
     variables: seq[VarItem]
     children: seq[VarScope]
 
-when isMainModule:
+when true:
   var scope1 = VarScope(
     variables: newSeq[VarItem](),
     children: newSeq[VarScope]()
diff --git a/tests/errmsgs/t8339.nim b/tests/errmsgs/t8339.nim
index f0a97658a..720e080c0 100644
--- a/tests/errmsgs/t8339.nim
+++ b/tests/errmsgs/t8339.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 8
   errormsg: "type mismatch: got <seq[int]> but expected 'seq[float]'"
+  line: 8
 """
 
 import sequtils
diff --git a/tests/errmsgs/t9908_01.nim b/tests/errmsgs/t9908_01.nim
new file mode 100644
index 000000000..b9d37b67b
--- /dev/null
+++ b/tests/errmsgs/t9908_01.nim
@@ -0,0 +1,10 @@
+discard """
+errormsg: "ordinal type expected"
+line: 10
+"""
+
+# https://github.com/nim-lang/Nim/issues/9908
+
+type
+  X = enum
+    a = ("a", "b")
diff --git a/tests/errmsgs/t9908_02.nim b/tests/errmsgs/t9908_02.nim
new file mode 100644
index 000000000..7ff3d1ff7
--- /dev/null
+++ b/tests/errmsgs/t9908_02.nim
@@ -0,0 +1,10 @@
+discard """
+errormsg: "ordinal type expected"
+line: 10
+"""
+
+# https://github.com/nim-lang/Nim/pull/9909#issuecomment-445519287
+
+type
+  E = enum
+    myVal = 80.9
diff --git a/tests/errmsgs/tproper_stacktrace.nim b/tests/errmsgs/tproper_stacktrace.nim
index 134946651..c0090a595 100644
--- a/tests/errmsgs/tproper_stacktrace.nim
+++ b/tests/errmsgs/tproper_stacktrace.nim
@@ -66,7 +66,7 @@ template verifyStackTrace*(expectedStackTrace: string, body: untyped) =
 
 
 
-when isMainModule:
+when true:
 # <-- Align with line 70 in the text editor
   block:
     proc bar() =
diff --git a/tests/errmsgs/treportunused.nim b/tests/errmsgs/treportunused.nim
new file mode 100644
index 000000000..c74fea46f
--- /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]
+'''
+action: compile
+"""
+
+# 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/exception/tcontinuexc.nim b/tests/exception/tcontinuexc.nim
index 2a05da9c0..b7560a605 100644
--- a/tests/exception/tcontinuexc.nim
+++ b/tests/exception/tcontinuexc.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tcontinuexc.nim"
   outputsub: "ECcaught"
   exitcode: "1"
 """
@@ -25,6 +24,3 @@ finally:
   echo "caught"
 
 #OUT ECcaught
-
-
-
diff --git a/tests/exception/texceptionbreak.nim b/tests/exception/texceptionbreak.nim
index 00dd8ed9f..6548192c6 100644
--- a/tests/exception/texceptionbreak.nim
+++ b/tests/exception/texceptionbreak.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tnestedbreak.nim"
   output: "1\n2\n3\n4"
 """
 
diff --git a/tests/exception/texcsub.nim b/tests/exception/texcsub.nim
index 02125d2c0..463e95613 100644
--- a/tests/exception/texcsub.nim
+++ b/tests/exception/texcsub.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "texcsub.nim"
   output: "caught!"
 """
 # Test inheritance for exception matching:
@@ -12,6 +11,3 @@ except:
   echo "wtf!?"
 
 #OUT caught!
-
-
-
diff --git a/tests/exception/tfinally.nim b/tests/exception/tfinally.nim
index 7a218b444..c5b1dd841 100644
--- a/tests/exception/tfinally.nim
+++ b/tests/exception/tfinally.nim
@@ -1,6 +1,6 @@
 discard """
-  file: "tfinally.nim"
-  output: '''came
+  output: '''
+came
 here
 3
 msg1
@@ -59,4 +59,4 @@ try:
 except:
   echo "except2"
 finally:
-  echo "finally2"
\ No newline at end of file
+  echo "finally2"
diff --git a/tests/exception/tfinally2.nim b/tests/exception/tfinally2.nim
index f1acf2774..dae1a468a 100644
--- a/tests/exception/tfinally2.nim
+++ b/tests/exception/tfinally2.nim
@@ -1,9 +1,10 @@
 discard """
-  file: "tfinally2.nim"
-  output: '''A
+output: '''
+A
 B
 C
-D'''
+D
+'''
 """
 # Test break in try statement:
 
@@ -24,7 +25,4 @@ proc main: int =
   finally:
     echo("D")
 
-discard main() #OUT ABCD
-
-
-
+discard main()
diff --git a/tests/exception/tfinally3.nim b/tests/exception/tfinally3.nim
index 6098672a2..9053d397d 100644
--- a/tests/exception/tfinally3.nim
+++ b/tests/exception/tfinally3.nim
@@ -1,7 +1,8 @@
 discard """
-  file: "tfinally3.nim"
-  outputsub: '''false
-Within finally->try'''
+  outputsub: '''
+false
+Within finally->try
+'''
   exitCode: 1
 """
 # Test break in try statement:
diff --git a/tests/exception/tfinally4.nim b/tests/exception/tfinally4.nim
index 3aa707ff6..feaf1bc96 100644
--- a/tests/exception/tfinally4.nim
+++ b/tests/exception/tfinally4.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tfinally4.nim"
   output: "B1\nA1\n1\nB1\nB2\ncatch\nA1\n1\nB1\nA1\nA2\n2\nB1\nB2\ncatch\nA1\nA2\n0\nB1\nA1\n1\nB1\nB2\nA1\n1\nB1\nA1\nA2\n2\nB1\nB2\nA1\nA2\n3"
 """
 
diff --git a/tests/exception/tnestedreturn.nim b/tests/exception/tnestedreturn.nim
index bf26f4903..acb83d2c8 100644
--- a/tests/exception/tnestedreturn.nim
+++ b/tests/exception/tnestedreturn.nim
@@ -1,6 +1,5 @@
 discard """
   targets: "c cpp"
-  file: "tnestedreturn.nim"
   output: "A\nB\nC\n"
 """
 
diff --git a/tests/exception/tnestedreturn2.nim b/tests/exception/tnestedreturn2.nim
index 79523a883..167d09b96 100644
--- a/tests/exception/tnestedreturn2.nim
+++ b/tests/exception/tnestedreturn2.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tnestedreturn2.nim"
   outputsub: "Error: unhandled exception: Problem [OSError]"
   exitcode: "1"
 """
diff --git a/tests/exception/tonraise.nim b/tests/exception/tonraise.nim
deleted file mode 100644
index a155f0b8e..000000000
--- a/tests/exception/tonraise.nim
+++ /dev/null
@@ -1,34 +0,0 @@
-discard """
-  output: '''i: 1
-success'''
-"""
-
-type
-  ESomething = object of Exception
-  ESomeOtherErr = object of Exception
-
-proc genErrors(s: string) =
-  if s == "error!":
-    raise newException(ESomething, "Test")
-  else:
-    raise newException(EsomeotherErr, "bla")
-
-proc foo() =
-  var i = 0
-  try:
-    inc i
-    onRaise(proc (e: ref Exception): bool =
-      echo "i: ", i)
-    genErrors("errssor!")
-  except ESomething:
-    echo("ESomething happened")
-  except:
-    echo("Some other error happened")
-
-  # test that raise handler is gone:
-  try:
-    genErrors("error!")
-  except ESomething:
-    echo "success"
-
-foo()
diff --git a/tests/exception/treraise.nim b/tests/exception/treraise.nim
index b2a11d34f..17a38aa53 100644
--- a/tests/exception/treraise.nim
+++ b/tests/exception/treraise.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "treraise.nim"
   outputsub: "Error: unhandled exception: bla [ESomeOtherErr]"
   exitcode: "1"
 """
@@ -19,6 +18,3 @@ except ESomething:
   echo("Error happened")
 except:
   raise
-
-
-
diff --git a/tests/exception/tunhandledexc.nim b/tests/exception/tunhandledexc.nim
index c318aec81..6ca311d38 100644
--- a/tests/exception/tunhandledexc.nim
+++ b/tests/exception/tunhandledexc.nim
@@ -1,6 +1,7 @@
 discard """
-  file: "tunhandledexc.nim"
-  outputsub: "Error: unhandled exception: bla [ESomeOtherErr]"
+  cmd: "nim $target -d:release $options $file"
+  outputsub: '''tunhandledexc.nim(15)    genErrors
+Error: unhandled exception: bla [ESomeOtherErr]'''
   exitcode: "1"
 """
 type
diff --git a/tests/exception/twrongexc.nim b/tests/exception/twrongexc.nim
index b224d4c83..9c656f3d9 100644
--- a/tests/exception/twrongexc.nim
+++ b/tests/exception/twrongexc.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "twrongexc.nim"
   outputsub: "Error: unhandled exception:  [ValueError]"
   exitcode: "1"
 """
@@ -7,7 +6,3 @@ try:
   raise newException(ValueError, "")
 except OverflowError:
   echo("Error caught")
-
-
-
-
diff --git a/tests/exprs/texprstmt.nim b/tests/exprs/texprstmt.nim
index 6c9759cf5..742670cc1 100644
--- a/tests/exprs/texprstmt.nim
+++ b/tests/exprs/texprstmt.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 10
   errormsg: "expression 'result[1 .. BackwardsIndex(1)]' is of type 'string' and has to be discarded"
+  line: 10
 """
 
 # bug #578
diff --git a/tests/exprs/tifexpr_typeinference.nim b/tests/exprs/tifexpr_typeinference.nim
index 3ae95c571..ccaea3e80 100644
--- a/tests/exprs/tifexpr_typeinference.nim
+++ b/tests/exprs/tifexpr_typeinference.nim
@@ -1,11 +1,15 @@
+discard """
+action: compile
+"""
+
 #bug #712
 
 import tables
 
-proc test(): TTable[string, string] =
+proc test(): Table[string, string] =
   discard
 
-proc test2(): TTable[string, string] =
+proc test2(): Table[string, string] =
   discard
 
 var x = 5
diff --git a/tests/exprs/tstmtexp.nim b/tests/exprs/tstmtexp.nim
index 0fb835bc6..75d8dd081 100644
--- a/tests/exprs/tstmtexp.nim
+++ b/tests/exprs/tstmtexp.nim
@@ -1,9 +1,8 @@
 discard """
+  errormsg: "expression '5' is of type 'int literal(5)' and has to be discarded"
   file: "tstmtexp.nim"
   line: 8
-  errormsg: "expression '5' is of type 'int literal(5)' and has to be discarded"
 """
 # Test 3
 
 1+4
-
diff --git a/tests/flags/tgenscript.nim b/tests/flags/tgenscript.nim
index 6a037b5d8..bf83ab972 100644
--- a/tests/flags/tgenscript.nim
+++ b/tests/flags/tgenscript.nim
@@ -1,5 +1,6 @@
 discard """
-  file: "tgenscript.nim"
+  target: "c"
+  action: compile
 """
 
 echo "--genscript"
diff --git a/tests/float/tfloat1.nim b/tests/float/tfloat1.nim
index ed99260ea..54d49a7c1 100644
--- a/tests/float/tfloat1.nim
+++ b/tests/float/tfloat1.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tfloat1.nim"
   outputsub: "Error: unhandled exception: FPU operation caused an overflow [FloatOverflowError]"
   exitcode: "1"
 """
@@ -11,5 +10,3 @@ var x = 0.8
 var y = 0.0
 
 echo x / y #OUT Error: unhandled exception: FPU operation caused an overflow
-
-
diff --git a/tests/float/tfloat2.nim b/tests/float/tfloat2.nim
index b84120fba..130c71087 100644
--- a/tests/float/tfloat2.nim
+++ b/tests/float/tfloat2.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tfloat2.nim"
   outputsub: "Error: unhandled exception: FPU operation caused a NaN result [FloatInvalidOpError]"
   exitcode: "1"
 """
@@ -11,5 +10,3 @@ var x = 0.0
 var y = 0.0
 
 echo x / y #OUT Error: unhandled exception: FPU operation caused a NaN result
-
-
diff --git a/tests/float/tfloat3.nim b/tests/float/tfloat3.nim
index a14c6c396..215470cfc 100644
--- a/tests/float/tfloat3.nim
+++ b/tests/float/tfloat3.nim
@@ -1,15 +1,15 @@
 discard """
-  file: "tfloat3.nim"
-  output: "Nim    3.4368930843, 0.3299290698 C double: 3.4368930843, 0.3299290698"
+  output: '''
+Nim 3.4368930843, 0.3299290698
+C double: 3.4368930843, 0.3299290698'''
 """
 
 import math, strutils
 
 {.emit: """
 void printFloats(void) {
-    double y = 1.234567890123456789;
-
-    printf("C double: %.10f, %.10f ", exp(y), cos(y));
+  double y = 1.234567890123456789;
+  printf("C double: %.10f, %.10f\n", exp(y), cos(y));
 }
 """.}
 
@@ -17,8 +17,5 @@ proc c_printf(frmt: cstring) {.importc: "printf", header: "<stdio.h>", varargs.}
 proc printFloats {.importc, nodecl.}
 
 var x: float = 1.234567890123456789
-c_printf("Nim    %.10f, %.10f ", exp(x), cos(x))
+c_printf("Nim %.10f, %.10f\n", exp(x), cos(x))
 printFloats()
-
-
-
diff --git a/tests/float/tfloat4.nim b/tests/float/tfloat4.nim
index 68df56be8..56280111c 100644
--- a/tests/float/tfloat4.nim
+++ b/tests/float/tfloat4.nim
@@ -1,8 +1,7 @@
 discard """
-  file: "tfloat4.nim"
   output: "passed all tests."
-  exitcode: 0
 """
+
 import math, strutils
 
 proc c_sprintf(buf, fmt: cstring) {.importc:"sprintf", header: "<stdio.h>", varargs.}
diff --git a/tests/float/tfloat5.nim b/tests/float/tfloat5.nim
index aa7dc6c53..0708838fc 100644
--- a/tests/float/tfloat5.nim
+++ b/tests/float/tfloat5.nim
@@ -1,9 +1,10 @@
 discard """
-  file: "tfloat5.nim"
-  output: '''0 : 0.0
+output: '''
 0 : 0.0
 0 : 0.0
-0 : 0.0'''
+0 : 0.0
+0 : 0.0
+'''
 """
 
 import parseutils
diff --git a/tests/float/tfloat6.nim b/tests/float/tfloat6.nim
index 8e043a658..c4cd6e932 100644
--- a/tests/float/tfloat6.nim
+++ b/tests/float/tfloat6.nim
@@ -1,12 +1,13 @@
 discard """
-  file: "tfloat6.nim"
-  output: '''1e-06 : 1e-06
+  output: '''
+1e-06 : 1e-06
 1e-06 : 1e-06
 0.001 : 0.001
 1e-06 : 1e-06
 1e-06 : 1e-06
 10.000001 : 10.000001
-100.000001 : 100.000001'''
+100.000001 : 100.000001
+'''
   disabled: "windows"
 """
 
diff --git a/tests/float/tfloat7.nim b/tests/float/tfloat7.nim
index 5fd0d43d9..a6d7af10b 100644
--- a/tests/float/tfloat7.nim
+++ b/tests/float/tfloat7.nim
@@ -1,12 +1,13 @@
 discard """
-  file: "tfloat6.nim"
-  output: '''passed.
+output: '''
 passed.
 passed.
 passed.
 passed.
 passed.
-passed.'''
+passed.
+passed.
+'''
 """
 
 import strutils
diff --git a/tests/float/tfloatmod.nim b/tests/float/tfloatmod.nim
new file mode 100644
index 000000000..0b84ec7e0
--- /dev/null
+++ b/tests/float/tfloatmod.nim
@@ -0,0 +1,130 @@
+discard """
+  targets: "c c++ js"
+  output: "ok"
+  exitcode: "0"
+"""
+
+# Test `mod` on float64 both at compiletime and at runtime
+import math
+
+# Testdata from golang
+const testValues: array[10, tuple[f64, expected: float64]] = [
+  (4.9790119248836735e+00, 4.197615023265299782906368e-02),
+  (7.7388724745781045e+00, 2.261127525421895434476482e+00),
+  (-2.7688005719200159e-01, 3.231794108794261433104108e-02),
+  (-5.0106036182710749e+00, 4.989396381728925078391512e+00),
+  (9.6362937071984173e+00, 3.637062928015826201999516e-01),
+  (2.9263772392439646e+00, 1.220868282268106064236690e+00),
+  (5.2290834314593066e+00, 4.770916568540693347699744e+00),
+  (2.7279399104360102e+00, 1.816180268691969246219742e+00),
+  (1.8253080916808550e+00, 8.734595415957246977711748e-01),
+  (-8.6859247685756013e+00, 1.314075231424398637614104e+00)]
+
+const simpleTestData = [
+  (5.0, 3.0, 2.0),
+  (5.0, -3.0, 2.0),
+  (-5.0, 3.0, -2.0),
+  (-5.0, -3.0, -2.0),
+  (10.0, 1.0, 0.0),
+  (10.0, 0.5, 0.0),
+  (10.0, 1.5, 1.0),
+  (-10.0, 1.0, -0.0),
+  (-10.0, 0.5, -0.0),
+  (-10.0, 1.5, -1.0),
+  (1.5, 1.0, 0.5),
+  (1.25, 1.0, 0.25),
+  (1.125, 1.0, 0.125)
+  ]
+
+const specialCases = [
+  (-Inf, -Inf, Nan),
+  (-Inf, -Pi, Nan),
+  (-Inf, 0.0, Nan),
+  (-Inf, Pi, Nan),
+  (-Inf, Inf, Nan),
+  (-Inf, Nan, Nan),
+  (-PI, -Inf, -PI),
+  (-PI, 0.0, Nan),
+  (-PI, Inf, -PI),
+  (-PI, Nan, Nan),
+  (-0.0, -Inf, -0.0),
+  (-0.0, 0.0, Nan),
+  (-0.0, Inf, -0.0),
+  (-0.0, Nan, Nan),
+  (0.0, -Inf, 0.0),
+  (0.0, 0.0, Nan),
+  (0.0, Inf, 0.0),
+  (0.0, Nan, Nan),
+  (PI, -Inf, PI),
+  (PI, 0.0, Nan),
+  (PI, Inf, PI),
+  (PI, Nan, Nan),
+  (Inf, -Inf, Nan),
+  (Inf, -PI, Nan),
+  (Inf, 0.0, Nan),
+  (Inf, PI, Nan),
+  (Inf, Inf, Nan),
+  (Inf, Nan, Nan),
+  (Nan, -Inf, Nan),
+  (Nan, -PI, Nan),
+  (Nan, 0.0, Nan),
+  (Nan, PI, Nan),
+  (Nan, Inf, Nan),
+  (Nan, Nan, Nan)]
+
+const extremeValues = [
+  (5.9790119248836734e+200, 1.1258465975523544, 0.6447968302508578),
+  (1.0e-100, 1.0e100, 1.0e-100)]
+
+proc errmsg(x, y, r, expected: float64): string =
+  $x & " mod " & $y & " == " & $r & " but expected " & $expected
+
+proc golangtest() =
+  let x = 10.0
+  for tpl in testValues:
+    let (y, expected) = tpl
+    let r = x mod y
+    doAssert(r == expected, errmsg(x, y, r, expected))
+
+proc simpletest() =
+  for tpl in simpleTestData:
+    let(x, y, expected) = tpl
+    let r = x mod y
+    doAssert(r == expected, errmsg(x, y, r, expected))
+
+proc testSpecialCases() =
+  proc isnan(f: float64): bool =
+    case classify(f)
+    of fcNan:
+      result = true
+    else:
+      result = false
+
+  for tpl in specialCases:
+    let(x, y, expected) = tpl
+    let r = x mod y
+    doAssert((r == expected) or (r.isnan and expected.isnan),
+              errmsg(x, y, r, expected))
+
+proc testExtremeValues() =
+  for tpl in extremeValues:
+    let (x, y, expected) = tpl
+    let r = x mod y
+    doAssert(r == expected, errmsg(x, y, r, expected))
+
+static:
+  # compiletime evaluation
+  golangtest()
+  simpletest()
+  testSpecialCases()
+  testExtremeValues()
+
+proc main() =
+  # runtime evaluation
+  golangtest()
+  simpletest()
+  testSpecialCases()
+  testExtremeValues()
+
+main()
+echo "ok"
diff --git a/tests/float/tfloatnan.nim b/tests/float/tfloatnan.nim
index aa288d342..29937a862 100644
--- a/tests/float/tfloatnan.nim
+++ b/tests/float/tfloatnan.nim
@@ -1,6 +1,6 @@
 discard """
-  file: "tfloatnan.nim"
-  output: '''Nim: nan
+output: '''
+Nim: nan
 Nim: nan (float)
 Nim: nan (double)
 '''
diff --git a/tests/float/tissue5821.nim b/tests/float/tissue5821.nim
index e8aa4a1d9..c4f561f09 100644
--- a/tests/float/tissue5821.nim
+++ b/tests/float/tissue5821.nim
@@ -1,7 +1,7 @@
 discard """
-  file: "tissue5821.nim"
-  output: ''''''
+output: "ok"
 """
+
 proc main(): void =
   let a: float32 = 47.11'f32
   doAssert a == 47.11'f32
@@ -10,4 +10,6 @@ proc main(): void =
   doAssert b != 10.123402823e+38'f64
   doAssert b == 10.234402823e+38'f64
 
-main()
\ No newline at end of file
+  echo "ok"
+
+main()
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/t5707.nim b/tests/generics/t5707.nim
deleted file mode 100644
index a155e1597..000000000
--- a/tests/generics/t5707.nim
+++ /dev/null
@@ -1,6 +0,0 @@
-import sugar
-
-proc foo[T]: seq[int] =
-    return lc[x | (x <- 1..10, x mod 2 == 0), int]
-
-doAssert foo[float32]() == @[2, 4, 6, 8, 10]
diff --git a/tests/generics/t6137.nim b/tests/generics/t6137.nim
index 639675f35..abf02a756 100644
--- a/tests/generics/t6137.nim
+++ b/tests/generics/t6137.nim
@@ -1,7 +1,6 @@
 discard """
-  action: "reject"
-  line: 29
   errormsg: "\'vectFunc\' doesn't have a concrete type, due to unspecified generic parameters."
+  line: 28
 """
 
 type
diff --git a/tests/generics/t7141.nim b/tests/generics/t7141.nim
index 8a128d828..b1e9cbf43 100644
--- a/tests/generics/t7141.nim
+++ b/tests/generics/t7141.nim
@@ -1,7 +1,6 @@
 discard """
-  action: "reject"
-  line: 7
   errormsg: "cannot instantiate: \'T\'"
+  line: 6
 """
 
 proc foo[T](x: T) =
diff --git a/tests/generics/t8270.nim b/tests/generics/t8270.nim
index 707e981fa..1e731d1d4 100644
--- a/tests/generics/t8270.nim
+++ b/tests/generics/t8270.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 6
   errormsg: "cannot instantiate: \'T\'"
+  line: 6
 """
 
 proc m[T](x: T): int = discard
diff --git a/tests/generics/tbintre2.nim b/tests/generics/tbintre2.nim
deleted file mode 100644
index eb46b5157..000000000
--- a/tests/generics/tbintre2.nim
+++ /dev/null
@@ -1,31 +0,0 @@
-discard """
-  file: "tbintre2.nim"
-  output: "helloworld99110223"
-"""
-# Same test, but check module boundaries
-
-import tbintree
-
-var
-  root: PBinaryTree[string]
-  x = newNode("hello")
-add(root, x)
-add(root, "world")
-if find(root, "world"):
-  for str in items(root):
-    stdout.write(str)
-else:
-  stdout.writeLine("BUG")
-
-var
-  r2: PBinaryTree[int]
-add(r2, newNode(110))
-add(r2, 223)
-add(r2, 99)
-for y in items(r2):
-  stdout.write(y)
-
-#OUT helloworld99110223
-
-
-
diff --git a/tests/generics/tbintree.nim b/tests/generics/tbintree.nim
index 13163f764..a1a13c7b5 100644
--- a/tests/generics/tbintree.nim
+++ b/tests/generics/tbintree.nim
@@ -1,6 +1,9 @@
 discard """
-  file: "tbintree.nim"
-  output: "helloworld99110223"
+  output: '''hello
+world
+99
+110
+223'''
 """
 type
   TBinaryTree[T] = object      # TBinaryTree is a generic type with
@@ -82,7 +85,7 @@ proc debug[T](a: PBinaryTree[T]) =
     echo a.data
     debug(a.ri)
 
-when isMainModule:
+when true:
   var
     root: PBinaryTree[string]
     x = newNode("hello")
@@ -90,9 +93,9 @@ when isMainModule:
   add(root, "world")
   if find(root, "world"):
     for str in items(root):
-      stdout.write(str)
+      echo(str)
   else:
-    stdout.writeLine("BUG")
+    echo("BUG")
 
   var
     r2: PBinaryTree[int]
@@ -100,8 +103,4 @@ when isMainModule:
   add(r2, 223)
   add(r2, 99)
   for y in items(r2):
-    stdout.write(y)
-
-#OUT helloworld99110223
-
-
+    echo(y)
diff --git a/tests/generics/texplicitgeneric1.nim b/tests/generics/texplicitgeneric1.nim
index ac0197c1a..16f4f7330 100644
--- a/tests/generics/texplicitgeneric1.nim
+++ b/tests/generics/texplicitgeneric1.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "texplicitgeneric1.nim"
   output: "Key: 12 value: 12Key: 13 value: 13 Key: A value: 12 Key: B value: 13"
 """
 # test explicit type instantiation
@@ -34,5 +33,4 @@ c.add('B', "13")
 for k, v in items(c):
   stdout.write(" Key: ", $k, " value: ", v)
 
-
-
+stdout.write "\n"
diff --git a/tests/generics/texplicitgeneric2.nim b/tests/generics/texplicitgeneric2.nim
index c4af17b7b..573b10ae8 100644
--- a/tests/generics/texplicitgeneric2.nim
+++ b/tests/generics/texplicitgeneric2.nim
@@ -33,3 +33,4 @@ c.add('B', "13")
 for k, v in items(c):
   stdout.write(" Key: ", $k, " value: ", v)
 
+stdout.write "\n"
diff --git a/tests/generics/tgeneric0.nim b/tests/generics/tgeneric0.nim
index 6698ecec0..3a35ebaba 100644
--- a/tests/generics/tgeneric0.nim
+++ b/tests/generics/tgeneric0.nim
@@ -1,6 +1,7 @@
 discard """
   output: '''
-100 0
+100
+0
 '''
 """
 
@@ -72,7 +73,7 @@ block tgeneric1:
 
   proc print[T](heap: PBinHeap[T]) =
     for i in countup(0, heap.last):
-      stdout.write($heap.heap[i].data, " ")
+      stdout.write($heap.heap[i].data, "\n")
 
   var heap: PBinHeap[int]
 
diff --git a/tests/generics/tgeneric3.nim b/tests/generics/tgeneric3.nim
index 6897d9de2..4cb12f91b 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
@@ -420,55 +430,50 @@ iterator keys* [T,D] (n: PNode[T,D]): T =
         i = Path[level].Xi
         inc(i)
 
-
-when isMainModule:
-
-  proc test() =
-    var oldvalue: int
-    var root = internalPut[int, int](nil, 312, 312, oldvalue)
-    var someOtherRoot = internalPut[string, int](nil, "312", 312, oldvalue)
-    var it1 = internalFind(root, 312)
-    echo it1.value
-
-    for i in 1..1_000_000:
-      root = internalPut(root, i, i, oldvalue)
-
-    var cnt = 0
-    oldvalue = -1
-    when true : # code compiles, when this or the other when is switched to false
-      for k in root.keys :
-        if k <= oldvalue :
-          echo k
-        oldvalue = k
-        inc(cnt)
-      echo cnt
+proc test() =
+  var oldvalue: int
+  var root = internalPut[int, int](nil, 312, 312, oldvalue)
+  var someOtherRoot = internalPut[string, int](nil, "312", 312, oldvalue)
+  var it1 = internalFind(root, 312)
+  echo it1.value
+
+  for i in 1..1_000_000:
+    root = internalPut(root, i, i, oldvalue)
+
+  var cnt = 0
+  oldvalue = -1
+  when true : # code compiles, when this or the other when is switched to false
+    for k in root.keys :
+      if k <= oldvalue :
+        echo k
+      oldvalue = k
+      inc(cnt)
+    echo cnt
+  when true :
+    cnt = 0
+    VisitAll(root, proc(key, val: int) = inc(cnt))
+    echo cnt
     when true :
-      cnt = 0
-      VisitAll(root, proc(key, val: int) = inc(cnt))
-      echo cnt
-      when true :
-        root = VisitAll(root, proc(key: int, value: var int): bool =
-          return key mod 2 == 0 )
-      cnt = 0
-      oldvalue = -1
-      VisitAll(root, proc(key: int, value: int) {.closure.} =
-        if key <= oldvalue :
-          echo key
-        oldvalue = key
-        inc(cnt) )
-      echo cnt
       root = VisitAll(root, proc(key: int, value: var int): bool =
-        return key mod 2 != 0 )
-      cnt = 0
-      oldvalue = -1
-      VisitAll(root, proc(key: int, value: int) {.closure.} =
-        if key <= oldvalue :
-          echo "error ", key
-        oldvalue = key
-        inc(cnt) )
-      echo cnt
-      #traceTree(root)
-
-
-
-  test()
+        return key mod 2 == 0 )
+    cnt = 0
+    oldvalue = -1
+    VisitAll(root, proc(key: int, value: int) {.closure.} =
+      if key <= oldvalue :
+        echo key
+      oldvalue = key
+      inc(cnt) )
+    echo cnt
+    root = VisitAll(root, proc(key: int, value: var int): bool =
+      return key mod 2 != 0 )
+    cnt = 0
+    oldvalue = -1
+    VisitAll(root, proc(key: int, value: int) {.closure.} =
+      if key <= oldvalue :
+        echo "error ", key
+      oldvalue = key
+      inc(cnt) )
+    echo cnt
+    #traceTree(root)
+
+test()
diff --git a/tests/generics/tgenericprocvar.nim b/tests/generics/tgenericprocvar.nim
index dca9c8538..7935d90c2 100644
--- a/tests/generics/tgenericprocvar.nim
+++ b/tests/generics/tgenericprocvar.nim
@@ -34,3 +34,4 @@ proc test(data: seq[int], value: int): seq[int] =
 for x in items(test(@[1,2,3], 2)):
   stdout.write(x)
 
+stdout.write "\n"
diff --git a/tests/generics/tissues.nim b/tests/generics/tgenerics_issues.nim
index e958549d6..a1d464b97 100644
--- a/tests/generics/tissues.nim
+++ b/tests/generics/tgenerics_issues.nim
@@ -24,12 +24,11 @@ G:0,1:0.1
 G:0,1:0.1
 H:1:0.1
 '''
+joinable: false
 """
 
-
 import macros, sequtils, sets, sugar, tables, typetraits
 
-
 block t88:
   type
     BaseClass[V] = object of RootObj
@@ -763,3 +762,11 @@ block t3717:
 
   var f: Foo[Foo[int]]
   discard foo(f)
+
+
+
+block t5707:
+  proc foo[T]: seq[int] =
+      return lc[x | (x <- 1..10, x mod 2 == 0), int]
+
+  doAssert foo[float32]() == @[2, 4, 6, 8, 10]
diff --git a/tests/generics/tvarious.nim b/tests/generics/tgenerics_various.nim
index 5e18995f5..9e6186534 100644
--- a/tests/generics/tvarious.nim
+++ b/tests/generics/tgenerics_various.nim
@@ -5,12 +5,11 @@ direct
 generic
 generic
 '''
+joinable: false
 """
 
-
 import algorithm, sugar, sequtils, typetraits, asyncdispatch
 
-
 block tconfusing_arrow:
   type Deck = object
     value: int
diff --git a/tests/generics/tgenerictmpl2.nim b/tests/generics/tgenerictmpl2.nim
index ac92d3281..2efb000b3 100644
--- a/tests/generics/tgenerictmpl2.nim
+++ b/tests/generics/tgenerictmpl2.nim
@@ -21,7 +21,7 @@ ttmpl(1)
 ttmpl[int](1) #<- crash case #1
 
 tproc[int]()
-discard tproc[int]
+let _ = tproc[int]
 ttmpl[int]()  #<- crash case #2
 ttmpl[int]    #<- crash case #3
 
diff --git a/tests/generics/tgenericvariant.nim b/tests/generics/tgenericvariant.nim
index 348d3da6e..5ba3a2e7c 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,12 +22,15 @@ 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)
 
-when isMainModule:
+proc main() =
   var Test = Just("Test")
   echo(Test.value)
   var mSomething = safeReadLine()
   echo(mSomething.value)
+  mSomething = safeReadLine()
+
+main()
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/toverloading_typedesc.nim b/tests/generics/toverloading_typedesc.nim
index 94f4d860d..5ab700828 100644
--- a/tests/generics/toverloading_typedesc.nim
+++ b/tests/generics/toverloading_typedesc.nim
@@ -10,7 +10,7 @@ type
   LBar = object
 
 
-when isMainModule:
+when true:
   doAssert FBar.new() == 3
 
   proc new(_: typedesc[LFoo]): int = 0
diff --git a/tests/generics/tparser_generator.nim b/tests/generics/tparser_generator.nim
index 01ddd29b8..8f8fea382 100644
--- a/tests/generics/tparser_generator.nim
+++ b/tests/generics/tparser_generator.nim
@@ -1,6 +1,7 @@
 discard """
   output: '''Match failed: spam
 Match failed: ham'''
+joinable: false
 """
 
 # bug #6220
@@ -397,19 +398,18 @@ template grammar*[K](Kind, Text, Symbol: typedesc; default: K, code: untyped): t
 template grammar*[K](Kind: typedesc; default: K, code: untyped): typed {.hint[XDeclaredButNotUsed]: off.} =
   grammar(Kind, string, char, default, code)
 
-when isMainModule:
-  block:
-    type DummyKind = enum dkDefault
-    grammar(DummyKind, string, char, dkDefault):
-      let rule = token("h[a]+m") + ignore(token(r"\s+")) + (literal("eggs") / literal("beans"))
-      var text = "ham beans"
-      discard rule.parse(text)
-
-      var recursive = newRule()
-      recursive -> (literal("(") + recursive + literal(")")) / token(r"\d+")
-      for test in ["spam", "57", "(25)", "((25))"]:
-        discard recursive.parse(test)
-
-      let repeated = +literal("spam") + ?literal("ham") + *literal("salami")
-      for test in ["ham", "spam", "spamspamspam" , "spamham", "spamsalami", "spamsalamisalami"]:
-        discard  repeated.parse(test)
+block:
+  type DummyKind = enum dkDefault
+  grammar(DummyKind, string, char, dkDefault):
+    let rule = token("h[a]+m") + ignore(token(r"\s+")) + (literal("eggs") / literal("beans"))
+    var text = "ham beans"
+    discard rule.parse(text)
+
+    var recursive = newRule()
+    recursive -> (literal("(") + recursive + literal(")")) / token(r"\d+")
+    for test in ["spam", "57", "(25)", "((25))"]:
+      discard recursive.parse(test)
+
+    let repeated = +literal("spam") + ?literal("ham") + *literal("salami")
+    for test in ["ham", "spam", "spamspamspam" , "spamham", "spamsalami", "spamsalamisalami"]:
+      discard  repeated.parse(test)
diff --git a/tests/generics/trtree.nim b/tests/generics/trtree.nim
index 75de2a1c4..6ec1c8f6f 100644
--- a/tests/generics/trtree.nim
+++ b/tests/generics/trtree.nim
@@ -1,8 +1,12 @@
 discard """
   output: '''1 [2, 3, 4, 7]
 [0, 0]'''
+  target: "c"
+  joinable: false
 """
 
+# don't join because the code is too messy.
+
 # Nim RTree and R*Tree implementation
 # S. Salewski, 06-JAN-2018
 
@@ -81,13 +85,13 @@ proc distance(c1, c2: BoxCenter): auto =
 proc overlap(r1, r2: Box): auto =
   result = type(r1[0].a)(1)
   for i in 0 .. r1.high:
-    result *= (min(r1[i]. b, r2[i]. b) - max(r1[i]. a, r2[i]. a))
+    result *= (min(r1[i].b, r2[i].b) - max(r1[i].a, r2[i].a))
     if result <= 0: return 0
 
 proc union(r1, r2: Box): Box =
   for i in 0 .. r1.high:
-    result[i]. a = min(r1[i]. a, r2[i]. a)
-    result[i]. b = max(r1[i]. b, r2[i]. b)
+    result[i].a = min(r1[i].a, r2[i].a)
+    result[i].b = max(r1[i].b, r2[i].b)
 
 proc intersect(r1, r2: Box): bool =
   for i in 0 .. r1.high:
@@ -98,12 +102,12 @@ proc intersect(r1, r2: Box): bool =
 proc area(r: Box): auto = #type(r[0].a) =
   result = type(r[0].a)(1)
   for i in 0 .. r.high:
-    result *= r[i]. b - r[i]. a
+    result *= r[i].b - r[i].a
 
 proc margin(r: Box): auto = #type(r[0].a) =
   result = type(r[0].a)(0)
   for i in 0 .. r.high:
-    result += r[i]. b - r[i]. a
+    result += r[i].b - r[i].a
 
 # how much enlargement does r1 need to include r2
 proc enlargement(r1, r2: Box): auto =
@@ -238,12 +242,12 @@ proc rstarSplit[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; n: var Node[M, D,
   for d2 in 0 ..< 2 * D:
     let d = d2 div 2
     if d2 mod 2 == 0:
-      sortPlus(n.a, lx, proc (x, y: NL):  int = cmp(x.b[d].a, y.b[d].a))
+      sortPlus(n.a, lx, proc (x, y: NL): int = cmp(x.b[d].a, y.b[d].a))
     else:
-      sortPlus(n.a, lx, proc (x, y: NL):  int = cmp(x.b[d].b, y.b[d].b))
+      sortPlus(n.a, lx, proc (x, y: NL): int = cmp(x.b[d].b, y.b[d].b))
     for i in t.m - 1 .. n.a.high - t.m + 1:
       var b = lx.b
-      for j in 0 ..< i: # we can precalculate union() for range 0 .. t.m - 1, but that seems to give no real benefit. Maybe for very large M?
+      for j in 0 ..< i: # we can precalculate union() for range 0 .. t.m - 1, but that seems to give no real benefit.Maybe for very large M?
         #echo "x",j
         b = union(n.a[j].b, b)
       var m = margin(b)
@@ -446,7 +450,7 @@ proc reInsert[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; n: var Node[M, D, R
   while p.a[i].n != n:
     inc(i)
   let c = center(p.a[i].b)
-  sortPlus(n.a, lx, proc (x, y: NL):  int = cmp(distance(center(x.b), c), distance(center(y.b), c)))
+  sortPlus(n.a, lx, proc (x, y: NL): int = cmp(distance(center(x.b), c), distance(center(y.b), c)))
   n.numEntries = M - t.p
   swap(n.a[n.numEntries], lx)
   inc n.numEntries
@@ -588,70 +592,68 @@ proc delete*[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; leaf: L[D, RT, LT]): boo
       t.root.parent = nil
     return true
 
-when isMainModule:
-
-  var t = [4, 1, 3, 2]
-  var xt = 7
-  sortPlus(t, xt, system.cmp, SortOrder.Ascending)
-  echo xt, " ", t
-
-  type
-    RSE = L[2, int, int]
-    RSeq = seq[RSE]
-
-  proc rseq_search(rs: RSeq; rse: RSE): seq[int] =
-    result = newSeq[int]()
-    for i in rs:
-      if intersect(i.b, rse.b):
-        result.add(i.l)
-
-  proc rseq_delete(rs: var RSeq; rse: RSE): bool =
-    for i in 0 .. rs.high:
-      if rs[i] == rse:
-        #rs.delete(i)
-        rs[i] = rs[rs.high]
-        rs.setLen(rs.len - 1)
-        return true
-
-  import random, algorithm
-
-  proc test(n: int) =
-    var b: Box[2, int]
-    echo center(b)
-    var x1, x2, y1, y2: int
-    var t = newRStarTree[8, 2, int, int]()
-    #var t = newRTree[8, 2, int, int]()
-    var rs = newSeq[RSE]()
-    for i in 0 .. 5:
-      for i in 0 .. n - 1:
-        x1 = rand(1000)
-        y1 = rand(1000)
-        x2 = x1 + rand(25)
-        y2 = y1 + rand(25)
-        b = [(x1, x2), (y1, y2)]
-        let el: L[2, int, int] = (b, i + 7)
-        t.insert(el)
-        rs.add(el)
-
-      for i in 0 .. (n div 4):
-        let j = rand(rs.high)
-        var el = rs[j]
-        assert t.delete(el)
-        assert rs.rseq_delete(el)
-
-      for i in 0 .. n - 1:
-        x1 = rand(1000)
-        y1 = rand(1000)
-        x2 = x1 + rand(100)
-        y2 = y1 + rand(100)
-        b = [(x1, x2), (y1, y2)]
-        let el: L[2, int, int] = (b, i)
-        let r = search(t, b)
-        let r2 = rseq_search(rs, el)
-        assert r.len == r2.len
-        assert r.sorted(system.cmp) == r2.sorted(system.cmp)
-
-  test(1500)
-
-  # 651 lines
 
+var t = [4, 1, 3, 2]
+var xt = 7
+sortPlus(t, xt, system.cmp, SortOrder.Ascending)
+echo xt, " ", t
+
+type
+  RSE = L[2, int, int]
+  RSeq = seq[RSE]
+
+proc rseq_search(rs: RSeq; rse: RSE): seq[int] =
+  result = newSeq[int]()
+  for i in rs:
+    if intersect(i.b, rse.b):
+      result.add(i.l)
+
+proc rseq_delete(rs: var RSeq; rse: RSE): bool =
+  for i in 0 .. rs.high:
+    if rs[i] == rse:
+      #rs.delete(i)
+      rs[i] = rs[rs.high]
+      rs.setLen(rs.len - 1)
+      return true
+
+import random, algorithm
+
+proc test(n: int) =
+  var b: Box[2, int]
+  echo center(b)
+  var x1, x2, y1, y2: int
+  var t = newRStarTree[8, 2, int, int]()
+  #var t = newRTree[8, 2, int, int]()
+  var rs = newSeq[RSE]()
+  for i in 0 .. 5:
+    for i in 0 .. n - 1:
+      x1 = rand(1000)
+      y1 = rand(1000)
+      x2 = x1 + rand(25)
+      y2 = y1 + rand(25)
+      b = [(x1, x2), (y1, y2)]
+      let el: L[2, int, int] = (b, i + 7)
+      t.insert(el)
+      rs.add(el)
+
+    for i in 0 .. (n div 4):
+      let j = rand(rs.high)
+      var el = rs[j]
+      assert t.delete(el)
+      assert rs.rseq_delete(el)
+
+    for i in 0 .. n - 1:
+      x1 = rand(1000)
+      y1 = rand(1000)
+      x2 = x1 + rand(100)
+      y2 = y1 + rand(100)
+      b = [(x1, x2), (y1, y2)]
+      let el: L[2, int, int] = (b, i)
+      let r = search(t, b)
+      let r2 = rseq_search(rs, el)
+      assert r.len == r2.len
+      assert r.sorted(system.cmp) == r2.sorted(system.cmp)
+
+test(1500)
+
+# 651 lines
diff --git a/tests/generics/tthread_generic.nim b/tests/generics/tthread_generic.nim
index def1acfe1..2af5a7615 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
@@ -25,7 +26,7 @@ proc `@||->`*[T](fn: proc(): T {.thread.},
 proc `||->`*[T](fn: proc(): T{.thread.}, callback: proc(val: T){.thread.}) =
   discard fn @||-> callback
 
-when isMainModule:
+when true:
   import os
   proc testFunc(): int {.thread.} =
     return 1
@@ -36,4 +37,3 @@ when isMainModule:
   echo("test")
   joinThread(thr)
   os.sleep(3000)
-
diff --git a/tests/generics/twrong_floatlit_type.nim b/tests/generics/twrong_floatlit_type.nim
index c1830cd5a..04bacc0d9 100644
--- a/tests/generics/twrong_floatlit_type.nim
+++ b/tests/generics/twrong_floatlit_type.nim
@@ -108,7 +108,7 @@ proc `/`*[S](a, b: Vector2D[S]): Vector2D[S] =
 proc vec[S](x, y: S): Vector2D[S] =
   Vector2D[S](x: x, y: y)
 
-if isMainModule:
+if true:
   # Comment out this let, and the program will fail to
   # compile with a type mismatch, as expected.
 
diff --git a/tests/global/t5958.nim b/tests/global/t5958.nim
index 5abcad4a9..9b7642363 100644
--- a/tests/global/t5958.nim
+++ b/tests/global/t5958.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 9
   errormsg: "undeclared identifier: 'a'"
+  line: 9
 """
 
 static:
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/implicit/timplicit.nim b/tests/implicit/timplicit.nim
index 70f14db53..bb701249c 100644
--- a/tests/implicit/timplicit.nim
+++ b/tests/implicit/timplicit.nim
@@ -6,6 +6,7 @@ discard """
 4
 2
 88
+timplicit done
 '''
 """
 
@@ -43,4 +44,6 @@ block:
   var indirect = p
   x.indirect(44)
 
-  echo x[]
\ No newline at end of file
+  echo x[]
+
+  echo "timplicit done"
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/tcountup.nim b/tests/iter/tcountup.nim
index 1559041aa..f93f1536e 100644
--- a/tests/iter/tcountup.nim
+++ b/tests/iter/tcountup.nim
@@ -1,14 +1,9 @@
 discard """
-  file: "tcountup.nim"
   output: "0123456789"
 """
 
-# Test new countup and unary <
+# Test new countup
 
-for i in 0 .. < 10'i64:
+for i in 0 ..< 10'i64:
   stdout.write(i)
-
-#OUT 0123456789
-
-
-
+echo "\n"
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/titer10.nim b/tests/iter/titer10.nim
index 6a6afc780..9c76b62e1 100644
--- a/tests/iter/titer10.nim
+++ b/tests/iter/titer10.nim
@@ -23,7 +23,7 @@ when true:
       for val in sortable:
           yield val
 
-  when isMainModule:
+  when true:
     proc main =
       for val in byDistance([2, 3, 5, 1], 3):
           echo val
diff --git a/tests/iter/titer11.nim b/tests/iter/titer11.nim
index 6c410e945..c4c7d4a16 100644
--- a/tests/iter/titer11.nim
+++ b/tests/iter/titer11.nim
@@ -1,6 +1,6 @@
 discard """
-  file: "titer11.nim"
-  output: '''[
+output: '''
+[
 1
 2
 3
diff --git a/tests/iter/titer3.nim b/tests/iter/titer3.nim
index cc603fd85..9dcfd7be5 100644
--- a/tests/iter/titer3.nim
+++ b/tests/iter/titer3.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "titer3.nim"
   output: '''1231
 4
 6
diff --git a/tests/iter/titer4.nim b/tests/iter/titer4.nim
index 9b52f8055..912883a63 100644
--- a/tests/iter/titer4.nim
+++ b/tests/iter/titer4.nim
@@ -1,10 +1,8 @@
 discard """
+  errormsg: "iterator within for loop context expected"
   file: "titer4.nim"
   line: 7
-  errormsg: "iterator within for loop context expected"
 """
 # implicit items/pairs, but not if we have 3 for loop vars:
 for x, y, z in {'a'..'z'}: #ERROR_MSG iterator within for loop context expected
   nil
-
-
diff --git a/tests/iter/titer5.nim b/tests/iter/titer5.nim
index bbd50fcb1..cb691ffdb 100644
--- a/tests/iter/titer5.nim
+++ b/tests/iter/titer5.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "titer5.nim"
   output: "abcxyz"
 """
 # Test method call syntax for iterators:
@@ -11,6 +10,4 @@ for x in lines.split():
   stdout.write(x)
 
 #OUT abcxyz
-
-
-
+stdout.write "\n"
diff --git a/tests/iter/titer6.nim b/tests/iter/titer6.nim
index b7c8fee80..69a10d868 100644
--- a/tests/iter/titer6.nim
+++ b/tests/iter/titer6.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "titer6.nim"
   output: "000"
 """
 # Test iterator with more than 1 yield statement
@@ -33,5 +32,4 @@ proc wordWrap2(s: string, maxLineWidth = 80,
   for word, isSep in tokenize2(s, seps):
     var w = 0
 
-
-
+stdout.write "\n"
diff --git a/tests/iter/titer7.nim b/tests/iter/titer7.nim
index c2bd9b9cb..9cba3038d 100644
--- a/tests/iter/titer7.nim
+++ b/tests/iter/titer7.nim
@@ -45,9 +45,9 @@ proc square(x:int): int =
 let list = @[1,2,3,4,5,6,7,8,9]
 
 echo ("--- evens")
-for item in list / isEven : echo(item)
+for item in list / isEven: echo(item)
 echo ("--- squares")
-for item in list >> square : echo(item)
+for item in list >> square: echo(item)
 #echo ("--- squares of evens, only")
 # next line doesn't compile. Generic types are not inferred
 #for item in list />> (isEven, square) : echo(item)
diff --git a/tests/iter/tissues.nim b/tests/iter/titer_issues.nim
index 773e7dbff..773e7dbff 100644
--- a/tests/iter/tissues.nim
+++ b/tests/iter/titer_issues.nim
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/tconcat.nim b/tests/iter/titerconcat.nim
index 477ac5e26..477ac5e26 100644
--- a/tests/iter/tconcat.nim
+++ b/tests/iter/titerconcat.nim
diff --git a/tests/iter/titervaropenarray.nim b/tests/iter/titervaropenarray.nim
index 1e70ce247..701f652df 100644
--- a/tests/iter/titervaropenarray.nim
+++ b/tests/iter/titervaropenarray.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "titer2.nim"
   output: "123"
 """
 # Try to break the transformation pass:
@@ -12,5 +11,4 @@ var x = [[1, 2, 3], [4, 5, 6]]
 for y in iterAndZero(x[0]): write(stdout, $y)
 #OUT 123
 
-
-
+write stdout, "\n"
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/treciter.nim b/tests/iter/treciter.nim
index dacdbdfd7..7b61326f4 100644
--- a/tests/iter/treciter.nim
+++ b/tests/iter/treciter.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "recursive dependency: \'myrec\'"
   file: "treciter.nim"
   line: 9
-  errormsg: "recursive dependency: \'myrec\'"
 """
 # Test that an error message occurs for a recursive iterator
 
@@ -10,5 +10,3 @@ iterator myrec(n: int): int =
     yield x
 
 for x in myrec(10): echo x
-
-
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/twrongiter.nim b/tests/iter/twrongiter.nim
index 33394219b..577b8c4f1 100644
--- a/tests/iter/twrongiter.nim
+++ b/tests/iter/twrongiter.nim
@@ -1,6 +1,6 @@
 discard """
-line: 12
 errormsg: "type mismatch"
+line: 12
 """
 
 proc first(it: iterator(): int): seq[int] =
diff --git a/tests/iter/tyieldintry.nim b/tests/iter/tyieldintry.nim
index 6d24417a6..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 =
@@ -440,4 +440,32 @@ block:
 
   test(it, 1, 2, 5)
 
+block: #9694 - yield in ObjConstr
+  type Foo = object
+    a, b: int
+
+  template yieldAndNum: int =
+    yield 1
+    2
+
+  iterator it(): int {.closure.} =
+    let a = Foo(a: 5, b: yieldAndNum())
+    checkpoint(a.b)
+
+  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/t7224.nim b/tests/js/t7224.nim
index 2d7ee1336..be9d0ae9c 100644
--- a/tests/js/t7224.nim
+++ b/tests/js/t7224.nim
@@ -7,7 +7,7 @@ t7224.ccc, line: 15
 t7224.ddd, line: 12
 '''
 """
-  
+
 proc ddd() =
   raise newException(IOError, "didn't do stuff")
 
@@ -22,5 +22,6 @@ proc aaa() =
 
 try:
   aaa()
+
 except IOError as e:
   echo getStackTrace(e)
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/taddnilstr.nim b/tests/js/taddnilstr.nim
deleted file mode 100644
index f5b934fdd..000000000
--- a/tests/js/taddnilstr.nim
+++ /dev/null
@@ -1,4 +0,0 @@
-var x = "foo".cstring
-var y: string
-add(y, x)
-doAssert y == "foo"
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/js/tnilstrs.nim b/tests/js/tnilstrs.nim
new file mode 100644
index 000000000..c0048cb24
--- /dev/null
+++ b/tests/js/tnilstrs.nim
@@ -0,0 +1,17 @@
+block:
+  var x: string
+  var y = "foo"
+
+  echo x
+  doAssert x == ""
+  doAssert "" == x
+
+  add(x, y)
+  y[0] = 'm'
+  doAssert y == "moo" and x == "foo"
+
+block:
+  var x = "foo".cstring
+  var y: string
+  add(y, x)
+  doAssert y == "foo"
\ No newline at end of file
diff --git a/tests/js/tstrconcat.nim b/tests/js/tstrconcat.nim
deleted file mode 100644
index 37c8db687..000000000
--- a/tests/js/tstrconcat.nim
+++ /dev/null
@@ -1,5 +0,0 @@
-var x: string
-var y = "foo"
-add(x, y)
-y[0] = 'm'
-doAssert y == "moo" and x == "foo"
diff --git a/tests/js/tvarargs.nim b/tests/js/tvarargs.nim
index b8c532767..8d57af58d 100644
--- a/tests/js/tvarargs.nim
+++ b/tests/js/tvarargs.nim
@@ -11,5 +11,5 @@ type
 
 var console* {.importc.}: Console
 
-when isMainModule:
+when true:
   console.log "Hello, world"
diff --git a/tests/let/tlet.nim b/tests/let/tlet.nim
index 6703ba254..25d7b9bf7 100644
--- a/tests/let/tlet.nim
+++ b/tests/let/tlet.nim
@@ -1,6 +1,6 @@
 discard """
-  line: "10"
   errormsg: "'name' cannot be assigned to"
+  line: "10"
 """
 
 echo("What's your name? ")
@@ -8,4 +8,3 @@ let name = readLine(stdin)
 while name == "":
   echo("Please tell me your name: ")
   name = readLine(stdin)
-
diff --git a/tests/let/tlet2.nim b/tests/let/tlet2.nim
index 2df15fa5c..63e7d6128 100644
--- a/tests/let/tlet2.nim
+++ b/tests/let/tlet2.nim
@@ -1,6 +1,6 @@
 discard """
-  line: "13"
   errormsg: "type mismatch: got <int literal(8), int literal(5), int, int>"
+  line: "13"
 """
 
 proc divmod(a, b: int, res, remainder: var int) =
@@ -13,4 +13,3 @@ let
 divmod(8, 5, x, y) # modifies x and y
 echo(x)
 echo(y)
-
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/lexer/tind1.nim b/tests/lexer/tind1.nim
index ffbde48fd..2185c3074 100644
--- a/tests/lexer/tind1.nim
+++ b/tests/lexer/tind1.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 24
   errormsg: "invalid indentation"
+  line: 24
 """
 
 import macros
diff --git a/tests/lexer/tinvalidintegerliteral1.nim b/tests/lexer/tinvalidintegerliteral1.nim
index 08ab82a22..6bf7624f3 100644
--- a/tests/lexer/tinvalidintegerliteral1.nim
+++ b/tests/lexer/tinvalidintegerliteral1.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "invalid number"
   file: "tinvalidintegerliteral1.nim"
   line: 7
-  errormsg: "invalid number"
 """
 
 echo 0b
diff --git a/tests/lexer/tinvalidintegerliteral2.nim b/tests/lexer/tinvalidintegerliteral2.nim
index bc8793e4e..eb6efc131 100644
--- a/tests/lexer/tinvalidintegerliteral2.nim
+++ b/tests/lexer/tinvalidintegerliteral2.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "invalid number"
   file: "tinvalidintegerliteral2.nim"
   line: 7
-  errormsg: "invalid number"
 """
 
 echo 0x
diff --git a/tests/lexer/tinvalidintegerliteral3.nim b/tests/lexer/tinvalidintegerliteral3.nim
index 9c2fe69df..e09cda54a 100644
--- a/tests/lexer/tinvalidintegerliteral3.nim
+++ b/tests/lexer/tinvalidintegerliteral3.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "0O5 is an invalid int literal; For octal literals use the '0o' prefix."
   file: "tinvalidintegerliteral3.nim"
   line: 7
-  errormsg: "0O5 is an invalid int literal; For octal literals use the '0o' prefix."
 """
 
 echo 0O5
diff --git a/tests/lexer/tmissingnl.nim b/tests/lexer/tmissingnl.nim
index 095d9570e..dc939bcd2 100644
--- a/tests/lexer/tmissingnl.nim
+++ b/tests/lexer/tmissingnl.nim
@@ -1,10 +1,9 @@
 discard """
+  errormsg: "invalid indentation"
   file: "tmissingnl.nim"
   line: 7
-  errormsg: "invalid indentation"
 """
 
 import strutils let s: seq[int] = @[0, 1, 2, 3, 4, 5, 6]
 
 #s[1..3] = @[]
-
diff --git a/tests/lexer/tstrlits.nim b/tests/lexer/tstrlits.nim
index d13baf7ff..8e8250a5b 100644
--- a/tests/lexer/tstrlits.nim
+++ b/tests/lexer/tstrlits.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tstrlits.nim"
   output: "a\"\"long string\"\"\"\"\"abc\"def_'2'●𝌆𝌆A"
 """
 # Test the new different string literals
@@ -17,8 +16,4 @@ const
 stdout.write(rawQuote)
 stdout.write(tripleEmpty)
 stdout.write(raw)
-stdout.write(escaped)
-#OUT a""long string"""""abc"def_'2'●𝌆𝌆A
-
-
-
+stdout.writeLine(escaped)
diff --git a/tests/lexer/tunderscores.nim b/tests/lexer/tunderscores.nim
index f64f36977..1896a2898 100644
--- a/tests/lexer/tunderscores.nim
+++ b/tests/lexer/tunderscores.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "invalid token: trailing underscore"
   file: "tunderscores.nim"
   line: 8
-  errormsg: "invalid token: trailing underscore"
 """
 # Bug #502670
 
@@ -9,6 +9,3 @@ var ef_ = 3  #ERROR_MSG invalid token: _
 var a__b = 1
 var c___d = 2
 echo(ab, cd, ef_)
-
-
-
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 715c969f3..d231a4336 100644
--- a/tests/macros/tgetimpl.nim
+++ b/tests/macros/tgetimpl.nim
@@ -1,7 +1,7 @@
 discard """
-  msg: '''"muhaha"
+  nimout: '''"muhaha"
 proc poo(x, y: int) =
-  let y = x 
+  let y = x
   echo ["poo"]'''
 """
 
@@ -16,14 +16,13 @@ proc poo(x, y: int) =
 
 macro m(x: typed): untyped =
   echo repr x.getImpl
-  result = x
 
-discard m foo
-discard m poo
+m(foo)
+m(poo)
 
 #------------
 
-macro checkOwner(x: typed, check_id: static[int]): untyped = 
+macro checkOwner(x: typed, check_id: static[int]): untyped =
   let sym = case check_id:
     of 0: x
     of 1: x.getImpl.body[0][0][0]
@@ -32,11 +31,11 @@ macro checkOwner(x: typed, check_id: static[int]): untyped =
     else: x
   result = newStrLitNode($sym.owner.symKind)
 
-macro isSameOwner(x, y: typed): untyped = 
-  result = 
+macro isSameOwner(x, y: typed): untyped =
+  result =
     if x.owner == y.owner: bindSym"true"
     else: bindSym"false"
-    
+
 
 static:
   doAssert checkOwner(foo, 0) == "nskModule"
@@ -47,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/tgettypeinst.nim b/tests/macros/tgettypeinst.nim
index 2f1abe193..c2cde9a43 100644
--- a/tests/macros/tgettypeinst.nim
+++ b/tests/macros/tgettypeinst.nim
@@ -183,3 +183,32 @@ test(Vec4[float32]):
 # bug #4862
 static:
   discard typedesc[(int, int)].getTypeImpl
+
+# custom pragmas
+template myAttr() {.pragma.}
+template myAttr2() {.pragma.}
+template myAttr3() {.pragma.}
+template serializationKey(key: string) {.pragma.}
+
+type
+  MyObj = object {.packed,myAttr,serializationKey: "one".}
+    myField {.myAttr2,serializationKey: "two".}: int
+    myField2 {.myAttr3,serializationKey: "three".}: float
+
+# field pragmas not currently supported
+test(MyObj):
+  type
+    _ = object {.packed,myAttr,serializationKey: "one".}
+      myField: int
+      myField2: float
+
+block t9600:
+  type
+    Apple = ref object of RootObj
+
+  macro mixer(x: typed): untyped =
+    let w = getType(x)
+    let v = getTypeImpl(w[1])
+
+  var z: Apple
+  mixer(z)
diff --git a/tests/macros/tmacro4.nim b/tests/macros/tmacro4.nim
index 164afaeb7..7c2839aba 100644
--- a/tests/macros/tmacro4.nim
+++ b/tests/macros/tmacro4.nim
@@ -11,7 +11,7 @@ macro test_macro*(s: string, n: untyped): untyped =
   add(ass, newIdentNode("str"))
   add(ass, newStrLitNode("after"))
   add(result, ass)
-when isMainModule:
+when true:
   var str: string = "before"
   test_macro(str):
     var i : integer = 123
diff --git a/tests/macros/tmacrogenerics.nim b/tests/macros/tmacrogenerics.nim
index 919a15b46..bb562cacb 100644
--- a/tests/macros/tmacrogenerics.nim
+++ b/tests/macros/tmacrogenerics.nim
@@ -1,8 +1,9 @@
 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/tgensym.nim b/tests/macros/tmacrogensym.nim
index 1237b8bf7..1237b8bf7 100644
--- a/tests/macros/tgensym.nim
+++ b/tests/macros/tmacrogensym.nim
diff --git a/tests/macros/tissues.nim b/tests/macros/tmacros_issues.nim
index ecdcd5da9..657f30fc4 100644
--- a/tests/macros/tissues.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/tvarious.nim b/tests/macros/tmacros_various.nim
index 15bd28a37..9eece00bd 100644
--- a/tests/macros/tvarious.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/tnewlit.nim b/tests/macros/tnewlit.nim
index 3ba1e09e1..194f035ba 100644
--- a/tests/macros/tnewlit.nim
+++ b/tests/macros/tnewlit.nim
@@ -147,3 +147,23 @@ block:
   # x needs to be of type seq[string]
   var x = test_newLit_empty_seq_string
   x.add("xyz")
+
+type
+  MyEnum = enum
+    meA
+    meB
+
+macro test_newLit_Enum: untyped =
+  result = newLit(meA)
+
+block:
+  let tmp: MyEnum = meA
+  doAssert tmp == test_newLit_Enum
+
+macro test_newLit_set: untyped =
+  let myset = {MyEnum.low .. MyEnum.high}
+  result = newLit(myset)
+
+block:
+  let tmp: set[MyEnum] = {MyEnum.low .. MyEnum.high}
+  doAssert tmp == test_newLit_set
diff --git a/tests/macros/tquotedo.nim b/tests/macros/tquotedo.nim
new file mode 100644
index 000000000..cd1f69116
--- /dev/null
+++ b/tests/macros/tquotedo.nim
@@ -0,0 +1,25 @@
+discard """
+output: '''
+123
+Hallo Welt
+Hallo Welt
+'''
+"""
+
+import macros
+
+macro mac(): untyped =
+  quote do:
+    proc test(): int =
+      (proc(): int = result = 123)()
+
+mac()
+echo test()
+
+macro foobar(arg: untyped): untyped =
+  result = arg
+  result.add quote do:
+    `result`
+
+foobar:
+  echo "Hallo Welt"
diff --git a/tests/macros/tquotewords.nim b/tests/macros/tquotewords.nim
index fa00ba9de..e718d25f9 100644
--- a/tests/macros/tquotewords.nim
+++ b/tests/macros/tquotewords.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tquotewords.nim"
   output: "thisanexample"
 """
 # Test an idea I recently had:
diff --git a/tests/macros/trecmacro.nim b/tests/macros/trecmacro.nim
index 69ebe3da3..d804178bc 100644
--- a/tests/macros/trecmacro.nim
+++ b/tests/macros/trecmacro.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "recursive dependency: 'dump'"
   file: "trecmacro.nim"
   line: 8
-  errormsg: "recursive dependency: 'dump'"
 """
 
 macro dump(n: untyped): untyped =
diff --git a/tests/macros/tsametype.nim b/tests/macros/tsametype.nim
index 865fb4cb8..5219a3767 100644
--- a/tests/macros/tsametype.nim
+++ b/tests/macros/tsametype.nim
@@ -9,6 +9,7 @@ true
 false
 true
 false'''
+joinable: false
 """
 
 import macros
diff --git a/tests/macros/tslice.nim b/tests/macros/tslice.nim
new file mode 100644
index 000000000..c64289ec6
--- /dev/null
+++ b/tests/macros/tslice.nim
@@ -0,0 +1,38 @@
+import macros
+
+macro test(): untyped =
+  result = nnkStmtList.newTree()
+  let n = nnkStmtList.newTree(
+    newIdentNode("one"),
+    newIdentNode("two"),
+    newIdentNode("three"),
+    newIdentNode("four"),
+    newIdentNode("five"),
+    newIdentNode("six")
+  )
+
+  var i = 1
+  for x in n[1 .. ^2]:
+    assert x == n[i]
+    i.inc
+  assert i == 5
+
+  i = 3
+  for x in n[3..^1]:
+    assert x == n[i]
+    i.inc
+  assert i == 6
+
+  i = 0
+  for x in n[0..3]:
+    assert x == n[i]
+    i.inc
+  assert i == 4
+
+  i = 0
+  for x in n[0..5]:
+    assert x == n[i]
+    i.inc
+  assert i == 6
+
+test()
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/macros/tstringinterp.nim b/tests/macros/tstringinterp.nim
index 305f40ac5..74c73599b 100644
--- a/tests/macros/tstringinterp.nim
+++ b/tests/macros/tstringinterp.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tstringinterp.nim"
   output: "Hello Alice, 64 | Hello Bob, 10$"
 """
 
@@ -71,3 +70,4 @@ var
   s2 = formatStyleInterpolation"Hello ${bob}, ${sum(alice.len, bob.len, 2)}$$"
 
 write(stdout, s1 & " | " & s2)
+write(stdout, "\n")
diff --git a/tests/magics/tmagics.nim b/tests/magics/tmagics.nim
index d13a036bd..fa138320c 100644
--- a/tests/magics/tmagics.nim
+++ b/tests/magics/tmagics.nim
@@ -8,20 +8,21 @@ true
 false
 true
 '''
+joinable: false
 """
 
 block tlowhigh:
   type myEnum = enum e1, e2, e3, e4, e5
   var a: array[myEnum, int]
-  
+
   for i in low(a) .. high(a):
     a[i] = 0
-  
+
   proc sum(a: openarray[int]): int =
     result = 0
     for i in low(a)..high(a):
       inc(result, a[i])
-  
+
   doAssert sum([1, 2, 3, 4]) == 10
 
 
@@ -43,3 +44,14 @@ block t8693:
   doAssert bar(Foo, Foo)
   doAssert bar(any, Foo)
   doAssert bar(Foo, any) == false
+
+block t9442:
+  var v1: ref char
+  var v2: string
+  var v3: seq[char]
+  GC_ref(v1)
+  GC_unref(v1)
+  GC_ref(v2)
+  GC_unref(v2)
+  GC_ref(v3)
+  GC_unref(v3)
diff --git a/tests/manyloc/argument_parser/argument_parser.nim b/tests/manyloc/argument_parser/argument_parser.nim
index d42842f93..9a37ef8c9 100644
--- a/tests/manyloc/argument_parser/argument_parser.nim
+++ b/tests/manyloc/argument_parser/argument_parser.nim
@@ -486,7 +486,7 @@ proc echo_help*(expected: seq[Tparameter_specification] = @[],
     echo line
 
 
-when isMainModule:
+when true:
   # Simply tests code embedded in docs.
   let
     parsed_param1 = new_parsed_parameter(PK_FLOAT, 3.41)
diff --git a/tests/manyloc/argument_parser/ex_wget.nim b/tests/manyloc/argument_parser/ex_wget.nim
index 625a6f595..ebbf1933f 100644
--- a/tests/manyloc/argument_parser/ex_wget.nim
+++ b/tests/manyloc/argument_parser/ex_wget.nim
@@ -81,7 +81,7 @@ proc process_commandline(): Tcommandline_results =
     echo "Will use progress type $1" % [result.options[PARAM_PROGRESS[0]].str_val]
 
 
-when isMainModule:
+when true:
   let args = process_commandline()
   for param in args.positional_parameters:
     echo "Downloading $1" % param.str_val
diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim
index 3026cc4b9..fe9909750 100644
--- a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim
+++ b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim
@@ -252,7 +252,7 @@ template forwardPacketT*(typeName: expr): stmt {.dirty, immediate.} =
   proc `pack typeName`*(p: var typeName; s: PStream) =
     writeData(s, addr p, sizeof(p))
 
-when isMainModule:
+when true:
   type
     SomeEnum = enum
       A = 0'i8,
diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim
index 3fb4dc7d9..b36b49823 100644
--- a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim
+++ b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim
@@ -2,7 +2,7 @@ import macros, macro_dsl, estreams
 from strutils import format
 
 template newLenName() =
-  let lenName {.inject.} = ^("len"& $lenNames)
+  let lenName {.inject.} = ^("len" & $lenNames)
   inc(lenNames)
 
 template defPacketImports*() {.dirty.} =
@@ -18,7 +18,7 @@ macro defPacket*(typeNameN: untyped, typeFields: untyped): untyped =
   var
     constructorParams = newNimNode(nnkFormalParams).und(typeName)
     constructor = newNimNode(nnkProcDef).und(
-      postfix(^("new"& $typeName.ident), "*"),
+      postfix(^("new" & $typeName.ident), "*"),
       emptyNode(),
       emptyNode(),
       constructorParams,
@@ -41,7 +41,7 @@ macro defPacket*(typeNameN: untyped, typeFields: untyped): untyped =
       emptyNode(),
       emptyNode())
     read = newNimNode(nnkProcDef).und(
-      newIdentNode("read"& $typeName.ident).postfix("*"),
+      newIdentNode("read" & $typeName.ident).postfix("*"),
       emptyNode(),
       emptyNode(),
       newNimNode(nnkFormalParams).und(
@@ -70,7 +70,7 @@ macro defPacket*(typeNameN: untyped, typeFields: untyped): untyped =
         let
           item = ^"item"  ## item name in our iterators
           seqType = typeFields[i][1][1] ## type of seq
-          readName = newIdentNode("read"& $seqType.ident)
+          readName = newIdentNode("read" & $seqType.ident)
         readBody.add(newNimNode(nnkLetSection).und(
           newNimNode(nnkIdentDefs).und(
             lenName,
@@ -100,7 +100,7 @@ macro defPacket*(typeNameN: untyped, typeFields: untyped): untyped =
         #set the default value to @[] (new sequence)
         typeFields[i][2] = "@".prefix(newNimNode(nnkBracket))
       else:
-        error("Unknown type: "& treeRepr(typeFields[i]))
+        error("Unknown type: " & treeRepr(typeFields[i]))
     of nnkIdent: ##normal type
       case $typeFields[i][1].ident
       of "string": # length encoded string
@@ -109,12 +109,12 @@ macro defPacket*(typeNameN: untyped, typeFields: untyped): untyped =
       of "int8", "int16", "int32", "float32", "float64", "char", "bool":
         packBody.add(newCall(
           "writeBE", streamID, dotName))
-        readBody.add(resName := newCall("read"& $typeFields[i][1].ident, streamID))
+        readBody.add(resName := newCall("read" & $typeFields[i][1].ident, streamID))
       else:  ## hopefully the type you specified was another defpacket() type
         packBody.add(newCall("pack", streamID, dotName))
-        readBody.add(resName := newCall("read"& $typeFields[i][1].ident, streamID))
+        readBody.add(resName := newCall("read" & $typeFields[i][1].ident, streamID))
     else:
-      error("I dont know what to do with: "& treerepr(typeFields[i]))
+      error("I dont know what to do with: " & treerepr(typeFields[i]))
 
   var
     toStringFunc = newNimNode(nnkProcDef).und(
@@ -137,7 +137,7 @@ macro defPacket*(typeNameN: untyped, typeFields: untyped): untyped =
           newNimNode(nnkCall).und(# [6][0][1]
             ^"format",  ## format
             emptyNode()))))  ## "[TypeName   $1   $2]"
-    formatStr = "["& $typeName.ident
+    formatStr = "[" & $typeName.ident
 
   const emptyFields = {nnkEmpty, nnkNilLit}
   var objFields = newNimNode(nnkRecList)
@@ -206,7 +206,7 @@ macro forwardPacket*(typeName: untyped, underlyingType: untyped): untyped =
     streamID = ^"s"
   result = newNimNode(nnkStmtList).und(
     newProc(
-      (^("read"& $typeName.ident)).postfix("*"),
+      (^("read" & $typeName.ident)).postfix("*"),
       [ iddefs("s", "PBuffer", newNimNode(nnkNilLit)) ],
       typeName),
     newProc(
@@ -244,7 +244,7 @@ template forwardPacketT*(typeName: untyped; underlyingType: untyped) {.dirty.} =
     #writeData(s, addr p, sizeof(p))
     buffer.write(underlyingType(ord))
 
-when isMainModule:
+when false:
   type
     SomeEnum = enum
       A = 0'i8,
diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim b/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim
index 33d2a7177..3341f42c2 100644
--- a/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim
+++ b/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim
@@ -50,7 +50,7 @@ macro `?`(a: untyped): untyped =
   result = ($a[1].ident)[0].lit
 ## echo(?F,?a,?t,?t,?y)
 
-when isMainModule:
+when false:
   macro foo(x: untyped) =
     result = newNimNode(nnkStmtList)
     result.add(newNimNode(nnkCall).und(!!"echo", "Hello thar".lit))
diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim b/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim
index 5a1dffc93..ad0d20f1c 100644
--- a/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim
+++ b/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim
@@ -24,7 +24,7 @@ proc writeLEStr*(s: PStream, str: string) =
   s.write(str.len.int16)
   s.write(str)
 
-when isMainModule:
+when true:
   var testStream = newStringStream()
 
   testStream.writeLEStr("Hello")
diff --git a/tests/manyloc/keineschweine/dependencies/nake/nake.nim b/tests/manyloc/keineschweine/dependencies/nake/nake.nim
index 5341c1079..83569e30e 100644
--- a/tests/manyloc/keineschweine/dependencies/nake/nake.nim
+++ b/tests/manyloc/keineschweine/dependencies/nake/nake.nim
@@ -50,7 +50,7 @@ template withDir*(dir: string; body: stmt): stmt =
   body
   cd(curDir)
 
-when isMainModule:
+when true:
   if not existsFile("nakefile.nim"):
     echo "No nakefile.nim found. Current working dir is ", getCurrentDir()
     quit 1
diff --git a/tests/manyloc/keineschweine/enet_server/enet_client.nim b/tests/manyloc/keineschweine/enet_server/enet_client.nim
index ac600c0af..7b8576a14 100644
--- a/tests/manyloc/keineschweine/enet_server/enet_client.nim
+++ b/tests/manyloc/keineschweine/enet_server/enet_client.nim
@@ -217,7 +217,7 @@ proc lobbyUpdate*(dt: float) =
   gui.update(dt)
   i = (i + 1) mod 60
   if i == 0:
-    fpsText.setString("FPS: "& ff(1.0/dt))
+    fpsText.setString("FPS: " & ff(1.0/dt))
 
 proc lobbyDraw*(window: PRenderWindow) =
   window.clear(Black)
diff --git a/tests/manyloc/keineschweine/enet_server/enet_server.nim b/tests/manyloc/keineschweine/enet_server/enet_server.nim
index eae7c034e..3bb259386 100644
--- a/tests/manyloc/keineschweine/enet_server/enet_server.nim
+++ b/tests/manyloc/keineschweine/enet_server/enet_server.nim
@@ -102,7 +102,7 @@ handlers[HZoneJoinReq] = proc(client: PClient; buffer: PBuffer) =
 
 
 
-when isMainModule:
+when true:
   import parseopt, matchers, os, json
 
 
diff --git a/tests/manyloc/keineschweine/keineschweine.nim b/tests/manyloc/keineschweine/keineschweine.nim
index 59347ee46..b6fd3cc19 100644
--- a/tests/manyloc/keineschweine/keineschweine.nim
+++ b/tests/manyloc/keineschweine/keineschweine.nim
@@ -230,7 +230,7 @@ proc explode*(b: PLiveBullet) =
 proc bulletUpdate(body: PBody, gravity: TVector, damping, dt: CpFloat){.cdecl.} =
   body.UpdateVelocity(gravity, damping, dt)
 
-template getPhysical() {.immediate.} =
+template getPhysical() {.dirty.} =
   result.body = space.addBody(newBody(
     record.physics.mass,
     record.physics.moment))
@@ -281,7 +281,7 @@ proc draw*(window: PRenderWindow; b: PLiveBullet) {.inline.} =
 
 
 proc free*(veh: PVehicle) =
-  ("Destroying vehicle "& veh.record.name).echo
+  ("Destroying vehicle " & veh.record.name).echo
   destroy(veh.sprite)
   if veh.shape.isNil: "Free'd vehicle's shape was NIL!".echo
   else: space.removeShape(veh.shape)
@@ -290,12 +290,12 @@ proc free*(veh: PVehicle) =
   veh.body.free()
   veh.shape.free()
   veh.sprite = nil
-  veh.body   = nil
+  veh.body = nil
   veh.shape  = nil
 
 
 proc newVehicle*(record: PVehicleRecord): PVehicle =
-  echo("Creating "& record.name)
+  echo("Creating " & record.name)
   new(result, free)
   result.record = record
   result.sprite = result.record.anim.spriteSheet.sprite.copy()
@@ -663,7 +663,7 @@ proc mainRender() =
 proc readyMainState() =
   specInputClient.setActive()
 
-when isMainModule:
+when true:
   import parseopt
 
   localPlayer = newPlayer()
diff --git a/tests/manyloc/keineschweine/lib/client_helpers.nim b/tests/manyloc/keineschweine/lib/client_helpers.nim
index 5f819a7d1..0ebb4ade1 100644
--- a/tests/manyloc/keineschweine/lib/client_helpers.nim
+++ b/tests/manyloc/keineschweine/lib/client_helpers.nim
@@ -8,7 +8,7 @@ type
     addy: enet.TAddress
     host*: PHost
     peer*: PPeer
-    handlers*: TTable[char, TScPktHandler]
+    handlers*: Table[char, TScPktHandler]
   TScPktHandler* = proc(serv: PServer; buffer: PBuffer)
   TFileTransfer = object
     fileName: string
diff --git a/tests/manyloc/keineschweine/lib/estreams.nim b/tests/manyloc/keineschweine/lib/estreams.nim
index 00a55c626..99cbb63d1 100644
--- a/tests/manyloc/keineschweine/lib/estreams.nim
+++ b/tests/manyloc/keineschweine/lib/estreams.nim
@@ -106,7 +106,7 @@ proc readChar*(buffer: PBuffer): char {.inline.} = return readInt8(buffer).char
 proc readBool*(buffer: PBuffer): bool {.inline.} = return readInt8(buffer).bool
 
 
-when isMainModule:
+when false:
   var b = newBuffer(100)
   var str = "hello there"
   b.write str
diff --git a/tests/manyloc/keineschweine/lib/map_filter.nim b/tests/manyloc/keineschweine/lib/map_filter.nim
index f3f1df190..acb58c60e 100644
--- a/tests/manyloc/keineschweine/lib/map_filter.nim
+++ b/tests/manyloc/keineschweine/lib/map_filter.nim
@@ -17,7 +17,7 @@ template unless*(condition: untyped; body: untyped) {.dirty.} =
   if not condition:
     body
 
-when isMainModule:
+when false:
   proc dumpSeq[T](x: seq[T]) =
     for index, item in x.pairs:
       echo index, " ", item
diff --git a/tests/manyloc/keineschweine/lib/sg_assets.nim b/tests/manyloc/keineschweine/lib/sg_assets.nim
index 90f0a54e9..7caa9c3fb 100644
--- a/tests/manyloc/keineschweine/lib/sg_assets.nim
+++ b/tests/manyloc/keineschweine/lib/sg_assets.nim
@@ -222,7 +222,7 @@ template cacheImpl(procName, cacheName, resultType, body: untyped) {.dirty.} =
 
 template checkFile(path: untyped) {.dirty.} =
   if not existsFile(path):
-    errors.add("File missing: "& path)
+    errors.add("File missing: " & path)
 
 cacheImpl newSprite, SpriteSheets, PSpriteSheet:
   result.file = filename
@@ -231,7 +231,7 @@ cacheImpl newSprite, SpriteSheets, PSpriteSheet:
     result.frameh = strutils.parseInt(matches[1])
     checkFile("data/gfx"/result.file)
   else:
-    errors.add "Bad file: "&filename&" must be in format name_WxH.png"
+    errors.add "Bad file: " & filename & " must be in format name_WxH.png"
     return
 
 cacheImpl newSound, SoundCache, PSoundRecord:
@@ -314,10 +314,10 @@ proc validateSettings*(settings: JsonNode, errors: var seq[string]): bool =
     else:
       var id = 0
       for i in items.items:
-        if i.kind != JArray: errors.add("Item #$1 is not an array"% $id)
+        if i.kind != JArray: errors.add("Item #$1 is not an array" % $id)
         elif i.len != 3: errors.add("($1) Item record should have 3 fields"%($id))
         elif i[0].kind != JString or i[1].kind != JString or i[2].kind != JObject:
-          errors.add("($1) Item should be in form [name, type, {item: data}]"% $id)
+          errors.add("($1) Item should be in form [name, type, {item: data}]" % $id)
           result = false
         inc id
 
@@ -332,10 +332,10 @@ proc loadSettings*(rawJson: string, errors: var seq[string]): bool =
   try:
     settings = parseJson(rawJson)
   except JsonParsingError:
-    errors.add("JSON parsing error: "& getCurrentExceptionMsg())
+    errors.add("JSON parsing error: " & getCurrentExceptionMsg())
     return
   except:
-    errors.add("Unknown exception: "& getCurrentExceptionMsg())
+    errors.add("Unknown exception: " & getCurrentExceptionMsg())
     return
   if not validateSettings(settings, errors):
     return
@@ -378,7 +378,7 @@ proc loadSettings*(rawJson: string, errors: var seq[string]): bool =
     inc vID
     if itm.kind == Projectile:
       if itm.bullet.isNil:
-        errors.add("Projectile #$1 has no bullet!"% $vID)
+        errors.add("Projectile #$1 has no bullet!" % $vID)
       elif itm.bullet.id == -1:
         ## this item has an anonymous bullet, fix the ID and name
         itm.bullet.id = bID
diff --git a/tests/manyloc/keineschweine/lib/sg_gui.nim b/tests/manyloc/keineschweine/lib/sg_gui.nim
index 074e0604c..83ad0d1bf 100644
--- a/tests/manyloc/keineschweine/lib/sg_gui.nim
+++ b/tests/manyloc/keineschweine/lib/sg_gui.nim
@@ -260,7 +260,7 @@ proc update*(m: PMessageArea) =
       m.texts.add messageProto.copy()
   elif m.texts.len > m.sizeVisible:
     echo "cutting ", m.texts.len - m.sizeVisible, " fields"
-    for i in m.sizeVisible.. < m.texts.len:
+    for i in m.sizeVisible ..< m.texts.len:
       m.texts.pop().destroy()
   let nmsgs = m.messages.len()
   if m.sizeVisible == 0 or nmsgs == 0:
diff --git a/tests/manyloc/keineschweine/lib/sg_packets.nim b/tests/manyloc/keineschweine/lib/sg_packets.nim
index f3a0e8925..9a5aa5496 100644
--- a/tests/manyloc/keineschweine/lib/sg_packets.nim
+++ b/tests/manyloc/keineschweine/lib/sg_packets.nim
@@ -92,7 +92,7 @@ defPacket(DsMsg, tuple[msg: string])
 let HVerifyClient* = 'v'
 defPacket(SdVerifyClient, tuple[session: ScLogin])
 
-when isMainModule:
+when true:
 
   var buf = newBuffer(100)
   var m = toMd5("hello there")
diff --git a/tests/manyloc/keineschweine/lib/vehicles.nim b/tests/manyloc/keineschweine/lib/vehicles.nim
index e245c9e8c..2c6e54d2b 100644
--- a/tests/manyloc/keineschweine/lib/vehicles.nim
+++ b/tests/manyloc/keineschweine/lib/vehicles.nim
@@ -23,7 +23,7 @@ proc strafe_left*(obj: PVehicle, dt: float) =
     VectorZero)
 proc strafe_right*(obj: PVehicle, dt: float) =
   obj.body.applyImpulse(
-    vectorForAngle(obj.body.getAngle()).rperp()* obj.record.handling.strafe * dt,
+    vectorForAngle(obj.body.getAngle()).rperp() * obj.record.handling.strafe * dt,
     VectorZero)
 proc turn_right*(obj: PVehicle, dt: float) =
   #obj.angle = (obj.angle + (obj.record.handling.rotation.float / 10.0 * dt)) mod TAU
diff --git a/tests/manyloc/keineschweine/lib/zlib_helpers.nim b/tests/manyloc/keineschweine/lib/zlib_helpers.nim
index 076475964..895f41759 100644
--- a/tests/manyloc/keineschweine/lib/zlib_helpers.nim
+++ b/tests/manyloc/keineschweine/lib/zlib_helpers.nim
@@ -20,7 +20,7 @@ proc uncompress*(source: string, destLen: var int): string =
     echo "Error occurred: ", res
 
 
-when isMainModule:
+when true:
   import strutils
   var r = compress("Hello")
   echo repr(r)
diff --git a/tests/manyloc/keineschweine/server/old_dirserver.nim b/tests/manyloc/keineschweine/server/old_dirserver.nim
index 202dc6fe7..cfb0b0377 100644
--- a/tests/manyloc/keineschweine/server/old_dirserver.nim
+++ b/tests/manyloc/keineschweine/server/old_dirserver.nim
@@ -156,7 +156,7 @@ proc poll*(timeout: int = 250) =
       echo("Write ", c, " result: ", res, " data: ", repr(c.outputBuf.data))
       c.outputBuf.flush()
 
-when isMainModule:
+when true:
   import parseopt, matchers, strutils
   var cfgFile = "dirserver_settings.json"
   for kind, key, val in getOpt():
diff --git a/tests/manyloc/keineschweine/server/old_sg_server.nim b/tests/manyloc/keineschweine/server/old_sg_server.nim
index bddc74c6d..d046df9dd 100644
--- a/tests/manyloc/keineschweine/server/old_sg_server.nim
+++ b/tests/manyloc/keineschweine/server/old_sg_server.nim
@@ -141,7 +141,7 @@ proc poll*(timeout: int = 250) =
       echo("Write ", c, " result: ", res, " data: ", c.outputBuf.data)
       c.outputBuf.flush()
 
-when isMainModule:
+when true:
   import parseopt, matchers, strutils
   var zoneCfgFile = "./server_settings.json"
   for kind, key, val in getOpt():
diff --git a/tests/manyloc/nake/nake.nim b/tests/manyloc/nake/nake.nim
index ff3c10a17..ebcf21d19 100644
--- a/tests/manyloc/nake/nake.nim
+++ b/tests/manyloc/nake/nake.nim
@@ -50,7 +50,7 @@ template withDir*(dir: string; body: untyped) =
   body
   cd(curDir)
 
-when isMainModule:
+when true:
   if not existsFile("nakefile.nim"):
     echo "No nakefile.nim found. Current working dir is ", getCurrentDir()
     quit 1
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/tmatrix1.nim b/tests/metatype/tmatrix1.nim
index 0f325a17b..15913499f 100644
--- a/tests/metatype/tmatrix1.nim
+++ b/tests/metatype/tmatrix1.nim
@@ -8,10 +8,10 @@ type
   TMatrix2x2*[T] = TMatrixNM[range[0..1], range[0..1], T]
   TMatrix3x3*[T] = TMatrixNM[range[0..2], range[0..2], T]
 
-proc test*[T] (matrix: TMatrix2x2[T]) =
+proc test*[T](matrix: TMatrix2x2[T]) =
   echo "wrong proc called"
 
-proc test*[T] (matrix: TMatrix3x3[T]) =
+proc test*[T](matrix: TMatrix3x3[T]) =
   echo "right proc called"
 
 var matrix: TMatrix3x3[float]
diff --git a/tests/metatype/ttypeclasses.nim b/tests/metatype/tmeta_typeclasses.nim
index 720527088..720527088 100644
--- a/tests/metatype/ttypeclasses.nim
+++ b/tests/metatype/tmeta_typeclasses.nim
diff --git a/tests/metatype/tissues.nim b/tests/metatype/tmetatype_issues.nim
index 5c5380c9f..c5040f9ba 100644
--- a/tests/metatype/tissues.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/tvarious.nim b/tests/metatype/tmetatype_various.nim
index a56eca018..a56eca018 100644
--- a/tests/metatype/tvarious.nim
+++ b/tests/metatype/tmetatype_various.nim
diff --git a/tests/metatype/tmatrix.nim b/tests/metatype/tmetatypematrix.nim
index 4fd32a932..4cd0aa49f 100644
--- a/tests/metatype/tmatrix.nim
+++ b/tests/metatype/tmetatypematrix.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tmatrix.nim"
   output: "111"
 """
 # Test overloading of [] with multiple indices
@@ -44,5 +43,4 @@ for i in 0..w-1:
 
 for i in 0..w-1:
   stdout.write(m[i,i]) #OUT 111
-
-
+stdout.write "\n"
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/tstaticparams.nim b/tests/metatype/tstaticparams.nim
index ad6aa6589..09d505f94 100644
--- a/tests/metatype/tstaticparams.nim
+++ b/tests/metatype/tstaticparams.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tstaticparams.nim"
   output: "abracadabra\ntest\n3\n15\n4\n2\nfloat\n3\nfloat\nyin\nyang\n2\n4\n4\n2\n3"
 """
 
@@ -140,7 +139,7 @@ dontBind1 bb_2
 dontBind2 bb_1
 dontBind2 bb_2
 
-# https://github.com/nim-lang/Nim/issues/4524 
+# https://github.com/nim-lang/Nim/issues/4524
 const
   size* = 2
 
@@ -172,4 +171,3 @@ echo inSize([
   [1, 2, 3],
   [4, 5, 6]
 ])
-
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/method/tmethod.nim b/tests/method/tmethod.nim
index 0cfe24c70..005294d64 100644
--- a/tests/method/tmethod.nim
+++ b/tests/method/tmethod.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "\'method\' needs a parameter that has an object type"
   file: "tmethod.nim"
   line: 7
-  errormsg: "\'method\' needs a parameter that has an object type"
 """
 
 method m(i: int): int =
diff --git a/tests/method/tissues.nim b/tests/method/tmethod_issues.nim
index 80f54caee..80f54caee 100644
--- a/tests/method/tissues.nim
+++ b/tests/method/tmethod_issues.nim
diff --git a/tests/method/tvarious.nim b/tests/method/tmethod_various.nim
index fd022717b..fd022717b 100644
--- a/tests/method/tvarious.nim
+++ b/tests/method/tmethod_various.nim
diff --git a/tests/method/tmultim.nim b/tests/method/tmultim.nim
index 310502c56..7023e18bf 100644
--- a/tests/method/tmultim.nim
+++ b/tests/method/tmultim.nim
@@ -4,9 +4,12 @@ collide: unit, thing
 collide: unit, thing
 collide: thing, unit
 collide: thing, thing
-collide: unit, thing | collide: unit, thing | collide: thing, unit | 
+collide: unit, thing |
+collide: unit, thing |
+collide: thing, unit |
 do nothing
 '''
+  joinable: false
 """
 
 
@@ -55,10 +58,10 @@ method collide(a, b: Thing) {.base, inline.} =
   quit "to override!"
 
 method collide[T](a: Thing, b: Unit[T]) {.inline.} =
-  write stdout, "collide: thing, unit | "
+  echo "collide: thing, unit |"
 
 method collide[T](a: Unit[T], b: Thing) {.inline.} =
-  write stdout, "collide: unit, thing | "
+  echo "collide: unit, thing |"
 
 proc test(a, b: Thing) {.inline.} =
   collide(a, b)
@@ -69,7 +72,6 @@ var
 collide(bbb, Thing(ccc))
 test(bbb, ccc)
 collide(aaa, bbb)
-echo ""
 
 
 
diff --git a/tests/misc/t99bott.nim b/tests/misc/t99bott.nim
index 62ccfbe16..f60023818 100644
--- a/tests/misc/t99bott.nim
+++ b/tests/misc/t99bott.nim
@@ -1,9 +1,9 @@
 discard """
+  errormsg: "cannot evaluate at compile time: bn"
   file: "t99bott.nim"
   line: 26
-  errormsg: "cannot evaluate at compile time: bn"
-  disabled: false
 """
+
 ## 99 Bottles of Beer
 ## http://www.99-bottles-of-beer.net/
 ## Nim version
@@ -30,7 +30,3 @@ for bn in countdown(99, 1):
 
 echo "No more bottles of beer on the wall, no more bottles of beer."
 echo "Go to the store and buy some more, 99 bottles of beer on the wall."
-
-
-
-
diff --git a/tests/misc/tack.nim b/tests/misc/tack.nim
index a0afab9e8..458395ef6 100644
--- a/tests/misc/tack.nim
+++ b/tests/misc/tack.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tack.nim"
   output: "125"
 """
 # the Ackermann function
@@ -17,5 +16,4 @@ proc ack(x, y: int): int =
 
 # echo(ack(0, 0))
 write(stdout, ack(3, 4)) #OUT 125
-
-
+write stdout, "\n"
diff --git a/tests/misc/tbug511622.nim b/tests/misc/tbug511622.nim
index a5360423d..4b30e96e6 100644
--- a/tests/misc/tbug511622.nim
+++ b/tests/misc/tbug511622.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tbug511622.nim"
   output: "3"
 """
 import StrUtils, Math
@@ -11,6 +10,3 @@ proc FibonacciA(n: int): int64 =
   return int64((pow(p, fn) + pow(q, fn)) / sqrt(5.0))
 
 echo FibonacciA(4) #OUT 3
-
-
-
diff --git a/tests/misc/tcmdline.nim b/tests/misc/tcmdline.nim
index cb8cb402c..71e1301ca 100644
--- a/tests/misc/tcmdline.nim
+++ b/tests/misc/tcmdline.nim
@@ -1,3 +1,7 @@
+discard """
+outputsub: "Number of parameters: 0"
+joinable: false
+"""
 # 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/temit.nim b/tests/misc/temit.nim
index c83235659..ee7455d4c 100644
--- a/tests/misc/temit.nim
+++ b/tests/misc/temit.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "temit.nim"
   output: "509"
 """
 # Test the new ``emit`` pragma:
@@ -14,7 +13,3 @@ proc embedsC() =
   {.emit: """printf("%d\n", cvariable + (int)`nimVar`);""".}
 
 embedsC()
-
-
-
-
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/tevents.nim b/tests/misc/tevents.nim
index caf674084..045c9fc5b 100644
--- a/tests/misc/tevents.nim
+++ b/tests/misc/tevents.nim
@@ -1,8 +1,9 @@
 discard """
-file: "tevents.nim"
-output: '''HandlePrintEvent: Output -> Handled print event
+output: '''
+HandlePrintEvent: Output -> Handled print event
 HandlePrintEvent2: Output -> printing for ME
-HandlePrintEvent2: Output -> printing for ME'''
+HandlePrintEvent2: Output -> printing for ME
+'''
 """
 
 import events
@@ -45,4 +46,3 @@ ee.emit(obj.printEvent, eventargs)
 obj.printEvent.removeHandler(handleprintevent2)
 
 ee.emit(obj.printEvent, eventargs)
-
diff --git a/tests/misc/tgenconstraints.nim b/tests/misc/tgenconstraints.nim
index 6e8fdc738..829da5173 100644
--- a/tests/misc/tgenconstraints.nim
+++ b/tests/misc/tgenconstraints.nim
@@ -1,8 +1,8 @@
 discard """
+  errormsg: "cannot instantiate T2"
   file: "tgenconstraints.nim"
   line: 25
   disabled: true
-  errormsg: "cannot instantiate T2"
 """
 
 type
@@ -29,4 +29,3 @@ proc bar(x: int|TNumber): T1[type(x)] {.discardable.} =
 bar "test"
 bar 100
 bar 1.1
-
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..7172a6b46 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
@@ -7,7 +11,7 @@ type
   TMyEnum = enum
     meA, meB, meC, meD
 
-when isMainModule:
+when true:
   {.hint: "this is the main file".}
 
 proc fac[T](x: T): T =
@@ -80,5 +84,5 @@ for i in 2..6:
   for j in countdown(i+4, 2):
     echo(fac(i * j))
 
-when isMainModule:
+when true:
   {.hint: "this is the main file".}
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/thintoff.nim b/tests/misc/thintoff.nim
deleted file mode 100644
index 95318ce9b..000000000
--- a/tests/misc/thintoff.nim
+++ /dev/null
@@ -1,12 +0,0 @@
-discard """
-  file: "thintoff.nim"
-  output: "0"
-"""
-
-{.hint[XDeclaredButNotUsed]: off.}
-var
-  x: int
-
-echo x #OUT 0
-
-
diff --git a/tests/misc/tinc.nim b/tests/misc/tinc.nim
index 7819775e3..91f6223e2 100644
--- a/tests/misc/tinc.nim
+++ b/tests/misc/tinc.nim
@@ -1,12 +1,8 @@
 discard """
+  errormsg: "type mismatch: got <int>"
   file: "tinc.nim"
   line: 8
-  errormsg: "type mismatch: got <int>"
 """
 var x = 0
 
 inc(x+1)
-
-
-
-
diff --git a/tests/misc/tinit.nim b/tests/misc/tinit.nim
index 02607909b..207cb17e8 100644
--- a/tests/misc/tinit.nim
+++ b/tests/misc/tinit.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tinit.nim"
   output: "Hello from module! Hello from main module!"
 """
 # Test the new init section in modules
@@ -8,5 +7,3 @@ import minit
 
 write(stdout, "Hello from main module!\n")
 #OUT Hello from module! Hello from main module!
-
-
diff --git a/tests/misc/tinout.nim b/tests/misc/tinout.nim
index 46af2f5de..bae0fb185 100644
--- a/tests/misc/tinout.nim
+++ b/tests/misc/tinout.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "type mismatch: got <int literal(3)>"
   file: "tinout.nim"
   line: 12
-  errormsg: "type mismatch: got <int literal(3)>"
 """
 # Test in out checking for parameters
 
@@ -12,5 +12,3 @@ proc b() =
     abc(3) #ERROR
 
 b()
-
-
diff --git a/tests/misc/tinvalidarrayaccess.nim b/tests/misc/tinvalidarrayaccess.nim
index 03105b41b..57ad38b85 100644
--- a/tests/misc/tinvalidarrayaccess.nim
+++ b/tests/misc/tinvalidarrayaccess.nim
@@ -1,14 +1,21 @@
 discard """
-  errormsg: "index out of bounds"
-  line: 11
+  errormsg: "index out of bounds: (a:0) <= (i:2) <= (b:1) "
+  line: 18
 """
 
+block:
+  try:
+    let a = @[1,2]
+    echo a[3]
+  except Exception as e:
+    doAssert e.msg == "index out of bounds: (i:3) <= (n:1) "
 
-type TTestArr = array[0..1, int16]
-var f: TTestArr
-f[0] = 30
-f[1] = 40
-f[2] = 50
-f[3] = 60
+block:
+  type TTestArr = array[0..1, int16]
+  var f: TTestArr
+  f[0] = 30
+  f[1] = 40
+  f[2] = 50
+  f[3] = 60
 
-echo(repr(f))
+  echo(repr(f))
diff --git a/tests/misc/tinvalidarrayaccess2.nim b/tests/misc/tinvalidarrayaccess2.nim
new file mode 100644
index 000000000..86d349457
--- /dev/null
+++ b/tests/misc/tinvalidarrayaccess2.nim
@@ -0,0 +1,16 @@
+discard """
+  errormsg: "index out of bounds: (a:0) <= (i:3) <= (b:1) "
+  line: 9
+"""
+
+# Note: merge in tinvalidarrayaccess.nim pending https://github.com/nim-lang/Nim/issues/9906
+
+let a = [1,2]
+echo a[3]
+
+when false:
+  # TOOD: this case is not yet handled, giving: "index out of bounds"
+  proc fun()=
+    let a = @[1,2]
+    echo a[3]
+  static: fun()
diff --git a/tests/misc/tinvalidnewseq.nim b/tests/misc/tinvalidnewseq.nim
index 66e9388ef..dec00fd4a 100644
--- a/tests/misc/tinvalidnewseq.nim
+++ b/tests/misc/tinvalidnewseq.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "type mismatch: got <array[0..6, string], int literal(7)>"
   file: "tinvalidnewseq.nim"
   line: 15
-  errormsg: "type mismatch: got <array[0..6, string], int literal(7)>"
 """
 import re, strutils
 
@@ -22,6 +22,3 @@ var r: TUrl
 
 r = parseUrl(r"http://google.com/search?var=bleahdhsad")
 echo(r.domain)
-
-
-
diff --git a/tests/misc/tissue710.nim b/tests/misc/tissue710.nim
index e2cca0024..ec125b840 100644
--- a/tests/misc/tissue710.nim
+++ b/tests/misc/tissue710.nim
@@ -1,7 +1,7 @@
 discard """
+  errorMsg: "attempting to call routine: '||'"
   file: "tissue710.nim"
   line: 8
-  errorMsg: "attempting to call routine: '||'"
 """
 var sum = 0
 for x in 3..1000:
diff --git a/tests/misc/tlastmod.nim b/tests/misc/tlastmod.nim
index 538b5e656..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: TTime
-  a = getLastModificationTime(paramStr(1))
-  b = getLastModificationTime(paramStr(2))
+    a, b: Time
+  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..2d9a64461 100644
--- a/tests/misc/tnew.nim
+++ b/tests/misc/tnew.nim
@@ -1,3 +1,11 @@
+discard """
+outputsub: '''
+Simple tree node allocation worked!
+Simple cycle allocation worked!
+'''
+joinable: false
+"""
+
 # 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/tnoinst.nim b/tests/misc/tnoinst.nim
index 25ebe8dfc..85db1e8e7 100644
--- a/tests/misc/tnoinst.nim
+++ b/tests/misc/tnoinst.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 12
   errormsg: "instantiate 'notConcrete' explicitly"
+  line: 12
   disabled: "true"
 """
 
@@ -14,4 +14,3 @@ proc wrap[T]() =
 
 
 wrap[int]()
-
diff --git a/tests/misc/tnolen.nim b/tests/misc/tnolen.nim
index 2831e5048..e0e8025d4 100644
--- a/tests/misc/tnolen.nim
+++ b/tests/misc/tnolen.nim
@@ -1,9 +1,8 @@
 discard """
-  line: 8
   errormsg: "type mismatch: got <int literal(3)>"
+  line: 8
 """
 
 # please finally disallow Len(3)
 
 echo len(3)
-
diff --git a/tests/misc/tnoop.nim b/tests/misc/tnoop.nim
index e1e25b44e..a1365cfbe 100644
--- a/tests/misc/tnoop.nim
+++ b/tests/misc/tnoop.nim
@@ -1,8 +1,9 @@
 discard """
   nimout: '''
-  found 'a' of kind 'var''''
+  found 'a' of kind 'var'
+  '''
   file: "tnoop.nim"
-  line: 12
+  line: 13
   errormsg: "attempting to call routine: 'a'"
 """
 
diff --git a/tests/misc/tnot.nim b/tests/misc/tnot.nim
index 5c268981e..a3669705b 100644
--- a/tests/misc/tnot.nim
+++ b/tests/misc/tnot.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "type mismatch"
   file: "tnot.nim"
   line: 14
-  errormsg: "type mismatch"
 """
 # BUG: following compiles, but should not:
 
diff --git a/tests/misc/tparseopt.nim b/tests/misc/tparseopt.nim
index badbc59ad..cbed5d476 100644
--- a/tests/misc/tparseopt.nim
+++ b/tests/misc/tparseopt.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tparseopt.nim"
   output: '''
 parseopt
 first round
@@ -9,6 +8,8 @@ kind: cmdLongOption	key:val  --  left:
 kind: cmdLongOption	key:val  --  debug:3
 kind: cmdShortOption	key:val  --  l:4
 kind: cmdShortOption	key:val  --  r:2
+cmdLongOption foo
+cmdLongOption path
 parseoptNoVal
 kind: cmdLongOption	key:val  --  left:
 kind: cmdLongOption	key:val  --  debug:3
@@ -34,44 +35,49 @@ from parseopt2 import nil
 
 
 block:
-    echo "parseopt"
-    for kind, key, val in parseopt.getopt():
-      echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
+  echo "parseopt"
+  for kind, key, val in parseopt.getopt():
+    echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
 
-    # pass custom cmdline arguments
-    echo "first round"
-    var argv = "--left --debug:3 -l=4 -r:2"
-    var p = parseopt.initOptParser(argv)
-    for kind, key, val in parseopt.getopt(p):
-      echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
-      break
-    # reset getopt iterator and check arguments are returned correctly.
-    echo "second round"
-    for kind, key, val in parseopt.getopt(p):
-      echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
+  # pass custom cmdline arguments
+  echo "first round"
+  var argv = "--left --debug:3 -l=4 -r:2"
+  var p = parseopt.initOptParser(argv)
+  for kind, key, val in parseopt.getopt(p):
+    echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
+    break
+  # reset getopt iterator and check arguments are returned correctly.
+  echo "second round"
+  for kind, key, val in parseopt.getopt(p):
+    echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
+
+  # bug #9619
+  var x = parseopt.initOptParser(@["--foo:", "--path"], allowWhitespaceAfterColon = false)
+  for kind, key, val in parseopt.getopt(x):
+    echo kind, " ", key
 
 block:
-    echo "parseoptNoVal"
-    # test NoVal mode with custom cmdline arguments
-    var argv = "--left --debug:3 -l -r:2 --debug 2 --debug=1 -r1 -r=0 -lr4"
-    var p = parseopt.initOptParser(argv,
-                                   shortNoVal = {'l'}, longNoVal = @["left"])
-    for kind, key, val in parseopt.getopt(p):
-      echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
+  echo "parseoptNoVal"
+  # test NoVal mode with custom cmdline arguments
+  var argv = "--left --debug:3 -l -r:2 --debug 2 --debug=1 -r1 -r=0 -lr4"
+  var p = parseopt.initOptParser(argv,
+                                  shortNoVal = {'l'}, longNoVal = @["left"])
+  for kind, key, val in parseopt.getopt(p):
+    echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
 
 block:
-    echo "parseopt2"
-    for kind, key, val in parseopt2.getopt():
-      echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
+  echo "parseopt2"
+  for kind, key, val in parseopt2.getopt():
+    echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
 
-    # pass custom cmdline arguments
-    echo "first round"
-    var argv: seq[string] = @["--left", "--debug:3", "-l=4", "-r:2"]
-    var p = parseopt2.initOptParser(argv)
-    for kind, key, val in parseopt2.getopt(p):
-      echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
-      break
-    # reset getopt iterator and check arguments are returned correctly.
-    echo "second round"
-    for kind, key, val in parseopt2.getopt(p):
-      echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
+  # pass custom cmdline arguments
+  echo "first round"
+  var argv: seq[string] = @["--left", "--debug:3", "-l=4", "-r:2"]
+  var p = parseopt2.initOptParser(argv)
+  for kind, key, val in parseopt2.getopt(p):
+    echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
+    break
+  # reset getopt iterator and check arguments are returned correctly.
+  echo "second round"
+  for kind, key, val in parseopt2.getopt(p):
+    echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
diff --git a/tests/misc/tpos.nim b/tests/misc/tpos.nim
index bedb62e62..f7607d643 100644
--- a/tests/misc/tpos.nim
+++ b/tests/misc/tpos.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tpos.nim"
   output: "6"
 """
 # test this particular function
@@ -30,6 +29,5 @@ proc mypos(sub, s: string, start: int = 0): int =
 var sub = "hello"
 var s = "world hello"
 write(stdout, mypos(sub, s))
+write stdout, "\n"
 #OUT 6
-
-
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..5be89530f 100644
--- a/tests/misc/tradix.nim
+++ b/tests/misc/tradix.nim
@@ -1,9 +1,37 @@
+discard """
+output: '''
+start tradix.nim
+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:
 ## We use a radix tree with node compression.
 ## There are two node kinds:
 
+echo "start tradix.nim"
+
 const BitsPerUnit = 8*sizeof(int)
 
 type
@@ -101,7 +129,7 @@ proc excl*(r: PRadixNode, a: ByteAddress): bool =
 proc addLeaf(r: var PRadixNode, a: int): bool =
   if r == nil:
     # a linear node:
-    var x = cast[ptr TRadixNodeLinear](alloc(sizeof(TRadixNodeLinear)))
+    var x = cast[ptr TRadixNodeLinear](alloc0(sizeof(TRadixNodeLinear)))
     x.kind = rnLeafLinear
     x.len = 1'i8
     x.keys[0] = toU8(a)
@@ -137,7 +165,7 @@ proc addInner(r: var PRadixNode, a: int, d: int): bool =
   var k = a shr d and 0xff
   if r == nil:
     # a linear node:
-    var x = cast[ptr TRadixNodeLinear](alloc(sizeof(TRadixNodeLinear)))
+    var x = cast[ptr TRadixNodeLinear](alloc0(sizeof(TRadixNodeLinear)))
     x.kind = rnLinear
     x.len = 1'i8
     x.keys[0] = toU8(k)
@@ -221,99 +249,3 @@ proc main() =
   for x in elements(r): echo(x)
 
 main()
-
-
-when false:
-  proc traverse(r: PRadixNode, prefix: int, d: int) =
-    if r == nil: return
-    case r.kind
-    of rnLeafBits:
-      assert(d == 0)
-      var x = cast[ptr TRadixNodeLeafBits](r)
-      # iterate over any bit:
-      for i in 0..high(x.b):
-        if x.b[i] != 0: # test all bits for zero
-          for j in 0..BitsPerUnit-1:
-            if testBit(x.b[i], j):
-              visit(prefix or i*BitsPerUnit+j)
-    of rnLeafLinear:
-      assert(d == 0)
-      var x = cast[ptr TRadixNodeLeafLinear](r)
-      for i in 0..ze(x.len)-1:
-        visit(prefix or ze(x.keys[i]))
-    of rnFull:
-      var x = cast[ptr TRadixNodeFull](r)
-      for i in 0..high(r.b):
-        if r.b[i] != nil:
-          traverse(r.b[i], prefix or (i shl d), d-8)
-    of rnLinear:
-      var x = cast[ptr TRadixNodeLinear](r)
-      for i in 0..ze(x.len)-1:
-        traverse(x.vals[i], prefix or (ze(x.keys[i]) shl d), d-8)
-
-  type
-    TRadixIter {.final.} = object
-      r: PRadixNode
-      p: int
-      x: int
-
-  proc init(i: var TRadixIter, r: PRadixNode) =
-    i.r = r
-    i.x = 0
-    i.p = 0
-
-  proc nextr(i: var TRadixIter): PRadixNode =
-    if i.r == nil: return nil
-    case i.r.kind
-    of rnFull:
-      var r = cast[ptr TRadixNodeFull](i.r)
-      while i.x <= high(r.b):
-        if r.b[i.x] != nil:
-          i.p = i.x
-          return r.b[i.x]
-        inc(i.x)
-    of rnLinear:
-      var r = cast[ptr TRadixNodeLinear](i.r)
-      if i.x < ze(r.len):
-        i.p = ze(r.keys[i.x])
-        result = r.vals[i.x]
-        inc(i.x)
-    else: assert(false)
-
-  proc nexti(i: var TRadixIter): int =
-    result = -1
-    case i.r.kind
-    of rnLeafBits:
-      var r = cast[ptr TRadixNodeLeafBits](i.r)
-      # iterate over any bit:
-      for i in 0..high(r.b):
-        if x.b[i] != 0: # test all bits for zero
-          for j in 0..BitsPerUnit-1:
-            if testBit(x.b[i], j):
-              visit(prefix or i*BitsPerUnit+j)
-    of rnLeafLinear:
-      var r = cast[ptr TRadixNodeLeafLinear](i.r)
-      if i.x < ze(r.len):
-        result = ze(r.keys[i.x])
-        inc(i.x)
-
-  iterator elements(r: PRadixNode): ByteAddress {.inline.} =
-    var
-      a, b, c, d: TRadixIter
-    init(a, r)
-    while true:
-      var x = nextr(a)
-      if x != nil:
-        init(b, x)
-        while true:
-          var y = nextr(b)
-          if y != nil:
-            init(c, y)
-            while true:
-              var z = nextr(c)
-              if z != nil:
-                init(d, z)
-                while true:
-                  var q = nexti(d)
-                  if q != -1:
-                    yield a.p shl 24 or b.p shl 16 or c.p shl 8 or q
diff --git a/tests/misc/trawstr.nim b/tests/misc/trawstr.nim
index 55e508acc..aa41071d5 100644
--- a/tests/misc/trawstr.nim
+++ b/tests/misc/trawstr.nim
@@ -1,12 +1,10 @@
 discard """
+  errormsg: "closing \" expected"
   file: "trawstr.nim"
   line: 10
-  errormsg: "closing \" expected"
 """
 # Test the new raw strings:
 
 const
   xxx = r"This is a raw string!"
   yyy = "This not\" #ERROR
-
-
diff --git a/tests/misc/treadln.nim b/tests/misc/treadln.nim
index 1edbea992..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.
 
@@ -5,8 +13,9 @@ var
   inp: File
   line: string
 
-if open(inp, "readme.txt"):
+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/treservedcidentsasfields.nim b/tests/misc/treservedcidentsasfields.nim
new file mode 100644
index 000000000..a9a954651
--- /dev/null
+++ b/tests/misc/treservedcidentsasfields.nim
@@ -0,0 +1,39 @@
+discard """

+  targets: "c cpp"

+"""

+

+import macros

+

+macro make_test_type(idents: varargs[untyped]): untyped =

+  result = nnkStmtList.newTree()

+

+  var ident_defs: seq[NimNode] = @[]

+  for i in idents:

+    ident_defs.add newIdentDefs(i, ident("int"))

+

+  result.add newTree(nnkTypeSection,

+    newTree(nnkTypeDef,

+      ident("TestType"),

+      newEmptyNode(),

+      newTree(nnkObjectTy,

+        newEmptyNode(),

+        newEmptyNode(),

+        newTree(nnkRecList,

+          ident_defs

+        )

+      )

+    )

+  )

+

+make_test_type(

+  auto, bool, catch, char, class, compl, const_cast, default, delete, double,

+  dynamic_cast, explicit, extern, false, float, friend, goto, int, long,

+  mutable, namespace, new, operator, private, protected, public, register,

+  reinterpret_cast, restrict, short, signed, sizeof, static_cast, struct, switch,

+  this, throw, true, typedef, typeid, typeof, typename, union, packed, unsigned,

+  virtual, void, volatile, wchar_t, alignas, alignof, constexpr, decltype, nullptr,

+  noexcept, thread_local, static_assert, char16_t, char32_t

+)

+

+# Make sure the type makes it to codegen.

+var test_instance: TestType

diff --git a/tests/misc/tshadow_magic_type.nim b/tests/misc/tshadow_magic_type.nim
index 03c83079e..3176a4596 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,10 +22,10 @@ proc seq*() =
 
 proc lrange*(key: string): TRedisList =
   var foo: TListItem
-  foo.kind = RedisNil
+  foo.kind = RedisString
+  foo.str = key
   result = @[foo]
 
-when isMainModule:
-  var p = lrange("mylist")
-  for i in items(p):
-    echo(i.str)
+var p = lrange("mylist")
+for i in items(p):
+  echo(i.str)
diff --git a/tests/misc/tsimtych.nim b/tests/misc/tsimtych.nim
index 037172bd5..74a6ad4c0 100644
--- a/tests/misc/tsimtych.nim
+++ b/tests/misc/tsimtych.nim
@@ -1,12 +1,10 @@
 discard """
+  errormsg: "type mismatch: got <bool> but expected \'string\'"
   file: "tsimtych.nim"
   line: 10
-  errormsg: "type mismatch: got <bool> but expected \'string\'"
 """
 # Test 2
 # Simple type checking
 
 var a: string
 a = false #ERROR
-
-
diff --git a/tests/misc/tsizeof.nim b/tests/misc/tsizeof.nim
index ecdd44fca..f60c7fa00 100644
--- a/tests/misc/tsizeof.nim
+++ b/tests/misc/tsizeof.nim
@@ -10,14 +10,16 @@ type
   TMyArray2 = array[1..3, int32]
   TMyArray3 = array[TMyEnum, float64]
 
+var failed = false
+
 const
   mysize1 = sizeof(TMyArray1)
   mysize2 = sizeof(TMyArray2)
   mysize3 = sizeof(TMyArray3)
 
-assert mysize1 == 3
-assert mysize2 == 12
-assert mysize3 == 32
+doAssert mysize1 == 3
+doAssert mysize2 == 12
+doAssert mysize3 == 32
 
 import macros, typetraits
 
@@ -38,6 +40,7 @@ macro testSizeAlignOf(args: varargs[untyped]): untyped =
         if nim_align != c_align:
           msg.add  " align(get, expected): " & $nim_align & " != " & $c_align
         echo msg
+        failed = true
 
 
 macro testOffsetOf(a,b1,b2: untyped): untyped =
@@ -48,7 +51,8 @@ macro testOffsetOf(a,b1,b2: untyped): untyped =
       c_offset   = c_offsetof(`a`,`b1`)
       nim_offset = offsetof(`a`,`b2`)
     if c_offset != nim_offset:
-      echo `typeName`, ".", `member`, " offset: ", c_offset, " != ", nim_offset
+      echo `typeName`, ".", `member`, " offsetError, C: ", c_offset, " nim: ", nim_offset
+      failed = true
 
 template testOffsetOf(a,b: untyped): untyped =
   testOffsetOf(a,b,b)
@@ -100,21 +104,16 @@ macro testAlign(arg:untyped):untyped =
     let nimAlign = alignof(`arg`)
     if cAlign != nimAlign:
       echo `prefix`, cAlign, " != ", nimAlign
+      failed = true
 
-testAlign(pointer)
-testAlign(int)
-testAlign(uint)
-testAlign(int8)
-testAlign(int16)
-testAlign(int32)
-testAlign(int64)
-testAlign(uint8)
-testAlign(uint16)
-testAlign(uint32)
-testAlign(uint64)
-testAlign(float)
-testAlign(float32)
-testAlign(float64)
+macro testSize(arg:untyped):untyped =
+  let prefix = newLit(arg.lineinfo & "  sizeof " & arg.repr & " ")
+  result = quote do:
+    let cSize = c_sizeof(`arg`)
+    let nimSize = sizeof(`arg`)
+    if cSize != nimSize:
+      echo `prefix`, cSize, " != ", nimSize
+      failed = true
 
 type
   MyEnum {.pure.} = enum
@@ -142,14 +141,6 @@ type
     ValueA
     ValueB
 
-testAlign(MyEnum)
-testAlign(OtherEnum)
-testAlign(Enum1)
-testAlign(Enum2)
-testAlign(Enum4)
-testAlign(Enum8)
-
-
 template testinstance(body: untyped): untyped =
   block:
     {.pragma: objectconfig.}
@@ -159,6 +150,32 @@ template testinstance(body: untyped): untyped =
     {.pragma: objectconfig, packed.}
     body
 
+
+proc testPrimitiveTypes(): void =
+  testAlign(pointer)
+  testAlign(int)
+  testAlign(uint)
+  testAlign(int8)
+  testAlign(int16)
+  testAlign(int32)
+  testAlign(int64)
+  testAlign(uint8)
+  testAlign(uint16)
+  testAlign(uint32)
+  testAlign(uint64)
+  testAlign(float)
+  testAlign(float32)
+  testAlign(float64)
+
+  testAlign(MyEnum)
+  testAlign(OtherEnum)
+  testAlign(Enum1)
+  testAlign(Enum2)
+  testAlign(Enum4)
+  testAlign(Enum8)
+
+testPrimitiveTypes()
+
 testinstance:
   type
 
@@ -274,8 +291,6 @@ testinstance:
 
   const trivialSize = sizeof(TrivialType) # needs to be able to evaluate at compile time
 
-  testAlign(SimpleAlignment)
-
   proc main(): void =
     var t : TrivialType
     var a : SimpleAlignment
@@ -286,6 +301,7 @@ testinstance:
     var f : PaddingAfterBranch
     var g : RecursiveStuff
     var ro : RootObj
+
     var
       e1: Enum1
       e2: Enum2
@@ -295,8 +311,20 @@ testinstance:
       eoa: EnumObjectA
       eob: EnumObjectB
 
+
+    testAlign(SimpleAlignment)
+
     testSizeAlignOf(t,a,b,c,d,e,f,g,ro, e1, e2, e4, e8, eoa, eob)
 
+    when not defined(cpp):
+      type
+        WithBitsize {.objectconfig.} = object
+          bitfieldA {.bitsize: 16.}: uint32
+          bitfieldB {.bitsize: 16.}: uint32
+
+      var wbs: WithBitsize
+      testSize(wbs)
+
     testOffsetOf(TrivialType, x)
     testOffsetOf(TrivialType, y)
     testOffsetOf(TrivialType, z)
@@ -304,6 +332,7 @@ testinstance:
     testOffsetOf(SimpleAlignment, a)
     testOffsetOf(SimpleAlignment, b)
     testOffsetOf(SimpleAlignment, c)
+
     testOffsetOf(AlignAtEnd, a)
     testOffsetOf(AlignAtEnd, b)
     testOffsetOf(AlignAtEnd, c)
@@ -322,11 +351,11 @@ testinstance:
 
     testOffsetOf(Foobar, c)
 
-    testOffsetOf(Bazing, a)
-
-    testOffsetOf(InheritanceA, a)
-    testOffsetOf(InheritanceB, b)
-    testOffsetOf(InheritanceC, c)
+    when not defined(cpp):
+      testOffsetOf(Bazing, a)
+      testOffsetOf(InheritanceA, a)
+      testOffsetOf(InheritanceB, b)
+      testOffsetOf(InheritanceC, c)
 
     testOffsetOf(EnumObjectA, a)
     testOffsetOf(EnumObjectA, b)
@@ -350,5 +379,22 @@ testinstance:
 
   main()
 
+{.emit: """/*TYPESECTION*/
+typedef struct{
+  float a; float b;
+} Foo;
+""".}
+
+type
+  Foo {.importc.} = object
+
+  Bar = object
+    b: byte
+    foo: Foo
+
+assert sizeof(Bar) == 12
 
-echo "OK"
+if failed:
+  quit("FAIL")
+else:
+  echo "OK"
diff --git a/tests/misc/tsizeof2.nim b/tests/misc/tsizeof2.nim
index 67379871d..130f28e21 100644
--- a/tests/misc/tsizeof2.nim
+++ b/tests/misc/tsizeof2.nim
@@ -9,3 +9,9 @@ type
 const i = sizeof(MyStruct)
 
 echo i
+
+# bug #9868
+proc foo(a: SomeInteger): array[sizeof(a), byte] =
+  discard
+
+discard foo(1)
diff --git a/tests/misc/tslices.nim b/tests/misc/tslices.nim
index 388a46509..d063c5ebf 100644
--- a/tests/misc/tslices.nim
+++ b/tests/misc/tslices.nim
@@ -1,6 +1,6 @@
 discard """
-  file: "tslices.nim"
-  output: '''456456
+output: '''
+456456
 456456
 456456
 Zugr5nd
@@ -56,4 +56,3 @@ echo mystr
 var s = "abcdef"
 s[1 .. ^2] = "xyz"
 assert s == "axyzf"
-
diff --git a/tests/misc/tsortdev.nim b/tests/misc/tsortdev.nim
index f360d9646..0b2a4f3e8 100644
--- a/tests/misc/tsortdev.nim
+++ b/tests/misc/tsortdev.nim
@@ -1,5 +1,5 @@
 discard """
-  output: "done"
+  output: "done tsortdev"
 """
 
 import algorithm, strutils
@@ -55,5 +55,4 @@ proc main() =
 for i in 0..1_000:
   main()
 
-echo "done"
-
+echo "done tsortdev"
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/tstrange.nim b/tests/misc/tstrange.nim
index fee0f44e4..82a82d267 100644
--- a/tests/misc/tstrange.nim
+++ b/tests/misc/tstrange.nim
@@ -1,8 +1,9 @@
 discard """
-  file: "tstrange.nim"
-  output: '''hallo40
+output: '''
+hallo40
 1
-2'''
+2
+'''
 """
 # test for extremely strange bug
 
@@ -25,4 +26,3 @@ write(stdout, ack(5, 4))
 let h=3
 for x in 0.. <h.int:
   echo x
-
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/misc/tvarious1.nim b/tests/misc/tvarious1.nim
index 595c77919..9c0b541db 100644
--- a/tests/misc/tvarious1.nim
+++ b/tests/misc/tvarious1.nim
@@ -1,6 +1,6 @@
 discard """
-  file: "tlenopenarray.nim"
-  output: '''1
+output: '''
+1
 0
 Whopie
 12
diff --git a/tests/misc/tvarnums.nim b/tests/misc/tvarnums.nim
index 5daa2c4b8..39269b4c0 100644
--- a/tests/misc/tvarnums.nim
+++ b/tests/misc/tvarnums.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tvarnums.nim"
   output: "Success!"
 """
 # Test variable length binary integers
@@ -138,5 +137,3 @@ tm(low(int32))
 tm(high(int32))
 
 writeLine(stdout, "Success!") #OUT Success!
-
-
diff --git a/tests/modules/m9627/a.nim b/tests/modules/m9627/a.nim
new file mode 100644
index 000000000..0dd32430e
--- /dev/null
+++ b/tests/modules/m9627/a.nim
@@ -0,0 +1 @@
+var a = 10
diff --git a/tests/modules/m9627/b.nim b/tests/modules/m9627/b.nim
new file mode 100644
index 000000000..2806a78ed
--- /dev/null
+++ b/tests/modules/m9627/b.nim
@@ -0,0 +1 @@
+var b = 9
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/t9627.nim b/tests/modules/t9627.nim
new file mode 100644
index 000000000..daba46374
--- /dev/null
+++ b/tests/modules/t9627.nim
@@ -0,0 +1,7 @@
+discard """
+  output: "109"
+"""
+
+include m9627 / [a, b]
+
+echo a, b
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/modules/timportas.nim b/tests/modules/timportas.nim
index a92162117..2f7bf7f6a 100644
--- a/tests/modules/timportas.nim
+++ b/tests/modules/timportas.nim
@@ -10,7 +10,7 @@ import times as bar3 except convert
 import definitions as baz
 
 discard foo.v
-discard bar.now
-discard bar2.now
-discard bar3.now
-discard baz.v
\ No newline at end of file
+discard bar.now()
+discard bar2.now()
+discard bar3.now()
+discard baz.v
diff --git a/tests/modules/timportexcept.nim b/tests/modules/timportexcept.nim
index 93a7fd642..40b748088 100644
--- a/tests/modules/timportexcept.nim
+++ b/tests/modules/timportexcept.nim
@@ -1,10 +1,9 @@
 discard """
-  line: 9
   errormsg: "undeclared identifier: '%'"
+  line: 9
 """
 
 import strutils except `%`
 
 # doesn't work
 echo "$1" % "abc"
-
diff --git a/tests/modules/tmismatchedvisibility.nim b/tests/modules/tmismatchedvisibility.nim
index 2e8636d1e..4bf244807 100644
--- a/tests/modules/tmismatchedvisibility.nim
+++ b/tests/modules/tmismatchedvisibility.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 8
   errormsg: "public implementation 'tmismatchedvisibility.foo(a: int)[declared in tmismatchedvisibility.nim(6, 5)]' has non-public forward declaration in "
+  line: 8
 """
 
 proc foo(a: int): int
diff --git a/tests/modules/tnamspc.nim b/tests/modules/tnamspc.nim
index 2f488644c..93ce71568 100644
--- a/tests/modules/tnamspc.nim
+++ b/tests/modules/tnamspc.nim
@@ -1,12 +1,10 @@
 discard """
+  errormsg: "undeclared identifier: \'global\'"
   file: "tnamspc.nim"
   line: 10
-  errormsg: "undeclared identifier: \'global\'"
 """
 # Test17 - test correct handling of namespaces
 
 import mnamspc1
 
 global = 9 #ERROR
-
-
diff --git a/tests/modules/tnotuniquename.nim b/tests/modules/tnotuniquename.nim
index 2d8ce4869..403c8a47e 100644
--- a/tests/modules/tnotuniquename.nim
+++ b/tests/modules/tnotuniquename.nim
@@ -1,6 +1,6 @@
 discard """
-  file: "tnotuniquename/mnotuniquename.nim"
   errormsg: "module names need to be unique per Nimble package"
+  file: "tnotuniquename/mnotuniquename.nim"
 """
 
 import mnotuniquename
diff --git a/tests/modules/tnotuniquename2.nim b/tests/modules/tnotuniquename2.nim
index 8e486d19f..7aa4de515 100644
--- a/tests/modules/tnotuniquename2.nim
+++ b/tests/modules/tnotuniquename2.nim
@@ -1,6 +1,6 @@
 discard """
-  file: "tnotuniquename/mnotuniquename.nim"
   errormsg: "module names need to be unique per Nimble package"
+  file: "tnotuniquename/mnotuniquename.nim"
 """
 
 import mnotuniquename
diff --git a/tests/modules/topaque.nim b/tests/modules/topaque.nim
index 84e2388bc..94ff8ff25 100644
--- a/tests/modules/topaque.nim
+++ b/tests/modules/topaque.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "undeclared field: \'buffer\'"
   file: "topaque.nim"
   line: 16
-  errormsg: "undeclared field: \'buffer\'"
 """
 # Test the new opaque types
 
@@ -14,5 +14,3 @@ var
 L.filename = "ha"
 L.line = 34
 L.buffer[0] = '\0' #ERROR_MSG undeclared field: 'buffer'
-
-
diff --git a/tests/modules/trecinca.nim b/tests/modules/trecinca.nim
index 7a74d7a46..56798dedd 100644
--- a/tests/modules/trecinca.nim
+++ b/tests/modules/trecinca.nim
@@ -1,12 +1,10 @@
 discard """
+  errormsg: "recursive dependency: 'trecincb.nim'"
   file: "trecincb.nim"
   line: 9
-  errormsg: "recursive dependency: 'trecincb.nim'"
 """
 # Test recursive includes
 
 include trecincb
 
 echo "trecina"
-
-
diff --git a/tests/modules/trecincb.nim b/tests/modules/trecincb.nim
index 1d3eb5503..30a5d7800 100644
--- a/tests/modules/trecincb.nim
+++ b/tests/modules/trecincb.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "recursive dependency: 'trecincb.nim'"
   file: "trecincb.nim"
   line: 9
-  errormsg: "recursive dependency: 'trecincb.nim'"
 """
 # Test recursive includes
 
@@ -9,5 +9,3 @@ discard """
 include trecincb
 
 echo "trecinb"
-
-
diff --git a/tests/modules/trecmod.nim b/tests/modules/trecmod.nim
index 5f053bcae..43e510e87 100644
--- a/tests/modules/trecmod.nim
+++ b/tests/modules/trecmod.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "recursive module dependency detected"
   file: "mrecmod.nim"
   line: 1
-  errormsg: "recursive module dependency detected"
   disabled: true
 """
 # recursive module
diff --git a/tests/modules/tselfimport.nim b/tests/modules/tselfimport.nim
index ddb3a5b09..7e50bef7c 100644
--- a/tests/modules/tselfimport.nim
+++ b/tests/modules/tselfimport.nim
@@ -1,9 +1,8 @@
 discard """
+  errormsg: "A module cannot import itself"
   file: "tselfimport.nim"
   line: 7
-  errormsg: "A module cannot import itself"
 """
 import strutils as su # guard against regression
 import tselfimport #ERROR
 echo("Hello World")
-
diff --git a/tests/namedparams/tnamedparams.nim b/tests/namedparams/tnamedparams.nim
index 8799e8a15..d0774f0d8 100644
--- a/tests/namedparams/tnamedparams.nim
+++ b/tests/namedparams/tnamedparams.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "type mismatch: got <input: string, filename: string, line: int literal(1), col: int literal(23)>"
   file: "tnamedparams.nim"
   line: 8
-  errormsg: "type mismatch: got <input: string, filename: string, line: int literal(1), col: int literal(23)>"
 """
 import pegs
 
@@ -10,6 +10,3 @@ discard parsePeg(
       filename = "filename",
       line = 1,
       col = 23)
-
-
-
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/newconfig/tfoo.nims b/tests/newconfig/tfoo.nims
index b9b9a87af..a9e40956e 100644
--- a/tests/newconfig/tfoo.nims
+++ b/tests/newconfig/tfoo.nims
@@ -3,9 +3,6 @@ mode = ScriptMode.Whatif
 
 exec "gcc -v"
 
-# test that ospaths actually compiles:
-import ospaths
-
 --forceBuild
 --path: "../friends"
 
diff --git a/tests/niminaction/Chapter2/explicit_discard.nim b/tests/niminaction/Chapter2/explicit_discard.nim
index 3e94c335b..9a3b4407e 100644
--- a/tests/niminaction/Chapter2/explicit_discard.nim
+++ b/tests/niminaction/Chapter2/explicit_discard.nim
@@ -1,7 +1,7 @@
 discard """
-  line: 7
   errormsg: "has to be discarded"
+  line: 7
 """
 
 proc myProc(name: string): string = "Hello " & name
-myProc("Dominik")
\ No newline at end of file
+myProc("Dominik")
diff --git a/tests/niminaction/Chapter2/no_def_eq.nim b/tests/niminaction/Chapter2/no_def_eq.nim
index 77f0a7dd8..b9d62e036 100644
--- a/tests/niminaction/Chapter2/no_def_eq.nim
+++ b/tests/niminaction/Chapter2/no_def_eq.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 16
   errormsg: "type mismatch"
+  line: 16
 """
 
 type
@@ -13,4 +13,4 @@ type
 let dog: Dog = Dog(name: "Fluffy")
 let cat: Cat = Cat(name: "Fluffy")
 
-echo(dog == cat)
\ No newline at end of file
+echo(dog == cat)
diff --git a/tests/niminaction/Chapter2/no_iterator.nim b/tests/niminaction/Chapter2/no_iterator.nim
index 331d69480..555fac21a 100644
--- a/tests/niminaction/Chapter2/no_iterator.nim
+++ b/tests/niminaction/Chapter2/no_iterator.nim
@@ -1,7 +1,7 @@
 discard """
-  line: 6
   errormsg: "type mismatch"
+  line: 6
 """
 
 for i in 5:
-  echo i
\ No newline at end of file
+  echo i
diff --git a/tests/niminaction/Chapter2/no_seq_type.nim b/tests/niminaction/Chapter2/no_seq_type.nim
index 493be270a..f1494124b 100644
--- a/tests/niminaction/Chapter2/no_seq_type.nim
+++ b/tests/niminaction/Chapter2/no_seq_type.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 6
   errormsg: "cannot infer the type of the sequence"
+  line: 6
 """
 
-var list = @[]
\ No newline at end of file
+var list = @[]
diff --git a/tests/niminaction/Chapter2/resultreject.nim b/tests/niminaction/Chapter2/resultreject.nim
index de59af7d9..87c84bf0a 100644
--- a/tests/niminaction/Chapter2/resultreject.nim
+++ b/tests/niminaction/Chapter2/resultreject.nim
@@ -1,13 +1,13 @@
 discard """
-  line: 27
   errormsg: "has to be discarded"
+  line: 27
 """
 
 # Page 35.
 
 proc implicit: string =
   "I will be returned"
-  
+
 proc discarded: string =
   discard "I will not be returned"
 
@@ -16,7 +16,7 @@ proc explicit: string =
 
 proc resultVar: string =
   result = "I will be returned"
-  
+
 proc resultVar2: string =
   result = ""
   result.add("I will be ")
@@ -30,4 +30,4 @@ doAssert implicit() == "I will be returned"
 doAssert discarded() == nil
 doAssert explicit() == "I will be returned"
 doAssert resultVar() == "I will be returned"
-doAssert resultVar2() == "I will be returned"
\ No newline at end of file
+doAssert resultVar2() == "I will be returned"
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/protocol.nim b/tests/niminaction/Chapter3/ChatApp/src/protocol.nim
index af515861c..4c122d4cc 100644
--- a/tests/niminaction/Chapter3/ChatApp/src/protocol.nim
+++ b/tests/niminaction/Chapter3/ChatApp/src/protocol.nim
@@ -37,7 +37,7 @@ proc createMessage*(username, message: string): string =
     "message": %message
   }) & "\c\l"
 
-when isMainModule:
+when true:
   block:
     let data = """{"username": "dom", "message": "hello"}"""
     let parsed = parseMessage(data)
diff --git a/tests/niminaction/Chapter3/ChatApp/src/server.nim b/tests/niminaction/Chapter3/ChatApp/src/server.nim
index 8c572aeb0..fbf0e5110 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
@@ -75,10 +79,10 @@ proc loop(server: Server, port = 7687) {.async.} =
 
 # Check whether this module has been imported as a dependency to another
 # module, or whether this module is the main module.
-when isMainModule:
+when true:
   # Initialise a new server.
   var server = newServer()
   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..766f07fa5 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
 
@@ -75,5 +79,5 @@ proc readChunks(filename: string, chunksize = 1000000): Stats =
   file.close()
 
 
-when isMainModule:
+when true:
   echo readChunks(filename)
diff --git a/tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim b/tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim
index 8df3b6aeb..19b157926 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
 
@@ -60,5 +64,5 @@ proc readChunks(filename: string, chunksize = 1000000): Stats =
   file.close()
 
 
-when isMainModule:
+when true:
   echo readChunks(filename)
diff --git a/tests/niminaction/Chapter6/WikipediaStats/naive.nim b/tests/niminaction/Chapter6/WikipediaStats/naive.nim
index ed4fba8e2..687177f74 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
 
@@ -25,5 +29,5 @@ proc parse(filename: string): tuple[projectName, pageTitle: string,
 
   file.close()
 
-when isMainModule:
+when true:
   echo parse(filename)
diff --git a/tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim b/tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim
index 7181145e9..2c4a59d83 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
@@ -66,7 +70,7 @@ proc readPageCounts(filename: string, chunkSize = 1_000_000) =
 
   echo("Most popular is: ", mostPopular)
 
-when isMainModule:
+when true:
   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..f4bae3df5 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,
@@ -28,7 +32,7 @@ proc readPageCounts(filename: string) =
 
   echo("Most popular is: ", mostPopular)
 
-when isMainModule:
+when true:
   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/src/views/user.nim b/tests/niminaction/Chapter7/Tweeter/src/views/user.nim
index f3791b493..18f3713b3 100644
--- a/tests/niminaction/Chapter7/Tweeter/src/views/user.nim
+++ b/tests/niminaction/Chapter7/Tweeter/src/views/user.nim
@@ -40,7 +40,7 @@
 </div>
 #end proc
 #
-#when isMainModule:
+#when true:
 #  echo renderUser(User(username: "d0m96<>", following: @[]))
 #  echo renderMessages(@[
 #    Message(username: "d0m96", time: getTime(), msg: "Hello World!"),
diff --git a/tests/niminaction/Chapter7/Tweeter/tests/database_test.nim b/tests/niminaction/Chapter7/Tweeter/tests/database_test.nim
index 926ca452c..a3cab4cba 100644
--- a/tests/niminaction/Chapter7/Tweeter/tests/database_test.nim
+++ b/tests/niminaction/Chapter7/Tweeter/tests/database_test.nim
@@ -1,6 +1,10 @@
+discard """
+outputsub: "All tests finished successfully!"
+"""
+
 import database, os, times
 
-when isMainModule:
+when true:
   removeFile("tweeter_test.db")
   var db = newDatabase("tweeter_test.db")
   db.setup()
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/notnil/tnotnil.nim b/tests/notnil/tnotnil.nim
index aff3f8959..c33b6fcac 100644
--- a/tests/notnil/tnotnil.nim
+++ b/tests/notnil/tnotnil.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 13
   errormsg: "type mismatch"
+  line: 13
 """
 {.experimental: "notnil".}
 type
diff --git a/tests/objects/tobjconstr.nim b/tests/objects/tobjconstr.nim
index 7238d10c7..1e4d89d68 100644
--- a/tests/objects/tobjconstr.nim
+++ b/tests/objects/tobjconstr.nim
@@ -1,14 +1,15 @@
 discard """
-  output: '''(k: kindA, a: (x: "abc", z: [1, 1, 3]), method: ())
-(k: kindA, a: (x: "abc", z: [1, 2, 3]), method: ())
-(k: kindA, a: (x: "abc", z: [1, 3, 3]), method: ())
-(k: kindA, a: (x: "abc", z: [1, 4, 3]), method: ())
-(k: kindA, a: (x: "abc", z: [1, 5, 3]), method: ())
-(k: kindA, a: (x: "abc", z: [1, 6, 3]), method: ())
-(k: kindA, a: (x: "abc", z: [1, 7, 3]), method: ())
-(k: kindA, a: (x: "abc", z: [1, 8, 3]), method: ())
-(k: kindA, a: (x: "abc", z: [1, 9, 3]), method: ())
-(k: kindA, a: (x: "abc", z: [1, 10, 3]), method: ())
+  output: '''
+(k: kindA, a: (x: "abc", z: @[1, 1, 3]), method: ())
+(k: kindA, a: (x: "abc", z: @[1, 2, 3]), method: ())
+(k: kindA, a: (x: "abc", z: @[1, 3, 3]), method: ())
+(k: kindA, a: (x: "abc", z: @[1, 4, 3]), method: ())
+(k: kindA, a: (x: "abc", z: @[1, 5, 3]), method: ())
+(k: kindA, a: (x: "abc", z: @[1, 6, 3]), method: ())
+(k: kindA, a: (x: "abc", z: @[1, 7, 3]), method: ())
+(k: kindA, a: (x: "abc", z: @[1, 8, 3]), method: ())
+(k: kindA, a: (x: "abc", z: @[1, 9, 3]), method: ())
+(k: kindA, a: (x: "abc", z: @[1, 10, 3]), method: ())
 (y: 0, x: 123)
 (y: 678, x: 123)
 (z: 89, y: 0, x: 128)
@@ -16,7 +17,8 @@ discard """
 (y: 678, x: 123)
 (y: 0, x: 123)
 (y: 678, x: 123)
-(y: 123, x: 678)'''
+(y: 123, x: 678)
+'''
 """
 
 type
@@ -32,13 +34,6 @@ type
       a: TArg
       `method`: TEmpty # bug #1791
 
-proc `$`[T](s: seq[T]): string =
-  result = "["
-  for i, x in s:
-    if i > 0: result.add(", ")
-    result.add($x)
-  result.add("]")
-
 proc main() =
   for i in 1..10:
     let d = TDummy(k: kindA, a: TArg(x: "abc", z: @[1,i,3]), `method`: TEmpty())
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/objects/tissues.nim b/tests/objects/tobjects_issues.nim
index fddfff7d5..fddfff7d5 100644
--- a/tests/objects/tissues.nim
+++ b/tests/objects/tobjects_issues.nim
diff --git a/tests/objects/tvarious.nim b/tests/objects/tobjects_various.nim
index 504681b99..504681b99 100644
--- a/tests/objects/tvarious.nim
+++ b/tests/objects/tobjects_various.nim
diff --git a/tests/objects/tobjpragma.nim b/tests/objects/tobjpragma.nim
index 0a6cc893b..789b3ec4e 100644
--- a/tests/objects/tobjpragma.nim
+++ b/tests/objects/tobjpragma.nim
@@ -1,13 +1,14 @@
 discard """
-  file: "tobjpragma.nim"
-  output: '''2
+  output: '''
+2
 3
 9
 257
 1
 2
-3'''
-  disabled: "true"
+3
+'''
+disabled: "true"
 """
 
 # Disabled since some versions of GCC ignore the 'packed' attribute
diff --git a/tests/objects/toop1.nim b/tests/objects/toop1.nim
index f4880e3c6..f22ddaf62 100644
--- a/tests/objects/toop1.nim
+++ b/tests/objects/toop1.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "toop1.nim"
   output: "34[]o 5"
 """
 # Test the stuff in the tutorial
diff --git a/tests/objvariant/tadrdisc.nim b/tests/objvariant/tadrdisc.nim
index 258fb42f3..a68dddf66 100644
--- a/tests/objvariant/tadrdisc.nim
+++ b/tests/objvariant/tadrdisc.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "type mismatch: got <TKind>"
   file: "tadrdisc.nim"
   line: 20
-  errormsg: "type mismatch: got <TKind>"
 """
 # Test that the address of a dicriminants cannot be taken
 
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/objvariant/temptycaseobj.nim b/tests/objvariant/temptycaseobj.nim
index 53171e054..2b2c40514 100644
--- a/tests/objvariant/temptycaseobj.nim
+++ b/tests/objvariant/temptycaseobj.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 11
   errormsg: "identifier expected, but got 'keyword of'"
+  line: 11
 """
 
 type
@@ -10,5 +10,3 @@ type
     of enA:
     of enU: x, y: int
     of enO: a, b: string
-
-
diff --git a/tests/objvariant/tvariantstack.nim b/tests/objvariant/tvariantstack.nim
index 0cdde5a20..31a0d8b82 100644
--- a/tests/objvariant/tvariantstack.nim
+++ b/tests/objvariant/tvariantstack.nim
@@ -1,6 +1,5 @@
 discard """
-  file: "tvariantstack.nim"
-  output: "came here"
+output: "came here"
 """
 #BUG
 type
diff --git a/tests/openarray/t8259.nim b/tests/openarray/t8259.nim
index 40ff2b2f1..c07576997 100644
--- a/tests/openarray/t8259.nim
+++ b/tests/openarray/t8259.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 6
   errormsg: "invalid type: 'openarray[int]' for result"
+  line: 6
 """
 
 proc foo(a: openArray[int]):auto = a
diff --git a/tests/openarray/topena1.nim b/tests/openarray/topena1.nim
index 0dbc5506a..ed3a0cedb 100644
--- a/tests/openarray/topena1.nim
+++ b/tests/openarray/topena1.nim
@@ -1,12 +1,9 @@
 discard """
+  errormsg: "invalid type"
   file: "topena1.nim"
   line: 9
-  errormsg: "invalid type"
 """
 # Tests a special bug
 
 var
   x: ref openarray[string] #ERROR_MSG invalid type
-
-
-
diff --git a/tests/openarray/topenarrayrepr.nim b/tests/openarray/topenarrayrepr.nim
index d276756bc..3784d4bbb 100644
--- a/tests/openarray/topenarrayrepr.nim
+++ b/tests/openarray/topenarrayrepr.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "topenarrayrepr.nim"
   output: "5 - [1]"
 """
 type
@@ -12,6 +11,3 @@ proc Bar(n: int, m: openarray[int64]) =
   echo($n & " - " & repr(m))
 
 Foo(5, Bar) #OUT 5 - [1]
-
-
-
diff --git a/tests/openarray/topenlen.nim b/tests/openarray/topenlen.nim
index fec8e87b7..83d58ac5c 100644
--- a/tests/openarray/topenlen.nim
+++ b/tests/openarray/topenlen.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "topenlen.nim"
   output: "7"
 """
 # Tests a special bug
@@ -14,5 +13,3 @@ proc p(a, b: openarray[string]): int =
 
 discard choose(["sh", "-c", $p([""], ["a"])])
 echo($p(["", "ha", "abc"], ["xyz"])) #OUT 7
-
-
diff --git a/tests/openarray/tptrarrayderef.nim b/tests/openarray/tptrarrayderef.nim
index 1e73be108..5c63f6f98 100644
--- a/tests/openarray/tptrarrayderef.nim
+++ b/tests/openarray/tptrarrayderef.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tptrarrayderef.nim"
   output: "OK"
 """
 
@@ -15,7 +14,7 @@ var
 proc mutate[T](arr:openarray[T], brr: openArray[T]) =
   for i in 0..arr.len-1:
     doAssert(arr[i] == brr[i])
-    
+
 mutate(arr, arr)
 
 #bug #2240
@@ -46,9 +45,9 @@ proc getFilledBuffer(sz: int): ref seq[char] =
   s[] = newSeq[char](sz)
   fillBuffer(s[])
   return s
-  
+
 let aa = getFilledBuffer(3)
 for i in 0..aa[].len-1:
   doAssert(aa[i] == chr(i))
-  
-echo "OK"
\ No newline at end of file
+
+echo "OK"
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..01b78eb11 100644
--- a/tests/osproc/ta_out.nim
+++ b/tests/osproc/ta_out.nim
@@ -1,3 +1,18 @@
+discard """
+output: '''
+start ta_out
+to stdout
+to stdout
+to stderr
+to stderr
+to stdout
+to stdout
+end ta_out
+'''
+"""
+
+echo "start ta_out"
+
 # This file is prefixed with an "a", because other tests
 # depend on it and it must be compiled first.
 stdout.writeLine("to stdout")
@@ -14,3 +29,5 @@ stdout.writeLine("to stdout")
 stdout.flushFile()
 stdout.writeLine("to stdout")
 stdout.flushFile()
+
+echo "end ta_out"
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/texecps.nim b/tests/osproc/texecps.nim
index 887d79bfb..10715fa0f 100644
--- a/tests/osproc/texecps.nim
+++ b/tests/osproc/texecps.nim
@@ -1,8 +1,3 @@
-discard """
-  file: "texecps.nim"
-  output: ""
-"""
-
 import osproc, streams, strutils, os
 
 const NumberOfProcesses = 13
@@ -14,8 +9,7 @@ proc execCb(idx: int, p: Process) =
   if exitCode < len(gResults):
     gResults[exitCode] = p.outputStream.readAll.strip
 
-when isMainModule:
-
+when true:
   if paramCount() == 0:
     gResults = newSeq[string](NumberOfProcesses)
     var checks = newSeq[string](NumberOfProcesses)
diff --git a/tests/osproc/texitcode.nim b/tests/osproc/texitcode.nim
index 4eaab6da2..558017716 100644
--- a/tests/osproc/texitcode.nim
+++ b/tests/osproc/texitcode.nim
@@ -1,7 +1,7 @@
 discard """
-  file: "texitcode.nim"
   output: ""
 """
+
 import osproc, os
 
 const filename = when defined(Windows): "tafalse.exe" else: "tafalse"
diff --git a/tests/osproc/tstderr.nim b/tests/osproc/tstderr.nim
index 7a39522a3..55b11eba5 100644
--- a/tests/osproc/tstderr.nim
+++ b/tests/osproc/tstderr.nim
@@ -1,10 +1,15 @@
 discard """
-  output: '''--------------------------------------
+  output: '''
+start tstderr
+--------------------------------------
 to stderr
 to stderr
 --------------------------------------
 '''
 """
+
+echo "start tstderr"
+
 import osproc, os, streams
 
 const filename = "ta_out".addFileExt(ExeExt)
diff --git a/tests/osproc/tstdin.nim b/tests/osproc/tstdin.nim
index 9b49ed786..8579680ab 100644
--- a/tests/osproc/tstdin.nim
+++ b/tests/osproc/tstdin.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tstdin.nim"
   output: "10"
 """
 import osproc, os, streams
diff --git a/tests/osproc/tstdout.nim b/tests/osproc/tstdout.nim
index 0cb5bd9c0..e3ed3986a 100644
--- a/tests/osproc/tstdout.nim
+++ b/tests/osproc/tstdout.nim
@@ -1,11 +1,13 @@
 discard """
   output: '''--------------------------------------
+start ta_out
 to stdout
 to stdout
 to stderr
 to stderr
 to stdout
 to stdout
+end ta_out
 --------------------------------------
 '''
 """
diff --git a/tests/osproc/tworkingdir.nim b/tests/osproc/tworkingdir.nim
index 7d58d5ae6..3a3c1b6ab 100644
--- a/tests/osproc/tworkingdir.nim
+++ b/tests/osproc/tworkingdir.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tworkingdir.nim"
   output: ""
 """
 
diff --git a/tests/overflw/toverflw.nim b/tests/overflw/toverflw.nim
index 20bc56a53..aef597e6c 100644
--- a/tests/overflw/toverflw.nim
+++ b/tests/overflw/toverflw.nim
@@ -1,8 +1,6 @@
 discard """
-  file: "toverflw.nim"
   output: "ok"
   cmd: "nim $target -d:release $options $file"
-
 """
 # Tests nim's ability to detect overflows
 
diff --git a/tests/overflw/toverflw2.nim b/tests/overflw/toverflw2.nim
index 75bd4cdf5..91b900ca4 100644
--- a/tests/overflw/toverflw2.nim
+++ b/tests/overflw/toverflw2.nim
@@ -1,10 +1,7 @@
 discard """
-  file: "toverflw2.nim"
   outputsub: "Error: unhandled exception: over- or underflow [OverflowError]"
   exitcode: "1"
 """
 var a : int32 = 2147483647
 var b : int32 = 2147483647
 var c = a + b
-
-
diff --git a/tests/overflw/tovfint.nim b/tests/overflw/tovfint.nim
index f775d2e1c..5c440a540 100644
--- a/tests/overflw/tovfint.nim
+++ b/tests/overflw/tovfint.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tovfint.nim"
   output: "works!"
 """
 # this tests the new overflow literals
@@ -19,5 +18,3 @@ else:
     write(stdout, "broken!\n")
 
 #OUT works!
-
-
diff --git a/tests/overload/toverl.nim b/tests/overload/toverl.nim
index 807b643a4..64257be77 100644
--- a/tests/overload/toverl.nim
+++ b/tests/overload/toverl.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "redefinition of \'TNone\'"
   file: "toverl.nim"
   line: 11
-  errormsg: "redefinition of \'TNone\'"
 """
 # Test for overloading
 
@@ -9,5 +9,3 @@ type
   TNone {.exportc: "_NONE", final.} = object
 
 proc TNone(a, b: int) = nil #ERROR_MSG attempt to redefine 'TNone'
-
-
diff --git a/tests/overload/tissues.nim b/tests/overload/toverload_issues.nim
index 7980f51a9..fe1603a44 100644
--- a/tests/overload/tissues.nim
+++ b/tests/overload/toverload_issues.nim
@@ -119,28 +119,24 @@ template test(loopCount: int, testBody: untyped): typed =
     test(loopCount, 0, testBody)
     echo "done extraI passed 0"
 
-when isMainModule:
-  var
-    loops = 0
-
-  test 0, 0:
-    loops += 1
-  echo "test 0 complete, loops=", loops
-
-  test 1, 1.0:
-    loops += 1
-  echo "test 1.0 complete, loops=", loops
-
-  when true:
-    # when true we get the following compile time error:
-    #   b.nim(35, 6) Error: expression 'loops += 1' has no type (or is ambiguous)
-    loops = 0
-    test 2:
-      loops += 1
-    echo "test no extra complete, loops=", loops
+var
+  loops = 0
 
+test 0, 0:
+  loops += 1
+echo "test 0 complete, loops=", loops
 
+test 1, 1.0:
+  loops += 1
+echo "test 1.0 complete, loops=", loops
 
+when true:
+  # when true we get the following compile time error:
+  #   b.nim(35, 6) Error: expression 'loops += 1' has no type (or is ambiguous)
+  loops = 0
+  test 2:
+    loops += 1
+  echo "test no extra complete, loops=", loops
 
 # bug #2229
 type
diff --git a/tests/overload/tvarious.nim b/tests/overload/toverload_various.nim
index 4c17b6031..4c17b6031 100644
--- a/tests/overload/tvarious.nim
+++ b/tests/overload/toverload_various.nim
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..5139920ea 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
 
@@ -22,5 +34,5 @@ proc main =
   sync()
   for ix in 1..3: channels[ix].close()
 
-when isMainModule:
+when true:
   main()
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/tgc_unsafe.nim b/tests/parallel/tgc_unsafe.nim
index a4d96cd73..baf0dc24a 100644
--- a/tests/parallel/tgc_unsafe.nim
+++ b/tests/parallel/tgc_unsafe.nim
@@ -28,5 +28,5 @@ proc main =
   sync()
   for ix in 1..3: channels[ix].close()
 
-when isMainModule:
+when true:
   main()
diff --git a/tests/parallel/tgc_unsafe2.nim b/tests/parallel/tgc_unsafe2.nim
index 40bfbdadb..40af728fb 100644
--- a/tests/parallel/tgc_unsafe2.nim
+++ b/tests/parallel/tgc_unsafe2.nim
@@ -1,10 +1,10 @@
 discard """
+  errormsg: "'consumer' is not GC-safe as it calls 'track'"
   line: 28
   nimout: '''tgc_unsafe2.nim(22, 6) Warning: 'trick' is not GC-safe as it accesses 'global' which is a global using GC'ed memory [GcUnsafe2]
 tgc_unsafe2.nim(26, 6) Warning: 'track' is not GC-safe as it calls 'trick' [GcUnsafe2]
 tgc_unsafe2.nim(28, 6) Error: 'consumer' is not GC-safe as it calls 'track'
 '''
-  errormsg: "'consumer' is not GC-safe as it calls 'track'"
 """
 
 import threadpool
@@ -35,5 +35,5 @@ proc main =
   sync()
   for ix in 1..3: channels[ix].close()
 
-when isMainModule:
+when true:
   main()
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..694eb77db 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
@@ -35,6 +36,6 @@ proc update =
     for i in 0 .. people.high:
       spawn people[i].greet()
 
-when isMainModule:
+when true:
   setup()
   update()
diff --git a/tests/parallel/tsimple_array_checks.nim b/tests/parallel/tsimple_array_checks.nim
index 9874d3299..5d6e87efe 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
@@ -37,5 +59,5 @@ proc maino =
 
 maino() # Doesn't work outside a proc
 
-when isMainModule:
+when true:
   main()
diff --git a/tests/parallel/tsysspawnbadarg.nim b/tests/parallel/tsysspawnbadarg.nim
index 2d3ffd241..a8f1ed401 100644
--- a/tests/parallel/tsysspawnbadarg.nim
+++ b/tests/parallel/tsysspawnbadarg.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 9
   errormsg: "'spawn' takes a call expression"
+  line: 9
   cmd: "nim $target --threads:on $options $file"
 """
 
diff --git a/tests/parallel/twrong_refcounts.nim b/tests/parallel/twrong_refcounts.nim
index 57e0588a0..ac428762d 100644
--- a/tests/parallel/twrong_refcounts.nim
+++ b/tests/parallel/twrong_refcounts.nim
@@ -48,6 +48,6 @@ proc update =
 
 # ---
 
-when isMainModule:
+when true:
   setup()
   update()
diff --git a/tests/parser/tdomulttest.nim b/tests/parser/tdomulttest.nim
index 418192ac8..9e1afd034 100644
--- a/tests/parser/tdomulttest.nim
+++ b/tests/parser/tdomulttest.nim
@@ -1,14 +1,14 @@
 discard """
-  file: "tdomulttest.nim"
   output: "555\ntest\nmulti lines\n99999999\nend"
-  disabled: true
 """
+
 proc foo(bar, baz: proc (x: int): int) =
   echo bar(555)
   echo baz(99999999)
 
 foo do (x: int) -> int:
   return x
+
 do (x: int) -> int:
   echo("test")
   echo("multi lines")
diff --git a/tests/parser/tinvcolonlocation1.nim b/tests/parser/tinvcolonlocation1.nim
index 2fddab2f8..7fca5deb7 100644
--- a/tests/parser/tinvcolonlocation1.nim
+++ b/tests/parser/tinvcolonlocation1.nim
@@ -1,8 +1,8 @@
 discard """
+  errormsg: "expected: ':', but got: 'echo'"
   file: "tinvcolonlocation1.nim"
   line: 8
   column: 7
-  errormsg: "expected: ':', but got: 'echo'"
 """
 try #<- missing ':'
   echo "try"
diff --git a/tests/parser/tinvcolonlocation2.nim b/tests/parser/tinvcolonlocation2.nim
index 4251598b9..e3de393b8 100644
--- a/tests/parser/tinvcolonlocation2.nim
+++ b/tests/parser/tinvcolonlocation2.nim
@@ -1,8 +1,8 @@
 discard """
+  errormsg: "expected: ':', but got: 'keyword finally'"
   file: "tinvcolonlocation2.nim"
   line: 11
   column: 8
-  errormsg: "expected: ':', but got: 'keyword finally'"
 """
 try:
   echo "try"
diff --git a/tests/parser/tinvcolonlocation3.nim b/tests/parser/tinvcolonlocation3.nim
index a8db658eb..46252f24e 100644
--- a/tests/parser/tinvcolonlocation3.nim
+++ b/tests/parser/tinvcolonlocation3.nim
@@ -1,8 +1,8 @@
 discard """
+  errormsg: "expected: ':', but got: 'echo'"
   file: "tinvcolonlocation3.nim"
   line: 12
   column: 7
-  errormsg: "expected: ':', but got: 'echo'"
 """
 try:
   echo "try"
diff --git a/tests/parser/tinvwhen.nim b/tests/parser/tinvwhen.nim
index 99701bdf5..7a47f69a4 100644
--- a/tests/parser/tinvwhen.nim
+++ b/tests/parser/tinvwhen.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "invalid indentation"
   file: "tinvwhen.nim"
   line: 11
-  errormsg: "invalid indentation"
 """
 # This was parsed even though it should not!
 
@@ -11,5 +11,3 @@ proc getcwd(buf: cstring, buflen: cint): cstring
     when defined(unix): {.importc: "getcwd", header: "<unistd.h>".} #ERROR_MSG invalid indentation
     elif defined(windows): {.importc: "getcwd", header: "<direct.h>"}
     else: {.error: "os library not ported to your OS. Please help!".}
-
-
diff --git a/tests/parser/toprprec.nim b/tests/parser/toprprec.nim
index 1acd381e7..363ad1c18 100644
--- a/tests/parser/toprprec.nim
+++ b/tests/parser/toprprec.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "toprprec.nim"
   output: "done"
 """
 # Test operator precedence:
diff --git a/tests/parser/tprecedence.nim b/tests/parser/tprecedence.nim
index d586f14a3..aff7c6aca 100644
--- a/tests/parser/tprecedence.nim
+++ b/tests/parser/tprecedence.nim
@@ -1,7 +1,8 @@
 discard """
   output: '''holla
 true
-defabc 4'''
+defabc 4
+0'''
 """
 
 # Test top level semicolon works properly:
@@ -19,3 +20,23 @@ proc foo[S, T](x: S, y: T): T = x & y
 proc bar[T](x: T): T = x
 
 echo "def".foo[:string, string]("abc"), " ", 4.bar[:int]
+
+# bug #9574
+proc isFalse(a: int): bool = false
+
+assert not isFalse(3)
+
+# bug #9633
+
+type
+  MyField = object
+    b: seq[string]
+
+  MyObject = object
+    f: MyField
+
+proc getX(x: MyObject): lent MyField {.inline.} =
+  x.f
+
+let a = MyObject()
+echo a.getX.b.len
diff --git a/tests/parser/tstrongspaces.nim b/tests/parser/tstrongspaces.nim
deleted file mode 100644
index adab7f709..000000000
--- a/tests/parser/tstrongspaces.nim
+++ /dev/null
@@ -1,83 +0,0 @@
-#? strongSpaces
-
-discard """
-  output: '''35
-true
-true
-4
-true
-1
-false
-77
-(Field0: 1, Field1: 2, Field2: 2)
-ha
-true
-tester args
-all
-all args
-19
--3
-false
--2
-'''
-"""
-
-echo 2+5 * 5
-
-# Keyword operators
-echo 1 + 16 shl 1 == 1 + (16 shl 1)
-echo 2 and 1  in  {0, 30}
-echo 2+2 * 2 shr 1
-echo false  or  2 and 1  in  {0, 30}
-
-proc `^`(a, b: int): int = a + b div 2
-echo 19 mod 16 ^ 4  +  2 and 1
-echo 18 mod 16 ^ 4 > 0
-
-# echo $foo gotcha
-let foo = 77
-echo $foo
-
-echo (1, 2, 2)
-
-template `&`(a, b: int): int = a and b
-template `|`(a, b: int): int = a - b
-template `++`(a, b: int): bool = a + b == 8009
-
-when true:
-  let b = 66
-  let c = 90
-  let bar = 8000
-  if foo+4 * 4 == 8  and  b&c | 9  ++
-      bar:
-    echo "ho"
-  else:
-    echo "ha"
-
-  let booA = foo+4 * 4  -  b&c | 9  +
-      bar
-  # is parsed as
-  let booB = ((foo+4)*4) - ((b&c) | 9) + bar
-
-  echo booA == booB
-
-
-template `|`(a, b): untyped = (if a.len > 0: a else: b)
-
-const
-  tester = "tester"
-  args = "args"
-
-echo tester & " " & args|"all"
-echo "all"  |  tester & " " & args
-echo "all"|tester & " " & args
-
-# Test arrow like operators. See also tests/macros/tclosuremacro.nim
-proc `+->`(a, b: int): int = a + b*4
-template `===>`(a, b: int): int = a - b shr 1
-
-echo 3 +-> 2 + 2 and 4
-var arrowed = 3+->2 + 2 and 4  # arrowed = 4
-echo arrowed ===> 15
-echo (2 * 3+->2) == (2*3 +-> 2)
-echo arrowed ===> 2 + 3+->2
diff --git a/tests/parser/ttupleunpack.nim b/tests/parser/ttupleunpack.nim
index aaa06f9f4..c7ab9ea15 100644
--- a/tests/parser/ttupleunpack.nim
+++ b/tests/parser/ttupleunpack.nim
@@ -1,9 +1,3 @@
-discard """
-  file: "ttupleunpack.nim"
-  output: ""
-  exitcode: 0
-"""
-
 proc returnsTuple(): (int, int, int) = (4, 2, 3)
 
 proc main2 =
diff --git a/tests/pragmas/t6448.nim b/tests/pragmas/t6448.nim
index 61e4a35d9..a1bd747a0 100644
--- a/tests/pragmas/t6448.nim
+++ b/tests/pragmas/t6448.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 9
   errormsg: '''ambiguous call; both foobar.async'''
+  line: 9
 """
 
 import foobar
@@ -9,7 +9,7 @@ import asyncdispatch, macros
 proc bar() {.async.} =
   echo 42
 
-proc foo() {.async.} = 
+proc foo() {.async.} =
   await bar()
 
 asyncCheck foo()
diff --git a/tests/pragmas/t8741.nim b/tests/pragmas/t8741.nim
index 41f2f9e8a..c132c3543 100644
--- a/tests/pragmas/t8741.nim
+++ b/tests/pragmas/t8741.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 9
   errormsg: "cannot attach a custom pragma to 'a'"
+  line: 9
 """
 
 for a {.gensym, inject.} in @[1,2,3]:
diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim
index ae0f39631..0bc4d2f18 100644
--- a/tests/pragmas/tcustom_pragma.nim
+++ b/tests/pragmas/tcustom_pragma.nim
@@ -174,3 +174,25 @@ type
 var foo: Something
 foo.cardinal = north
 doAssert foo.b.hasCustomPragma(thingy) == true
+
+
+proc myproc(s: string): int = 
+  {.thingy.}:
+    s.len
+
+doAssert myproc("123") == 3
+
+let xx = compiles:
+  proc myproc_bad(s: string): int = 
+    {.not_exist.}:
+      s.len
+doAssert: xx == false
+
+
+macro checkSym(s: typed{nkSym}): untyped = 
+  let body = s.getImpl.body
+  doAssert body[1].kind == nnkPragmaBlock
+  doAssert body[1][0].kind == nnkPragma
+  doAssert body[1][0][0] == bindSym"thingy"
+
+checkSym(myproc)
\ No newline at end of file
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/pragmas/tused.nim b/tests/pragmas/tused.nim
index 83c62b7bb..7616c1215 100644
--- a/tests/pragmas/tused.nim
+++ b/tests/pragmas/tused.nim
@@ -1,11 +1,13 @@
 discard """
   nimout: '''
 compile start
-tused.nim(15, 8) Hint: 'tused.echoSub(a: int, b: int)[declared in tused.nim(15, 7)]' is declared but not used [XDeclaredButNotUsed]
+tused.nim(17, 8) Hint: 'tused.echoSub(a: int, b: int)[declared in tused.nim(17, 7)]' is declared but not used [XDeclaredButNotUsed]
 compile end'''
   output: "8\n8"
+  joinable: false
 """
 
+# not joinable because paths in nimout differ when imported
 static:
   echo "compile start"
 
@@ -31,5 +33,11 @@ block:
   implementArithOpsNew(int)
   echoAdd 3, 5
 
+# issue #9896
+type
+  MyEnum {.used.} = enum
+    Val1, Val2, Val3
+
+
 static:
   echo "compile end"
diff --git a/tests/pragmas/tuserpragma2.nim b/tests/pragmas/tuserpragma2.nim
index bf8844e66..ce16c4649 100644
--- a/tests/pragmas/tuserpragma2.nim
+++ b/tests/pragmas/tuserpragma2.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "can raise an unlisted exception: ref Exception"
   file: "tuserpragma2.nim"
   line: 11
-  errormsg: "can raise an unlisted exception: ref Exception"
 """
 
 # bug #7216
diff --git a/tests/proc/tprocredef.nim b/tests/proc/tprocredef.nim
index 4ec771510..0cd6ec770 100644
--- a/tests/proc/tprocredef.nim
+++ b/tests/proc/tprocredef.nim
@@ -1,9 +1,8 @@
 discard """
+  errormsg: "redefinition of \'foo\'"
   file: "tprocredef.nim"
   line: 8
-  errormsg: "redefinition of \'foo\'"
 """
 
 proc foo(a: int, b: string) = discard
 proc foo(a: int, b: string) = discard
-
diff --git a/tests/range/tsubrange.nim b/tests/range/tsubrange.nim
index 914e7c6e7..f778c55eb 100644
--- a/tests/range/tsubrange.nim
+++ b/tests/range/tsubrange.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 20
   errormsg: "cannot convert 60 to TRange"
+  line: 20
 """
 
 type
@@ -18,4 +18,3 @@ p y
 
 const
   myConst: TRange = 60
-
diff --git a/tests/range/tsubrange2.nim b/tests/range/tsubrange2.nim
index 7097faed2..e0fb71c5f 100644
--- a/tests/range/tsubrange2.nim
+++ b/tests/range/tsubrange2.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tsubrange2.nim"
   outputsub: "value out of range: 50 [RangeError]"
   exitcode: "1"
 """
@@ -14,4 +13,3 @@ var
   r: TRange
   y = 50
 p y
-
diff --git a/tests/range/tsubrange3.nim b/tests/range/tsubrange3.nim
index f5bb2f161..d3aae87df 100644
--- a/tests/range/tsubrange3.nim
+++ b/tests/range/tsubrange3.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tsubrange.nim"
   outputsub: "value out of range: 50 [RangeError]"
   exitcode: "1"
 """
diff --git a/tests/rational/trat_float.nim b/tests/rational/trat_float.nim
index 24797c4a0..663973bf9 100644
--- a/tests/rational/trat_float.nim
+++ b/tests/rational/trat_float.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: '''type mismatch: got'''
   file: "trat_float.nim"
   line: "9,19"
-  errormsg: '''type mismatch: got'''
 """
 import rationals
 var
diff --git a/tests/realtimeGC/shared.nim b/tests/realtimeGC/shared.nim
index 2d1dd6c3c..1abe42089 100644
--- a/tests/realtimeGC/shared.nim
+++ b/tests/realtimeGC/shared.nim
@@ -1,5 +1,6 @@
 discard """
-  cmd: "nim $target --debuginfo --hints:on --app:lib $options $file"
+cmd: "nim $target --debuginfo --hints:on --app:lib $options $file"
+action: compile
 """
 
 import strutils
diff --git a/tests/seq/tseq.nim b/tests/seq/tseq.nim
index 6528d518e..6a28bc8e6 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:
@@ -179,3 +203,4 @@ block ttoseq:
     stdout.write(x)
   var y: type("a b c".split)
   y = "xzy"
+  stdout.write("\n")
diff --git a/tests/sets/t2669.nim b/tests/sets/t2669.nim
index 6b8eb0f54..0a92818fa 100644
--- a/tests/sets/t2669.nim
+++ b/tests/sets/t2669.nim
@@ -1,6 +1,6 @@
 discard """
-line: 6
 errormsg: "cannot convert 6 to range 1..5(int8)"
+line: 6
 """
 
 var c: set[range[1i8..5i8]] = {1i8, 2i8, 6i8}
diff --git a/tests/sets/tsets.nim b/tests/sets/tsets.nim
index 13a5f54e6..bde25cf81 100644
--- a/tests/sets/tsets.nim
+++ b/tests/sets/tsets.nim
@@ -1,7 +1,8 @@
 discard """
-  file: "tsets.nim"
-  output: '''Ha ein F ist in s!
-false'''
+output: '''
+Ha ein F ist in s!
+false
+'''
 """
 # Test the handling of sets
 
diff --git a/tests/sets/tvarious.nim b/tests/sets/tsets_various.nim
index 7cb9a6eec..8a63763b4 100644
--- a/tests/sets/tvarious.nim
+++ b/tests/sets/tsets_various.nim
@@ -102,9 +102,9 @@ block tsets2:
 
 block tsets3:
   let
-    s1: TSet[int] = toSet([1, 2, 4, 8, 16])
-    s2: TSet[int] = toSet([1, 2, 3, 5, 8])
-    s3: TSet[int] = toSet([3, 5, 7])
+    s1: HashSet[int] = toSet([1, 2, 4, 8, 16])
+    s2: HashSet[int] = toSet([1, 2, 3, 5, 8])
+    s3: HashSet[int] = toSet([3, 5, 7])
 
   block union:
     let
diff --git a/tests/statictypes/t9255.nim b/tests/statictypes/t9255.nim
index bc8df6656..86bc8c7f1 100644
--- a/tests/statictypes/t9255.nim
+++ b/tests/statictypes/t9255.nim
@@ -8,6 +8,6 @@ type mismatch: got <static[proc (a0: int): string{.noSideEffect, gcsafe, locks:
 macro fun(a: static float): untyped =
   discard
 
-when isMainModule:
+when true:
   proc bar(a0: int): string = discard
   fun(bar)
diff --git a/tests/stdlib/nre/captures.nim b/tests/stdlib/nre/captures.nim
index 31de71154..bd5e83ecc 100644
--- a/tests/stdlib/nre/captures.nim
+++ b/tests/stdlib/nre/captures.nim
@@ -9,16 +9,16 @@ suite "captures":
   test "capture bounds are correct":
     let ex1 = re("([0-9])")
     check("1 23".find(ex1).matchBounds == 0 .. 0)
-    check("1 23".find(ex1).captureBounds[0].get == 0 .. 0)
+    check("1 23".find(ex1).captureBounds[0] == 0 .. 0)
     check("1 23".find(ex1, 1).matchBounds == 2 .. 2)
     check("1 23".find(ex1, 3).matchBounds == 3 .. 3)
 
     let ex2 = re("()()()()()()()()()()([0-9])")
-    check("824".find(ex2).captureBounds[0].get == 0 .. -1)
-    check("824".find(ex2).captureBounds[10].get == 0 .. 0)
+    check("824".find(ex2).captureBounds[0] == 0 .. -1)
+    check("824".find(ex2).captureBounds[10] == 0 .. 0)
 
     let ex3 = re("([0-9]+)")
-    check("824".find(ex3).captureBounds[0].get == 0 .. 2)
+    check("824".find(ex3).captureBounds[0] == 0 .. 2)
 
   test "named captures":
     let ex1 = "foobar".find(re("(?<foo>foo)(?<bar>bar)"))
@@ -26,13 +26,19 @@ suite "captures":
     check(ex1.captures["bar"] == "bar")
 
     let ex2 = "foo".find(re("(?<foo>foo)(?<bar>bar)?"))
+    check("foo" in ex2.captureBounds)
     check(ex2.captures["foo"] == "foo")
-    check(ex2.captures["bar"] == "")
+    check(not ("bar" in ex2.captures))
+    expect KeyError:
+        discard ex2.captures["bar"]
 
   test "named capture bounds":
     let ex1 = "foo".find(re("(?<foo>foo)(?<bar>bar)?"))
-    check(ex1.captureBounds["foo"] == some(0..2))
-    check(ex1.captureBounds["bar"] == none(Slice[int]))
+    check("foo" in ex1.captureBounds)
+    check(ex1.captureBounds["foo"] == 0..2)
+    check(not ("bar" in ex1.captures))
+    expect KeyError:
+        discard ex1.captures["bar"]
 
   test "capture count":
     let ex1 = re("(?<foo>foo)(?<bar>bar)?")
@@ -41,19 +47,18 @@ suite "captures":
 
   test "named capture table":
     let ex1 = "foo".find(re("(?<foo>foo)(?<bar>bar)?"))
-    check(ex1.captures.toTable == {"foo" : "foo", "bar" : ""}.toTable())
-    check(ex1.captureBounds.toTable == {"foo" : some(0..2), "bar" : none(Slice[int])}.toTable())
-    check(ex1.captures.toTable("") == {"foo" : "foo", "bar" : ""}.toTable())
+    check(ex1.captures.toTable == {"foo" : "foo"}.toTable())
+    check(ex1.captureBounds.toTable == {"foo" : 0..2}.toTable())
 
     let ex2 = "foobar".find(re("(?<foo>foo)(?<bar>bar)?"))
     check(ex2.captures.toTable == {"foo" : "foo", "bar" : "bar"}.toTable())
 
   test "capture sequence":
     let ex1 = "foo".find(re("(?<foo>foo)(?<bar>bar)?"))
-    check(ex1.captures.toSeq == @["foo", ""])
+    check(ex1.captures.toSeq == @[some("foo"), none(string)])
     check(ex1.captureBounds.toSeq == @[some(0..2), none(Slice[int])])
-    check(ex1.captures.toSeq("") == @["foo", ""])
+    check(ex1.captures.toSeq(some("")) == @[some("foo"), some("")])
 
     let ex2 = "foobar".find(re("(?<foo>foo)(?<bar>bar)?"))
-    check(ex2.captures.toSeq == @["foo", "bar"])
+    check(ex2.captures.toSeq == @[some("foo"), some("bar")])
 
diff --git a/tests/stdlib/nre/match.nim b/tests/stdlib/nre/match.nim
index 38ee5214b..06b69fd04 100644
--- a/tests/stdlib/nre/match.nim
+++ b/tests/stdlib/nre/match.nim
@@ -10,9 +10,9 @@ suite "match":
     check("abc".match(re"(\w)").captures[0] == "a")
     check("abc".match(re"(?<letter>\w)").captures["letter"] == "a")
     check("abc".match(re"(\w)\w").captures[-1] == "ab")
-    check("abc".match(re"(\w)").captureBounds[0].get == 0 .. 0)
-    check("abc".match(re"").captureBounds[-1].get == 0 .. -1)
-    check("abc".match(re"abc").captureBounds[-1].get == 0 .. 2)
+    check("abc".match(re"(\w)").captureBounds[0] == 0 .. 0)
+    check("abc".match(re"").captureBounds[-1] == 0 .. -1)
+    check("abc".match(re"abc").captureBounds[-1] == 0 .. 2)
 
   test "match test cases":
     check("123".match(re"").matchBounds == 0 .. -1)
diff --git a/tests/stdlib/nre/replace.nim b/tests/stdlib/nre/replace.nim
index b762271a2..812a7f384 100644
--- a/tests/stdlib/nre/replace.nim
+++ b/tests/stdlib/nre/replace.nim
@@ -16,5 +16,7 @@ suite "replace":
     check("123".replace(re"(?<foo>\d)(\d)", "${foo}$#$#") == "1123")
 
   test "replacing missing captures should throw instead of segfaulting":
-    discard "ab".replace(re"(a)|(b)", "$1$2")
-    discard "b".replace(re"(a)?(b)", "$1$2")
+    expect IndexError: discard "ab".replace(re"(a)|(b)", "$1$2")
+    expect IndexError: discard "b".replace(re"(a)?(b)", "$1$2")
+    expect KeyError: discard "b".replace(re"(a)?", "${foo}")
+    expect KeyError: discard "b".replace(re"(?<foo>a)?", "${foo}")
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/somesql.sql b/tests/stdlib/somesql.sql
index 285f93cec..74afcbab0 100644
--- a/tests/stdlib/somesql.sql
+++ b/tests/stdlib/somesql.sql
@@ -295,4 +295,4 @@ create table anon207(
   anon209 varchar(30) not null,
   anon204 varchar(30) default null,
   anon70 int not null  references anon40(anon41));
-
+select * from anon207 where anon41 in (1, 2, 3);
diff --git a/tests/stdlib/t8925.nim b/tests/stdlib/t8925.nim
index d3dc1ea86..dbf55fd88 100644
--- a/tests/stdlib/t8925.nim
+++ b/tests/stdlib/t8925.nim
@@ -1,6 +1,6 @@
 discard """
-  file: "strscans.nim"
   errormsg: "type mismatch between pattern '$i' (position: 1) and HourRange var 'hour'"
+  file: "strscans.nim"
 """
 
 import strscans
diff --git a/tests/stdlib/tbitops.nim b/tests/stdlib/tbitops.nim
index 8301256c4..d8c6da1d4 100644
--- a/tests/stdlib/tbitops.nim
+++ b/tests/stdlib/tbitops.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tbitops.nim"
   output: "OK"
 """
 import bitops
diff --git a/tests/stdlib/tbitops2.nim b/tests/stdlib/tbitops2.nim
index 31952316c..e8c7318be 100644
--- a/tests/stdlib/tbitops2.nim
+++ b/tests/stdlib/tbitops2.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tbitops.nim"
   output: "OK"
 """
 import bitops
diff --git a/tests/stdlib/tcgi.nim b/tests/stdlib/tcgi.nim
new file mode 100644
index 000000000..bc177125e
--- /dev/null
+++ b/tests/stdlib/tcgi.nim
@@ -0,0 +1,17 @@
+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/thtmlparser.nim b/tests/stdlib/thtmlparser.nim
index d59e8b302..0457585d0 100644
--- a/tests/stdlib/thtmlparser.nim
+++ b/tests/stdlib/thtmlparser.nim
@@ -78,3 +78,61 @@ block t2814:
       echo "case " & ltype[0] & " failed !"
       quit(2)
   echo "true"
+
+block t6154:
+  let foo = """
+  <!DOCTYPE html>
+  <html>
+      <head>
+        <title> foobar </title>
+      </head>
+      <body>
+        <p class=foo id=bar></p>
+        <p something=&#9;foo&#9;bar&#178;></p>
+        <p something=  &#9;foo&#9;bar&#178; foo  =bloo></p>
+        <p class="foo2" id="bar2"></p>
+        <p wrong= ></p>
+        <p data-foo data-bar="correct!" enabled  ></p>
+        <p quux whatever></p>
+      </body>
+  </html>
+  """
+
+  var errors: seq[string] = @[]
+  let html = parseHtml(newStringStream(foo), "statichtml", errors=errors)
+  doAssert "statichtml(11, 18) Error: attribute value expected" in errors
+  let ps = html.findAll("p")
+  doAssert ps.len == 7
+
+  doAssert ps[0].attrsLen == 2
+  doAssert ps[0].attr("class") == "foo"
+  doAssert ps[0].attr("id") == "bar"
+  doassert ps[0].len == 0
+
+  doAssert ps[1].attrsLen == 1
+  doAssert ps[1].attr("something") == "\tfoo\tbar²"
+  doassert ps[1].len == 0
+
+  doAssert ps[2].attrsLen == 2
+  doAssert ps[2].attr("something") == "\tfoo\tbar²"
+  doAssert ps[2].attr("foo") == "bloo"
+  doassert ps[2].len == 0
+
+  doAssert ps[3].attrsLen == 2
+  doAssert ps[3].attr("class") == "foo2"
+  doAssert ps[3].attr("id") == "bar2"
+  doassert ps[3].len == 0
+
+  doAssert ps[4].attrsLen == 1
+  doAssert ps[4].attr("wrong") == ""
+
+  doAssert ps[5].attrsLen == 3
+  doAssert ps[5].attr("data-foo") == ""
+  doAssert ps[5].attr("data-bar") == "correct!"
+  doAssert ps[5].attr("enabled") == ""
+  doassert ps[5].len == 0
+
+  doAssert ps[6].attrsLen == 2
+  doAssert ps[6].attr("quux") == ""
+  doAssert ps[6].attr("whatever") == ""
+  doassert ps[6].len == 0
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/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim
index bf0bb3ea7..33332447b 100644
--- a/tests/stdlib/tjsonmacro.nim
+++ b/tests/stdlib/tjsonmacro.nim
@@ -1,10 +1,9 @@
 discard """
-  file: "tjsonmacro.nim"
   output: ""
 """
 import json, strutils, options, tables
 
-when isMainModule:
+when true:
   # Tests inspired by own use case (with some additional tests).
   # This should succeed.
   type
diff --git a/tests/stdlib/tjsonmacro_reject.nim b/tests/stdlib/tjsonmacro_reject.nim
index 00506449f..ada365d7d 100644
--- a/tests/stdlib/tjsonmacro_reject.nim
+++ b/tests/stdlib/tjsonmacro_reject.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "Use a named tuple instead of: (string, float)"
   file: "tjsonmacro_reject.nim"
   line: 11
-  errormsg: "Use a named tuple instead of: (string, float)"
 """
 
 import json
@@ -15,4 +15,4 @@ let j = """
   {"engine": {"name": "V8", "capacity": 5.5}, model: "Skyline"}
 """
 let parsed = parseJson(j)
-echo(to(parsed, Car))
\ No newline at end of file
+echo(to(parsed, Car))
diff --git a/tests/stdlib/tjsonmacro_reject2.nim b/tests/stdlib/tjsonmacro_reject2.nim
index b01153553..e13dad307 100644
--- a/tests/stdlib/tjsonmacro_reject2.nim
+++ b/tests/stdlib/tjsonmacro_reject2.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "The `to` macro does not support ref objects with cycles."
   file: "tjsonmacro_reject2.nim"
   line: 10
-  errormsg: "The `to` macro does not support ref objects with cycles."
 """
 import json
 
@@ -18,4 +18,4 @@ let data = """
 """
 
 let dataParsed = parseJson(data)
-let dataDeser = to(dataParsed, Cycle)
\ No newline at end of file
+let dataDeser = to(dataParsed, Cycle)
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/tlists.nim b/tests/stdlib/tlists.nim
index 37e73c53f..a288af781 100644
--- a/tests/stdlib/tlists.nim
+++ b/tests/stdlib/tlists.nim
@@ -8,14 +8,15 @@ const
   data = [1, 2, 3, 4, 5, 6]
 
 block SinglyLinkedListTest1:
-  var L: TSinglyLinkedList[int]
+  var L: SinglyLinkedList[int]
   for d in items(data): L.prepend(d)
-  assert($L == "[6, 5, 4, 3, 2, 1]")
+  for d in items(data): L.append(d)
+  assert($L == "[6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6]")
 
   assert(4 in L)
 
 block SinglyLinkedListTest2:
-  var L: TSinglyLinkedList[string]
+  var L: SinglyLinkedList[string]
   for d in items(data): L.prepend($d)
   assert($L == """["6", "5", "4", "3", "2", "1"]""")
 
@@ -23,7 +24,7 @@ block SinglyLinkedListTest2:
 
 
 block DoublyLinkedListTest1:
-  var L: TDoublyLinkedList[int]
+  var L: DoublyLinkedList[int]
   for d in items(data): L.prepend(d)
   for d in items(data): L.append(d)
   L.remove(L.find(1))
@@ -32,7 +33,7 @@ block DoublyLinkedListTest1:
   assert(4 in L)
 
 block SinglyLinkedRingTest1:
-  var L: TSinglyLinkedRing[int]
+  var L: SinglyLinkedRing[int]
   L.prepend(4)
   assert($L == "[4]")
   L.prepend(4)
@@ -42,7 +43,7 @@ block SinglyLinkedRingTest1:
 
 
 block DoublyLinkedRingTest1:
-  var L: TDoublyLinkedRing[int]
+  var L: DoublyLinkedRing[int]
   L.prepend(4)
   assert($L == "[4]")
   L.prepend(4)
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..21a65369f 100644
--- a/tests/stdlib/tmemfiles1.nim
+++ b/tests/stdlib/tmemfiles1.nim
@@ -1,6 +1,3 @@
-discard """
-  file: "tmemfiles1.nim"
-"""
 import memfiles, os
 var
   mm: MemFile
@@ -8,5 +5,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 19821ea26..98e03b5bb 100644
--- a/tests/stdlib/tmemlines.nim
+++ b/tests/stdlib/tmemlines.nim
@@ -1,5 +1,9 @@
+discard """
+outputsub: ""
+"""
+
 import memfiles
-var inp = memfiles.open("readme.txt")
+var inp = memfiles.open("tests/stdlib/tmemlines.nim")
 for line in lines(inp):
   echo("#" & line & "#")
 close(inp)
diff --git a/tests/stdlib/tmemlinesBuf.nim b/tests/stdlib/tmemlinesBuf.nim
index 21edc2322..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("readme.txt")
+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/tmemmapstreams.nim b/tests/stdlib/tmemmapstreams.nim
index 243574f1a..dd011d777 100644
--- a/tests/stdlib/tmemmapstreams.nim
+++ b/tests/stdlib/tmemmapstreams.nim
@@ -1,6 +1,6 @@
 discard """
-  file: "tmemmapstreams.nim"
-  output: '''Created size: 10
+output: '''
+Created size: 10
 Position after writing: 5
 Position after writing one char: 6
 Peeked data: Hello
diff --git a/tests/stdlib/tmemslices.nim b/tests/stdlib/tmemslices.nim
index 951807cc4..c0d6d3960 100644
--- a/tests/stdlib/tmemslices.nim
+++ b/tests/stdlib/tmemslices.nim
@@ -1,5 +1,11 @@
+discard """
+outputsub: "rlwuiadtrnzb"
+"""
+
+# chatever the sub pattern it will find itself
+
 import memfiles
-var inp = memfiles.open("readme.txt")
+var inp = memfiles.open("tests/stdlib/tmemslices.nim")
 for mem in memSlices(inp):
   if mem.size > 3:
     echo("#" & $mem & "#")
diff --git a/tests/stdlib/tnativesockets.nim b/tests/stdlib/tnativesockets.nim
deleted file mode 100644
index c683647bc..000000000
--- a/tests/stdlib/tnativesockets.nim
+++ /dev/null
@@ -1,8 +0,0 @@
-import nativesockets, unittest
-
-suite "nativesockets":
-  test "getHostname":
-    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/tos.nim b/tests/stdlib/tos.nim
index c10f7036b..467f64fff 100644
--- a/tests/stdlib/tos.nim
+++ b/tests/stdlib/tos.nim
@@ -170,6 +170,25 @@ block modificationTime:
     echo getLastModificationTime("a") == tm
   removeFile("a")
 
+block walkDirRec:
+  createDir("walkdir_test/a/b")
+  open("walkdir_test/a/b/file_1", fmWrite).close()
+  open("walkdir_test/a/file_2", fmWrite).close()
+
+  for p in walkDirRec("walkdir_test"):
+    doAssert p.fileExists
+    doAssert p.startsWith("walkdir_test")
+
+  var s: seq[string]
+  for p in walkDirRec("walkdir_test", {pcFile}, {pcDir}, relative=true):
+    s.add(p)
+
+  doAssert s.len == 2
+  doAssert "a" / "b" / "file_1" in s
+  doAssert "a" / "file_2" in s
+
+  removeDir("walkdir_test")
+
 block normalizedPath:
   when defined(posix):
     block relative:
diff --git a/tests/stdlib/tospaths.nim b/tests/stdlib/tospaths.nim
index 9e2a5605c..bee9bab76 100644
--- a/tests/stdlib/tospaths.nim
+++ b/tests/stdlib/tospaths.nim
@@ -1,5 +1,4 @@
 discard """

-  file: "tospaths.nim"

   output: ""

 """

 # test the ospaths module

diff --git a/tests/stdlib/tosproc.nim b/tests/stdlib/tosproc.nim
new file mode 100644
index 000000000..9d57d4574
--- /dev/null
+++ b/tests/stdlib/tosproc.nim
@@ -0,0 +1,23 @@
+discard """
+  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/tparsesql.nim b/tests/stdlib/tparsesql.nim
index 126020ed6..8cf8fa848 100644
--- a/tests/stdlib/tparsesql.nim
+++ b/tests/stdlib/tparsesql.nim
@@ -1,7 +1,3 @@
-discard """
-  file: "tparsesql.nim"
-"""
-
 import parsesql
 
 doAssert $parseSQL("SELECT foo FROM table;") == "select foo from table;"
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 229035d22..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):
@@ -5,7 +9,7 @@ when not defined(windows):
   import posix
 
   var
-    u: Tutsname
+    u: Utsname
 
   discard uname(u)
 
@@ -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..1f9283ec4 100644
--- a/tests/stdlib/tquit.nim
+++ b/tests/stdlib/tquit.nim
@@ -1,3 +1,10 @@
+discard """
+output: '''
+just exiting...
+'''
+joinable: false
+"""
+
 # Test the new beforeQuit variable:
 
 proc myExit() {.noconv.} =
diff --git a/tests/stdlib/tregex.nim b/tests/stdlib/tregex.nim
index ae6714de1..21f4e6743 100644
--- a/tests/stdlib/tregex.nim
+++ b/tests/stdlib/tregex.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tregex.nim"
   output: "key: keyAYes!"
 """
 # Test the new regular expression module
@@ -27,5 +26,3 @@ else:
     echo("Bug!")
 
   #OUT key: keyAYes!
-
-
diff --git a/tests/stdlib/trepr.nim b/tests/stdlib/trepr.nim
index 18fe7e054..33cb581ef 100644
--- a/tests/stdlib/trepr.nim
+++ b/tests/stdlib/trepr.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "trepr.nim"
   output: "{a, b}{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}"
 """
 
@@ -26,4 +25,3 @@ when false:
 #  "a", "b", "c", "d", "e"
 #]
 #echo(repr(testseq))
-
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/tsqlparser.nim b/tests/stdlib/tsqlparser.nim
index 4a7b2f7d7..11ee22e2b 100644
--- a/tests/stdlib/tsqlparser.nim
+++ b/tests/stdlib/tsqlparser.nim
@@ -6,7 +6,7 @@ discard """
 
 import parsesql, streams, os
 
-var tree = parseSql(newFileStream(getAppDir() / "somesql.sql"), "somesql")
+var tree = parseSql(newFileStream(parentDir(currentSourcePath) / "somesql.sql"), "somesql")
 discard renderSql(tree)
 
 echo "true"
diff --git a/tests/stdlib/tissues.nim b/tests/stdlib/tstdlib_issues.nim
index b5a1c8206..b5a1c8206 100644
--- a/tests/stdlib/tissues.nim
+++ b/tests/stdlib/tstdlib_issues.nim
diff --git a/tests/stdlib/tvarious.nim b/tests/stdlib/tstdlib_various.nim
index 7abc9a391..d1723df78 100644
--- a/tests/stdlib/tvarious.nim
+++ b/tests/stdlib/tstdlib_various.nim
@@ -219,7 +219,7 @@ block tsplit2:
 
 block tsqlparser:
   # Just check that we can parse 'somesql' and render it without crashes.
-  var tree = parseSql(newFileStream(getAppDir() / "somesql.sql"), "somesql")
+  var tree = parseSql(newFileStream( parentDir(currentSourcePath) / "somesql.sql"), "somesql")
   discard renderSql(tree)
 
 
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/tstreams2.nim b/tests/stdlib/tstreams2.nim
index 90102d8e3..70f0bac32 100644
--- a/tests/stdlib/tstreams2.nim
+++ b/tests/stdlib/tstreams2.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tstreams2.nim"
   output: '''fs is: nil'''
 """
 import streams
diff --git a/tests/stdlib/tstreams3.nim b/tests/stdlib/tstreams3.nim
index b2c9170e3..e3b395e05 100644
--- a/tests/stdlib/tstreams3.nim
+++ b/tests/stdlib/tstreams3.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tstreams3.nim"
   output: "threw exception"
 """
 import streams
diff --git a/tests/stdlib/tstring.nim b/tests/stdlib/tstring.nim
index 660746150..852ff4fb7 100644
--- a/tests/stdlib/tstring.nim
+++ b/tests/stdlib/tstring.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tstring.nim"
   output: "OK"
 """
 const characters = "abcdefghijklmnopqrstuvwxyz"
diff --git a/tests/stdlib/tstrscans.nim b/tests/stdlib/tstrscans.nim
new file mode 100644
index 000000000..08fc14e45
--- /dev/null
+++ b/tests/stdlib/tstrscans.nim
@@ -0,0 +1,86 @@
+discard """
+  output: ""
+"""
+
+import strscans
+
+block ParsePasswd:
+  proc parsePasswd(content: string): seq[string] =
+    result = @[]
+    var idx = 0
+    while true:
+      var entry = ""
+      if scanp(content, idx, +(~{'\L', '\0'} -> entry.add($_)), '\L'):
+        result.add entry
+      else:
+        break
+
+  const etc_passwd = """root:x:0:0:root:/root:/bin/bash
+daemon:x:1:1:daemon:/usr/sbin:/bin/sh
+bin:x:2:2:bin:/bin:/bin/sh
+sys:x:3:3:sys:/dev:/bin/sh
+nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
+messagebus:x:103:107::/var/run/dbus:/bin/false
+"""
+
+  const parsed_etc_passwd = @[
+    "root:x:0:0:root:/root:/bin/bash",
+    "daemon:x:1:1:daemon:/usr/sbin:/bin/sh",
+    "bin:x:2:2:bin:/bin:/bin/sh",
+    "sys:x:3:3:sys:/dev:/bin/sh",
+    "nobody:x:65534:65534:nobody:/nonexistent:/bin/sh",
+    "messagebus:x:103:107::/var/run/dbus:/bin/false",
+    ]
+  doAssert etc_passwd.parsePasswd == parsed_etc_passwd
+
+block LastNot:
+  var idx : int
+
+  idx = 0
+  doAssert scanp("foo", idx,  'f', 'o', ~'a')
+
+  idx = 0
+  doAssert scanp("foo", idx,  'f', 'o', ~'o') == false
+
+  idx = 0
+  doAssert scanp("foox", idx,  'f', 'o', ~'o') == false
+
+  idx = 0
+  doAssert scanp("foox", idx,  'f', 'o', ~'a')
+
+block LastOptional:
+  var idx = 0
+  doAssert scanp("foo", idx, 'f', 'o', 'o', ?'o')
+
+block Tuple:
+  var idx = 0
+  doAssert scanp("foo", idx,  ('f', 'o', 'o'))
+
+block NotWithOptional:
+  var idx : int
+
+  idx = 0
+  doAssert scanp("bc", idx, ~(?'b', 'c')) == false
+
+  idx = 0
+  doAssert scanp("c", idx, ~(?'b', 'c')) == false
+
+  idx = 0
+  doAssert scanp("b", idx, ~(?'b', 'c'))
+
+block NotEmpty:
+  var idx = 0
+  doAssert scanp("", idx, ~()) == false
+
+block EmptyTuple:
+  var idx = 0
+  doAssert scanp("ab", idx, 'a', (), 'b')
+
+block Arrow:
+  let text = "foo;bar;baz;"
+  var idx = 0
+  var res = ""
+  doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';')
+  doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';')
+  doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';')
+  doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';') == false
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/tstrutil.nim b/tests/stdlib/tstrutil.nim
index 64b8f8ecc..fffa85bd1 100644
--- a/tests/stdlib/tstrutil.nim
+++ b/tests/stdlib/tstrutil.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tstrutil.nim"
   output: "ha/home/a1xyz/usr/bin"
 """
 # test the new strutils module
diff --git a/tests/stdlib/tsugar.nim b/tests/stdlib/tsugar.nim
index a870bf6fe..111ca96a4 100644
--- a/tests/stdlib/tsugar.nim
+++ b/tests/stdlib/tsugar.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tsugar.nim"
   output: ""
 """
 import sugar
diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim
index 660c9325f..ed87b15ac 100644
--- a/tests/stdlib/ttimes.nim
+++ b/tests/stdlib/ttimes.nim
@@ -1,8 +1,5 @@
 discard """
-  file: "ttimes.nim"
   target: "c js"
-  output: '''[Suite] ttimes
-'''
 """
 
 import times, strutils, unittest
@@ -84,6 +81,15 @@ template runTimezoneTests() =
     # formatting timezone as 'Z' for UTC
     parseTest("2001-01-12T22:04:05Z", "yyyy-MM-dd'T'HH:mm:ss" & tzFormat,
         "2001-01-12T22:04:05Z", 11)
+  # timezone offset formats
+  parseTest("2001-01-12T15:04:05 +7", "yyyy-MM-dd'T'HH:mm:ss z",
+      "2001-01-12T08:04:05Z", 11)
+  parseTest("2001-01-12T15:04:05 +07", "yyyy-MM-dd'T'HH:mm:ss zz",
+      "2001-01-12T08:04:05Z", 11)
+  parseTest("2001-01-12T15:04:05 +07:00", "yyyy-MM-dd'T'HH:mm:ss zzz",
+      "2001-01-12T08:04:05Z", 11)
+  parseTest("2001-01-12T15:04:05 +07:30:59", "yyyy-MM-dd'T'HH:mm:ss zzzz",
+      "2001-01-12T07:33:06Z", 11)
   # Kitchen     = "3:04PM"
   parseTestTimeOnly("3:04PM", "h:mmtt", "15:04:00")
 
@@ -116,7 +122,7 @@ suite "ttimes":
   when defined(linux) or defined(macosx):
     let tz_dir = getEnv("TZDIR", "/usr/share/zoneinfo")
     const f = "yyyy-MM-dd HH:mm zzz"
-    
+
     let orig_tz = getEnv("TZ")
     var tz_cnt = 0
     for tz_fn in walkFiles(tz_dir & "/**/*"):
@@ -143,7 +149,7 @@ suite "ttimes":
       check initDateTime(29, mOct, 2017, 01, 00, 00).isDst
       check initDateTime(29, mOct, 2017, 03, 01, 00).format(f) == "2017-10-29 03:01 +01:00"
       check (not initDateTime(29, mOct, 2017, 03, 01, 00).isDst)
-      
+
       check initDateTime(21, mOct, 2017, 01, 00, 00).format(f) == "2017-10-21 01:00 +02:00"
 
     test "issue #6520":
@@ -161,10 +167,10 @@ suite "ttimes":
       check diff == initDuration(seconds = 2208986872)
 
     test "issue #6465":
-      putEnv("TZ", "Europe/Stockholm")      
+      putEnv("TZ", "Europe/Stockholm")
       let dt = parse("2017-03-25 12:00", "yyyy-MM-dd hh:mm")
       check $(dt + initTimeInterval(days = 1)) == "2017-03-26T12:00:00+02:00"
-      check $(dt + initDuration(days = 1)) == "2017-03-26T13:00:00+02:00"      
+      check $(dt + initDuration(days = 1)) == "2017-03-26T13:00:00+02:00"
 
     test "datetime before epoch":
       check $fromUnix(-2147483648).utc == "1901-12-13T20:45:52Z"
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/helpers/readall_echo.nim b/tests/system/helpers/readall_echo.nim
index 79937bf6f..2891ef3ae 100644
--- a/tests/system/helpers/readall_echo.nim
+++ b/tests/system/helpers/readall_echo.nim
@@ -1,2 +1,2 @@
-when isMainModule:
+when true:
   echo(stdin.readAll)
diff --git a/tests/system/t7894.nim b/tests/system/t7894.nim
index 2808e5020..b7ca1eec8 100644
--- a/tests/system/t7894.nim
+++ b/tests/system/t7894.nim
@@ -1,18 +1,25 @@
 discard """
+disabled: "travis"
+disabled: "appveyor"
+joinable: false
 """
 
-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..7e0dec9d3 100644
--- a/tests/system/talloc2.nim
+++ b/tests/system/talloc2.nim
@@ -1,6 +1,10 @@
 discard """
+disabled: "windows"
+joinable: false
 """
 
+# 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/tostring.nim b/tests/system/tostring.nim
index 04b37f133..ea4a44417 100644
--- a/tests/system/tostring.nim
+++ b/tests/system/tostring.nim
@@ -1,5 +1,5 @@
 discard """
-  output: ""
+  output: "DONE: tostring.nim"
 """
 
 doAssert "@[23, 45]" == $(@[23, 45])
@@ -115,3 +115,6 @@ block:
   var s: string
   s.addQuoted a2
   doAssert s == "\"fo\\\"o2\""
+
+
+echo "DONE: tostring.nim"
diff --git a/tests/system/tparams.nim b/tests/system/tparams.nim
index dd5511b8f..dcd620b20 100644
--- a/tests/system/tparams.nim
+++ b/tests/system/tparams.nim
@@ -1,6 +1,8 @@
 discard """
+joinable: false
 """
 
+# not joinable because it executes itself with parameters
 import os
 import osproc
 import parseopt2
@@ -13,7 +15,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/system/trealloc.nim b/tests/system/trealloc.nim
index dc5f712d6..7180b8eda 100644
--- a/tests/system/trealloc.nim
+++ b/tests/system/trealloc.nim
@@ -1,5 +1,6 @@
 discard """
   output: '''success'''
+  joinable: false
 """
 
 # bug #4818
diff --git a/tests/template/sunset.tmpl b/tests/template/sunset.nimf
index 465b12a5e..465b12a5e 100644
--- a/tests/template/sunset.tmpl
+++ b/tests/template/sunset.nimf
diff --git a/tests/template/t2416.nim b/tests/template/t2416.nim
deleted file mode 100644
index f73880718..000000000
--- a/tests/template/t2416.nim
+++ /dev/null
@@ -1,2 +0,0 @@
-import i2416
-i2416()
diff --git a/tests/template/t2do.nim b/tests/template/t2do.nim
deleted file mode 100644
index f5f6393dc..000000000
--- a/tests/template/t2do.nim
+++ /dev/null
@@ -1,23 +0,0 @@
-discard """
-  output: "8.0"
-"""
-
-# bug #2057
-
-proc mpf_get_d(x: int): float = float(x)
-proc mpf_cmp_d(a: int; b: float): int = 0
-
-template toFloatHelper(result, tooSmall, tooLarge: untyped) =
-  result = mpf_get_d(a)
-  if result == 0.0 and mpf_cmp_d(a,0.0) != 0:
-    tooSmall
-  if result == Inf:
-    tooLarge
-
-proc toFloat*(a: int): float =
-  toFloatHelper(result) do:
-    raise newException(ValueError, "number too small")
-  do:
-    raise newException(ValueError, "number too large")
-
-echo toFloat(8)
diff --git a/tests/template/t_otemplates.nim b/tests/template/t_otemplates.nim
index 6597bd37a..8d2ac38a6 100644
--- a/tests/template/t_otemplates.nim
+++ b/tests/template/t_otemplates.nim
@@ -340,6 +340,6 @@ macro tmpl*(body: untyped): untyped =
 
 
 # Run tests
-when isMainModule:
+when true:
     include otests
     echo "Success"
diff --git a/tests/template/tcan_access_hidden_field.nim b/tests/template/tcan_access_hidden_field.nim
deleted file mode 100644
index a6f6490cc..000000000
--- a/tests/template/tcan_access_hidden_field.nim
+++ /dev/null
@@ -1,9 +0,0 @@
-discard """
-  output: 33
-"""
-
-import mcan_access_hidden_field
-
-var myfoo = createFoo(33, 44)
-
-echo myfoo.geta
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/tdefault_nil.nim b/tests/template/tdefault_nil.nim
deleted file mode 100644
index 783f77388..000000000
--- a/tests/template/tdefault_nil.nim
+++ /dev/null
@@ -1,14 +0,0 @@
-
-# bug #2629
-import sequtils, os
-
-template glob_rst(basedir: string = ""): untyped =
-  if baseDir.len == 0:
-    to_seq(walk_files("*.rst"))
-  else:
-    to_seq(walk_files(basedir/"*.rst"))
-
-let
-  rst_files = concat(glob_rst(), glob_rst("docs"))
-
-when isMainModule: echo rst_files
diff --git a/tests/template/template_issues.nim b/tests/template/template_issues.nim
new file mode 100644
index 000000000..15d6ab2b1
--- /dev/null
+++ b/tests/template/template_issues.nim
@@ -0,0 +1,209 @@
+discard """
+output: '''
+@[]
+5
+0
+a
+hi
+'''
+"""
+
+
+import macros, json
+
+
+block t2057:
+  proc mpf_get_d(x: int): float = float(x)
+  proc mpf_cmp_d(a: int; b: float): int = 0
+
+  template toFloatHelper(result, tooSmall, tooLarge: untyped) =
+    result = mpf_get_d(a)
+    if result == 0.0 and mpf_cmp_d(a,0.0) != 0:
+      tooSmall
+    if result == Inf:
+      tooLarge
+
+  proc toFloat(a: int): float =
+    toFloatHelper(result) do:
+      raise newException(ValueError, "number too small")
+    do:
+      raise newException(ValueError, "number too large")
+
+  doAssert toFloat(8) == 8.0
+
+
+
+import sequtils, os
+block t2629:
+  template glob_rst(basedir: string = ""): untyped =
+    if baseDir.len == 0:
+      to_seq(walk_files("*.rst"))
+    else:
+      to_seq(walk_files(basedir/"*.rst"))
+
+  let rst_files = concat(glob_rst(), glob_rst("docs"))
+
+  when true: echo rst_files
+
+
+block t5417:
+  macro genBody: untyped =
+    let sbx = genSym(nskLabel, "test")
+    when true:
+      result = quote do:
+        block `sbx`:
+          break `sbx`
+    else:
+      template foo(s1, s2) =
+        block s1:
+          break s2
+      result = getAst foo(sbx, sbx)
+
+  proc test() =
+    genBody()
+
+
+
+block t909:
+  template baz() =
+    proc bar() =
+      var x = 5
+      iterator foo(): int {.closure.} =
+        echo x
+      var y = foo
+      discard y()
+
+  macro test(): untyped =
+    result = getAst(baz())
+
+  test()
+  bar()
+
+
+
+block t993:
+  type PNode = ref object of RootObj
+
+  template litNode(name, ty)  =
+    type name = ref object of PNode
+      val: ty
+  litNode PIntNode, int
+
+  template withKey(j: JsonNode; key: string; varname,
+                    body: untyped): typed =
+    if j.hasKey(key):
+      let varname{.inject.}= j[key]
+      block:
+        body
+
+  var j = parsejson("{\"zzz\":1}")
+  withkey(j, "foo", x):
+    echo(x)
+
+
+
+
+block t1337:
+  template someIt(a, pred): untyped =
+    var it {.inject.} = 0
+    pred
+
+  proc aProc(n: auto) =
+    n.someIt(echo(it))
+
+  aProc(89)
+
+
+
+import mlt
+block t4564:
+  type Bar = ref object of RootObj
+  proc foo(a: Bar): int = 0
+  var a: Bar
+  let b = a.foo() > 0
+
+
+
+block t8052:
+  type
+    UintImpl[N: static[int], T: SomeUnsignedInt] = object
+      raw_data: array[N, T]
+
+  template genLoHi(TypeImpl: untyped): untyped =
+    template loImpl[N: static[int], T: SomeUnsignedInt](dst: TypeImpl[N div 2, T], src: TypeImpl[N, T]) =
+      let halfSize = N div 2
+      for i in 0 ..< halfSize:
+        dst.raw_data[i] = src.raw_data[i]
+
+    proc lo[N: static[int], T: SomeUnsignedInt](x: TypeImpl[N,T]): TypeImpl[N div 2, T] {.inline.}=
+      loImpl(result, x)
+
+  genLoHi(UintImpl)
+
+  var a: UintImpl[4, uint32]
+
+  a.raw_data = [1'u32, 2'u32, 3'u32, 4'u32]
+  doAssert a.lo.raw_data.len == 2
+  doAssert a.lo.raw_data[0] == 1
+  doAssert a.lo.raw_data[1] == 2
+
+
+
+block t2585:
+  type
+    RenderPass = object
+       state: ref int
+    RenderData = object
+        fb: int
+        walls: seq[RenderPass]
+    Mat2 = int
+    Vector2[T] = T
+    Pixels=int
+
+  template use(fb: int, st: untyped): untyped =
+      echo "a ", $fb
+      st
+      echo "a ", $fb
+
+  proc render(rdat: var RenderData; passes: var openarray[RenderPass]; proj: Mat2;
+              indexType = 1) =
+      for i in 0 ..< len(passes):
+          echo "blah ", repr(passes[i])
+
+  proc render2(rdat: var RenderData; screenSz: Vector2[Pixels]; proj: Mat2) =
+      use rdat.fb:
+          render(rdat, rdat.walls, proj, 1)
+
+
+
+block t4292:
+  template foo(s: string): string = s
+  proc variadicProc(v: varargs[string, foo]) = echo v[0]
+  variadicProc("a")
+
+
+
+block t2670:
+  template testTemplate(b: bool): typed =
+    when b:
+        var a = "hi"
+    else:
+        var a = 5
+    echo a
+  testTemplate(true)
+
+
+
+block t4097:
+  var i {.compileTime.} = 2
+
+  template defineId(t: typedesc) =
+    const id {.genSym.} = i
+    static: inc(i)
+    proc idFor(T: typedesc[t]): int {.inline, raises: [].} = id
+
+  defineId(int8)
+  defineId(int16)
+
+  doAssert idFor(int8) == 2
+  doAssert idFor(int16) == 3
\ No newline at end of file
diff --git a/tests/template/template_various.nim b/tests/template/template_various.nim
new file mode 100644
index 000000000..029942621
--- /dev/null
+++ b/tests/template/template_various.nim
@@ -0,0 +1,251 @@
+discard """
+output: '''
+i2416
+33
+foo55
+foo8.0
+fooaha
+bar7
+immediate
+10
+4true
+132
+'''
+"""
+
+import macros
+
+
+
+
+import i2416
+i2416()
+
+
+import mcan_access_hidden_field
+var myfoo = createFoo(33, 44)
+echo myfoo.geta
+
+
+import mgensym_generic_cross_module
+foo(55)
+foo 8.0
+foo "aha"
+bar 7
+
+
+
+block generic_templates:
+  type
+    SomeObj = object of RootObj
+    Foo[T, U] = object
+      x: T
+      y: U
+
+  template someTemplate[T](): tuple[id: int32, obj: T] =
+    var result: tuple[id: int32, obj: T] = (0'i32, T())
+    result
+
+  let ret = someTemplate[SomeObj]()
+
+  # https://github.com/nim-lang/Nim/issues/7829
+  proc inner[T](): int =
+    discard
+
+  template outer[A](): untyped =
+    inner[A]()
+
+  template outer[B](x: int): untyped =
+    inner[B]()
+
+  var i1 = outer[int]()
+  var i2 = outer[int](i1)
+
+  # https://github.com/nim-lang/Nim/issues/7883
+  template t1[T: int|int64](s: string): T =
+     var t: T
+     t
+
+  template t1[T: int|int64](x: int, s: string): T =
+     var t: T
+     t
+
+  var i3: int = t1[int]("xx")
+
+
+
+block tgetast_typeliar:
+  proc error(s: string) = quit s
+
+  macro assertOrReturn(condition: bool; message: string): typed =
+    var line = condition.lineInfo()
+    result = quote do:
+      block:
+        if not likely(`condition`):
+          error("Assertion failed: " & $(`message`) & "\n" & `line`)
+          return
+
+  macro assertOrReturn(condition: bool): typed =
+    var message = condition.toStrLit()
+    result = getAst assertOrReturn(condition, message)
+
+  proc point(size: int16): tuple[x, y: int16] =
+    # returns random point in square area with given `size`
+    assertOrReturn size > 0
+
+
+
+type
+  MyFloat = object
+    val: float
+converter to_myfloat(x: float): MyFloat {.inline.} =
+  MyFloat(val: x)
+
+block pattern_with_converter:
+  proc `+`(x1, x2: MyFloat): MyFloat =
+    MyFloat(val: x1.val + x2.val)
+
+  proc `*`(x1, x2: MyFloat): MyFloat =
+      MyFloat(val: x1.val * x2.val)
+
+  template optMul{`*`(a, 2.0)}(a: MyFloat): MyFloat =
+    a + a
+
+  func floatMyFloat(x: MyFloat): MyFloat =
+    result = x * 2.0
+
+  func floatDouble(x: float): float =
+    result = x * 2.0
+
+  doAssert floatDouble(5) == 10.0
+
+
+
+block prefer_immediate:
+  # Test that immediate templates are preferred over non-immediate templates
+
+  template foo(a, b: untyped) = echo "foo expr"
+  template foo(a, b: int) = echo "foo int"
+  template foo(a, b: float) = echo "foo float"
+  template foo(a, b: string) = echo "foo string"
+  template foo(a, b: untyped) {.immediate.} = echo "immediate"
+  template foo(a, b: bool) = echo "foo bool"
+  template foo(a, b: char) = echo "foo char"
+
+  foo(undeclaredIdentifier, undeclaredIdentifier2)
+
+
+
+
+block procparshadow:
+  template something(name: untyped) =
+    proc name(x: int) =
+      var x = x # this one should not be rejected by the compiler (#5225)
+      echo x
+
+  something(what)
+  what(10)
+
+  # bug #4750
+  type
+    O = object
+      i: int
+    OP = ptr O
+
+  template alf(p: pointer): untyped =
+    cast[OP](p)
+
+  proc t1(al: pointer) =
+    var o = alf(al)
+
+  proc t2(alf: pointer) =
+    var x = alf
+    var o = alf(x)
+
+
+
+block symchoicefield:
+  type Foo = object
+    len: int
+
+  var f = Foo(len: 40)
+
+  template getLen(f: Foo): int = f.len
+
+  doAssert f.getLen == 40
+  # This fails, because `len` gets the nkOpenSymChoice
+  # treatment inside the template early pass and then
+  # it can't be recognized as a field anymore
+
+
+
+import os, times
+include "sunset.nimf"
+block ttempl:
+  const
+    tabs = [["home", "index"],
+            ["news", "news"],
+            ["documentation", "documentation"],
+            ["download", "download"],
+            ["FAQ", "question"],
+            ["links", "links"]]
+
+
+  var i = 0
+  for item in items(tabs):
+    var content = $i
+    var file: File
+    if open(file, changeFileExt(item[1], "html"), fmWrite):
+      write(file, sunsetTemplate(current=item[1], ticker="", content=content,
+                                  tabs=tabs))
+      close(file)
+    else:
+      write(stdout, "cannot open file for writing")
+    inc(i)
+
+
+
+block ttempl4:
+  template `:=`(name, val: untyped): typed =
+    var name = val
+
+  ha := 1 * 4
+  hu := "ta-da" == "ta-da"
+  echo ha, hu
+
+
+
+
+import mtempl5
+block ttempl5:
+  echo templ()
+
+  #bug #892
+  proc parse_to_close(value: string, index: int, open='(', close=')'): int =
+      discard
+
+  # Call parse_to_close
+  template get_next_ident: typed =
+      discard "{something}".parse_to_close(0, open = '{', close = '}')
+
+  get_next_ident()
+
+  #identifier expected, but found '(open|open|open)'
+  #bug #880 (also example in the manual!)
+  template typedef(name: untyped, typ: typedesc) =
+    type
+      `T name` {.inject.} = typ
+      `P name` {.inject.} = ref `T name`
+
+  typedef(myint, int)
+  var x: PMyInt
+
+
+
+block templreturntype:
+  template `=~` (a: int, b: int): bool = false
+  var foo = 2 =~ 3
+
+
+
+
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/tgenerictemplates.nim b/tests/template/tgenerictemplates.nim
deleted file mode 100644
index 142505b1a..000000000
--- a/tests/template/tgenerictemplates.nim
+++ /dev/null
@@ -1,37 +0,0 @@
-type
-  SomeObj = object of RootObj
-
-  Foo[T, U] = object
-    x: T
-    y: U
-
-template someTemplate[T](): tuple[id: int32, obj: T] =
-  var result: tuple[id: int32, obj: T] = (0'i32, T())
-  result
-
-let ret = someTemplate[SomeObj]()
-
-# https://github.com/nim-lang/Nim/issues/7829
-proc inner*[T](): int =
-  discard
-
-template outer*[A](): untyped =
-  inner[A]()
-
-template outer*[B](x: int): untyped =
-  inner[B]()
-
-var i1 = outer[int]()
-var i2 = outer[int](i1)
-
-# https://github.com/nim-lang/Nim/issues/7883
-template t1[T: int|int64](s: string): T =
-   var t: T
-   t
-
-template t1[T: int|int64](x: int, s: string): T =
-   var t: T
-   t
-
-var i3: int = t1[int]("xx")
-
diff --git a/tests/template/tgensym_generic_cross_module.nim b/tests/template/tgensym_generic_cross_module.nim
deleted file mode 100644
index 856ab676d..000000000
--- a/tests/template/tgensym_generic_cross_module.nim
+++ /dev/null
@@ -1,14 +0,0 @@
-discard """
-  output: '''foo55
-foo8.0
-fooaha
-bar7'''
-"""
-# bug #5419
-import mgensym_generic_cross_module
-
-foo(55)
-foo 8.0
-foo "aha"
-bar 7
-
diff --git a/tests/template/tgensym_label.nim b/tests/template/tgensym_label.nim
deleted file mode 100644
index fd3b0a1ee..000000000
--- a/tests/template/tgensym_label.nim
+++ /dev/null
@@ -1,18 +0,0 @@
-
-# bug #5417
-import macros
-
-macro genBody: untyped =
-  let sbx = genSym(nskLabel, "test")
-  when true:
-    result = quote do:
-      block `sbx`:
-        break `sbx`
-  else:
-    template foo(s1, s2) =
-      block s1:
-        break s2
-    result = getAst foo(sbx, sbx)
-
-proc test() =
-  genBody()
diff --git a/tests/template/tgensymregression.nim b/tests/template/tgensymregression.nim
index 4cc64a831..4194e3e88 100644
--- a/tests/template/tgensymregression.nim
+++ b/tests/template/tgensymregression.nim
@@ -15,7 +15,7 @@ template mathPerComponent(op: untyped): untyped =
 mathPerComponent(`***`)
 # bug #5285
 when true:
-  if isMainModule:
+  if true:
     var v1: array[3, float64]
     var v2: array[3, float64]
     echo repr(v1 *** v2)
diff --git a/tests/template/tgetast_typeliar.nim b/tests/template/tgetast_typeliar.nim
deleted file mode 100644
index c9a612582..000000000
--- a/tests/template/tgetast_typeliar.nim
+++ /dev/null
@@ -1,23 +0,0 @@
-
-# just ensure this keeps compiling:
-
-import macros
-
-proc error(s: string) = quit s
-
-macro assertOrReturn*(condition: bool; message: string): typed =
-  var line = condition.lineInfo()
-  result = quote do:
-    block:
-      if not likely(`condition`):
-        error("Assertion failed: " & $(`message`) & "\n" & `line`)
-        return
-
-macro assertOrReturn*(condition: bool): typed =
-  var message = condition.toStrLit()
-  result = getAst assertOrReturn(condition, message)
-
-proc point*(size: int16): tuple[x, y: int16] =
-  # returns random point in square area with given `size`
-
-  assertOrReturn size > 0
diff --git a/tests/template/thygienictempl.nim b/tests/template/thygienictempl.nim
index de40450aa..9020c3e28 100644
--- a/tests/template/thygienictempl.nim
+++ b/tests/template/thygienictempl.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 
 var
   e = "abc"
@@ -14,5 +18,5 @@ template test_in(a, b, c: untyped): bool {.dirty.} =
   var result {.gensym.}: bool = false
   false
 
-when isMainModule:
+when true:
   assert test_in(ret2, "test", str_val)
diff --git a/tests/template/tissue909.nim b/tests/template/tissue909.nim
deleted file mode 100644
index 6786ff48c..000000000
--- a/tests/template/tissue909.nim
+++ /dev/null
@@ -1,16 +0,0 @@
-import macros
-
-template baz() =
-  proc bar() =
-    var x = 5
-    iterator foo(): int {.closure.} =
-      echo x
-    var y = foo
-    discard y()
-
-macro test(): untyped =
-  result = getAst(baz())
-  echo(treeRepr(result))
-
-test()
-bar()
diff --git a/tests/template/tissue993.nim b/tests/template/tissue993.nim
deleted file mode 100644
index 552890bb4..000000000
--- a/tests/template/tissue993.nim
+++ /dev/null
@@ -1,20 +0,0 @@
-
-type PNode* = ref object of RootObj
-
-template litNode(name, ty)  =
-  type name* = ref object of PNode
-    val*: ty
-litNode PIntNode, int
-
-import json
-
-template withKey*(j: JsonNode; key: string; varname,
-                  body: untyped): typed =
-  if j.hasKey(key):
-    let varname{.inject.}= j[key]
-    block:
-      body
-
-var j = parsejson("{\"zzz\":1}")
-withkey(j, "foo", x):
-  echo(x)
diff --git a/tests/template/tit.nim b/tests/template/tit.nim
deleted file mode 100644
index 76b1d151b..000000000
--- a/tests/template/tit.nim
+++ /dev/null
@@ -1,11 +0,0 @@
-
-# bug #1337
-
-template someIt(a, pred): untyped =
-  var it {.inject.} = 0
-  pred
-
-proc aProc(n: auto) =
-  n.someIt(echo(it))
-
-aProc(89)
diff --git a/tests/template/tlt.nim b/tests/template/tlt.nim
deleted file mode 100644
index 75c7dd991..000000000
--- a/tests/template/tlt.nim
+++ /dev/null
@@ -1,7 +0,0 @@
-
-import mlt
-# bug #4564
-type Bar* = ref object of RootObj
-proc foo(a: Bar): int = 0
-var a: Bar
-let b = a.foo() > 0
diff --git a/tests/template/tnested_template.nim b/tests/template/tnested_template.nim
deleted file mode 100644
index 37166009d..000000000
--- a/tests/template/tnested_template.nim
+++ /dev/null
@@ -1,23 +0,0 @@
-# bug #8052
-
-type
-  UintImpl*[N: static[int], T: SomeUnsignedInt] = object
-    raw_data*: array[N, T]
-
-template genLoHi(TypeImpl: untyped): untyped =
-  template loImpl[N: static[int], T: SomeUnsignedInt](dst: TypeImpl[N div 2, T], src: TypeImpl[N, T]) =
-    let halfSize = N div 2
-    for i in 0 ..< halfSize:
-      dst.raw_data[i] = src.raw_data[i]
-
-  proc lo*[N: static[int], T: SomeUnsignedInt](x: TypeImpl[N,T]): TypeImpl[N div 2, T] {.inline.}=
-    loImpl(result, x)
-
-genLoHi(UintImpl)
-
-var a: UintImpl[4, uint32]
-
-a.raw_data = [1'u32, 2'u32, 3'u32, 4'u32]
-assert a.lo.raw_data.len == 2
-assert a.lo.raw_data[0] == 1
-assert a.lo.raw_data[1] == 2
diff --git a/tests/template/tparams_gensymed.nim b/tests/template/tparams_gensymed.nim
index 3fb0dd4a5..91fa26596 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
@@ -59,3 +70,43 @@ proc genericProc(x: any) =
 
 concreteProc(7) # This works
 genericProc(7)  # This doesn't compile
+
+import tables
+
+# bug #9476
+proc getTypeInfo*(T: typedesc): pointer =
+  var dummy: T
+  getTypeInfo(dummy)
+
+
+macro implementUnary(op: untyped): untyped =
+  result = newStmtList()
+
+  template defineTable(tableSymbol) =
+    var tableSymbol = initTable[pointer, pointer]()
+  let tableSymbol = genSym(nskVar, "registeredProcs")
+  result.add(getAst(defineTable(tableSymbol)))
+
+  template defineRegisterInstantiation(tableSym, regTemplSym, instSym, op) =
+    template regTemplSym*(T: typedesc) =
+      let ti = getTypeInfo(T)
+
+      proc instSym(xOrig: int): int {.gensym, cdecl.} =
+        let x {.inject.} = xOrig
+        op
+
+      tableSym[ti] = cast[pointer](instSym)
+
+  let regTemplSymbol = ident("registerInstantiation")
+  let instSymbol = ident("instantiation")
+  result.add(getAst(defineRegisterInstantiation(
+    tableSymbol, regTemplSymbol, instSymbol, op
+  )))
+
+  echo result.repr
+
+
+implementUnary(): x*x
+
+registerInstantiation(int)
+registerInstantiation(float)
diff --git a/tests/template/tpattern_with_converter.nim b/tests/template/tpattern_with_converter.nim
deleted file mode 100644
index e0632552b..000000000
--- a/tests/template/tpattern_with_converter.nim
+++ /dev/null
@@ -1,27 +0,0 @@
-discard """
-  output: 10.0
-"""
-
-type
-  MyFloat = object
-    val: float
-
-converter to_myfloat*(x: float): MyFloat {.inline.} =
-  MyFloat(val: x)
-
-proc `+`(x1, x2: MyFloat): MyFloat =
-  MyFloat(val: x1.val + x2.val)
-
-proc `*`(x1, x2: MyFloat): MyFloat =
-    MyFloat(val: x1.val * x2.val)
-
-template optMul{`*`(a, 2.0)}(a: MyFloat): MyFloat =
-  a + a
-
-func floatMyFloat(x: MyFloat): MyFloat =
-  result = x * 2.0
-
-func floatDouble(x: float): float =
-  result = x * 2.0
-
-echo floatDouble(5)
\ No newline at end of file
diff --git a/tests/template/tprefer_immediate.nim b/tests/template/tprefer_immediate.nim
deleted file mode 100644
index 3a4cfc07b..000000000
--- a/tests/template/tprefer_immediate.nim
+++ /dev/null
@@ -1,15 +0,0 @@
-discard """
-  output: '''immediate'''
-"""
-
-# Test that immediate templates are preferred over non-immediate templates
-
-template foo(a, b: untyped) = echo "foo expr"
-template foo(a, b: int) = echo "foo int"
-template foo(a, b: float) = echo "foo float"
-template foo(a, b: string) = echo "foo string"
-template foo(a, b: untyped) {.immediate.} = echo "immediate"
-template foo(a, b: bool) = echo "foo bool"
-template foo(a, b: char) = echo "foo char"
-
-foo(undeclaredIdentifier, undeclaredIdentifier2)
diff --git a/tests/template/tprocparshadow.nim b/tests/template/tprocparshadow.nim
deleted file mode 100644
index de1c2d941..000000000
--- a/tests/template/tprocparshadow.nim
+++ /dev/null
@@ -1,30 +0,0 @@
-discard """
-  output: "10"
-"""
-
-template something(name: untyped) =
-  proc name(x: int) =
-    var x = x # this one should not be rejected by the compiler (#5225)
-    echo x
-
-something(what)
-what(10)
-
-# bug #4750
-
-type
-  O = object
-    i: int
-
-  OP = ptr O
-
-template alf(p: pointer): untyped =
-  cast[OP](p)
-
-
-proc t1(al: pointer) =
-  var o = alf(al)
-
-proc t2(alf: pointer) =
-  var x = alf
-  var o = alf(x)
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/tstmt_semchecked_twice.nim b/tests/template/tstmt_semchecked_twice.nim
deleted file mode 100644
index c6463ae06..000000000
--- a/tests/template/tstmt_semchecked_twice.nim
+++ /dev/null
@@ -1,30 +0,0 @@
-
-# bug #2585
-
-type
-    RenderPass = object
-       state: ref int
-
-    RenderData* = object
-        fb: int
-        walls: seq[RenderPass]
-
-    Mat2 = int
-    Vector2[T] = T
-    Pixels=int
-
-template use*(fb: int, st: untyped): untyped =
-    echo "a ", $fb
-    st
-    echo "a ", $fb
-
-proc render(rdat: var RenderData; passes: var openarray[RenderPass]; proj: Mat2;
-            indexType = 1) =
-    for i in 0 .. <len(passes):
-        echo "blah ", repr(passes[i])
-
-
-
-proc render2*(rdat: var RenderData; screenSz: Vector2[Pixels]; proj: Mat2) =
-    use rdat.fb:
-        render(rdat, rdat.walls, proj, 1)
diff --git a/tests/template/tsymchoicefield.nim b/tests/template/tsymchoicefield.nim
deleted file mode 100644
index 4483c2aa2..000000000
--- a/tests/template/tsymchoicefield.nim
+++ /dev/null
@@ -1,11 +0,0 @@
-type Foo = object
-  len: int
-
-var f = Foo(len: 40)
-
-template getLen(f: Foo): int = f.len
-
-echo f.getLen
-# This fails, because `len` gets the nkOpenSymChoice
-# treatment inside the template early pass and then
-# it can't be recognized as a field anymore
diff --git a/tests/template/ttemp_in_varargs.nim b/tests/template/ttemp_in_varargs.nim
deleted file mode 100644
index be78e6ef2..000000000
--- a/tests/template/ttemp_in_varargs.nim
+++ /dev/null
@@ -1,9 +0,0 @@
-discard """
-  output: '''a'''
-"""
-
-# bug #4292
-
-template foo(s: string): string = s
-proc variadicProc*(v: varargs[string, foo]) = echo v[0]
-variadicProc("a")
diff --git a/tests/template/ttempl.nim b/tests/template/ttempl.nim
deleted file mode 100644
index c022201f2..000000000
--- a/tests/template/ttempl.nim
+++ /dev/null
@@ -1,27 +0,0 @@
-# Test the new template file mechanism
-
-import
-  os, times
-
-include "sunset.tmpl"
-
-const
-  tabs = [["home", "index"],
-          ["news", "news"],
-          ["documentation", "documentation"],
-          ["download", "download"],
-          ["FAQ", "question"],
-          ["links", "links"]]
-
-
-var i = 0
-for item in items(tabs):
-  var content = $i
-  var file: File
-  if open(file, changeFileExt(item[1], "html"), fmWrite):
-    write(file, sunsetTemplate(current=item[1], ticker="", content=content,
-                               tabs=tabs))
-    close(file)
-  else:
-    write(stdout, "cannot open file for writing")
-  inc(i)
diff --git a/tests/template/ttempl2.nim b/tests/template/ttempl2.nim
index aaa2f1344..eb67bea0c 100644
--- a/tests/template/ttempl2.nim
+++ b/tests/template/ttempl2.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "undeclared identifier: \'b\'"
   file: "ttempl2.nim"
   line: 18
-  errormsg: "undeclared identifier: \'b\'"
 """
 template declareInScope(x: untyped, t: typeDesc): untyped {.immediate.} =
   var x: t
@@ -16,4 +16,3 @@ a = 42  # works, `a` is known here
 
 declareInNewScope(b, int)
 b = 42  #ERROR_MSG undeclared identifier: 'b'
-
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/template/ttempl4.nim b/tests/template/ttempl4.nim
deleted file mode 100644
index d1d26385f..000000000
--- a/tests/template/ttempl4.nim
+++ /dev/null
@@ -1,7 +0,0 @@
-
-template `:=`(name, val: untyped): typed =
-  var name = val
-
-ha := 1 * 4
-hu := "ta-da" == "ta-da"
-echo ha, hu
diff --git a/tests/template/ttempl5.nim b/tests/template/ttempl5.nim
deleted file mode 100644
index fd3ea0cad..000000000
--- a/tests/template/ttempl5.nim
+++ /dev/null
@@ -1,28 +0,0 @@
-
-import mtempl5
-
-echo templ()
-
-#bug #892
-
-proc parse_to_close(value: string, index: int, open='(', close=')'): int =
-    discard
-
-# Call parse_to_close
-template get_next_ident: typed =
-    discard "{something}".parse_to_close(0, open = '{', close = '}')
-
-get_next_ident()
-
-
-#identifier expected, but found '(open|open|open)'
-
-#bug #880 (also example in the manual!)
-
-template typedef(name: untyped, typ: typedesc) =
-  type
-    `T name`* {.inject.} = typ
-    `P name`* {.inject.} = ref `T name`
-
-typedef(myint, int)
-var x: PMyInt
diff --git a/tests/template/ttemplreturntype.nim b/tests/template/ttemplreturntype.nim
deleted file mode 100644
index 642fa1b72..000000000
--- a/tests/template/ttemplreturntype.nim
+++ /dev/null
@@ -1,4 +0,0 @@
-
-template `=~` (a: int, b: int): bool = false
-var foo = 2 =~ 3
-
diff --git a/tests/template/twhen_gensym.nim b/tests/template/twhen_gensym.nim
deleted file mode 100644
index f1a8d0eb7..000000000
--- a/tests/template/twhen_gensym.nim
+++ /dev/null
@@ -1,13 +0,0 @@
-discard """
-  output: "hi"
-"""
-
-# bug #2670
-template testTemplate(b: bool): typed =
-    when b:
-        var a = "hi"
-    else:
-        var a = 5
-    echo a
-
-testTemplate(true)
diff --git a/tests/template/twrongopensymchoice.nim b/tests/template/twrongopensymchoice.nim
index 360c92037..7a2bb48d3 100644
--- a/tests/template/twrongopensymchoice.nim
+++ b/tests/template/twrongopensymchoice.nim
@@ -20,5 +20,5 @@ proc main =
   var f = Foo.new()
   echo f.b
 
-when isMainModule:
+when true:
   main()
diff --git a/tests/template/typedescids.nim b/tests/template/typedescids.nim
deleted file mode 100644
index 1df2f69fb..000000000
--- a/tests/template/typedescids.nim
+++ /dev/null
@@ -1,17 +0,0 @@
-discard """
-  output: '''2 3'''
-"""
-
-# bug #4097
-
-var i {.compileTime.} = 2
-
-template defineId*(t: typedesc) =
-  const id {.genSym.} = i
-  static: inc(i)
-  proc idFor*(T: typedesc[t]): int {.inline, raises: [].} = id
-
-defineId(int8)
-defineId(int16)
-
-echo idFor(int8), " ", idFor(int16)
diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims
index d3eb9808e..b9a6097c2 100644
--- a/tests/test_nimscript.nims
+++ b/tests/test_nimscript.nims
@@ -9,7 +9,7 @@ import lists
 import math
 # import marshal
 import options
-import ospaths
+import os
 # import parsecfg
 # import parseopt
 import parseutils
diff --git a/tests/testament/tshouldfail.nim b/tests/testament/tshouldfail.nim
new file mode 100644
index 000000000..d35dd99ac
--- /dev/null
+++ b/tests/testament/tshouldfail.nim
@@ -0,0 +1,31 @@
+discard """
+cmd: "testament/tester --directory:testament --colors:off --backendLogging:off --nim:../compiler/nim category shouldfail"
+action: compile
+nimout: '''
+FAIL: tccodecheck.nim C
+Failure: reCodegenFailure
+Expected:
+baz
+FAIL: tcolumn.nim C
+Failure: reLinesDiffer
+FAIL: terrormsg.nim C
+Failure: reMsgsDiffer
+FAIL: texitcode1.nim C
+Failure: reExitcodesDiffer
+FAIL: tfile.nim C
+Failure: reFilesDiffer
+FAIL: tline.nim C
+Failure: reLinesDiffer
+FAIL: tmaxcodesize.nim C
+Failure: reCodegenFailure
+max allowed size: 1
+FAIL: tnimout.nim C
+Failure: reMsgsDiffer
+FAIL: toutput.nim C
+Failure: reOutputsDiffer
+FAIL: toutputsub.nim C
+Failure: reOutputsDiffer
+FAIL: tsortoutput.nim C
+Failure: reOutputsDiffer
+'''
+"""
diff --git a/tests/threads/t8535.nim b/tests/threads/t8535.nim
index a8d69657b..e1b5a1369 100644
--- a/tests/threads/t8535.nim
+++ b/tests/threads/t8535.nim
@@ -12,5 +12,5 @@ type
 
 var foo {.threadvar.}: CircAlloc[1,Job]
 
-when isMainModule:
+when true:
   echo foo.index
diff --git a/tests/threads/tactors2.nim b/tests/threads/tactors2.nim
index b011ef140..e8afe203c 100644
--- a/tests/threads/tactors2.nim
+++ b/tests/threads/tactors2.nim
@@ -12,7 +12,7 @@ proc thread_proc(input: some_type): some_type {.thread.} =
   result.bla = 1
 
 proc main() =
-  var actorPool: TActorPool[some_type, some_type]
+  var actorPool: ActorPool[some_type, some_type]
   createActorPool(actorPool, 1)
 
   var some_data: some_type
diff --git a/tests/threads/threadex.nim b/tests/threads/threadex.nim
index 679bfcb12..e61ce5c9c 100644
--- a/tests/threads/threadex.nim
+++ b/tests/threads/threadex.nim
@@ -1,5 +1,5 @@
 discard """
-  outputsub: "All rights reserved."
+  outputsub: "Just a simple text for test"
 """
 
 type
@@ -28,7 +28,7 @@ proc consume() {.thread.} =
 proc produce() {.thread.} =
   prodId = getThreadId()
   var m: TMsg
-  var input = open("readme.txt")
+  var input = open("tests/dummy.txt")
   var line = ""
   while input.readLine(line):
     m.data = line
diff --git a/tests/threads/tthreadanalysis2.nim b/tests/threads/tthreadanalysis2.nim
index c1ec3ae39..067e186a8 100644
--- a/tests/threads/tthreadanalysis2.nim
+++ b/tests/threads/tthreadanalysis2.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "'threadFunc' is not GC-safe"
   file: "tthreadanalysis2.nim"
   line: 37
-  errormsg: "'threadFunc' is not GC-safe"
   cmd: "nim $target --hints:on --threads:on $options $file"
 """
 
@@ -49,4 +49,3 @@ proc main =
   joinThreads(thr)
 
 main()
-
diff --git a/tests/threads/tthreadheapviolation1.nim b/tests/threads/tthreadheapviolation1.nim
index 59ecb742c..379bd55e6 100644
--- a/tests/threads/tthreadheapviolation1.nim
+++ b/tests/threads/tthreadheapviolation1.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 11
   errormsg: "'horrible' is not GC-safe"
+  line: 11
   cmd: "nim $target --hints:on --threads:on $options $file"
 """
 
@@ -16,5 +16,3 @@ proc horrible() {.thread.} =
 
 createThread[void](t, horrible)
 joinThread(t)
-
-
diff --git a/tests/trmacros/targlist.nim b/tests/trmacros/targlist.nim
deleted file mode 100644
index 46235dab1..000000000
--- a/tests/trmacros/targlist.nim
+++ /dev/null
@@ -1,9 +0,0 @@
-discard """
-  output: "12false3ha"
-"""
-
-proc f(x: varargs[string, `$`]) = discard
-template optF{f(x)}(x: varargs[untyped]) =
-  writeLine(stdout, x)
-
-f 1, 2, false, 3, "ha"
diff --git a/tests/trmacros/tcse.nim b/tests/trmacros/tcse.nim
deleted file mode 100644
index 315570d8f..000000000
--- a/tests/trmacros/tcse.nim
+++ /dev/null
@@ -1,13 +0,0 @@
-discard """
-  output: "4"
-"""
-
-template cse{f(a, a, x)}(a: typed{(nkDotExpr|call|nkBracketExpr)&noSideEffect},
-                         f: typed, x: varargs[typed]): untyped =
-  let aa = a
-  f(aa, aa, x)+4
-
-var
-  a: array[0..10, int]
-  i = 3
-echo a[i] + a[i]
diff --git a/tests/trmacros/tdisallowif.nim b/tests/trmacros/tdisallowif.nim
index 18dfd1c82..36f60800e 100644
--- a/tests/trmacros/tdisallowif.nim
+++ b/tests/trmacros/tdisallowif.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 24
   errormsg: "usage of 'disallowIf' is a user-defined error"
+  line: 24
   disabled: true
 """
 
diff --git a/tests/trmacros/thoist.nim b/tests/trmacros/thoist.nim
deleted file mode 100644
index 657f210a1..000000000
--- a/tests/trmacros/thoist.nim
+++ /dev/null
@@ -1,13 +0,0 @@
-discard """
-  output: '''true
-true'''
-"""
-
-import pegs
-
-template optPeg{peg(pattern)}(pattern: string{lit}): Peg =
-  var gl {.global, gensym.} = peg(pattern)
-  gl
-
-echo match("(a b c)", peg"'(' @ ')'")
-echo match("W_HI_Le", peg"\y 'while'")
diff --git a/tests/trmacros/tmatrix.nim b/tests/trmacros/tmatrix.nim
deleted file mode 100644
index a14ad2db0..000000000
--- a/tests/trmacros/tmatrix.nim
+++ /dev/null
@@ -1,29 +0,0 @@
-discard """
-  output: "21"
-"""
-
-import macros
-
-type
-  TMat = object
-    dummy: int
-
-proc `*`(a, b: TMat): TMat = nil
-proc `+`(a, b: TMat): TMat = nil
-proc `-`(a, b: TMat): TMat = nil
-proc `$`(a: TMat): string = result = $a.dummy
-proc mat21(): TMat =
-  result.dummy = 21
-
-macro optOps{ (`+`|`-`|`*`) ** a }(a: TMat): untyped =
-  echo treeRepr(a)
-  result = newCall(bindSym"mat21")
-
-#macro optPlus{ `+` * a }(a: varargs[TMat]): expr =
-#  result = newIntLitNode(21)
-
-var x, y, z: TMat
-
-echo x + y * z - x
-
-#echo x + y + z
diff --git a/tests/trmacros/tnoalias.nim b/tests/trmacros/tnoalias.nim
deleted file mode 100644
index ec12d4712..000000000
--- a/tests/trmacros/tnoalias.nim
+++ /dev/null
@@ -1,16 +0,0 @@
-discard """
-  output: "23"
-"""
-
-template optslice{a = b + c}(a: untyped{noalias}, b, c: untyped): typed =
-  a = b
-  inc a, c
-
-var
-  x = 12
-  y = 10
-  z = 13
-
-x = y+z
-
-echo x
diff --git a/tests/trmacros/tnoalias2.nim b/tests/trmacros/tnoalias2.nim
deleted file mode 100644
index 9362e764f..000000000
--- a/tests/trmacros/tnoalias2.nim
+++ /dev/null
@@ -1,19 +0,0 @@
-discard """
-  output: '''0'''
-"""
-
-# bug #206
-template optimizeOut{testFunc(a, b)}(a: int, b: int{alias}): untyped = 0
-
-proc testFunc(a, b: int): int = result = a + b
-var testVar = 1
-echo testFunc(testVar, testVar)
-
-
-template ex{a = b + c}(a : int{noalias}, b, c : int) =
-  a = b
-  inc a, b
-  echo "came here"
-
-var x = 5
-x = x + x
diff --git a/tests/trmacros/tnoendlessrec.nim b/tests/trmacros/tnoendlessrec.nim
deleted file mode 100644
index 508770ca7..000000000
--- a/tests/trmacros/tnoendlessrec.nim
+++ /dev/null
@@ -1,10 +0,0 @@
-discard """
-  output: "4"
-"""
-
-# test that an endless recursion is avoided:
-
-template optLen{len(x)}(x: typed): int = len(x)
-
-var s = "lala"
-echo len(s)
diff --git a/tests/trmacros/tpartial.nim b/tests/trmacros/tpartial.nim
deleted file mode 100644
index c636684d7..000000000
--- a/tests/trmacros/tpartial.nim
+++ /dev/null
@@ -1,11 +0,0 @@
-discard """
-  output: '''-2'''
-"""
-
-proc p(x, y: int; cond: bool): int =
-  result = if cond: x + y else: x - y
-
-template optP{p(x, y, true)}(x, y): untyped = x - y
-template optP{p(x, y, false)}(x, y): untyped = x + y
-
-echo p(2, 4, true)
diff --git a/tests/trmacros/tpatterns.nim b/tests/trmacros/tpatterns.nim
deleted file mode 100644
index 907973637..000000000
--- a/tests/trmacros/tpatterns.nim
+++ /dev/null
@@ -1,23 +0,0 @@
-discard """
-  output: '''48
-hel
-lo'''
-"""
-
-template optZero{x+x}(x: int): int = x*3
-template andthen{`*`(x,3)}(x: int): int = x*4
-template optSubstr1{x = substr(x, a, b)}(x: string, a, b: int) = setlen(x, b+1)
-
-var y = 12
-echo y+y
-
-var s: array[0..2, string]
-s[0] = "hello"
-s[0] = substr(s[0], 0, 2)
-
-echo s[0]
-
-# Test varargs matching
-proc someVarargProc(k: varargs[string]) = doAssert(false) # this should not get called
-template someVarargProcSingleArg{someVarargProc([a])}(a: string) = echo a
-someVarargProc("lo")
diff --git a/tests/trmacros/trmacros_various.nim b/tests/trmacros/trmacros_various.nim
new file mode 100644
index 000000000..74b248739
--- /dev/null
+++ b/tests/trmacros/trmacros_various.nim
@@ -0,0 +1,110 @@
+discard """
+output: '''
+12false3ha
+21
+optimized
+'''
+"""
+
+import macros, pegs
+
+
+block arglist:
+  proc f(x: varargs[string, `$`]) = discard
+  template optF{f(x)}(x: varargs[untyped]) =
+    writeLine(stdout, x)
+
+  f 1, 2, false, 3, "ha"
+
+
+
+block tcse:
+  template cse{f(a, a, x)}(a: typed{(nkDotExpr|call|nkBracketExpr)&noSideEffect},
+                         f: typed, x: varargs[typed]): untyped =
+    let aa = a
+    f(aa, aa, x)+4
+
+  var
+    a: array[0..10, int]
+    i = 3
+  doAssert a[i] + a[i] == 4
+
+
+
+block hoist:
+  template optPeg{peg(pattern)}(pattern: string{lit}): Peg =
+    var gl {.global, gensym.} = peg(pattern)
+    gl
+  doAssert match("(a b c)", peg"'(' @ ')'")
+  doAssert match("W_HI_Le", peg"\y 'while'")
+
+
+
+block tmatrix:
+  type
+    TMat = object
+      dummy: int
+
+  proc `*`(a, b: TMat): TMat = nil
+  proc `+`(a, b: TMat): TMat = nil
+  proc `-`(a, b: TMat): TMat = nil
+  proc `$`(a: TMat): string = result = $a.dummy
+  proc mat21(): TMat =
+    result.dummy = 21
+
+  macro optOps{ (`+`|`-`|`*`) ** a }(a: TMat): untyped =
+    result = newCall(bindSym"mat21")
+
+  #macro optPlus{ `+` * a }(a: varargs[TMat]): expr =
+  #  result = newIntLitNode(21)
+
+  var x, y, z: TMat
+  echo x + y * z - x
+
+
+
+block tnoalias:
+  template optslice{a = b + c}(a: untyped{noalias}, b, c: untyped): typed =
+    a = b
+    inc a, c
+  var
+    x = 12
+    y = 10
+    z = 13
+  x = y+z
+  doAssert x == 23
+
+
+
+block tnoendlessrec:
+  # test that an endless recursion is avoided:
+  template optLen{len(x)}(x: typed): int = len(x)
+
+  var s = "lala"
+  doAssert len(s) == 4
+
+
+
+block tstatic_t_bug:
+  # bug #4227
+  type Vector64[N: static[int]] = array[N, int]
+
+  proc `*`[N: static[int]](a: Vector64[N]; b: float64): Vector64[N] =
+    result = a
+
+  proc `+=`[N: static[int]](a: var Vector64[N]; b: Vector64[N]) =
+    echo "regular"
+
+  proc linearCombinationMut[N: static[int]](a: float64, v: var Vector64[N], w: Vector64[N])  {. inline .} =
+    echo "optimized"
+
+  template rewriteLinearCombinationMut{v += `*`(w, a)}(a: float64, v: var Vector64, w: Vector64): auto =
+    linearCombinationMut(a, v, w)
+
+  proc main() =
+    const scaleVal = 9.0
+    var a, b: Vector64[7]
+    a += b * scaleval
+
+  main()
+
diff --git a/tests/trmacros/trmacros_various2.nim b/tests/trmacros/trmacros_various2.nim
new file mode 100644
index 000000000..d500c49de
--- /dev/null
+++ b/tests/trmacros/trmacros_various2.nim
@@ -0,0 +1,79 @@
+discard """
+output: '''
+0
+-2
+48
+hel
+lo
+my awesome concat
+'''
+"""
+
+
+block tnoalias2:
+  # bug #206
+  template optimizeOut{testFunc(a, b)}(a: int, b: int{alias}): untyped = 0
+
+  proc testFunc(a, b: int): int = result = a + b
+  var testVar = 1
+  echo testFunc(testVar, testVar)
+
+
+  template ex{a = b + c}(a : int{noalias}, b, c : int) =
+    a = b
+    inc a, b
+    echo "came here"
+
+  var x = 5
+  x = x + x
+
+
+
+block tpartial:
+  proc p(x, y: int; cond: bool): int =
+    result = if cond: x + y else: x - y
+
+  template optP{p(x, y, true)}(x, y): untyped = x - y
+  template optP{p(x, y, false)}(x, y): untyped = x + y
+
+  echo p(2, 4, true)
+
+
+
+block tpatterns:
+  template optZero{x+x}(x: int): int = x*3
+  template andthen{`*`(x,3)}(x: int): int = x*4
+  template optSubstr1{x = substr(x, a, b)}(x: string, a, b: int) = setlen(x, b+1)
+
+  var y = 12
+  echo y+y
+
+  var s: array[0..2, string]
+  s[0] = "hello"
+  s[0] = substr(s[0], 0, 2)
+
+  echo s[0]
+
+  # Test varargs matching
+  proc someVarargProc(k: varargs[string]) = doAssert(false) # this should not get called
+  template someVarargProcSingleArg{someVarargProc([a])}(a: string) = echo a
+  someVarargProc("lo")
+
+
+
+block tstar:
+  var
+    calls = 0
+
+  proc `&&`(s: varargs[string]): string =
+    result = s[0]
+    for i in 1..len(s)-1: result.add s[i]
+    inc calls
+
+  template optConc{ `&&` * a }(a: string): string = &&a
+
+  let space = " "
+  echo "my" && (space & "awe" && "some " ) && "concat"
+
+  # check that it's been optimized properly:
+  doAssert calls == 1
diff --git a/tests/trmacros/tstar.nim b/tests/trmacros/tstar.nim
deleted file mode 100644
index 86f698232..000000000
--- a/tests/trmacros/tstar.nim
+++ /dev/null
@@ -1,19 +0,0 @@
-discard """
-  output: "my awesome concat"
-"""
-
-var
-  calls = 0
-
-proc `&&`(s: varargs[string]): string =
-  result = s[0]
-  for i in 1..len(s)-1: result.add s[i]
-  inc calls
-
-template optConc{ `&&` * a }(a: string): string = &&a
-
-let space = " "
-echo "my" && (space & "awe" && "some " ) && "concat"
-
-# check that it's been optimized properly:
-doAssert calls == 1
diff --git a/tests/trmacros/tstatic_t_bug.nim b/tests/trmacros/tstatic_t_bug.nim
deleted file mode 100644
index cdfa53514..000000000
--- a/tests/trmacros/tstatic_t_bug.nim
+++ /dev/null
@@ -1,24 +0,0 @@
-discard """
-  output: "optimized"
-"""
-# bug #4227
-type Vector64[N: static[int]] = array[N, int]
-
-proc `*`*[N: static[int]](a: Vector64[N]; b: float64): Vector64[N] =
-  result = a
-
-proc `+=`*[N: static[int]](a: var Vector64[N]; b: Vector64[N]) =
-  echo "regular"
-
-proc linearCombinationMut[N: static[int]](a: float64, v: var Vector64[N], w: Vector64[N])  {. inline .} =
-  echo "optimized"
-
-template rewriteLinearCombinationMut*{v += `*`(w, a)}(a: float64, v: var Vector64, w: Vector64): auto =
-  linearCombinationMut(a, v, w)
-
-proc main() =
-  const scaleVal = 9.0
-  var a, b: Vector64[7]
-  a += b * scaleval
-
-main()
diff --git a/tests/tuples/tanontuples.nim b/tests/tuples/tanontuples.nim
deleted file mode 100644
index f514670d3..000000000
--- a/tests/tuples/tanontuples.nim
+++ /dev/null
@@ -1,26 +0,0 @@
-discard """
-  output: '''61, 125
-(Field0: 0) (Field0: 13)'''
-"""
-
-import macros
-
-proc `^` (a, b: int): int =
-  result = 1
-  for i in 1..b: result = result * a
-
-var m = (0, 5)
-var n = (56, 3)
-
-m = (n[0] + m[1], m[1] ^ n[1])
-
-echo m[0], ", ", m[1]
-
-# also test we can produce unary anon tuples in a macro:
-macro mm(): untyped =
-  result = newTree(nnkTupleConstr, newLit(13))
-
-proc nowTuple(): (int,) =
-  result = (0,)
-
-echo nowTuple(), " ", mm()
diff --git a/tests/tuples/tconver_tuple.nim b/tests/tuples/tconver_tuple.nim
deleted file mode 100644
index 306da77fe..000000000
--- a/tests/tuples/tconver_tuple.nim
+++ /dev/null
@@ -1,23 +0,0 @@
-# Bug 4479
-
-type
-  MyTuple = tuple
-    num: int
-    strings: seq[string]
-    ints: seq[int]
-
-var foo = MyTuple((
-  num: 7,
-  strings: @[],
-  ints: @[],
-))
-
-var bar = (
-  num: 7,
-  strings: @[],
-  ints: @[],
-).MyTuple
-
-var fooUnnamed = MyTuple((7, @[], @[]))
-var n = 7
-var fooSym = MyTuple((num: n, strings: @[], ints: @[]))
diff --git a/tests/tuples/tdifferent_instantiations.nim b/tests/tuples/tdifferent_instantiations.nim
deleted file mode 100644
index 93b1777b5..000000000
--- a/tests/tuples/tdifferent_instantiations.nim
+++ /dev/null
@@ -1,9 +0,0 @@
-# bug #1910
-import tables
-
-var p: OrderedTable[tuple[a:int], int]
-var q: OrderedTable[tuple[x:int], int]
-for key in p.keys:
-  echo key.a
-for key in q.keys:
-  echo key.x
diff --git a/tests/tuples/tgeneric_tuple.nim b/tests/tuples/tgeneric_tuple.nim
deleted file mode 100644
index 32f081596..000000000
--- a/tests/tuples/tgeneric_tuple.nim
+++ /dev/null
@@ -1,9 +0,0 @@
-# bug #2121
-
-type
-  Item[K,V] = tuple
-    key: K
-    value: V
-
-var q = newseq[Item[int,int]](0)
-let (x,y) = q[0]
diff --git a/tests/tuples/tgeneric_tuple2.nim b/tests/tuples/tgeneric_tuple2.nim
deleted file mode 100644
index c0c292388..000000000
--- a/tests/tuples/tgeneric_tuple2.nim
+++ /dev/null
@@ -1,17 +0,0 @@
-
-# bug #2369
-
-type HashedElem[T] = tuple[num: int, storedVal: ref T]
-
-proc append[T](tab: var seq[HashedElem[T]], n: int, val: ref T) =
-    #tab.add((num: n, storedVal: val))
-    var he: HashedElem[T] = (num: n, storedVal: val)
-    #tab.add(he)
-
-var g: seq[HashedElem[int]] = @[]
-
-proc foo() =
-    var x: ref int
-    new(x)
-    x[] = 77
-    g.append(44, x)
diff --git a/tests/tuples/ttuples_issues.nim b/tests/tuples/ttuples_issues.nim
new file mode 100644
index 000000000..9380bd027
--- /dev/null
+++ b/tests/tuples/ttuples_issues.nim
@@ -0,0 +1,77 @@
+discard """
+output: '''
+'''
+"""
+
+
+import tables
+
+
+block t4479:
+  type
+    MyTuple = tuple
+      num: int
+      strings: seq[string]
+      ints: seq[int]
+
+  var foo = MyTuple((
+    num: 7,
+    strings: @[],
+    ints: @[],
+  ))
+
+  var bar = (
+    num: 7,
+    strings: @[],
+    ints: @[],
+  ).MyTuple
+
+  var fooUnnamed = MyTuple((7, @[], @[]))
+  var n = 7
+  var fooSym = MyTuple((num: n, strings: @[], ints: @[]))
+
+
+block t1910:
+  var p = newOrderedTable[tuple[a:int], int]()
+  var q = newOrderedTable[tuple[x:int], int]()
+  for key in p.keys:
+    echo key.a
+  for key in q.keys:
+    echo key.x
+
+
+block t2121:
+  type
+    Item[K,V] = tuple
+      key: K
+      value: V
+
+  var q = newseq[Item[int,int]](1)
+  let (x,y) = q[0]
+
+
+block t2369:
+  type HashedElem[T] = tuple[num: int, storedVal: ref T]
+
+  proc append[T](tab: var seq[HashedElem[T]], n: int, val: ref T) =
+      #tab.add((num: n, storedVal: val))
+      var he: HashedElem[T] = (num: n, storedVal: val)
+      #tab.add(he)
+
+  var g: seq[HashedElem[int]] = @[]
+
+  proc foo() =
+      var x: ref int
+      new(x)
+      x[] = 77
+      g.append(44, x)
+
+
+block t1986:
+  proc test(): int64 =
+    return 0xdeadbeef.int64
+
+  const items = [
+    (var1: test(), var2: 100'u32),
+    (var1: test(), var2: 192'u32)
+  ]
diff --git a/tests/tuples/ttuples_various.nim b/tests/tuples/ttuples_various.nim
new file mode 100644
index 000000000..010893ced
--- /dev/null
+++ b/tests/tuples/ttuples_various.nim
@@ -0,0 +1,136 @@
+discard """
+output: '''
+it's nil
+@[1, 2, 3]
+'''
+"""
+
+import macros
+
+
+block anontuples:
+  proc `^` (a, b: int): int =
+    result = 1
+    for i in 1..b: result = result * a
+
+  var m = (0, 5)
+  var n = (56, 3)
+
+  m = (n[0] + m[1], m[1] ^ n[1])
+
+  doAssert m == (61, 125)
+
+  # also test we can produce unary anon tuples in a macro:
+  macro mm(): untyped =
+    result = newTree(nnkTupleConstr, newLit(13))
+
+  proc nowTuple(): (int,) =
+    result = (0,)
+
+  doAssert nowTuple() == (Field0: 0)
+  doAssert mm() == (Field0: 13)
+
+
+
+block unpack_asgn:
+  proc foobar(): (int, int) = (2, 4)
+
+  # test within a proc:
+  proc pp(x: var int) =
+    var y: int
+    (y, x) = foobar()
+
+  template pt(x) =
+    var y: int
+    (x, y) = foobar()
+
+  # test within a generic:
+  proc pg[T](x, y: var T) =
+    pt(x)
+
+  # test as a top level statement:
+  var x, y, a, b: int
+  # test for regression:
+  (x, y) = (1, 2)
+  (x, y) = fooBar()
+
+  doAssert x == 2
+  doAssert y == 4
+
+  pp(a)
+  doAssert a == 4
+
+  pg(a, b)
+  doAssert a == 2
+  doAssert b == 0
+
+
+
+block tuple_subscript:
+  proc`[]` (t: tuple, key: string): string =
+    for name, field in fieldPairs(t):
+      if name == key:
+        return $field
+    return ""
+
+  proc`[]` [A,B](t: tuple, key: string, op: (proc(x: A): B)): B =
+    for name, field in fieldPairs(t):
+      when field is A:
+        if name == key:
+          return op(field)
+
+  proc`[]=`[T](t: var tuple, key: string, val: T) =
+    for name, field in fieldPairs(t):
+      when field is T:
+        if name == key:
+          field = val
+
+  var tt = (a: 1, b: "str1")
+
+  # test built in operator
+  tt[0] = 5
+
+  doAssert tt[0] == 5
+  doAssert `[]`(tt, 0) == 5
+
+  # test overloaded operator
+  tt["b"] = "str2"
+  doAssert tt["b"] == "str2"
+  doAssert `[]`(tt, "b") == "str2"
+  doAssert tt["b", proc(s: string): int = s.len] == 4
+
+
+
+block tuple_with_seq:
+  template foo(s: string = "") =
+    if s.len == 0:
+      echo "it's nil"
+    else:
+      echo s
+  foo
+
+  # bug #2632
+  proc takeTup(x: tuple[s: string;x: seq[int]]) =
+    discard
+  takeTup(("foo", @[]))
+
+  #proc foobar(): () =
+  proc f(xs: seq[int]) =
+    discard
+
+  proc g(t: tuple[n:int, xs:seq[int]]) =
+    discard
+
+  when true:
+    f(@[]) # OK
+    g((1,@[1])) # OK
+    g((0,@[])) # NG
+
+  # bug #2630
+  type T = tuple[a: seq[int], b: int]
+  var t: T = (@[1,2,3], 7)
+
+  proc test(s: seq[int]): T =
+    echo s
+    (s, 7)
+  t = test(t.a)
diff --git a/tests/tuples/tuint_tuple.nim b/tests/tuples/tuint_tuple.nim
deleted file mode 100644
index 24bcead5e..000000000
--- a/tests/tuples/tuint_tuple.nim
+++ /dev/null
@@ -1,10 +0,0 @@
-# bug #1986 found by gdmoore
-
-proc test(): int64 =
-  return 0xdeadbeef.int64
-
-const items = [
-  (var1: test(), var2: 100'u32),
-  (var1: test(), var2: 192'u32)
-]
-
diff --git a/tests/tuples/tunpack_asgn.nim b/tests/tuples/tunpack_asgn.nim
deleted file mode 100644
index 1dc7ff074..000000000
--- a/tests/tuples/tunpack_asgn.nim
+++ /dev/null
@@ -1,34 +0,0 @@
-discard """
-  output: '''2 4
-4
-2 0'''
-"""
-
-proc foobar(): (int, int) = (2, 4)
-
-# test within a proc:
-proc pp(x: var int) =
-  var y: int
-  (y, x) = foobar()
-
-template pt(x) =
-  var y: int
-  (x, y) = foobar()
-
-# test within a generic:
-proc pg[T](x, y: var T) =
-  pt(x)
-
-# test as a top level statement:
-var x, y, a, b: int
-# test for regression:
-(x, y) = (1, 2)
-(x, y) = fooBar()
-
-echo x, " ", y
-
-pp(a)
-echo a
-
-pg(a, b)
-echo a, " ", b
diff --git a/tests/tuples/tuple_subscript.nim b/tests/tuples/tuple_subscript.nim
deleted file mode 100644
index 021793dc3..000000000
--- a/tests/tuples/tuple_subscript.nim
+++ /dev/null
@@ -1,40 +0,0 @@
-discard """
-  output: '''5
-5
-str2
-str2
-4'''
-"""
-
-proc`[]` (t: tuple, key: string): string =
-  for name, field in fieldPairs(t):
-    if name == key: 
-      return $field
-  return ""
-
-
-proc`[]` [A,B](t: tuple, key: string, op: (proc(x: A): B)): B =
-  for name, field in fieldPairs(t):
-    when field is A:
-      if name == key: 
-        return op(field)
-
-proc`[]=`[T](t: var tuple, key: string, val: T) =
-  for name, field in fieldPairs(t):
-    when field is T:
-      if name == key: 
-        field = val
-
-var tt = (a: 1, b: "str1")
-
-# test built in operator
-tt[0] = 5
-echo tt[0] 
-echo `[]`(tt, 0)
-
-
-# test overloaded operator
-tt["b"] = "str2"
-echo tt["b"] 
-echo `[]`(tt, "b")
-echo tt["b", proc(s: string) : int = s.len]
\ No newline at end of file
diff --git a/tests/tuples/tuple_with_seq.nim b/tests/tuples/tuple_with_seq.nim
deleted file mode 100644
index 00b07dd2c..000000000
--- a/tests/tuples/tuple_with_seq.nim
+++ /dev/null
@@ -1,46 +0,0 @@
-discard """
-  output: '''it's nil
-@[1, 2, 3]'''
-"""
-
-template foo(s: string = "") =
-  if s.len == 0:
-    echo "it's nil"
-  else:
-    echo s
-
-foo
-
-
-# bug #2632
-
-proc takeTup(x: tuple[s: string;x: seq[int]]) =
-  discard
-
-takeTup(("foo", @[]))
-
-
-#proc foobar(): () =
-
-proc f(xs: seq[int]) =
-  discard
-
-proc g(t: tuple[n:int, xs:seq[int]]) =
-  discard
-
-when isMainModule:
-  f(@[]) # OK
-  g((1,@[1])) # OK
-  g((0,@[])) # NG
-
-
-# bug #2630
-type T = tuple[a: seq[int], b: int]
-
-var t: T = (@[1,2,3], 7)
-
-proc test(s: seq[int]): T =
-  echo s
-  (s, 7)
-
-t = test(t.a)
diff --git a/tests/tuples/twrongtupleaccess.nim b/tests/tuples/twrongtupleaccess.nim
index b1684b097..591716a2e 100644
--- a/tests/tuples/twrongtupleaccess.nim
+++ b/tests/tuples/twrongtupleaccess.nim
@@ -1,10 +1,9 @@
 discard """
+  errormsg: "attempting to call undeclared routine: \'setBLAH\'"
   file: "twrongtupleaccess.nim"
   line: 9
-  errormsg: "attempting to call undeclared routine: \'setBLAH\'"
 """
 # Bugfix
 
 var v = (5.0, 10.0)
 v.setBLAH(10)
-
diff --git a/tests/typerel/t2plus.nim b/tests/typerel/t2plus.nim
index d099eeeb0..4b18b6221 100644
--- a/tests/typerel/t2plus.nim
+++ b/tests/typerel/t2plus.nim
@@ -16,7 +16,7 @@ proc foldRight[T,U](lst: seq[T], v: U, f: (T, U) -> U): U =
 proc mean[T: SomeNumber](xs: seq[T]): T =
   xs.foldRight(0.T, (xBAZ: auto, yBAZ: auto) => xBAZ + yBAZ) / T(xs.len)
 
-when isMainModule:
+when true:
   let x = mean(@[1.float, 2, 3])
   echo x
 
diff --git a/tests/typerel/t8172.nim b/tests/typerel/t8172.nim
index 8e0b32932..57b788250 100644
--- a/tests/typerel/t8172.nim
+++ b/tests/typerel/t8172.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 11
   errormsg: "cannot convert array[0..0, string] to varargs[string]"
+  line: 11
 """
 
 proc f(v: varargs[string]) =
diff --git a/tests/typerel/temptynode.nim b/tests/typerel/temptynode.nim
index df308fbc2..8c71a6092 100644
--- a/tests/typerel/temptynode.nim
+++ b/tests/typerel/temptynode.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 16
   errormsg: "type mismatch: got <void>"
+  line: 16
 """
 
 # bug #950
diff --git a/tests/typerel/texplicitcmp.nim b/tests/typerel/texplicitcmp.nim
index e91ac2ffe..b11aa2f4e 100644
--- a/tests/typerel/texplicitcmp.nim
+++ b/tests/typerel/texplicitcmp.nim
@@ -24,9 +24,8 @@ proc weird(json_params: Table) =
   sort(f, system.cmp[int])
   outp(f)
 
-when isMainModule:
-  var t = @[3, 2, 1]
-  sort(t, system.cmp[int])
-  outp(t)
-  works()
-  weird(initTable[string, JsonNode]())
+var t = @[3, 2, 1]
+sort(t, system.cmp[int])
+outp(t)
+works()
+weird(initTable[string, JsonNode]())
diff --git a/tests/typerel/tno_int_in_bool_context.nim b/tests/typerel/tno_int_in_bool_context.nim
index a4b4237d2..66e9da58a 100644
--- a/tests/typerel/tno_int_in_bool_context.nim
+++ b/tests/typerel/tno_int_in_bool_context.nim
@@ -1,8 +1,7 @@
 discard """
-  line: 6
   errormsg: "type mismatch: got <int literal(1)> but expected 'bool'"
+  line: 6
 """
 
 if 1:
   echo "wtf?"
-
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/tnocontains.nim b/tests/typerel/tnocontains.nim
index a93db2fc3..8bea8aa56 100644
--- a/tests/typerel/tnocontains.nim
+++ b/tests/typerel/tnocontains.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "type mismatch: got <string, string>"
   file: "tnocontains.nim"
   line: 10
-  errormsg: "type mismatch: got <string, string>"
 """
 
 # shouldn't compile since it doesn't do what you think it does without
diff --git a/tests/typerel/trefs.nim b/tests/typerel/trefs.nim
index d4383c562..e9862bd0f 100644
--- a/tests/typerel/trefs.nim
+++ b/tests/typerel/trefs.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "type mismatch"
   file: "trefs.nim"
   line: 20
-  errormsg: "type mismatch"
 """
 # test for ref types (including refs to procs)
 
@@ -18,6 +18,3 @@ var p: TProc
 p = foo
 write(stdout, "success!")
 p = wrongfoo  #ERROR_MSG type mismatch
-
-
-
diff --git a/tests/typerel/tregionptrs.nim b/tests/typerel/tregionptrs.nim
index 9eeded18b..504ec1011 100644
--- a/tests/typerel/tregionptrs.nim
+++ b/tests/typerel/tregionptrs.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 16
   errormsg: "type mismatch: got <BPtr> but expected 'APtr = ptr[RegionA, int]'"
+  line: 16
 """
 
 type
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/typerel/ttypedesc_as_genericparam1.nim b/tests/typerel/ttypedesc_as_genericparam1.nim
index 9ae464842..b7c3e727d 100644
--- a/tests/typerel/ttypedesc_as_genericparam1.nim
+++ b/tests/typerel/ttypedesc_as_genericparam1.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 6
   errormsg: "type mismatch: got <type int>"
+  line: 6
 """
 # bug #3079, #1146
 echo repr(int)
diff --git a/tests/typerel/ttypedesc_as_genericparam2.nim b/tests/typerel/ttypedesc_as_genericparam2.nim
index 0b4281269..ea06606f9 100644
--- a/tests/typerel/ttypedesc_as_genericparam2.nim
+++ b/tests/typerel/ttypedesc_as_genericparam2.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 9
   errormsg: "'repr' doesn't support 'void' type"
+  line: 9
 """
 
 # bug #2879
diff --git a/tests/typerel/ttypenoval.nim b/tests/typerel/ttypenoval.nim
index 720e5d662..c7829f9dd 100644
--- a/tests/typerel/ttypenoval.nim
+++ b/tests/typerel/ttypenoval.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "type mismatch: got <type int> but expected 'int'"
   file: "ttypenoval.nim"
   line: 38
-  errormsg: "type mismatch: got <type int> but expected 'int'"
 """
 
 # A min-heap.
@@ -51,5 +51,3 @@ var
 newBinHeap(heap, 256)
 add(heap, 1, 100)
 print(heap)
-
-
diff --git a/tests/typerel/typredef.nim b/tests/typerel/typredef.nim
index 0b6aed875..c502a834c 100644
--- a/tests/typerel/typredef.nim
+++ b/tests/typerel/typredef.nim
@@ -1,8 +1,7 @@
 discard """
+  errormsg: "illegal recursion in type \'Uint8\'"
   file: "typredef.nim"
   line: 7
-  errormsg: "illegal recursion in type \'Uint8\'"
 """
 type
   Uint8 = Uint8 #ERROR_MSG illegal recursion in type 'Uint8'
-
diff --git a/tests/types/t1252.nim b/tests/types/t1252.nim
deleted file mode 100644
index c6a12e9f7..000000000
--- a/tests/types/t1252.nim
+++ /dev/null
@@ -1,12 +0,0 @@
-discard """
-  output: '''true
-true
-true
-true
-'''
-"""
-
-echo float32 isnot float64
-echo float32 isnot float
-echo int32 isnot int64
-echo int32 isnot int
diff --git a/tests/types/t5640.nim b/tests/types/t5640.nim
deleted file mode 100644
index 5e1c99c4d..000000000
--- a/tests/types/t5640.nim
+++ /dev/null
@@ -1,6 +0,0 @@
-type
-  vecBase[I: static[int]] = distinct array[I, float32]
-  vec2* = vecBase[2]
-
-var v = vec2([0.0'f32, 0.0'f32])
-
diff --git a/tests/types/t5648.nim b/tests/types/t5648.nim
deleted file mode 100644
index c230cc12c..000000000
--- a/tests/types/t5648.nim
+++ /dev/null
@@ -1,21 +0,0 @@
-discard """
-output: "ptr Foo"
-"""
-
-import typetraits
-
-type Foo = object
-  bar*: int
-
-proc main() =
-  var f = create(Foo)
-  f.bar = 3
-  echo f.type.name
-
-  discard realloc(f, 0)
-
-  var g = Foo()
-  g.bar = 3
-
-main()
-
diff --git a/tests/types/t6456.nim b/tests/types/t6456.nim
index 2d2aad370..19bbc2c02 100644
--- a/tests/types/t6456.nim
+++ b/tests/types/t6456.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 6
   errormsg: "type \'ptr void\' is not allowed"
+  line: 6
 """
 
 proc foo(x: ptr void) =
diff --git a/tests/types/t7581.nim b/tests/types/t7581.nim
deleted file mode 100644
index 796f30271..000000000
--- a/tests/types/t7581.nim
+++ /dev/null
@@ -1 +0,0 @@
-discard int -1
\ No newline at end of file
diff --git a/tests/types/t7905.nim b/tests/types/t7905.nim
deleted file mode 100644
index ef75bb86c..000000000
--- a/tests/types/t7905.nim
+++ /dev/null
@@ -1,33 +0,0 @@
-discard """
-  output: '''
-(member: "hello world")
-(member: 123.456)
-(member: "hello world", x: ...)
-(member: 123.456, x: ...)
-'''
-"""
-
-template foobar(arg: typed): untyped =
-  type
-    MyType = object
-      member: type(arg)
-
-  var myVar: MyType
-  myVar.member = arg
-  echo myVar
-
-foobar("hello world")
-foobar(123.456'f64)
-
-template foobarRec(arg: typed): untyped =
-  type
-    MyType = object
-      member: type(arg)
-      x: ref MyType
-
-  var myVar: MyType
-  myVar.member = arg
-  echo myVar
-
-foobarRec("hello world")
-foobarRec(123.456'f64)
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/tassignemptytuple.nim b/tests/types/tassignemptytuple.nim
index bdfc653a5..9d5a311ba 100644
--- a/tests/types/tassignemptytuple.nim
+++ b/tests/types/tassignemptytuple.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "cannot infer the type of the tuple"
   file: "tassignemptytuple.nim"
   line: 11
-  errormsg: "cannot infer the type of the tuple"
 """
 
 var
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/types/tillegaltyperecursion.nim b/tests/types/tillegaltyperecursion.nim
index 6ead902b7..d8021c06f 100644
--- a/tests/types/tillegaltyperecursion.nim
+++ b/tests/types/tillegaltyperecursion.nim
@@ -59,7 +59,7 @@ proc Connect*(irc: var TIRC, nick: string, host: string, port: int = 6667) =
 
 
 
-when isMainModule:
+when true:
     var irc = initIRC()
     irc.Connect("AmryBot[Nim]","irc.freenode.net",6667)
     irc.sendRaw("JOIN #nim")
diff --git a/tests/types/tillrec.nim b/tests/types/tillrec.nim
index 18757140a..7584282b6 100644
--- a/tests/types/tillrec.nim
+++ b/tests/types/tillrec.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "illegal recursion in type \'TIllegal\'"
   file: "tillrec.nim"
   line: 13
-  errormsg: "illegal recursion in type \'TIllegal\'"
 """
 # test illegal recursive types
 
@@ -13,4 +13,3 @@ type
   TIllegal {.final.} = object  #ERROR_MSG illegal recursion in type 'TIllegal'
     y: int
     x: array[0..3, TIllegal]
-
diff --git a/tests/types/tissues_types.nim b/tests/types/tissues_types.nim
new file mode 100644
index 000000000..d3643842e
--- /dev/null
+++ b/tests/types/tissues_types.nim
@@ -0,0 +1,73 @@
+discard """
+  output: '''true
+true
+true
+true
+ptr Foo
+(member: "hello world")
+(member: 123.456)
+(member: "hello world", x: ...)
+(member: 123.456, x: ...)
+'''
+joinable: false
+"""
+# not joinable because it causes out of memory with --gc:boehm
+import typetraits
+
+block t1252:
+  echo float32 isnot float64
+  echo float32 isnot float
+  echo int32 isnot int64
+  echo int32 isnot int
+
+block t5640:
+  type
+    vecBase[I: static[int]] = distinct array[I, float32]
+    vec2 = vecBase[2]
+
+  var v = vec2([0.0'f32, 0.0'f32])
+
+block t5648:
+  type Foo = object
+    bar: int
+
+  proc main() =
+    var f = create(Foo)
+    f.bar = 3
+    echo f.type.name
+
+    discard realloc(f, 0)
+
+    var g = Foo()
+    g.bar = 3
+
+  main()
+
+block t7581:
+  discard int -1
+
+block t7905:
+  template foobar(arg: typed): untyped =
+    type
+      MyType = object
+        member: type(arg)
+
+    var myVar: MyType
+    myVar.member = arg
+    echo myVar
+
+  foobar("hello world")
+  foobar(123.456'f64)
+
+  template foobarRec(arg: typed): untyped =
+    type
+      MyType = object
+        member: type(arg)
+        x: ref MyType
+
+    var myVar: MyType
+    myVar.member = arg
+    echo myVar
+
+  foobarRec("hello world")
+  foobarRec(123.456'f64)
diff --git a/tests/types/tparameterizedparent0.nim b/tests/types/tparameterizedparent0.nim
index 1b72a4e21..90e7a9c0c 100644
--- a/tests/types/tparameterizedparent0.nim
+++ b/tests/types/tparameterizedparent0.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "inheritance only works with non-final objects"
   file: "tparameterizedparent0.nim"
   line: 14
-  errormsg: "inheritance only works with non-final objects"
 """
 # bug #5264
 type
diff --git a/tests/types/tparameterizedparent1.nim b/tests/types/tparameterizedparent1.nim
index 24fb9a565..5da8189f4 100644
--- a/tests/types/tparameterizedparent1.nim
+++ b/tests/types/tparameterizedparent1.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "inheritance only works with non-final objects"
   file: "tparameterizedparent1.nim"
   line: 14
-  errormsg: "inheritance only works with non-final objects"
 """
 # bug #5264
 type
diff --git a/tests/types/tparameterizedparent3.nim b/tests/types/tparameterizedparent3.nim
index 58aaf80ea..fcca6453e 100644
--- a/tests/types/tparameterizedparent3.nim
+++ b/tests/types/tparameterizedparent3.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "attempt to redefine: 'color'"
   file: "tparameterizedparent3.nim"
   line: 13
-  errormsg: "attempt to redefine: 'color'"
 """
 # bug #5264
 type
diff --git a/tests/types/tparameterizedparent4.nim b/tests/types/tparameterizedparent4.nim
index a37461bb4..4759d9d9b 100644
--- a/tests/types/tparameterizedparent4.nim
+++ b/tests/types/tparameterizedparent4.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "attempt to redefine: 'grain'"
   file: "tparameterizedparent4.nim"
   line: 23
-  errormsg: "attempt to redefine: 'grain'"
 """
 # bug #5264
 type
diff --git a/tests/untestable/tssl.nim b/tests/untestable/tssl.nim
index 664ad805c..fca6385f8 100644
--- a/tests/untestable/tssl.nim
+++ b/tests/untestable/tssl.nim
@@ -20,7 +20,7 @@ from strutils import contains, toHex
 
 from openssl import getOpenSSLVersion
 
-when isMainModule:
+when true:
   echo "version: 0x" & $getOpenSSLVersion().toHex()
 
   let client = newHttpClient()
diff --git a/tests/usingstmt/tusingstatement.nim b/tests/usingstmt/tusingstatement.nim
index 8585bcc9e..6e4998892 100644
--- a/tests/usingstmt/tusingstatement.nim
+++ b/tests/usingstmt/tusingstatement.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tusingstatement.nim"
   output: "Using test.Closing test."
 """
 
@@ -85,3 +84,5 @@ proc use(r: var TResource) =
 
 autoClose(r = openResource("test")):
   use r
+
+write stdout, "\n"
diff --git a/tests/varres/tnewseq_on_result_vart.nim b/tests/varres/tnewseq_on_result_vart.nim
index 18935a1d1..4a700468f 100644
--- a/tests/varres/tnewseq_on_result_vart.nim
+++ b/tests/varres/tnewseq_on_result_vart.nim
@@ -1,7 +1,7 @@
 
 discard """
-  line: 9
   errormsg: "address of 'result' may not escape its stack frame"
+  line: 9
 """
 # bug #5113
 
diff --git a/tests/varres/tprevent_forloopvar_mutations.nim b/tests/varres/tprevent_forloopvar_mutations.nim
index 15938bb77..43cc04f30 100644
--- a/tests/varres/tprevent_forloopvar_mutations.nim
+++ b/tests/varres/tprevent_forloopvar_mutations.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 15
   errmsg: "type mismatch: got <int>"
+  line: 15
   nimout: '''type mismatch: got <int>
 but expected one of:
 proc inc[T: Ordinal | uint | uint64](x: var T; y = 1)
diff --git a/tests/varres/tvarres1.nim b/tests/varres/tvarres1.nim
index 5a5247142..e58d7f083 100644
--- a/tests/varres/tvarres1.nim
+++ b/tests/varres/tvarres1.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "'bla' escapes its stack frame; context: 'bla'"
   file: "tvarres1.nim"
   line: 12
-  errormsg: "'bla' escapes its stack frame; context: 'bla'"
 """
 
 var
@@ -14,4 +14,3 @@ proc p(): var int =
 p() = 45
 
 echo g
-
diff --git a/tests/varres/tvarres2.nim b/tests/varres/tvarres2.nim
index 53a57d882..4ec0bb05b 100644
--- a/tests/varres/tvarres2.nim
+++ b/tests/varres/tvarres2.nim
@@ -1,7 +1,7 @@
 discard """
+  errormsg: "expression has no address"
   file: "tvarres2.nim"
   line: 11
-  errormsg: "expression has no address"
 """
 
 var
@@ -13,4 +13,3 @@ proc p(): var int =
 p() = 45
 
 echo g
-
diff --git a/tests/varres/tvarres_via_forwarding.nim b/tests/varres/tvarres_via_forwarding.nim
index 8fd3dfcfd..fb7201ad2 100644
--- a/tests/varres/tvarres_via_forwarding.nim
+++ b/tests/varres/tvarres_via_forwarding.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 10
   errormsg: "'y' escapes its stack frame; context: 'forward(y)'"
+  line: 10
 """
 
 proc forward(x: var int): var int = result = x
diff --git a/tests/varres/tvartup.nim b/tests/varres/tvartup.nim
index 1957a3e35..a8f15b232 100644
--- a/tests/varres/tvartup.nim
+++ b/tests/varres/tvartup.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tvartup.nim"
   output: "2 3"
 """
 # Test the new tuple unpacking
@@ -9,5 +8,3 @@ proc divmod(a, b: int): tuple[di, mo: int] =
 
 var (x, y) = divmod(15, 6)
 echo x, " ", y
-
-#OUT 2 3
diff --git a/tests/varres/twrong_parameter.nim b/tests/varres/twrong_parameter.nim
index 8a363dd19..58d01fd7e 100644
--- a/tests/varres/twrong_parameter.nim
+++ b/tests/varres/twrong_parameter.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 10
   errormsg: "'x' is not the first parameter; context: 'x.field[0]'"
+  line: 10
 """
 
 type
diff --git a/tests/varstmt/tvardecl.nim b/tests/varstmt/tvardecl.nim
index a6b508295..37bc4bad7 100644
--- a/tests/varstmt/tvardecl.nim
+++ b/tests/varstmt/tvardecl.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tvardecl.nim"
   output: "44"
 """
 # Test the new variable declaration syntax
@@ -10,6 +9,4 @@ var
   a, b: int = 4
 
 write(stdout, a)
-write(stdout, b) #OUT 44
-
-
+writeLine(stdout, b) #OUT 44
diff --git a/tests/vm/t2574.nim b/tests/vm/t2574.nim
index 86602aeaf..4332667b4 100644
--- a/tests/vm/t2574.nim
+++ b/tests/vm/t2574.nim
@@ -1,6 +1,6 @@
 discard """
-  line: 14
   errormsg: "cannot call method eval at compile time"
+  line: 14
 """
 
 type
diff --git a/tests/vm/t4952.nim b/tests/vm/t4952.nim
deleted file mode 100644
index fc76fa4df..000000000
--- a/tests/vm/t4952.nim
+++ /dev/null
@@ -1,17 +0,0 @@
-import macros
-
-proc doCheck(tree: NimNode) =
-  let res: tuple[n: NimNode] = (n: tree)
-  assert: tree.kind == res.n.kind
-  for sub in tree:
-    doCheck(sub)
-
-macro id(body: untyped): untyped =
-  doCheck(body)
-
-id(foo((i: int)))
-
-static:
-  let tree = newTree(nnkExprColonExpr)
-  let t = (n: tree)
-  assert: t.n.kind == tree.kind
diff --git a/tests/vm/t9043.nim b/tests/vm/t9043.nim
deleted file mode 100644
index 1ae2e383c..000000000
--- a/tests/vm/t9043.nim
+++ /dev/null
@@ -1,10 +0,0 @@
-discard """
-  nimout: "(Field0: 2, Field1: 2, Field2: 2, Field3: 2)"
-"""
-
-proc foo[N: static[int]](dims: array[N, int])=
-  const N1 = N
-  const N2 = dims.len
-  static: echo (N, dims.len, N1, N2)
-
-foo([1, 2])
diff --git a/tests/vm/tcastint.nim b/tests/vm/tcastint.nim
index 7b9ddd7d9..437342a74 100644
--- a/tests/vm/tcastint.nim
+++ b/tests/vm/tcastint.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tcastint.nim"
   output: "OK"
 """
 
@@ -113,8 +112,55 @@ proc test() =
     doAssert(not compiles(cast[uint32](I8)))
     doAssert(not compiles(cast[uint64](I8)))
 
+
+proc test_float_cast =
+
+  const
+    exp_bias = 1023'i64
+    exp_shift = 52
+    exp_mask = 0x7ff'i64 shl exp_shift
+    mantissa_mask = 0xfffffffffffff'i64
+
+  let f = 8.0
+  let fx = cast[int64](f)
+  let exponent = ((fx and exp_mask) shr exp_shift) - exp_bias
+  let mantissa = fx and mantissa_mask
+  doAssert(exponent == 3, $exponent)
+  doAssert(mantissa == 0, $mantissa)
+
+  # construct 2^N float, where N is integer
+  let x = -2'i64
+  let xx = (x + exp_bias) shl exp_shift
+  let xf = cast[float](xx)
+  doAssert(xf == 0.25, $xf)
+
+proc test_float32_cast =
+
+  const
+    exp_bias = 127'i32
+    exp_shift = 23
+    exp_mask = 0x7f800000'i32
+    mantissa_mask = 0x007ffff'i32
+
+  let f = -0.5'f32
+  let fx = cast[int32](f)
+  let exponent = ((fx and exp_mask) shr exp_shift) - exp_bias
+  let mantissa = fx and mantissa_mask
+  doAssert(exponent == -1, $exponent)
+  doAssert(mantissa == 0, $mantissa)
+
+  # construct 2^N float32 where N is integer
+  let x = 4'i32
+  let xx = (x + exp_bias) shl exp_shift
+  let xf = cast[float32](xx)
+  doAssert(xf == 16.0'f32, $xf)
+
 test()
+test_float_cast()
+test_float32_cast()
 static:
   test()
+  test_float_cast()
+  test_float32_cast()
 
 echo "OK"
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/tconstobj.nim b/tests/vm/tconstobj.nim
index 38fcdd844..021fcb728 100644
--- a/tests/vm/tconstobj.nim
+++ b/tests/vm/tconstobj.nim
@@ -1,10 +1,12 @@
 discard """
-  output: '''(name: "hello")
-(-1, 0)'''
+  output: '''
+(name: "hello")
+(-1, 0)
+(FirstName: "James", LastName: "Franco")
+'''
 """
 
 # bug #2774, bug #3195
-
 type Foo = object
   name: string
 
@@ -14,7 +16,6 @@ const fooArray = [
 
 echo fooArray[0]
 
-
 type
     Position = object
         x, y: int
@@ -34,3 +35,16 @@ const
      ]
 
 echo offset[1]
+
+# bug #1547
+import tables
+
+type Person* = object
+    FirstName*: string
+    LastName*: string
+
+let people = {
+    "001": Person(FirstName: "James", LastName: "Franco")
+}.toTable()
+
+echo people["001"]
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/tforwardproc.nim b/tests/vm/tforwardproc.nim
index 727ac6641..bcd929f0e 100644
--- a/tests/vm/tforwardproc.nim
+++ b/tests/vm/tforwardproc.nim
@@ -14,4 +14,4 @@ proc initArray(): array[10, int] =
   for f in 0..<10:
     result[f] = 3
 
-when isMainModule: echo repr(someTable)
+when true: echo repr(someTable)
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 d465e22b9..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
@@ -27,3 +27,54 @@ proc test() =
 
 static:
   test()
+
+#----------------------------------------------
+# Bugs #9701 and #9702
+type
+  MyKind = enum
+    kA, kB, kC
+
+  Base = ref object of RootObj
+    x: string
+
+  A = ref object of Base
+    a: string
+
+  B = ref object of Base
+    b: string
+
+  C = ref object of B
+    c: string
+
+template check_templ(n: Base, k: MyKind) =
+  if k == kA: doAssert(n of A) else: doAssert(not (n of A))
+  if k in {kB, kC}: doAssert(n of B) else: doAssert(not (n of B))
+  if k == kC: doAssert(n of C) else: doAssert(not (n of C))
+  doAssert(n of Base) 
+
+proc check_proc(n: Base, k: MyKind) =
+  if k == kA: doAssert(n of A) else: doAssert(not (n of A))
+  if k in {kB, kC}: doAssert(n of B) else: doAssert(not (n of B))
+  if k == kC: doAssert(n of C) else: doAssert(not (n of C))
+  doAssert(n of Base) 
+
+static:
+  let aa = new(A)
+  check_templ(aa, kA)
+  check_proc(aa, kA)
+  let bb = new(B)
+  check_templ(bb, kB)
+  check_proc(bb, kB)
+  let cc = new(C)
+  check_templ(cc, kC)
+  check_proc(cc, kC)
+    
+let aa = new(A)
+check_templ(aa, kA)
+check_proc(aa, kA)
+let bb = new(B)
+check_templ(bb, kB)
+check_proc(bb, kB)
+let cc = new(C)
+check_templ(cc, kC)
+check_proc(cc, kC)
diff --git a/tests/vm/tissues.nim b/tests/vm/tissues.nim
new file mode 100644
index 000000000..021b902ad
--- /dev/null
+++ b/tests/vm/tissues.nim
@@ -0,0 +1,30 @@
+discard """
+  nimout: "(Field0: 2, Field1: 2, Field2: 2, Field3: 2)"
+"""
+
+import macros
+
+block t9043:
+  proc foo[N: static[int]](dims: array[N, int])=
+    const N1 = N
+    const N2 = dims.len
+    static: echo (N, dims.len, N1, N2)
+
+  foo([1, 2])
+
+block t4952:
+  proc doCheck(tree: NimNode) =
+    let res: tuple[n: NimNode] = (n: tree)
+    assert: tree.kind == res.n.kind
+    for sub in tree:
+      doCheck(sub)
+
+  macro id(body: untyped): untyped =
+    doCheck(body)
+
+  id(foo((i: int)))
+
+  static:
+    let tree = newTree(nnkExprColonExpr)
+    let t = (n: tree)
+    assert: t.n.kind == tree.kind
diff --git a/tests/vm/tmitems.nim b/tests/vm/tmitems_vm.nim
index a0e64d6aa..87835d1cd 100644
--- a/tests/vm/tmitems.nim
+++ b/tests/vm/tmitems_vm.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: '''13'''
+  nimout: '''13'''
   output: '''3
 3
 3'''
diff --git a/tests/vm/tnimnode.nim b/tests/vm/tnimnode.nim
index 4210ab41d..f1c4d5e5a 100644
--- a/tests/vm/tnimnode.nim
+++ b/tests/vm/tnimnode.nim
@@ -14,7 +14,7 @@ var nodeSeq {.compileTime.} = newSeq[NimNode](2)
 proc checkNode(arg: NimNode; name: string): void {. compileTime .} =
   echo "checking ", name
 
-  assertEq arg.lispRepr , "StmtList(DiscardStmt(Empty()))"
+  assertEq arg.lispRepr, """(StmtList (DiscardStmt (Empty)))"""
 
   node = arg
   nodeArray = [arg]
@@ -24,12 +24,12 @@ proc checkNode(arg: NimNode; name: string): void {. compileTime .} =
   seqAppend.add(arg)   # bit this creates a copy
   arg.add newCall(ident"echo", newLit("Hello World"))
 
-  assertEq arg.lispRepr          , """StmtList(DiscardStmt(Empty()), Call(Ident("echo"), StrLit("Hello World")))"""
-  assertEq node.lispRepr         , """StmtList(DiscardStmt(Empty()), Call(Ident("echo"), StrLit("Hello World")))"""
-  assertEq nodeArray[0].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident("echo"), StrLit("Hello World")))"""
-  assertEq nodeSeq[0].lispRepr   , """StmtList(DiscardStmt(Empty()), Call(Ident("echo"), StrLit("Hello World")))"""
-  assertEq seqAppend[0].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident("echo"), StrLit("Hello World")))"""
-  assertEq seqAppend[1].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident("echo"), StrLit("Hello World")))"""
+  assertEq arg.lispRepr,          """(StmtList (DiscardStmt (Empty)) (Call (Ident "echo") (StrLit "Hello World")))"""
+  assertEq node.lispRepr,         """(StmtList (DiscardStmt (Empty)) (Call (Ident "echo") (StrLit "Hello World")))"""
+  assertEq nodeArray[0].lispRepr, """(StmtList (DiscardStmt (Empty)) (Call (Ident "echo") (StrLit "Hello World")))"""
+  assertEq nodeSeq[0].lispRepr,   """(StmtList (DiscardStmt (Empty)) (Call (Ident "echo") (StrLit "Hello World")))"""
+  assertEq seqAppend[0].lispRepr, """(StmtList (DiscardStmt (Empty)) (Call (Ident "echo") (StrLit "Hello World")))"""
+  assertEq seqAppend[1].lispRepr, """(StmtList (DiscardStmt (Empty)) (Call (Ident "echo") (StrLit "Hello World")))"""
 
   echo "OK"
 
diff --git a/tests/vm/tsetlen.nim b/tests/vm/tsetlen.nim
new file mode 100644
index 000000000..9fd30f331
--- /dev/null
+++ b/tests/vm/tsetlen.nim
@@ -0,0 +1,30 @@
+type Foo = object
+  index: int
+
+block:
+  proc fun[T]() =
+    var foo: T
+    var n = 10
+
+    var foos: seq[T]
+    foos.setLen n
+
+    n.inc
+    foos.setLen n
+
+    for i in 0 ..< n:
+      let temp = foos[i]
+      when T is object:
+        doAssert temp.index == 0
+      when T is ref object:
+        doAssert temp == nil
+      doAssert temp == foo
+
+  static:
+    fun[Foo]()
+    fun[int]()
+    fun[float]()
+    fun[string]()
+    fun[(int, string)]()
+    fun[ref Foo]()
+    fun[seq[int]]()
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 027db45d6..d762eb079 100644
--- a/tests/vm/tslurp.nim
+++ b/tests/vm/tslurp.nim
@@ -4,9 +4,9 @@ template getScriptDir(): string =
   parentDir(instantiationInfo(-1, true).filename)
 
 const
-  relRes = slurp"../../readme.txt"
-  absRes = slurp(parentDir(parentDir(getScriptDir())) / "readme.txt")
-
-echo relRes
-echo absRes
+  relRes = slurp"./tslurp.nim"
+  absRes = slurp(getScriptDir() / "tslurp.nim")
 
+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/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim
index 350f3c08e..bd3aa2fcd 100644
--- a/tests/vm/tvmmisc.nim
+++ b/tests/vm/tvmmisc.nim
@@ -1,7 +1,6 @@
 # bug #4462
 import macros
 import os
-import ospaths
 import strutils
 
 block:
@@ -71,7 +70,9 @@ block:
 # Tests for VM ops
 block:
   static:
-    assert "vm" in getProjectPath()
+    # for joint test, the project path is different, so I disabled it:
+    when false:
+      assert "vm" in getProjectPath()
 
     let b = getEnv("UNSETENVVAR")
     assert b == ""
diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim
index c54f820fe..03a694449 100644
--- a/tools/kochdocs.nim
+++ b/tools/kochdocs.nim
@@ -52,14 +52,25 @@ proc execCleanPath*(cmd: string,
   putEnv("PATH", prevPath)
 
 proc nimexec*(cmd: string) =
+  # Consider using `nimCompile` instead
   exec findNim() & " " & cmd
 
+proc nimCompile*(input: string, outputDir = "bin", mode = "c", options = "") =
+  # TODO: simplify pending https://github.com/nim-lang/Nim/issues/9513
+  var cmd = findNim() & " " & mode
+  let output = outputDir / input.splitFile.name.exe
+  cmd.add " -o:" & output
+  cmd.add " " & options
+  cmd.add " " & input
+  exec cmd
+
 const
   pdf = """
 doc/manual.rst
 doc/lib.rst
 doc/tut1.rst
 doc/tut2.rst
+doc/tut3.rst
 doc/nimc.rst
 doc/niminst.rst
 doc/gc.rst
@@ -72,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
@@ -95,7 +107,7 @@ doc/manual/var_t_return.rst
   doc = """
 lib/system.nim
 lib/system/nimscript.nim
-lib/pure/ospaths.nim
+lib/deprecated/pure/ospaths.nim
 lib/pure/parsejson.nim
 lib/pure/cstrutils.nim
 lib/core/macros.nim
@@ -115,7 +127,9 @@ lib/pure/os.nim
 lib/pure/strutils.nim
 lib/pure/math.nim
 lib/pure/matchers.nim
-lib/pure/editdistance.nim
+lib/std/editdistance.nim
+lib/std/wordwrap.nim
+lib/std/diff.nim
 lib/pure/algorithm.nim
 lib/pure/stats.nim
 lib/windows/winlean.nim
diff --git a/tools/nim-gdb.py b/tools/nim-gdb.py
index b98dc96fe..1a0d89fcb 100644
--- a/tools/nim-gdb.py
+++ b/tools/nim-gdb.py
@@ -209,6 +209,25 @@ class NimStringPrinter:
     else:
      return ""
 
+class NimRopePrinter:
+  pattern = re.compile(r'^tyObject_RopeObj_OFzf0kSiPTcNreUIeJgWVA \*$')
+
+  def __init__(self, val):
+    self.val = val
+
+  def display_hint(self):
+    return 'string'
+
+  def to_string(self):
+    if self.val:
+      left  = NimRopePrinter(self.val["left"]).to_string()
+      data  = NimStringPrinter(self.val["data"]).to_string()
+      right = NimRopePrinter(self.val["right"]).to_string()
+      return left + data + right
+    else:
+      return ""
+
+
 ################################################################################
 
 # proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
diff --git a/tools/nimfind.nim b/tools/nimfind.nim
new file mode 100644
index 000000000..b9c7d8ac9
--- /dev/null
+++ b/tools/nimfind.nim
@@ -0,0 +1,237 @@
+#
+#
+#           The Nim Compiler
+#        (c) Copyright 2018 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## Nimfind is a tool that helps to give editors IDE like capabilities.
+
+when not defined(nimcore):
+  {.error: "nimcore MUST be defined for Nim's core tooling".}
+when not defined(nimfind):
+  {.error: "nimfind MUST be defined for Nim's nimfind tool".}
+
+const Usage = """
+Nimfind - Tool to find declarations or usages for Nim symbols
+Usage:
+  nimfind [options] file.nim:line:col
+
+Options:
+  --help, -h              show this help
+  --rebuild               rebuild the index
+  --project:file.nim      use file.nim as the entry point
+
+In addition, all command line options of Nim that do not affect code generation
+are supported.
+"""
+
+import strutils, os, parseopt, parseutils
+
+import "../compiler" / [options, commands, modules, sem,
+  passes, passaux, msgs, nimconf,
+  extccomp, condsyms,
+  ast, scriptconfig,
+  idents, modulegraphs, vm, prefixmatches, lineinfos, cmdlinehelper,
+  pathutils]
+
+import db_sqlite
+
+proc createDb(db: DbConn) =
+  db.exec(sql"""
+  create table if not exists filenames(
+    id integer primary key,
+    fullpath varchar(8000) not null
+  );
+  """)
+  db.exec sql"create index if not exists FilenameIx on filenames(fullpath);"
+
+  # every sym can have potentially 2 different definitions due to forward
+  # declarations.
+  db.exec(sql"""
+  create table if not exists syms(
+    id integer primary key,
+    nimid integer not null,
+    name varchar(256) not null,
+    defline integer not null,
+    defcol integer not null,
+    deffile integer not null,
+    deflineB integer not null default 0,
+    defcolB integer not null default 0,
+    deffileB integer not null default 0,
+    foreign key (deffile) references filenames(id),
+    foreign key (deffileB) references filenames(id)
+  );
+  """)
+
+  db.exec(sql"""
+  create table if not exists usages(
+    id integer primary key,
+    nimid integer not null,
+    line integer not null,
+    col integer not null,
+    colB integer not null,
+    file integer not null,
+    foreign key (file) references filenames(id),
+    foreign key (nimid) references syms(nimid)
+  );
+  """)
+  db.exec sql"create index if not exists UsagesIx on usages(file, line);"
+
+proc toDbFileId*(db: DbConn; conf: ConfigRef; fileIdx: FileIndex): int =
+  if fileIdx == FileIndex(-1): return -1
+  let fullpath = toFullPath(conf, fileIdx)
+  let row = db.getRow(sql"select id from filenames where fullpath = ?", fullpath)
+  let id = row[0]
+  if id.len == 0:
+    result = int db.insertID(sql"insert into filenames(fullpath) values (?)",
+      fullpath)
+  else:
+    result = parseInt(id)
+
+type
+  FinderRef = ref object of RootObj
+    db: DbConn
+
+proc writeDef(graph: ModuleGraph; s: PSym; info: TLineInfo) =
+  let f = FinderRef(graph.backend)
+  f.db.exec(sql"""insert into syms(nimid, name, defline, defcol, deffile) values (?, ?, ?, ?, ?)""",
+    s.id, s.name.s, info.line, info.col,
+    toDbFileId(f.db, graph.config, info.fileIndex))
+
+proc writeDefResolveForward(graph: ModuleGraph; s: PSym; info: TLineInfo) =
+  let f = FinderRef(graph.backend)
+  f.db.exec(sql"""update syms set deflineB = ?, defcolB = ?, deffileB = ?
+    where nimid = ?""", info.line, info.col,
+    toDbFileId(f.db, graph.config, info.fileIndex), s.id)
+
+proc writeUsage(graph: ModuleGraph; s: PSym; info: TLineInfo) =
+  let f = FinderRef(graph.backend)
+  f.db.exec(sql"""insert into usages(nimid, line, col, colB, file) values (?, ?, ?, ?, ?)""",
+    s.id, info.line, info.col, info.col + s.name.s.len - 1,
+    toDbFileId(f.db, graph.config, info.fileIndex))
+
+proc performSearch(conf: ConfigRef; dbfile: AbsoluteFile) =
+  var db = open(connection=string dbfile, user="nim", password="",
+                database="nim")
+  let pos = conf.m.trackPos
+  let fid = toDbFileId(db, conf, pos.fileIndex)
+  let known = toFullPath(conf, pos.fileIndex)
+  let nimids = db.getRow(sql"""select distinct nimid from usages where line = ? and file = ? and ? between col and colB""",
+      pos.line, fid, pos.col)
+  if nimids.len > 0:
+    var idSet = ""
+    for id in nimids:
+      if idSet.len > 0: idSet.add ", "
+      idSet.add id
+    var outputLater = ""
+    for r in db.rows(sql"""select line, col, filenames.fullpath from usages
+                          inner join filenames on filenames.id = file
+                          where nimid in (?)""", idSet):
+      let line = parseInt(r[0])
+      let col = parseInt(r[1])
+      let file = r[2]
+      if file == known and line == pos.line.int:
+        # output the line we already know last:
+        outputLater.add file & ":" & $line & ":" & $(col+1) & "\n"
+      else:
+        echo file, ":", line, ":", col+1
+    if outputLater.len > 0: stdout.write outputLater
+  close(db)
+
+proc setupDb(g: ModuleGraph; dbfile: AbsoluteFile) =
+  var f = FinderRef()
+  removeFile(dbfile)
+  f.db = open(connection=string dbfile, user="nim", password="",
+            database="nim")
+  createDb(f.db)
+  f.db.exec(sql"pragma journal_mode=off")
+  # This MUST be turned off, otherwise it's way too slow even for testing purposes:
+  f.db.exec(sql"pragma SYNCHRONOUS=off")
+  f.db.exec(sql"pragma LOCKING_MODE=exclusive")
+  g.backend = f
+
+proc mainCommand(graph: ModuleGraph) =
+  let conf = graph.config
+  let dbfile = getNimcacheDir(conf) / RelativeFile"nimfind.db"
+  if not fileExists(dbfile) or optForceFullMake in conf.globalOptions:
+    clearPasses(graph)
+    registerPass graph, verbosePass
+    registerPass graph, semPass
+    conf.cmd = cmdIdeTools
+    wantMainModule(conf)
+    setupDb(graph, dbfile)
+
+    graph.onDefinition = writeUsage # writeDef
+    graph.onDefinitionResolveForward = writeUsage # writeDefResolveForward
+    graph.onUsage = writeUsage
+
+    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)
+    try:
+      compileProject(graph)
+    finally:
+      close(FinderRef(graph.backend).db)
+  performSearch(conf, dbfile)
+
+proc processCmdLine*(pass: TCmdLinePass, cmd: string; conf: ConfigRef) =
+  var p = parseopt.initOptParser(cmd)
+  while true:
+    parseopt.next(p)
+    case p.kind
+    of cmdEnd: break
+    of cmdLongoption, cmdShortOption:
+      case p.key.normalize
+      of "help", "h":
+        stdout.writeline(Usage)
+        quit()
+      of "project":
+        conf.projectName = p.val
+      of "rebuild":
+        incl conf.globalOptions, optForceFullMake
+      else: processSwitch(pass, p, conf)
+    of cmdArgument:
+      let info = p.key.split(':')
+      if info.len == 3:
+        let (dir, file, ext) = info[0].splitFile()
+        conf.projectName = findProjectNimFile(conf, dir)
+        if conf.projectName.len == 0: conf.projectName = info[0]
+        try:
+          conf.m.trackPos = newLineInfo(conf, AbsoluteFile info[0],
+                                        parseInt(info[1]), parseInt(info[2])-1)
+        except ValueError:
+          quit "invalid command line"
+      else:
+        quit "invalid command line"
+
+proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
+  let self = NimProg(
+    suggestMode: true,
+    processCmdLine: processCmdLine,
+    mainCommand: mainCommand
+  )
+  self.initDefinesProg(conf, "nimfind")
+
+  if paramCount() == 0:
+    stdout.writeline(Usage)
+    return
+
+  self.processCmdLineAndProjectPath(conf)
+
+  # Find Nim's prefix dir.
+  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""
+
+  discard self.loadConfigsAndRunMainCommand(cache, conf)
+
+handleCmdline(newIdentCache(), newConfigRef())
diff --git a/tools/nimfind.nims b/tools/nimfind.nims
new file mode 100644
index 000000000..3013c360d
--- /dev/null
+++ b/tools/nimfind.nims
@@ -0,0 +1,2 @@
+--define:nimfind
+--define:nimcore
diff --git a/tools/niminst/buildbat.tmpl b/tools/niminst/buildbat.nimf
index 6767461e3..6767461e3 100644
--- a/tools/niminst/buildbat.tmpl
+++ b/tools/niminst/buildbat.nimf
diff --git a/tools/niminst/buildsh.tmpl b/tools/niminst/buildsh.nimf
index acd58bda2..04ef35653 100644
--- a/tools/niminst/buildsh.tmpl
+++ b/tools/niminst/buildsh.nimf
@@ -1,7 +1,7 @@
 #? stdtmpl(subsChar='?') | standard
 #proc generateBuildShellScript(c: ConfigData): string =
 #  result = "#! /bin/sh\n# Generated from niminst\n" &
-#           "# Template is in tools/niminst/buildsh.tmpl\n" &
+#           "# Template is in tools/niminst/buildsh.nimf\n" &
 #           "# To regenerate run ``niminst csource`` or ``koch csource``\n"
 
 set -e
diff --git a/tools/niminst/debcreation.nim b/tools/niminst/debcreation.nim
index 0ecea132f..60aa48639 100644
--- a/tools/niminst/debcreation.nim
+++ b/tools/niminst/debcreation.nim
@@ -84,7 +84,7 @@ proc createCopyright(pkgName, mtnName, mtnEmail, version: string,
     addN("Files: " & f)
     addN("License: " & license)
 
-proc formatDateTime(t: TimeInfo, timezone: string): string =
+proc formatDateTime(t: DateTime, timezone: string): string =
   var day = ($t.weekday)[0..2] & ", "
 
   return "$1$2 $3 $4 $5:$6:$7 $8" % [day, intToStr(t.monthday, 2),
diff --git a/tools/niminst/deinstall.tmpl b/tools/niminst/deinstall.nimf
index 8b4477369..8b4477369 100644
--- a/tools/niminst/deinstall.tmpl
+++ b/tools/niminst/deinstall.nimf
diff --git a/tools/niminst/inno.tmpl b/tools/niminst/inno.nimf
index ef2da8a75..ef2da8a75 100644
--- a/tools/niminst/inno.tmpl
+++ b/tools/niminst/inno.nimf
diff --git a/tools/niminst/install.tmpl b/tools/niminst/install.nimf
index a78914ecd..a78914ecd 100644
--- a/tools/niminst/install.tmpl
+++ b/tools/niminst/install.nimf
diff --git a/tools/niminst/makefile.tmpl b/tools/niminst/makefile.nimf
index aadd0e94d..3467f025e 100644
--- a/tools/niminst/makefile.tmpl
+++ b/tools/niminst/makefile.nimf
@@ -1,7 +1,7 @@
 #? stdtmpl(subsChar='?') | standard
 #proc generateMakefile(c: ConfigData): string =
 #  result = "# Generated from niminst\n" &
-#           "# Template is in tools/niminst/makefile.tmpl\n" &
+#           "# Template is in tools/niminst/makefile.nimf\n" &
 #           "# To regenerate run ``niminst csource`` or ``koch csource``\n"
 
 CC ??= gcc
diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim
index 3c5572a07..9e428993a 100644
--- a/tools/niminst/niminst.nim
+++ b/tools/niminst/niminst.nim
@@ -126,13 +126,13 @@ proc skipRoot(f: string): string =
     inc i
   if result.len == 0: result = f
 
-include "inno.tmpl"
-include "nsis.tmpl"
-include "buildsh.tmpl"
-include "makefile.tmpl"
-include "buildbat.tmpl"
-include "install.tmpl"
-include "deinstall.tmpl"
+include "inno.nimf"
+include "nsis.nimf"
+include "buildsh.nimf"
+include "makefile.nimf"
+include "buildbat.nimf"
+include "install.nimf"
+include "deinstall.nimf"
 
 # ------------------------- configuration file -------------------------------
 
diff --git a/tools/niminst/nsis.tmpl b/tools/niminst/nsis.nimf
index f4eb1d0cd..f4eb1d0cd 100644
--- a/tools/niminst/nsis.tmpl
+++ b/tools/niminst/nsis.nimf
diff --git a/tools/nimweb.nim b/tools/nimweb.nim
index b7fee220a..460135f49 100644
--- a/tools/nimweb.nim
+++ b/tools/nimweb.nim
@@ -71,7 +71,7 @@ proc initConfigData(c: var TConfigData) =
       c.gitCommit = output.strip
   c.quotations = initTable[string, tuple[quote, author: string]]()
 
-include "website.tmpl"
+include "website.nimf"
 
 # ------------------------- configuration file -------------------------------
 
diff --git a/tools/vccenv/vccenv.nim b/tools/vccenv/vccenv.nim
index a5af7994e..1f172c7c0 100644
--- a/tools/vccenv/vccenv.nim
+++ b/tools/vccenv/vccenv.nim
@@ -3,6 +3,7 @@ import strtabs, os, osproc, streams, strutils
 const
   comSpecEnvKey = "ComSpec"
   vsComnToolsEnvKeys = [
+    "VS150COMNTOOLS",
     "VS140COMNTOOLS",
     "VS130COMNTOOLS",
     "VS120COMNTOOLS",
diff --git a/tools/website.tmpl b/tools/website.nimf
index 9e5eb2460..9e5eb2460 100644
--- a/tools/website.tmpl
+++ b/tools/website.nimf