summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml2
-rw-r--r--changelog.md39
-rw-r--r--changelogs/changelog_0_19_0.md2
-rw-r--r--compiler/ast.nim7
-rw-r--r--compiler/ccgexprs.nim60
-rw-r--r--compiler/ccgliterals.nim2
-rw-r--r--compiler/ccgstmts.nim17
-rw-r--r--compiler/ccgtypes.nim5
-rw-r--r--compiler/cgen.nim93
-rw-r--r--compiler/cgendata.nim11
-rw-r--r--compiler/closureiters.nim24
-rw-r--r--compiler/commands.nim12
-rw-r--r--compiler/condsyms.nim3
-rw-r--r--compiler/destroyer.nim25
-rw-r--r--compiler/dfa.nim14
-rw-r--r--compiler/docgen.nim2
-rw-r--r--compiler/importer.nim2
-rw-r--r--compiler/incremental.nim5
-rw-r--r--compiler/layouter.nim11
-rw-r--r--compiler/lexer.nim5
-rw-r--r--compiler/lineinfos.nim5
-rw-r--r--compiler/lookups.nim2
-rw-r--r--compiler/main.nim141
-rw-r--r--compiler/modulegraphs.nim29
-rw-r--r--compiler/modules.nim2
-rw-r--r--compiler/msgs.nim9
-rw-r--r--compiler/nim.nim3
-rw-r--r--compiler/options.nim6
-rw-r--r--compiler/parser.nim56
-rw-r--r--compiler/pathutils.nim17
-rw-r--r--compiler/pragmas.nim8
-rw-r--r--compiler/reorder.nim2
-rw-r--r--compiler/rod.nim2
-rw-r--r--compiler/rodimpl.nim59
-rw-r--r--compiler/scriptconfig.nim4
-rw-r--r--compiler/sem.nim9
-rw-r--r--compiler/semasgn.nim17
-rw-r--r--compiler/semcall.nim31
-rw-r--r--compiler/semexprs.nim63
-rw-r--r--compiler/semfold.nim24
-rw-r--r--compiler/semgnrc.nim23
-rw-r--r--compiler/semmagic.nim38
-rw-r--r--compiler/sempass2.nim7
-rw-r--r--compiler/semstmts.nim21
-rw-r--r--compiler/semtempl.nim22
-rw-r--r--compiler/semtypes.nim16
-rw-r--r--compiler/semtypinst.nim5
-rw-r--r--compiler/sigmatch.nim23
-rw-r--r--compiler/sizealignoffsetimpl.nim48
-rw-r--r--compiler/suggest.nim4
-rw-r--r--compiler/syntaxes.nim30
-rw-r--r--compiler/transf.nim29
-rw-r--r--compiler/types.nim4
-rw-r--r--compiler/vm.nim25
-rw-r--r--compiler/vmdef.nim3
-rw-r--r--compiler/vmdeps.nim5
-rw-r--r--compiler/vmgen.nim30
-rw-r--r--compiler/vmops.nim15
-rw-r--r--compiler/wordrecg.nim12
-rw-r--r--doc/advopt.txt4
-rw-r--r--doc/codeowners.rst2
-rw-r--r--doc/contributing.rst8
-rw-r--r--doc/filters.rst9
-rw-r--r--doc/grammar.txt9
-rw-r--r--doc/intern.rst2
-rw-r--r--doc/lib.rst5
-rw-r--r--doc/manual.rst71
-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--issue_template.md14
-rw-r--r--koch.nim59
-rw-r--r--lib/core/locks.nim2
-rw-r--r--lib/core/macros.nim30
-rw-r--r--lib/core/seqs.nim6
-rw-r--r--lib/core/typeinfo.nim2
-rw-r--r--lib/deprecated/pure/actors.nim1
-rw-r--r--lib/deprecated/pure/asyncio.nim5
-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.nim9
-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.nim17
-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/posix/inotify.nim1
-rw-r--r--lib/posix/posix.nim1
-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.nim10
-rw-r--r--lib/pure/asyncfutures.nim21
-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.nim9
-rw-r--r--lib/pure/collections/queues.nim2
-rw-r--r--lib/pure/collections/rtarrays.nim1
-rw-r--r--lib/pure/collections/sequtils.nim160
-rw-r--r--lib/pure/collections/sets.nim4
-rw-r--r--lib/pure/collections/tables.nim8
-rw-r--r--lib/pure/complex.nim646
-rw-r--r--lib/pure/coro.nim24
-rw-r--r--lib/pure/encodings.nim1
-rw-r--r--lib/pure/httpclient.nim4
-rw-r--r--lib/pure/includes/osenv.nim11
-rw-r--r--lib/pure/includes/oserr.nim4
-rw-r--r--lib/pure/math.nim3
-rw-r--r--lib/pure/os.nim903
-rw-r--r--lib/pure/ospaths.nim713
-rw-r--r--lib/pure/osproc.nim7
-rw-r--r--lib/pure/parseopt.nim21
-rw-r--r--lib/pure/parsesql.nim3
-rw-r--r--lib/pure/pegs.nim16
-rw-r--r--lib/pure/random.nim4
-rw-r--r--lib/pure/smtp.nim22
-rw-r--r--lib/pure/strutils.nim75
-rw-r--r--lib/pure/subexes.nim2
-rw-r--r--lib/pure/terminal.nim6
-rw-r--r--lib/pure/times.nim71
-rw-r--r--lib/pure/unicode.nim29
-rw-r--r--lib/pure/unittest.nim2
-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.nim19
-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/debugger.nim2
-rw-r--r--lib/system/dyncalls.nim7
-rw-r--r--lib/system/endb.nim2
-rw-r--r--lib/system/excpt.nim9
-rw-r--r--lib/system/gc_common.nim80
-rw-r--r--lib/system/mmdisp.nim1
-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/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.nim15
-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.html4
-rw-r--r--nimdoc/testproject/expected/testproject.html4
-rw-r--r--nimpretty/nimpretty.nim20
-rw-r--r--nimpretty/tests/exhaustive.nim3
-rw-r--r--nimpretty/tests/expected/exhaustive.nim3
-rw-r--r--nimsuggest/nimsuggest.nim106
-rw-r--r--nimsuggest/nimsuggest.nim.cfg2
-rw-r--r--testament/categories.nim36
-rw-r--r--testament/specs.nim13
-rw-r--r--testament/tester.nim43
-rw-r--r--tests/array/tarray.nim2
-rw-r--r--tests/assert/testhelper.nim2
-rw-r--r--tests/async/t7192.nim14
-rw-r--r--tests/async/t8982.nim33
-rw-r--r--tests/async/tasyncall.nim2
-rw-r--r--tests/async/tasyncssl.nim8
-rw-r--r--tests/async/tcallbacks.nim5
-rw-r--r--tests/async/tfuturevar.nim6
-rw-r--r--tests/casestmt/tlinearscanend.nim4
-rw-r--r--tests/ccgbugs/t6756.nim6
-rw-r--r--tests/ccgbugs/t8964.nim10
-rw-r--r--tests/ccgbugs/tcodegendecllambda.nim1
-rw-r--r--tests/ccgbugs/tgeneric_closure.nim8
-rw-r--r--tests/ccgbugs/trecursive_closure.nim4
-rw-r--r--tests/ccgbugs/tsighash_typename_regression.nim7
-rw-r--r--tests/ccgbugs/tuple_canon.nim7
-rw-r--r--tests/closure/tclosure.nim2
-rw-r--r--tests/closure/texplicit_dummy_closure.nim10
-rw-r--r--tests/closure/tmacrobust1512.nim40
-rw-r--r--tests/closure/ttimeinfo.nim15
-rw-r--r--tests/compiles/trecursive_generic_in_compiles.nim4
-rw-r--r--tests/concepts/tconcepts_issues.nim1
-rw-r--r--tests/concepts/tmapconcept.nim2
-rw-r--r--tests/concepts/tmatrixconcept.nim2
-rw-r--r--tests/concepts/tstackconcept.nim2
-rw-r--r--tests/converter/t7098.nim4
-rw-r--r--tests/converter/tconvcolors.nim4
-rw-r--r--tests/converter/tconverter_unique_ptr.nim107
-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/t8241.nim11
-rw-r--r--tests/cpp/tcasts.nim12
-rw-r--r--tests/cpp/tnativesockets.nim1
-rw-r--r--tests/cpp/tsigbreak.nim1
-rw-r--r--tests/defaultprocparam/tdefaultprocparam.nim6
-rw-r--r--tests/destructor/t6434.nim21
-rw-r--r--tests/destructor/texplicit_move.nim12
-rw-r--r--tests/destructor/tmove_objconstr.nim59
-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.nim15
-rw-r--r--tests/discard/tillegaldiscard.nim9
-rw-r--r--tests/dll/server.nim8
-rw-r--r--tests/effects/teffects6.nim5
-rw-r--r--tests/errmsgs/treportunused.nim29
-rw-r--r--tests/exception/t9657.nim6
-rw-r--r--tests/exception/tonraise.nim34
-rw-r--r--tests/exprs/tifexpr_typeinference.nim8
-rw-r--r--tests/flags/tgenscript.nim2
-rw-r--r--tests/float/tfloatmod.nim130
-rw-r--r--tests/generics/t2tables.nim4
-rw-r--r--tests/generics/tgeneric3.nim10
-rw-r--r--tests/generics/tgenerictmpl2.nim2
-rw-r--r--tests/generics/tgenericvariant.nim13
-rw-r--r--tests/generics/tlateboundstatic.nim2
-rw-r--r--tests/generics/trtree.nim19
-rw-r--r--tests/generics/tthread_generic.nim2
-rw-r--r--tests/global/tglobalforvar.nim4
-rw-r--r--tests/init/t8314.nim10
-rw-r--r--tests/init/tuninit1.nim3
-rw-r--r--tests/iter/timplicit_auto.nim2
-rw-r--r--tests/iter/titer.nim13
-rw-r--r--tests/iter/titer_no_tuple_unpack.nim16
-rw-r--r--tests/iter/titervaropenarray.nim3
-rw-r--r--tests/iter/tpermutations.nim11
-rw-r--r--tests/iter/tshallowcopy_closures.nim8
-rw-r--r--tests/iter/twrap_walkdir.nim5
-rw-r--r--tests/iter/tyieldintry.nim15
-rw-r--r--tests/js/tjsffi.nim24
-rw-r--r--tests/lexer/tident.nim14
-rw-r--r--tests/lookups/test.nim8
-rw-r--r--tests/lookups/tprefer_proc.nim4
-rw-r--r--tests/macros/tbindsym.nim2
-rw-r--r--tests/macros/tdumpastgen.nim2
-rw-r--r--tests/macros/tdumptree.nim9
-rw-r--r--tests/macros/tgetimpl.nim36
-rw-r--r--tests/macros/tgettype.nim6
-rw-r--r--tests/macros/tgettype2.nim32
-rw-r--r--tests/macros/tgettypeinst.nim11
-rw-r--r--tests/macros/tmacrogenerics.nim8
-rw-r--r--tests/macros/tmacros_issues.nim15
-rw-r--r--tests/macros/tmacros_various.nim15
-rw-r--r--tests/macros/tmemit.nim6
-rw-r--r--tests/macros/tnewlit.nim20
-rw-r--r--tests/macros/tquotedo.nim25
-rw-r--r--tests/macros/tslice.nim38
-rw-r--r--tests/macros/tstaticparamsmacro.nim9
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim20
-rw-r--r--tests/manyloc/keineschweine/enet_server/enet_client.nim2
-rw-r--r--tests/manyloc/keineschweine/keineschweine.nim8
-rw-r--r--tests/manyloc/keineschweine/lib/client_helpers.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/vehicles.nim2
-rw-r--r--tests/metatype/tbindtypedesc.nim8
-rw-r--r--tests/metatype/tmetatype_issues.nim16
-rw-r--r--tests/metatype/tsemistatic.nim2
-rw-r--r--tests/metatype/tstaticparammacro.nim8
-rw-r--r--tests/metatype/ttypedesc3.nim10
-rw-r--r--tests/metatype/ttypetraits.nim2
-rw-r--r--tests/misc/tcmdline.nim3
-rw-r--r--tests/misc/tcolonisproc.nim6
-rw-r--r--tests/misc/tdllvar.nim6
-rw-r--r--tests/misc/tendian.nim3
-rw-r--r--tests/misc/tgetstartmilsecs.nim7
-rw-r--r--tests/misc/thallo.nim6
-rw-r--r--tests/misc/theaproots.nim4
-rw-r--r--tests/misc/tlastmod.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.nim7
-rw-r--r--tests/misc/tnewuns.nim12
-rw-r--r--tests/misc/tparseopt.nim77
-rw-r--r--tests/misc/tprep.nim8
-rw-r--r--tests/misc/tquicksort.nim9
-rw-r--r--tests/misc/tradix.nim25
-rw-r--r--tests/misc/treadln.nim11
-rw-r--r--tests/misc/treadx.nim13
-rw-r--r--tests/misc/treservedcidentsasfields.nim39
-rw-r--r--tests/misc/tshadow_magic_type.nim10
-rw-r--r--tests/misc/tsizeof.nim100
-rw-r--r--tests/misc/tstrace.nim20
-rw-r--r--tests/misc/tstrdist.nim2
-rw-r--r--tests/misc/tunsigned64mod.nim8
-rw-r--r--tests/misc/tvarious.nim4
-rw-r--r--tests/modules/t8665.nim4
-rw-r--r--tests/modules/texport2.nim9
-rw-r--r--tests/modules/timportas.nim8
-rw-r--r--tests/newconfig/tfoo.nim2
-rw-r--r--tests/newconfig/tfoo.nims3
-rw-r--r--tests/niminaction/Chapter3/ChatApp/src/client.nim4
-rw-r--r--tests/niminaction/Chapter3/ChatApp/src/server.nim6
-rw-r--r--tests/niminaction/Chapter3/various3.nim29
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/concurrency.nim4
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim4
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/naive.nim4
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim6
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/race_condition.nim6
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/sequential_counts.nim6
-rw-r--r--tests/niminaction/Chapter7/Tweeter/src/createDatabase.nim6
-rw-r--r--tests/niminaction/Chapter7/Tweeter/src/tweeter.nim4
-rw-r--r--tests/niminaction/Chapter7/Tweeter/tests/database_test.nim4
-rw-r--r--tests/niminaction/Chapter8/canvas/canvas.nim4
-rw-r--r--tests/niminaction/Chapter8/sdl/sdl_test.nim4
-rw-r--r--tests/niminaction/Chapter8/sfml/sfml_test.nim3
-rw-r--r--tests/objects/tobjcov.nim5
-rw-r--r--tests/objects/tobject.nim4
-rw-r--r--tests/objects/tobjects.nim52
-rw-r--r--tests/objvariant/tcheckedfield1.nim4
-rw-r--r--tests/osproc/ta_in.nim4
-rw-r--r--tests/osproc/ta_out.nim11
-rw-r--r--tests/osproc/tafalse.nim4
-rw-r--r--tests/osproc/texitcode.nim1
-rw-r--r--tests/overload/tselfderef.nim5
-rw-r--r--tests/parallel/tarray_of_channels.nim12
-rw-r--r--tests/parallel/tdont_be_stupid.nim10
-rw-r--r--tests/parallel/tguard1.nim4
-rw-r--r--tests/parallel/tlet_spawn.nim5
-rw-r--r--tests/parallel/tmissing_deepcopy.nim3
-rw-r--r--tests/parallel/tsimple_array_checks.nim22
-rw-r--r--tests/parser/tprecedence.nim23
-rw-r--r--tests/parser/tstrongspaces.nim83
-rw-r--r--tests/pragmas/tnoreturn.nim1
-rw-r--r--tests/seq/tseq.nim24
-rw-r--r--tests/sets/tsets_various.nim6
-rw-r--r--tests/stdlib/tcputime.nim11
-rw-r--r--tests/stdlib/thashes.nim13
-rw-r--r--tests/stdlib/thttpcore.nim3
-rw-r--r--tests/stdlib/tjsonexternproc.nim8
-rw-r--r--tests/stdlib/tjsontestsuite.nim4
-rw-r--r--tests/stdlib/tlists.nim10
-rw-r--r--tests/stdlib/tmath2.nim85
-rw-r--r--tests/stdlib/tmemfiles1.nim3
-rw-r--r--tests/stdlib/tmemlines.nim4
-rw-r--r--tests/stdlib/tmemlinesBuf.nim11
-rw-r--r--tests/stdlib/tmemslices.nim6
-rw-r--r--tests/stdlib/tnativesockets.nim5
-rw-r--r--tests/stdlib/tnet.nim4
-rw-r--r--tests/stdlib/tosprocterminate.nim4
-rw-r--r--tests/stdlib/tparsopt.nim8
-rw-r--r--tests/stdlib/tposix.nim7
-rw-r--r--tests/stdlib/tquit.nim6
-rw-r--r--tests/stdlib/trepr2.nim5
-rw-r--r--tests/stdlib/trstgen.nim12
-rw-r--r--tests/stdlib/tsortcall.nim6
-rw-r--r--tests/stdlib/tstreams.nim17
-rw-r--r--tests/stdlib/tstrtabs.nim91
-rw-r--r--tests/stdlib/ttimes.nim9
-rw-r--r--tests/stdlib/twalker.nim13
-rw-r--r--tests/system/t7894.nim28
-rw-r--r--tests/system/talloc.nim3
-rw-r--r--tests/system/talloc2.nim3
-rw-r--r--tests/system/tio.nim12
-rw-r--r--tests/system/tnilconcats.nim7
-rw-r--r--tests/system/tparams.nim4
-rw-r--r--tests/template/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/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/tgetast_typeliar.nim23
-rw-r--r--tests/template/thygienictempl.nim4
-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.nim13
-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/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/typedescids.nim17
-rw-r--r--tests/test_nimscript.nims2
-rw-r--r--tests/threads/tactors2.nim2
-rw-r--r--tests/trmacros/targlist.nim9
-rw-r--r--tests/trmacros/tcse.nim13
-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/typerel/tnoargopenarray.nim5
-rw-r--r--tests/typerel/trettypeinference.nim2
-rw-r--r--tests/typerel/tsecondarrayproperty.nim5
-rw-r--r--tests/typerel/ttuple1.nim8
-rw-r--r--tests/types/taliasbugs.nim2
-rw-r--r--tests/types/tauto_canbe_void.nim8
-rw-r--r--tests/vm/tconsteval.nim2
-rw-r--r--tests/vm/tconsttable2.nim2
-rw-r--r--tests/vm/teval1.nim11
-rw-r--r--tests/vm/tgorge.nim7
-rwxr-xr-x[-rw-r--r--]tests/vm/tgorge.sh0
-rwxr-xr-x[-rw-r--r--]tests/vm/tgorgeex.sh0
-rw-r--r--tests/vm/tinheritance.nim53
-rw-r--r--tests/vm/tmitems.nim2
-rw-r--r--tests/vm/tsimpleglobals.nim2
-rw-r--r--tests/vm/tslurp.nim6
-rw-r--r--tests/vm/tstaticprintseq.nim2
-rw-r--r--tests/vm/tswap.nim2
-rw-r--r--tests/vm/ttouintconv.nim2
-rw-r--r--tests/vm/tvmmisc.nim1
-rw-r--r--tools/kochdocs.nim17
-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
460 files changed, 6141 insertions, 4263 deletions
diff --git a/.travis.yml b/.travis.yml
index 6fb19648e..4c3c687e2 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
diff --git a/changelog.md b/changelog.md
index 21b7b16a0..1a005639a 100644
--- a/changelog.md
+++ b/changelog.md
@@ -12,12 +12,19 @@
   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).
+  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
 
 
@@ -36,11 +43,16 @@ proc enumToString*(enums: openArray[enum]): string =
     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`.
 
@@ -49,12 +61,30 @@ proc enumToString*(enums: openArray[enum]): string =
 - Added `system.typeof` for more control over how `type` expressions
   can be deduced.
 
+- Added `macros.isInstantiationOf` for checking if the proc symbol 
+  is instantiation of generic proc symbol.
+
+
 ### Library changes
 
 - The string output of `macros.lispRepr` proc has been tweaked
   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.
@@ -62,6 +92,11 @@ proc enumToString*(enums: openArray[enum]): string =
 
 ### 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
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 5fc8e5978..6a73df3c7 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -565,13 +565,9 @@ const
   routineKinds* = {skProc, skFunc, skMethod, skIterator,
                    skConverter, skMacro, skTemplate}
   tfIncompleteStruct* = tfVarargs
-  tfUncheckedArray* = tfVarargs
   tfUnion* = tfNoSideEffect
   tfGcSafe* = tfThread
   tfObjHasKids* = tfEnumHasHoles
-  tfOldSchoolExprStmt* = tfVarargs # for now used to distinguish \
-    # 'varargs[expr]' from 'varargs[untyped]'. Eventually 'expr' will be
-    # deprecated and this mess can be cleaned up.
   tfReturnsNew* = tfInheritable
   skError* = skUnknown
 
@@ -660,7 +656,8 @@ type
     mNHint, mNWarning, mNError,
     mInstantiationInfo, mGetTypeInfo,
     mNimvm, mIntDefine, mStrDefine, mRunnableExamples,
-    mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf
+    mException, mBuiltinType, mSymOwner, mUncheckedArray, mGetImplTransf,
+    mSymIsInstantiationOf
 
 # things that we can evaluate safely at compile time, even if not asked for it:
 const
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 6678a07ca..388ab806e 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -173,21 +173,6 @@ proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
     linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
   elif dest.storage == OnHeap:
     # location is on heap
-    # now the writer barrier is inlined for performance:
-    #
-    #    if afSrcIsNotNil in flags:
-    #      UseMagic(p.module, 'nimGCref')
-    #      lineF(p, cpsStmts, 'nimGCref($1);$n', [rdLoc(src)])
-    #    elif afSrcIsNil notin flags:
-    #      UseMagic(p.module, 'nimGCref')
-    #      lineF(p, cpsStmts, 'if ($1) nimGCref($1);$n', [rdLoc(src)])
-    #    if afDestIsNotNil in flags:
-    #      UseMagic(p.module, 'nimGCunref')
-    #      lineF(p, cpsStmts, 'nimGCunref($1);$n', [rdLoc(dest)])
-    #    elif afDestIsNil notin flags:
-    #      UseMagic(p.module, 'nimGCunref')
-    #      lineF(p, cpsStmts, 'if ($1) nimGCunref($1);$n', [rdLoc(dest)])
-    #    lineF(p, cpsStmts, '$1 = $2;$n', [rdLoc(dest), rdLoc(src)])
     if canFormAcycle(dest.t):
       linefmt(p, cpsStmts, "#asgnRef((void**) $1, $2);$n",
               addrLoc(p.config, dest), rdLoc(src))
@@ -872,7 +857,7 @@ proc genArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
   var ty = skipTypes(a.t, abstractVarRange + abstractPtrs + tyUserTypeClasses)
   var first = intLiteral(firstOrd(p.config, ty))
   # emit range check:
-  if optBoundsCheck in p.options and tfUncheckedArray notin ty.flags:
+  if optBoundsCheck in p.options and ty.kind != tyUncheckedArray:
     if not isConstExpr(y):
       # semantic pass has already checked for const index expressions
       if firstOrd(p.config, ty) == 0:
@@ -909,11 +894,10 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
       rdLoc(a), rdLoc(b), rdLoc(arr))
   of tyArray:
     let first = intLiteral(firstOrd(p.config, ty))
-    if tfUncheckedArray notin ty.flags:
-      linefmt(p, cpsStmts,
-        "if ($2-$1 != -1 && " &
-        "($2-$1 < -1 || $1 < $3 || $1 > $4 || $2 < $3 || $2 > $4)) #raiseIndexError();$n",
-        rdCharLoc(a), rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty)))
+    linefmt(p, cpsStmts,
+      "if ($2-$1 != -1 && " &
+      "($2-$1 < -1 || $1 < $3 || $1 > $4 || $2 < $3 || $2 > $4)) #raiseIndexError();$n",
+      rdCharLoc(a), rdCharLoc(b), first, intLiteral(lastOrd(p.config, ty)))
   of tySequence, tyString:
     linefmt(p, cpsStmts,
       "if ($2-$1 != -1 && " &
@@ -1156,7 +1140,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
   getIntTemp(p, tmpL)
   lineCg(p, cpsStmts, "$1 = $2->$3++;$n", tmpL.r, rdLoc(a), lenField(p))
   dest.r = ropecg(p.module, "$1$3[$2]", rdLoc(a), tmpL.r, dataField(p))
-  genAssignment(p, dest, b, {needToCopy, afDestIsNil})
+  genAssignment(p, dest, b, {needToCopy})
   gcUsage(p.config, e)
 
 proc genReset(p: BProc, n: PNode) =
@@ -1395,7 +1379,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
       elem.storage = OnHeap # we know that sequences are on the heap
       initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.sons[1].typ, abstractInst)), a.storage)
       arr.r = ropecg(p.module, "$1[$2]", rdLoc(a), intLiteral(i))
-      genAssignment(p, elem, arr, {afDestIsNil, needToCopy})
+      genAssignment(p, elem, arr, {needToCopy})
   else:
     var i: TLoc
     getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i)
@@ -1406,7 +1390,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
     elem.storage = OnHeap # we know that sequences are on the heap
     initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.sons[1].typ, abstractInst)), a.storage)
     arr.r = ropecg(p.module, "$1[$2]", rdLoc(a), rdLoc(i))
-    genAssignment(p, elem, arr, {afDestIsNil, needToCopy})
+    genAssignment(p, elem, arr, {needToCopy})
     lineF(p, cpsStmts, "}$n", [])
 
 
@@ -1581,8 +1565,17 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     else: putIntoDest(p, d, e, rope(lengthOrd(p.config, typ)))
   else: internalError(p.config, e.info, "genArrayLen()")
 
+proc makePtrType(baseType: PType): PType =
+  result = newType(tyPtr, baseType.owner)
+  addSonSkipIntLit(result, baseType)
+
+proc makeAddr(n: PNode): PNode =
+  result = newTree(nkHiddenAddr, n)
+  result.typ = makePtrType(n.typ)
+
 proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
   if p.config.selectedGc == gcDestructors:
+    e.sons[1] = makeAddr(e[1])
     genCall(p, e, d)
     return
   var a, b, call: TLoc
@@ -1964,6 +1957,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
   of mAppendStrStr: genStrAppend(p, e, d)
   of mAppendSeqElem:
     if p.config.selectedGc == gcDestructors:
+      e.sons[1] = makeAddr(e[1])
       genCall(p, e, d)
     else:
       genSeqElemAppend(p, e, d)
@@ -2031,8 +2025,11 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
     let n = lowerings.wrapProcForSpawn(p.module.g.graph, p.module.module, e, e.typ, nil, nil)
     expr(p, n, d)
   of mParallel:
-    let n = semparallel.liftParallel(p.module.g.graph, p.module.module, e)
-    expr(p, n, d)
+    when defined(leanCompiler):
+      quit "compiler built without support for the 'parallel' statement"
+    else:
+      let n = semparallel.liftParallel(p.module.g.graph, p.module.module, e)
+      expr(p, n, d)
   of mDeepCopy:
     var a, b: TLoc
     let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1]
@@ -2429,15 +2426,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
     if ex.kind != nkEmpty:
       genLineDir(p, n)
       var a: TLoc
-      if ex.kind in nkCallKinds and (ex[0].kind != nkSym or
-                                     ex[0].sym.magic == mNone):
-        # bug #6037: do not assign to a temp in C++ mode:
-        incl a.flags, lfSingleUse
-        genCall(p, ex, a)
-        if lfSingleUse notin a.flags:
-          line(p, cpsStmts, a.r & ";\L")
-      else:
-        initLocExpr(p, ex, a)
+      initLocExprSingleUse(p, ex, a)
+      line(p, cpsStmts, "(void)(" & a.r & ");\L")
   of nkAsmStmt: genAsmStmt(p, n)
   of nkTryStmt:
     if p.module.compileToCpp and optNoCppExceptions notin p.config.globalOptions:
diff --git a/compiler/ccgliterals.nim b/compiler/ccgliterals.nim
index 34677ec06..ccfa49a1d 100644
--- a/compiler/ccgliterals.nim
+++ b/compiler/ccgliterals.nim
@@ -69,7 +69,7 @@ proc genStringLiteralV2(m: BModule; n: PNode): Rope =
     addf(m.s[cfsData], "static const NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n",
           [result, rope(len(n.strVal)), pureLit])
   else:
-    result = m.tmpBase & rope(id)
+    result = m.tmpBase & rope(id+1)
 
 proc genStringLiteralV2Const(m: BModule; n: PNode): Rope =
   let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 5ebe0323d..3665a7e85 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -509,7 +509,7 @@ proc genWhileStmt(p: BProc, t: PNode) =
          # for closure support weird loop bodies are generated:
       if loopBody.len == 2 and loopBody.sons[0].kind == nkEmpty:
         loopBody = loopBody.sons[1]
-      genComputedGoto(p, loopBody) # TODO foobar
+      genComputedGoto(p, loopBody)
     else:
       p.breakIdx = startBlock(p, "while (1) {$n")
       p.blocks[p.breakIdx].isLoop = true
@@ -874,14 +874,15 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
 
   discard pop(p.nestedTryStmts)
 
-  if not catchAllPresent and t[^1].kind == nkFinally:
-    # finally requires catch all presence
-    startBlock(p, "catch (...) {$n")
-    genSimpleBlock(p, t[^1][0])
-    line(p, cpsStmts, ~"throw;$n")
-    endBlock(p)
-
   if t[^1].kind == nkFinally:
+    # c++ does not have finally, therefore code needs to be generated twice
+    if not catchAllPresent:
+      # finally requires catch all presence
+      startBlock(p, "catch (...) {$n")
+      genStmts(p, t[^1][0])
+      line(p, cpsStmts, ~"throw;$n")
+      endBlock(p)
+
     genSimpleBlock(p, t[^1][0])
 
 proc genTry(p: BProc, t: PNode, d: var TLoc) =
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 75566fb38..bbfd72354 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -492,7 +492,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
     # with heavily templatized C++ code:
     if not isImportedCppType(rectype):
       let fieldType = field.loc.lode.typ.skipTypes(abstractInst)
-      if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
+      if fieldType.kind == tyUncheckedArray:
         addf(result, "$1 $2[SEQ_DECL_SIZE];$n",
             [getTypeDescAux(m, fieldType.elemType, check), sname])
       elif fieldType.kind == tySequence and m.config.selectedGC != gcDestructors:
@@ -1188,6 +1188,7 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
   let owner = t.skipTypes(typedescPtrs).owner.getModule
   if owner != m.module:
     # make sure the type info is created in the owner module
+    assert m.g.modules[owner.position] != nil
     discard genTypeInfo(m.g.modules[owner.position], origType, info)
     # reference the type info as extern here
     discard cgsym(m, "TNimType")
@@ -1213,8 +1214,8 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
       let x = fakeClosureType(m, t.owner)
       genTupleInfo(m, x, x, result, info)
   of tySequence:
+    genTypeInfoAux(m, t, t, result, info)
     if m.config.selectedGC != gcDestructors:
-      genTypeInfoAux(m, t, t, result, info)
       if m.config.selectedGC >= gcMarkAndSweep:
         let markerProc = genTraverseProc(m, origType, sig)
         addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index ab5584786..199a93be2 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -14,7 +14,10 @@ import
   nversion, nimsets, msgs, std / sha1, bitsets, idents, types,
   ccgutils, os, ropes, math, passes, wordrecg, treetab, cgmeth,
   condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
-  lowerings, semparallel, tables, sets, ndi, lineinfos, pathutils, transf
+  lowerings, tables, sets, ndi, lineinfos, pathutils, transf
+
+when not defined(leanCompiler):
+  import semparallel
 
 import strutils except `%` # collides with ropes.`%`
 
@@ -42,8 +45,7 @@ when options.hasTinyCBackend:
 # implementation
 
 proc addForwardedProc(m: BModule, prc: PSym) =
-  m.forwardedProcs.add(prc)
-  inc(m.g.forwardedProcsCounter)
+  m.g.forwardedProcs.add(prc)
 
 proc findPendingModule(m: BModule, s: PSym): BModule =
   var ms = getModule(s)
@@ -292,7 +294,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
 
 type
   TAssignmentFlag = enum
-    needToCopy, afDestIsNil, afDestIsNotNil, afSrcIsNil, afSrcIsNotNil
+    needToCopy
   TAssignmentFlags = set[TAssignmentFlag]
 
 proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
@@ -311,7 +313,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
       var nilLoc: TLoc
       initLoc(nilLoc, locTemp, loc.lode, OnStack)
       nilLoc.r = rope("NIM_NIL")
-      genRefAssign(p, loc, nilLoc, {afSrcIsNil})
+      genRefAssign(p, loc, nilLoc, {})
     else:
       linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc))
   else:
@@ -1391,7 +1393,6 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: AbsoluteFile): BModule
   result.preInitProc = newPreInitProc(result)
   initNodeTable(result.dataCache)
   result.typeStack = @[]
-  result.forwardedProcs = @[]
   result.typeNodesName = getTempName(result)
   result.nimTypesName = getTempName(result)
   # no line tracing for the init sections of the system module so that we
@@ -1407,49 +1408,6 @@ proc nullify[T](arr: var T) =
   for i in low(arr)..high(arr):
     arr[i] = Rope(nil)
 
-proc resetModule*(m: BModule) =
-  # between two compilations in CAAS mode, we can throw
-  # away all the data that was written to disk
-  m.headerFiles = @[]
-  m.declaredProtos = initIntSet()
-  m.forwTypeCache = initTable[SigHash, Rope]()
-  m.initProc = newProc(nil, m)
-  m.initProc.options = initProcOptions(m)
-  m.preInitProc = newPreInitProc(m)
-  initNodeTable(m.dataCache)
-  m.typeStack = @[]
-  m.forwardedProcs = @[]
-  m.typeNodesName = getTempName(m)
-  m.nimTypesName = getTempName(m)
-  if sfSystemModule in m.module.flags:
-    incl m.flags, preventStackTrace
-  else:
-    excl m.flags, preventStackTrace
-  nullify m.s
-  m.typeNodes = 0
-  m.nimTypes = 0
-  nullify m.extensionLoaders
-
-  # indicate that this is now cached module
-  # the cache will be invalidated by nullifying gModules
-  #m.fromCache = true
-  m.g = nil
-
-  # we keep only the "merge info" information for the module
-  # and the properties that can't change:
-  # m.filename
-  # m.cfilename
-  # m.isHeaderFile
-  # m.module ?
-  # m.typeCache
-  # m.declaredThings
-  # m.typeInfoMarker
-  # m.labels
-  # m.FrameDeclared
-
-proc resetCgenModules*(g: BModuleList) =
-  for m in cgenModules(g): resetModule(m)
-
 proc rawNewModule(g: BModuleList; module: PSym; conf: ConfigRef): BModule =
   result = rawNewModule(g, module, AbsoluteFile toFullPath(conf, module.position.FileIndex))
 
@@ -1528,20 +1486,6 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
   let tranformed_n = transformStmt(m.g.graph, m.module, n)
   genStmts(m.initProc, tranformed_n)
 
-proc finishModule(m: BModule) =
-  var i = 0
-  while i <= high(m.forwardedProcs):
-    # Note: ``genProc`` may add to ``m.forwardedProcs``, so we cannot use
-    # a ``for`` loop here
-    var prc = m.forwardedProcs[i]
-    if sfForward in prc.flags:
-      internalError(m.config, prc.info, "still forwarded: " & prc.name.s)
-    genProcNoForward(m, prc)
-    inc(i)
-  assert(m.g.forwardedProcsCounter >= i)
-  dec(m.g.forwardedProcsCounter, i)
-  setLen(m.forwardedProcs, 0)
-
 proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool =
   result = true
   if optForceFullMake notin m.config.globalOptions:
@@ -1637,12 +1581,26 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
   registerModuleToMain(m.g, m.module)
 
   if sfMainModule in m.module.flags:
-    if m.g.forwardedProcsCounter == 0:
+    if m.g.forwardedProcs.len == 0:
       incl m.flags, objHasKidsValid
     let disp = generateMethodDispatchers(graph)
     for x in disp: genProcAux(m, x.sym)
     genMainProc(m)
 
+proc genForwardedProcs(g: BModuleList) =
+  # Forward declared proc:s lack bodies when first encountered, so they're given
+  # a second pass here
+  # Note: ``genProcNoForward`` may add to ``forwardedProcs``
+  while g.forwardedProcs.len > 0:
+    let
+      prc = g.forwardedProcs.pop()
+      ms = getModule(prc)
+      m = g.modules[ms.position]
+    if sfForward in prc.flags:
+      internalError(m.config, prc.info, "still forwarded: " & prc.name.s)
+
+    genProcNoForward(m, prc)
+
 proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
   let g = BModuleList(backend)
   # we need to process the transitive closure because recursive module
@@ -1652,10 +1610,9 @@ proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
   let (outDir, _, _) = splitFile(config.outfile)
   if not outDir.isEmpty:
     createDir(outDir)
-  if g.generatedHeader != nil: finishModule(g.generatedHeader)
-  while g.forwardedProcsCounter > 0:
-    for m in cgenModules(g):
-      finishModule(m)
+
+  genForwardedProcs(g)
+
   for m in cgenModules(g):
     m.writeModule(pending=true)
   writeMapping(config, g.mapping)
diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim
index 0c6097fbe..28e36364e 100644
--- a/compiler/cgendata.nim
+++ b/compiler/cgendata.nim
@@ -112,7 +112,7 @@ type
     mainModProcs*, mainModInit*, otherModsInit*, mainDatInit*: Rope
     mapping*: Rope             # the generated mapping file (if requested)
     modules*: seq[BModule]     # list of all compiled modules
-    forwardedProcsCounter*: int
+    forwardedProcs*: seq[PSym] # proc:s that did not yet have a body
     generatedHeader*: BModule
     breakPointId*: int
     breakpoints*: Rope # later the breakpoints are inserted into the main proc
@@ -150,7 +150,6 @@ type
     preInitProc*: BProc       # code executed before the init proc
     typeStack*: TTypeSeq      # used for type generation
     dataCache*: TNodeTable
-    forwardedProcs*: TSymSeq  # keep forwarded procs here
     typeNodes*, nimTypes*: int # used for type info generation
     typeNodesName*, nimTypesName*: Rope # used for type info generation
     labels*: Natural          # for generating unique module-scope names
@@ -188,12 +187,12 @@ proc newProc*(prc: PSym, module: BModule): BProc =
   result.sigConflicts = initCountTable[string]()
 
 proc newModuleList*(g: ModuleGraph): BModuleList =
-  BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope](), config: g.config,
-    graph: g, nimtvDeps: @[], nimtvDeclared: initIntSet())
+  BModuleList(typeInfoMarker: initTable[SigHash, Rope](), config: g.config,
+    graph: g, nimtvDeclared: initIntSet())
 
 iterator cgenModules*(g: BModuleList): BModule =
-  for i in 0..high(g.modules):
+  for m in g.modules:
     # ultimately, we are iterating over the file ids here.
     # some "files" won't have an associated cgen module (like stdin)
     # and we must skip over them.
-    if g.modules[i] != nil: yield g.modules[i]
+    if m != nil: yield m
diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim
index 258372d76..c2d908193 100644
--- a/compiler/closureiters.nim
+++ b/compiler/closureiters.nim
@@ -462,10 +462,17 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode =
       result.typ = n.typ
 
       for i in 0 ..< n.len:
-        if n[i].kind == nkStmtListExpr:
+        case n[i].kind
+        of nkExprColonExpr:
+          if n[i][1].kind == nkStmtListExpr:
+            let (st, ex) = exprToStmtList(n[i][1])
+            result.add(st)
+            n[i][1] = ex
+        of nkStmtListExpr:
           let (st, ex) = exprToStmtList(n[i])
           result.add(st)
           n[i] = ex
+        else: discard
       result.add(n)
 
   of nkIfStmt, nkIfExpr:
@@ -852,15 +859,8 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode
       discard
 
     of nkStmtList, nkStmtListExpr:
-      assert(isEmptyType(n.typ), "nkStmtListExpr not lowered")
-
       result = addGotoOut(result, gotoOut)
       for i in 0 ..< n.len:
-        if n[i].hasYieldsInExpressions:
-          # Lower nkStmtListExpr nodes inside `n[i]` first
-          var ns = false
-          n[i] = ctx.lowerStmtListExprs(n[i], ns)
-
         if n[i].hasYields:
           # Create a new split
           let go = newNodeI(nkGotoState, n[i].info)
@@ -1294,11 +1294,17 @@ proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode =
     ctx.stateVarSym.typ = g.createClosureIterStateType(fn)
 
   ctx.stateLoopLabel = newSym(skLabel, getIdent(ctx.g.cache, ":stateLoop"), fn, fn.info)
-  let n = n.toStmtList
+  var n = n.toStmtList
 
   discard ctx.newState(n, nil)
   let gotoOut = newTree(nkGotoState, g.newIntLit(n.info, -1))
 
+  var ns = false
+  n = ctx.lowerStmtListExprs(n, ns)
+
+  if n.hasYieldsInExpressions():
+    internalError(ctx.g.config, "yield in expr not lowered")
+
   # Splitting transformation
   discard ctx.transformClosureIteratorBody(n, gotoOut)
 
diff --git a/compiler/commands.nim b/compiler/commands.nim
index b39cc0b72..fa17e9851 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -642,14 +642,19 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
   of "help", "h":
     expectNoArg(conf, switch, arg, pass, info)
     helpOnError(conf, pass)
-  of "symbolfiles", "incremental":
+  of "symbolfiles": discard "ignore for backwards compat"
+  of "incremental":
+    when not defined(nimIncremental):
+      localError(conf, info, "the compiler was not built with " &
+        "incremental compilation features; bootstrap with " &
+        "-d:nimIncremental to enable")
     case arg.normalize
     of "on": conf.symbolFiles = v2Sf
     of "off": conf.symbolFiles = disabledSf
     of "writeonly": conf.symbolFiles = writeOnlySf
     of "readonly": conf.symbolFiles = readOnlySf
     of "v2": conf.symbolFiles = v2Sf
-    else: localError(conf, info, "invalid option for --symbolFiles: " & arg)
+    else: localError(conf, info, "invalid option for --incremental: " & arg)
   of "skipcfg":
     expectNoArg(conf, switch, arg, pass, info)
     incl(conf.globalOptions, optSkipSystemConfigFile)
@@ -739,6 +744,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
     of "hint": conf.globalOptions = conf.globalOptions + {optStyleHint}
     of "error": conf.globalOptions = conf.globalOptions + {optStyleError}
     else: localError(conf, info, errOffHintsError % arg)
+  of "showallmismatches":
+    processOnOffSwitchG(conf, {optShowAllMismatches}, arg, pass, info)
   of "cppcompiletonamespace":
     if arg.len > 0:
       conf.cppCustomNamespace = arg
@@ -774,6 +781,7 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser;
     # nim filename.nims  is the same as "nim e filename.nims":
     if p.key.endswith(".nims"):
       config.command = "e"
+      incl(config.globalOptions, optWasNimscript)
       config.projectName = unixToNativePath(p.key)
       config.arguments = cmdLineRest(p)
       result = true
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index 648dcd8c4..9a4c1701c 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -85,7 +85,8 @@ proc initDefines*(symbols: StringTableRef) =
   defineSymbol("nimHasUserErrors")
   defineSymbol("nimUncheckedArrayTyp")
   defineSymbol("nimHasTypeof")
-
+  defineSymbol("nimErrorProcCanHaveBody")
+  defineSymbol("nimHasInstantiationOfInMacro")
   defineSymbol("nimHasNilSeqs")
   for f in low(Feature)..high(Feature):
     defineSymbol("nimHas" & $f)
diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim
index b621e99b9..c515ba1d4 100644
--- a/compiler/destroyer.nim
+++ b/compiler/destroyer.nim
@@ -261,6 +261,11 @@ proc isLastRead(n: PNode; c: var Con): bool =
 template interestingSym(s: PSym): bool =
   s.owner == c.owner and s.kind in InterestingSyms and hasDestructor(s.typ)
 
+template isUnpackedTuple(s: PSym): bool =
+  ## we move out all elements of unpacked tuples, 
+  ## hence unpacked tuples themselves don't need to be destroyed
+  s.kind == skTemp and s.typ.kind == tyTuple
+
 proc patchHead(n: PNode) =
   if n.kind in nkCallKinds and n[0].kind == nkSym and n.len > 1:
     let s = n[0].sym
@@ -446,6 +451,13 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
       ri2.add pArg(ri[i], c, i < L and parameters[i].kind == tySink)
     #recurse(ri, ri2)
     result.add ri2
+  of nkBracketExpr:
+    if ri[0].kind == nkSym and isUnpackedTuple(ri[0].sym):
+      # unpacking of tuple: move out the elements 
+      result = genSink(c, dest.typ, dest, ri)
+    else:
+      result = genCopy(c, dest.typ, dest, ri)
+    result.add p(ri, c)
   of nkObjConstr:
     result = genSink(c, dest.typ, dest, ri)
     let ri2 = copyTree(ri)
@@ -454,6 +466,17 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
       # so these all act like 'sink' parameters:
       ri2[i].sons[1] = pArg(ri[i][1], c, isSink = true)
     result.add ri2
+  of nkTupleConstr:
+    result = genSink(c, dest.typ, dest, ri)
+    let ri2 = copyTree(ri)
+    for i in 0..<ri.len:
+      # everything that is passed to an tuple constructor is consumed,
+      # so these all act like 'sink' parameters:
+      if ri[i].kind == nkExprColonExpr:
+        ri2[i].sons[1] = pArg(ri[i][1], c, isSink = true)
+      else:
+        ri2[i] = pArg(ri[i], c, isSink = true)
+    result.add ri2
   of nkSym:
     if ri.sym.kind != skParam and isLastRead(ri, c):
       # Rule 3: `=sink`(x, z); wasMoved(z)
@@ -483,7 +506,7 @@ proc p(n: PNode; c: var Con): PNode =
       if it.kind == nkVarTuple and hasDestructor(ri.typ):
         let x = lowerTupleUnpacking(c.graph, it, c.owner)
         result.add p(x, c)
-      elif it.kind == nkIdentDefs and hasDestructor(it[0].typ):
+      elif it.kind == nkIdentDefs and hasDestructor(it[0].typ) and not isUnpackedTuple(it[0].sym):
         for j in 0..L-2:
           let v = it[j]
           doAssert v.kind == nkSym
diff --git a/compiler/dfa.nim b/compiler/dfa.nim
index 4b624e93b..415cc4ab3 100644
--- a/compiler/dfa.nim
+++ b/compiler/dfa.nim
@@ -56,6 +56,7 @@ type
     inCall, inTryStmt: int
     blocks: seq[TBlock]
     tryStmtFixups: seq[TPosition]
+    owner: PSym
 
 proc debugInfo(info: TLineInfo): string =
   result = $info.line #info.toFilename & ":" & $info.line
@@ -259,8 +260,15 @@ proc genRaise(c: var Con; n: PNode) =
   else:
     c.code.add Instr(n: n, kind: goto, dest: high(int) - c.code.len)
 
+proc genImplicitReturn(c: var Con) =
+  if c.owner.kind in {skProc, skFunc, skMethod, skIterator, skConverter} and resultPos < c.owner.ast.len:
+    gen(c, c.owner.ast.sons[resultPos])
+
 proc genReturn(c: var Con; n: PNode) =
-  if n.sons[0].kind != nkEmpty: gen(c, n.sons[0])
+  if n.sons[0].kind != nkEmpty:
+    gen(c, n.sons[0])
+  else:
+    genImplicitReturn(c)
   c.code.add Instr(n: n, kind: goto, dest: high(int) - c.code.len)
 
 const
@@ -461,11 +469,13 @@ proc dfa(code: seq[Instr]; conf: ConfigRef) =
 proc dataflowAnalysis*(s: PSym; body: PNode; conf: ConfigRef) =
   var c = Con(code: @[], blocks: @[])
   gen(c, body)
+  genImplicitReturn(c)
   when defined(useDfa) and defined(debugDfa): echoCfg(c.code)
   dfa(c.code, conf)
 
 proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph =
   ## constructs a control flow graph for ``body``.
-  var c = Con(code: @[], blocks: @[])
+  var c = Con(code: @[], blocks: @[], owner: s)
   gen(c, body)
+  genImplicitReturn(c)
   shallowCopy(result, c.code)
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index f5795e1d2..6f61d020d 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -897,7 +897,7 @@ proc genOutFile(d: PDoc): Rope =
     setIndexTerm(d[], external, "", title)
   else:
     # Modules get an automatic title for the HTML, but no entry in the index.
-    title = "Module " & extractFilename(changeFileExt(d.filename, ""))
+    title = extractFilename(changeFileExt(d.filename, ""))
 
   let bodyname = if d.hasToc and not d.isPureRst: "doc.body_toc_group"
                  elif d.hasToc: "doc.body_toc"
diff --git a/compiler/importer.nim b/compiler/importer.nim
index 60b7872fe..131b1ad8a 100644
--- a/compiler/importer.nim
+++ b/compiler/importer.nim
@@ -100,7 +100,7 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
     if s.kind != skModule:
       if s.kind != skEnumField:
         if s.kind notin ExportableSymKinds:
-          internalError(c.config, s.info, "importAllSymbols: " & $s.kind)
+          internalError(c.config, s.info, "importAllSymbols: " & $s.kind & " " & s.name.s)
         if exceptSet.isNil or s.name.id notin exceptSet:
           rawImportSymbol(c, s)
     s = nextIter(i, fromMod.tab)
diff --git a/compiler/incremental.nim b/compiler/incremental.nim
index 47637b3c1..f66a75efd 100644
--- a/compiler/incremental.nim
+++ b/compiler/incremental.nim
@@ -59,8 +59,8 @@ when nimIncremental:
     let id = row[0]
     let fullhash = hashFileCached(conf, fileIdx, AbsoluteFile fullpath)
     if id.len == 0:
-      result = int incr.db.insertID(sql"insert into filenames(fullpath, fullhash) values (?, ?)",
-        fullpath, fullhash)
+      result = int incr.db.insertID(sql"insert into filenames(nimid, fullpath, fullhash) values (?, ?, ?)",
+        int(fileIdx), fullpath, fullhash)
     else:
       if row[1] != fullhash:
         incr.db.exec(sql"update filenames set fullhash = ? where fullpath = ?", fullhash, fullpath)
@@ -102,6 +102,7 @@ when nimIncremental:
     db.exec(sql"""
       create table if not exists filenames(
         id integer primary key,
+        nimid integer not null,
         fullpath varchar(8000) not null,
         fullHash varchar(256) not null
       );
diff --git a/compiler/layouter.nim b/compiler/layouter.nim
index f96f88da1..8605ade45 100644
--- a/compiler/layouter.nim
+++ b/compiler/layouter.nim
@@ -30,7 +30,7 @@ type
     lastTok: TTokType
     inquote, lastTokWasTerse: bool
     semicolons: SemicolonKind
-    col, lastLineNumber, lineSpan, indentLevel, indWidth: int
+    col, lastLineNumber, lineSpan, indentLevel, indWidth*: int
     keepIndents*: int
     doIndentMore*: int
     content: string
@@ -41,9 +41,10 @@ type
 proc openEmitter*(em: var Emitter, cache: IdentCache;
                   config: ConfigRef, fileIdx: FileIndex) =
   let fullPath = Absolutefile config.toFullPath(fileIdx)
-  em.indWidth = getIndentWidth(fileIdx, llStreamOpen(fullPath, fmRead),
-                               cache, config)
-  if em.indWidth == 0: em.indWidth = 2
+  if em.indWidth == 0:
+    em.indWidth = getIndentWidth(fileIdx, llStreamOpen(fullPath, fmRead),
+                                cache, config)
+    if em.indWidth == 0: em.indWidth = 2
   em.config = config
   em.fid = fileIdx
   em.lastTok = tkInvalid
@@ -245,7 +246,7 @@ proc emitTok*(em: var Emitter; L: TLexer; tok: TToken) =
     wr(TokTypeToStr[tok.tokType])
     if not em.inquote: wr(" ")
   of tkOpr, tkDotDot:
-    if tok.strongSpaceA == 0 and tok.strongSpaceB == 0:
+    if (tok.strongSpaceA == 0 and tok.strongSpaceB == 0) or em.inquote:
       # bug #9504: remember to not spacify a keyword:
       lastTokWasTerse = true
       # if not surrounded by whitespace, don't produce any whitespace either:
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index 877369c2a..635e6f08d 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -635,7 +635,8 @@ proc handleHexChar(L: var TLexer, xi: var int) =
     inc(L.bufpos)
   else:
     lexMessage(L, errGenerated,
-      "expected a hex digit, but found: " & L.buf[L.bufpos])
+      "expected a hex digit, but found: " & L.buf[L.bufpos] &
+        " ; maybe prepend with 0")
     # Need to progress for `nim check`
     inc(L.bufpos)
 
@@ -966,7 +967,7 @@ proc getPrecedence*(tok: TToken, strongSpaces: bool): int =
     of '?': result = 2
     else: considerAsgn(2)
   of tkDiv, tkMod, tkShl, tkShr: result = 9
-  of tkIn, tkNotin, tkIs, tkIsnot, tkNot, tkOf, tkAs: result = 5
+  of tkIn, tkNotin, tkIs, tkIsnot, tkOf, tkAs: result = 5
   of tkDotDot: result = 6
   of tkAnd: result = 4
   of tkOr, tkXor, tkPtr, tkRef: result = 3
diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim
index cd160313c..b1ecf779e 100644
--- a/compiler/lineinfos.nim
+++ b/compiler/lineinfos.nim
@@ -41,7 +41,7 @@ type
     hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
     hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
     hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
-    hintConditionAlwaysTrue, hintName, hintPattern,
+    hintConditionAlwaysTrue, hintConditionAlwaysFalse, hintName, hintPattern,
     hintExecuting, hintLinking, hintDependency,
     hintSource, hintPerformance, hintStackTrace, hintGCStats,
     hintGlobalVar,
@@ -107,6 +107,7 @@ const
     hintConf: "used config file '$1'",
     hintPath: "added path: '$1'",
     hintConditionAlwaysTrue: "condition is always true: '$1'",
+    hintConditionAlwaysFalse: "condition is always false: '$1'",
     hintName: "name should be: '$1'",
     hintPattern: "$1",
     hintExecuting: "$1",
@@ -140,7 +141,7 @@ const
     "Success", "SuccessX", "CC", "LineTooLong",
     "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
     "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
-    "Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency",
+    "Path", "CondTrue", "CondFalse", "Name", "Pattern", "Exec", "Link", "Dependency",
     "Source", "Performance", "StackTrace", "GCStats", "GlobalVar",
     "User", "UserRaw", "ExtendedContext",
   ]
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index d2e7fdcfa..2fb4e5241 100644
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -168,7 +168,7 @@ proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) =
         localError(c.config, s.info, "implementation of '$1' expected" %
             getSymRepr(c.config, s))
       inc missingImpls
-    elif {sfUsed, sfExported} * s.flags == {} and optHints in s.options:
+    elif {sfUsed, sfExported} * s.flags == {}:
       if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}:
         # XXX: implicit type params are currently skTypes
         # maybe they can be made skGenericParam as well.
diff --git a/compiler/main.nim b/compiler/main.nim
index 6c8b0343e..6afe57d87 100644
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -15,12 +15,15 @@ when not defined(nimcore):
 import
   llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs,
   os, condsyms, times,
-  wordrecg, sem, semdata, idents, passes, docgen, extccomp,
-  cgen, jsgen, json, nversion,
+  wordrecg, sem, semdata, idents, passes, extccomp,
+  cgen, json, nversion,
   platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
-  docgen2, parser, modules, ccgutils, sigmatch, ropes,
+  parser, modules, ccgutils, sigmatch, ropes,
   modulegraphs, tables, rod, lineinfos, pathutils
 
+when not defined(leanCompiler):
+  import jsgen, docgen, docgen2
+
 from magicsys import resetSysTypes
 
 proc codegenPass(g: ModuleGraph) =
@@ -57,13 +60,14 @@ proc commandCheck(graph: ModuleGraph) =
   semanticPasses(graph)  # use an empty backend for semantic checking only
   compileProject(graph)
 
-proc commandDoc2(graph: ModuleGraph; json: bool) =
-  graph.config.errorMax = high(int)  # do not stop after first error
-  semanticPasses(graph)
-  if json: registerPass(graph, docgen2JsonPass)
-  else: registerPass(graph, docgen2Pass)
-  compileProject(graph)
-  finishDoc2Pass(graph.config.projectName)
+when not defined(leanCompiler):
+  proc commandDoc2(graph: ModuleGraph; json: bool) =
+    graph.config.errorMax = high(int)  # do not stop after first error
+    semanticPasses(graph)
+    if json: registerPass(graph, docgen2JsonPass)
+    else: registerPass(graph, docgen2Pass)
+    compileProject(graph)
+    finishDoc2Pass(graph.config.projectName)
 
 proc commandCompileToC(graph: ModuleGraph) =
   let conf = graph.config
@@ -84,15 +88,16 @@ proc commandJsonScript(graph: ModuleGraph) =
   let proj = changeFileExt(graph.config.projectFull, "")
   extccomp.runJsonBuildInstructions(graph.config, proj)
 
-proc commandCompileToJS(graph: ModuleGraph) =
-  #incl(gGlobalOptions, optSafeCode)
-  setTarget(graph.config.target, osJS, cpuJS)
-  #initDefines()
-  defineSymbol(graph.config.symbols, "ecmascript") # For backward compatibility
-  defineSymbol(graph.config.symbols, "js")
-  semanticPasses(graph)
-  registerPass(graph, JSgenPass)
-  compileProject(graph)
+when not defined(leanCompiler):
+  proc commandCompileToJS(graph: ModuleGraph) =
+    #incl(gGlobalOptions, optSafeCode)
+    setTarget(graph.config.target, osJS, cpuJS)
+    #initDefines()
+    defineSymbol(graph.config.symbols, "ecmascript") # For backward compatibility
+    defineSymbol(graph.config.symbols, "js")
+    semanticPasses(graph)
+    registerPass(graph, JSgenPass)
+    compileProject(graph)
 
 proc interactivePasses(graph: ModuleGraph) =
   initDefines(graph.config.symbols)
@@ -177,49 +182,76 @@ proc mainCommand*(graph: ModuleGraph) =
     else:
       rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc")
   of "js", "compiletojs":
-    conf.cmd = cmdCompileToJS
-    commandCompileToJS(graph)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with JS code generator"
+    else:
+      conf.cmd = cmdCompileToJS
+      commandCompileToJS(graph)
   of "doc0":
-    wantMainModule(conf)
-    conf.cmd = cmdDoc
-    loadConfigs(DocConfig, cache, conf)
-    commandDoc(cache, conf)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      wantMainModule(conf)
+      conf.cmd = cmdDoc
+      loadConfigs(DocConfig, cache, conf)
+      commandDoc(cache, conf)
   of "doc2", "doc":
-    conf.cmd = cmdDoc
-    loadConfigs(DocConfig, cache, conf)
-    defineSymbol(conf.symbols, "nimdoc")
-    commandDoc2(graph, false)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      conf.cmd = cmdDoc
+      loadConfigs(DocConfig, cache, conf)
+      defineSymbol(conf.symbols, "nimdoc")
+      commandDoc2(graph, false)
   of "rst2html":
-    conf.cmd = cmdRst2html
-    loadConfigs(DocConfig, cache, conf)
-    commandRst2Html(cache, conf)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      conf.cmd = cmdRst2html
+      loadConfigs(DocConfig, cache, conf)
+      commandRst2Html(cache, conf)
   of "rst2tex":
-    conf.cmd = cmdRst2tex
-    loadConfigs(DocTexConfig, cache, conf)
-    commandRst2TeX(cache, conf)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      conf.cmd = cmdRst2tex
+      loadConfigs(DocTexConfig, cache, conf)
+      commandRst2TeX(cache, conf)
   of "jsondoc0":
-    wantMainModule(conf)
-    conf.cmd = cmdDoc
-    loadConfigs(DocConfig, cache, conf)
-    wantMainModule(conf)
-    defineSymbol(conf.symbols, "nimdoc")
-    commandJson(cache, conf)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      wantMainModule(conf)
+      conf.cmd = cmdDoc
+      loadConfigs(DocConfig, cache, conf)
+      wantMainModule(conf)
+      defineSymbol(conf.symbols, "nimdoc")
+      commandJson(cache, conf)
   of "jsondoc2", "jsondoc":
-    conf.cmd = cmdDoc
-    loadConfigs(DocConfig, cache, conf)
-    wantMainModule(conf)
-    defineSymbol(conf.symbols, "nimdoc")
-    commandDoc2(graph, true)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      conf.cmd = cmdDoc
+      loadConfigs(DocConfig, cache, conf)
+      wantMainModule(conf)
+      defineSymbol(conf.symbols, "nimdoc")
+      commandDoc2(graph, true)
   of "ctags":
-    wantMainModule(conf)
-    conf.cmd = cmdDoc
-    loadConfigs(DocConfig, cache, conf)
-    defineSymbol(conf.symbols, "nimdoc")
-    commandTags(cache, conf)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      wantMainModule(conf)
+      conf.cmd = cmdDoc
+      loadConfigs(DocConfig, cache, conf)
+      defineSymbol(conf.symbols, "nimdoc")
+      commandTags(cache, conf)
   of "buildindex":
-    conf.cmd = cmdDoc
-    loadConfigs(DocConfig, cache, conf)
-    commandBuildIndex(cache, conf)
+    when defined(leanCompiler):
+      quit "compiler wasn't built with documentation generator"
+    else:
+      conf.cmd = cmdDoc
+      loadConfigs(DocConfig, cache, conf)
+      commandBuildIndex(cache, conf)
   of "gendepend":
     conf.cmd = cmdGenDepend
     commandGenDepend(graph)
@@ -265,6 +297,7 @@ proc mainCommand*(graph: ModuleGraph) =
     conf.cmd = cmdInteractive
     commandInteractive(graph)
   of "e":
+    incl conf.globalOptions, optWasNimscript
     commandEval(graph, mainCommandArg(conf))
   of "nop", "help":
     # prevent the "success" message:
diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim
index 16704fab6..d05b301ae 100644
--- a/compiler/modulegraphs.nim
+++ b/compiler/modulegraphs.nim
@@ -63,6 +63,9 @@ type
     cacheCounters*: Table[string, BiggestInt]
     cacheTables*: Table[string, BTree[string, PNode]]
     passes*: seq[TPass]
+    onDefinition*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
+    onDefinitionResolveForward*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
+    onUsage*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
 
   TPassContext* = object of RootObj # the pass's context
   PPassContext* = ref TPassContext
@@ -78,6 +81,32 @@ type
 
 proc hash*(x: FileIndex): Hash {.borrow.}
 
+when defined(nimfind):
+  template onUse*(info: TLineInfo; s: PSym) =
+    when compiles(c.c.graph):
+      if c.c.graph.onUsage != nil: c.c.graph.onUsage(c.c.graph, s, info)
+    else:
+      if c.graph.onUsage != nil: c.graph.onUsage(c.graph, s, info)
+
+  template onDef*(info: TLineInfo; s: PSym) =
+    when compiles(c.c.graph):
+      if c.c.graph.onDefinition != nil: c.c.graph.onDefinition(c.c.graph, s, info)
+    else:
+      if c.graph.onDefinition != nil: c.graph.onDefinition(c.graph, s, info)
+
+  template onDefResolveForward*(info: TLineInfo; s: PSym) =
+    when compiles(c.c.graph):
+      if c.c.graph.onDefinitionResolveForward != nil:
+        c.c.graph.onDefinitionResolveForward(c.c.graph, s, info)
+    else:
+      if c.graph.onDefinitionResolveForward != nil:
+        c.graph.onDefinitionResolveForward(c.graph, s, info)
+
+else:
+  template onUse*(info: TLineInfo; s: PSym) = discard
+  template onDef*(info: TLineInfo; s: PSym) = discard
+  template onDefResolveForward*(info: TLineInfo; s: PSym) = discard
+
 proc stopCompile*(g: ModuleGraph): bool {.inline.} =
   result = g.doStopCompile != nil and g.doStopCompile()
 
diff --git a/compiler/modules.nim b/compiler/modules.nim
index 75e95e453..e2f322561 100644
--- a/compiler/modules.nim
+++ b/compiler/modules.nim
@@ -67,6 +67,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): P
       graph.config.mainPackageId = result.owner.id
 
     result.id = getModuleId(graph, fileIdx, AbsoluteFile toFullPath(graph.config, fileIdx))
+    registerModule(graph, result)
     discard processModule(graph, result,
       if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil)
   elif graph.isDirty(result):
@@ -128,6 +129,7 @@ proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIDX) =
 proc makeModule*(graph: ModuleGraph; filename: AbsoluteFile): PSym =
   result = graph.newModule(fileInfoIdx(graph.config, filename))
   result.id = getID()
+  registerModule(graph, result)
 
 proc makeModule*(graph: ModuleGraph; filename: string): PSym =
   result = makeModule(graph, AbsoluteFile filename)
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index dee1081f9..7e6b67cbe 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -190,10 +190,13 @@ template toFullPath*(conf: ConfigRef; info: TLineInfo): string =
 proc toMsgFilename*(conf: ConfigRef; info: TLineInfo): string =
   if info.fileIndex.int32 < 0:
     result = "???"
-  elif optListFullPaths in conf.globalOptions:
-    result = conf.m.fileInfos[info.fileIndex.int32].fullPath.string
+    return
+  let absPath = conf.m.fileInfos[info.fileIndex.int32].fullPath.string
+  let relPath = conf.m.fileInfos[info.fileIndex.int32].projPath.string
+  if optListFullPaths in conf.globalOptions:
+    result = absPath
   else:
-    result = conf.m.fileInfos[info.fileIndex.int32].projPath.string
+    result = if absPath.len < relPath.len: absPath else: relPath
 
 proc toLinenumber*(info: TLineInfo): int {.inline.} =
   result = int info.line
diff --git a/compiler/nim.nim b/compiler/nim.nim
index 5f3347255..1c4dbd3be 100644
--- a/compiler/nim.nim
+++ b/compiler/nim.nim
@@ -54,7 +54,8 @@ proc processCmdLine(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
     of cmdArgument:
       if processArgument(pass, p, argsCount, config): break
   if pass == passCmd2:
-    if optRun notin config.globalOptions and config.arguments.len > 0 and config.command.normalize != "run":
+    if {optRun, optWasNimscript} * config.globalOptions == {} and
+        config.arguments.len > 0 and config.command.normalize notin ["run", "e"]:
       rawMessage(config, errGenerated, errArgsNeedRunOption)
 
 proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
diff --git a/compiler/options.nim b/compiler/options.nim
index 1280cb59b..80d665d62 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -45,7 +45,7 @@ type                          # please make sure we have under 32 options
   TOptions* = set[TOption]
   TGlobalOption* = enum       # **keep binary compatible**
     gloptNone, optForceFullMake,
-    optDeadCodeElimUnused,    # deprecated, always on
+    optWasNimscript,
     optListCmd, optCompileOnly, optNoLinking,
     optCDebug,                # turn on debugging information
     optGenDynLib,             # generate a dynamic library
@@ -74,6 +74,7 @@ type                          # please make sure we have under 32 options
     optIdeTerse               # idetools: use terse descriptions
     optNoCppExceptions        # use C exception handling even with CPP
     optExcessiveStackTrace    # fully qualified module filenames
+    optShowAllMismatches      # show all overloading resolution candidates
     optWholeProject           # for 'doc2': output any dependency
     optMixedMode              # true if some module triggered C++ codegen
     optListFullPaths
@@ -401,7 +402,8 @@ proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in {cmdDoc,
 proc usesWriteBarrier*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc
 
 template compilationCachePresent*(conf: ConfigRef): untyped =
-  conf.symbolFiles in {v2Sf, writeOnlySf}
+  false
+#  conf.symbolFiles in {v2Sf, writeOnlySf}
 
 template optPreserveOrigSource*(conf: ConfigRef): untyped =
   optEmbedOrigSrc in conf.globalOptions
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 02083ca83..54b360a24 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -37,8 +37,7 @@ type
   TParser* = object            # A TParser object represents a file that
                                # is being parsed
     currInd: int               # current indentation level
-    firstTok, strongSpaces: bool # Has the first token been read?
-                                 # Is strongSpaces on?
+    firstTok: bool             # Has the first token been read?
     hasProgress: bool          # some while loop requires progress ensurance
     lex*: TLexer               # The lexer that is used for parsing
     tok*: TToken               # The current token
@@ -46,7 +45,7 @@ type
     inSemiStmtList*: int
     emptyNode: PNode
     when defined(nimpretty2):
-      em: Emitter
+      em*: Emitter
 
   SymbolMode = enum
     smNormal, smAllowNil, smAfterDot
@@ -102,8 +101,7 @@ proc getTok(p: var TParser) =
       emitTok(p.em, p.lex, p.tok)
 
 proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream,
-                 cache: IdentCache; config: ConfigRef;
-                 strongSpaces=false) =
+                 cache: IdentCache; config: ConfigRef) =
   ## Open a parser, using the given arguments to set up its internal state.
   ##
   initToken(p.tok)
@@ -112,13 +110,11 @@ proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream,
     openEmitter(p.em, cache, config, fileIdx)
   getTok(p)                   # read the first token
   p.firstTok = true
-  p.strongSpaces = strongSpaces
   p.emptyNode = newNode(nkEmpty)
 
 proc openParser*(p: var TParser, filename: AbsoluteFile, inputStream: PLLStream,
-                 cache: IdentCache; config: ConfigRef;
-                 strongSpaces=false) =
-  openParser(p, fileInfoIdx(config, filename), inputStream, cache, config, strongSpaces)
+                 cache: IdentCache; config: ConfigRef) =
+  openParser(p, fileInfoIdx(config, filename), inputStream, cache, config)
 
 proc closeParser(p: var TParser) =
   ## Close a parser, freeing up its resources.
@@ -286,7 +282,7 @@ proc checkBinary(p: TParser) {.inline.} =
 #|
 #| prefixOperator = operator
 #|
-#| optInd = COMMENT?
+#| optInd = COMMENT? IND?
 #| optPar = (IND{>} | IND{=})?
 #|
 #| simpleExpr = arrowExpr (OP0 optInd arrowExpr)* pragma?
@@ -706,8 +702,11 @@ proc namedParams(p: var TParser, callee: PNode,
   # progress guaranteed
   exprColonEqExprListAux(p, endTok, result)
 
-proc commandParam(p: var TParser, isFirstParam: var bool): PNode =
-  result = parseExpr(p)
+proc commandParam(p: var TParser, isFirstParam: var bool; mode: TPrimaryMode): PNode =
+  if mode == pmTypeDesc:
+    result = simpleExpr(p, mode)
+  else:
+    result = parseExpr(p)
   if p.tok.tokType == tkDo:
     result = postExprBlocks(p, result)
   elif p.tok.tokType == tkEquals and not isFirstParam:
@@ -780,7 +779,7 @@ proc primarySuffix(p: var TParser, r: PNode,
         when true:
           # progress NOT guaranteed
           p.hasProgress = false
-          addSon result, commandParam(p, isFirstParam)
+          addSon result, commandParam(p, isFirstParam, mode)
           if not p.hasProgress: break
         else:
           while p.tok.tokType != tkEof:
@@ -798,7 +797,7 @@ proc parseOperators(p: var TParser, headNode: PNode,
                     limit: int, mode: TPrimaryMode): PNode =
   result = headNode
   # expand while operators have priorities higher than 'limit'
-  var opPrec = getPrecedence(p.tok, p.strongSpaces)
+  var opPrec = getPrecedence(p.tok, false)
   let modeB = if mode == pmTypeDef: pmTypeDesc else: mode
   # the operator itself must not start on a new line:
   # progress guaranteed
@@ -815,7 +814,7 @@ proc parseOperators(p: var TParser, headNode: PNode,
     addSon(a, result)
     addSon(a, b)
     result = a
-    opPrec = getPrecedence(p.tok, p.strongSpaces)
+    opPrec = getPrecedence(p.tok, false)
 
 proc simpleExprAux(p: var TParser, limit: int, mode: TPrimaryMode): PNode =
   result = primary(p, mode)
@@ -1255,14 +1254,29 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
     if mode != pmSkipSuffix:
       result = primarySuffix(p, result, baseInd, mode)
 
+proc binaryNot(p: var TParser; a: PNode): PNode =
+  if p.tok.tokType == tkNot:
+    let notOpr = newIdentNodeP(p.tok.ident, p)
+    getTok(p)
+    optInd(p, notOpr)
+    let b = parseExpr(p)
+    result = newNodeP(nkInfix, p)
+    result.add notOpr
+    result.add a
+    result.add b
+  else:
+    result = a
+
 proc parseTypeDesc(p: var TParser): PNode =
-  #| typeDesc = simpleExpr
+  #| typeDesc = simpleExpr ('not' expr)?
   result = simpleExpr(p, pmTypeDesc)
+  result = binaryNot(p, result)
 
 proc parseTypeDefAux(p: var TParser): PNode =
-  #| typeDefAux = simpleExpr
+  #| typeDefAux = simpleExpr ('not' expr)?
   #|            | 'concept' typeClass
   result = simpleExpr(p, pmTypeDef)
+  result = binaryNot(p, result)
 
 proc makeCall(n: PNode): PNode =
   ## Creates a call if the given node isn't already a call.
@@ -1370,12 +1384,12 @@ proc parseExprStmt(p: var TParser): PNode =
       while true:
         getTok(p)
         optInd(p, result)
-        addSon(result, commandParam(p, isFirstParam))
+        addSon(result, commandParam(p, isFirstParam, pmNormal))
         if p.tok.tokType != tkComma: break
     elif p.tok.indent < 0 and isExprStart(p):
       result = newNode(nkCommand, a.info, @[a])
       while true:
-        addSon(result, commandParam(p, isFirstParam))
+        addSon(result, commandParam(p, isFirstParam, pmNormal))
         if p.tok.tokType != tkComma: break
         getTok(p)
         optInd(p, result)
@@ -2236,10 +2250,8 @@ proc parseString*(s: string; cache: IdentCache; config: ConfigRef;
   stream.lineOffset = line
 
   var parser: TParser
-  # XXX for now the builtin 'parseStmt/Expr' functions do not know about strong
-  # spaces...
   parser.lex.errorHandler = errorHandler
-  openParser(parser, AbsoluteFile filename, stream, cache, config, false)
+  openParser(parser, AbsoluteFile filename, stream, cache, config)
 
   result = parser.parseAll
   closeParser(parser)
diff --git a/compiler/pathutils.nim b/compiler/pathutils.nim
index 4873f90d6..703467bc4 100644
--- a/compiler/pathutils.nim
+++ b/compiler/pathutils.nim
@@ -73,23 +73,6 @@ iterator dirs(x: string): (int, int) =
   var it: PathIter
   while hasNext(it, x): yield next(it, x)
 
-when false:
-  iterator dirs(x: string): (int, int) =
-    var i = 0
-    var first = true
-    while i < x.len:
-      let prev = i
-      if first and x[i] in {DirSep, AltSep}:
-        # absolute path:
-        inc i
-      else:
-        while i < x.len and x[i] notin {DirSep, AltSep}: inc i
-      if i > prev:
-        yield (prev, i-1)
-      first = false
-      # skip all separators:
-      while i < x.len and x[i] in {DirSep, AltSep}: inc i
-
 proc isDot(x: string; bounds: (int, int)): bool =
   bounds[1] == bounds[0] and x[bounds[0]] == '.'
 
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 08e3c34d4..ef5223559 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -1019,8 +1019,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
         else: incl(sym.typ.flags, tfIncompleteStruct)
       of wUnchecked:
         noVal(c, it)
-        if sym.typ == nil: invalidPragma(c, it)
-        else: incl(sym.typ.flags, tfUncheckedArray)
+        if sym.typ == nil or sym.typ.kind notin {tyArray, tyUncheckedArray}:
+          invalidPragma(c, it)
+        else:
+          sym.typ.kind = tyUncheckedArray
       of wUnion:
         noVal(c, it)
         if sym.typ == nil: invalidPragma(c, it)
@@ -1060,6 +1062,8 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
           invalidPragma(c, it)
         else:
           sym.bitsize = expectIntLit(c, it)
+          if sym.bitsize <= 0:
+            localError(c.config, it.info, "bitsize needs to be positive")
       of wGuard:
         if sym == nil or sym.kind notin {skVar, skLet, skField}:
           invalidPragma(c, it)
diff --git a/compiler/reorder.nim b/compiler/reorder.nim
index 07462bb3e..8c4d0d307 100644
--- a/compiler/reorder.nim
+++ b/compiler/reorder.nim
@@ -1,6 +1,6 @@
 
 import
-  intsets, ast, idents, algorithm, renderer, parser, ospaths, strutils,
+  intsets, ast, idents, algorithm, renderer, parser, os, strutils,
   sequtils, msgs, modulegraphs, syntaxes, options, modulepaths, tables,
   lineinfos
 
diff --git a/compiler/rod.nim b/compiler/rod.nim
index f6fc24ec0..92489ffdd 100644
--- a/compiler/rod.nim
+++ b/compiler/rod.nim
@@ -22,6 +22,8 @@ when not nimIncremental:
 
   template storeRemaining*(g: ModuleGraph; module: PSym) = discard
 
+  template registerModule*(g: ModuleGraph; module: PSym) = discard
+
 else:
   include rodimpl
 
diff --git a/compiler/rodimpl.nim b/compiler/rodimpl.nim
index 839a9c6ca..730328642 100644
--- a/compiler/rodimpl.nim
+++ b/compiler/rodimpl.nim
@@ -321,6 +321,9 @@ proc encodeSym(g: ModuleGraph, s: PSym, result: var string) =
       result.add('\16')
       encodeVInt(s.gcUnsafetyReason.id, result)
       pushSym(w, s.gcUnsafetyReason)
+    if s.transformedBody != nil:
+      result.add('\24')
+      encodeNode(g, s.info, s.transformedBody, result)
   of skModule, skPackage:
     encodeInstantiations(g, s.usedGenerics, result)
     # we don't serialize:
@@ -363,13 +366,7 @@ proc storeType(g: ModuleGraph; t: PType) =
   db.exec(sql"insert into types(nimid, module, data) values (?, ?, ?)",
     t.id, mid, buf)
 
-proc storeNode*(g: ModuleGraph; module: PSym; n: PNode) =
-  if g.config.symbolFiles == disabledSf: return
-  var buf = newStringOfCap(160)
-  encodeNode(g, module.info, n, buf)
-  db.exec(sql"insert into toplevelstmts(module, position, data) values (?, ?, ?)",
-    abs(module.id), module.offset, buf)
-  inc module.offset
+proc transitiveClosure(g: ModuleGraph) =
   var i = 0
   while true:
     if i > 10_000:
@@ -388,9 +385,25 @@ proc storeNode*(g: ModuleGraph; module: PSym; n: PNode) =
       break
     inc i
 
+proc storeNode*(g: ModuleGraph; module: PSym; n: PNode) =
+  if g.config.symbolFiles == disabledSf: return
+  var buf = newStringOfCap(160)
+  encodeNode(g, module.info, n, buf)
+  db.exec(sql"insert into toplevelstmts(module, position, data) values (?, ?, ?)",
+    abs(module.id), module.offset, buf)
+  inc module.offset
+  transitiveClosure(g)
+
 proc recordStmt*(g: ModuleGraph; module: PSym; n: PNode) =
   storeNode(g, module, n)
 
+proc storeFilename(g: ModuleGraph; fullpath: AbsoluteFile; fileIdx: FileIndex) =
+  let id = db.getValue(sql"select id from filenames where fullpath = ?", fullpath.string)
+  if id.len == 0:
+    let fullhash = hashFileCached(g.config, fileIdx, fullpath)
+    db.exec(sql"insert into filenames(nimid, fullpath, fullhash) values (?, ?, ?)",
+        int(fileIdx), fullpath.string, fullhash)
+
 proc storeRemaining*(g: ModuleGraph; module: PSym) =
   if g.config.symbolFiles == disabledSf: return
   var stillForwarded: seq[PSym] = @[]
@@ -400,6 +413,13 @@ proc storeRemaining*(g: ModuleGraph; module: PSym) =
     else:
       stillForwarded.add s
   swap w.forwardedSyms, stillForwarded
+  transitiveClosure(g)
+  var nimid = 0
+  for x in items(g.config.m.fileInfos):
+    # don't store the "command line" entry:
+    if nimid != 0:
+      storeFilename(g, x.fullPath, FileIndex(nimid))
+    inc nimid
 
 # ---------------- decoder -----------------------------------
 
@@ -725,6 +745,9 @@ proc loadSymFromBlob(g; b; info: TLineInfo): PSym =
     if b.s[b.pos] == '\16':
       inc(b.pos)
       result.gcUnsafetyReason = loadSym(g, decodeVInt(b.s, b.pos), result.info)
+    if b.s[b.pos] == '\24':
+      inc b.pos
+      result.transformedBody = decodeNode(g, b, result.info)
   of skModule, skPackage:
     decodeInstantiations(g, b, result.info, result.usedGenerics)
   of skLet, skVar, skField, skForVar:
@@ -752,6 +775,9 @@ proc loadSym(g; id: int; info: TLineInfo): PSym =
   result = loadSymFromBlob(g, b, info)
   doAssert id == result.id, "symbol ID is not consistent!"
 
+proc registerModule*(g; module: PSym) =
+  g.incr.r.syms.add(abs module.id, module)
+
 proc loadModuleSymTab(g; module: PSym) =
   ## goal: fill  module.tab
   g.incr.r.syms.add(module.id, module)
@@ -765,7 +791,8 @@ proc loadModuleSymTab(g; module: PSym) =
       b.s.add '\0'
       s = loadSymFromBlob(g, b, module.info)
     assert s != nil
-    strTableAdd(module.tab, s)
+    if s.kind != skField:
+      strTableAdd(module.tab, s)
   if sfSystemModule in module.flags:
     g.systemModule = module
 
@@ -843,8 +870,9 @@ proc replay(g: ModuleGraph; module: PSym; n: PNode) =
         internalAssert g.config, false
   of nkImportStmt:
     for x in n:
-      internalAssert g.config, x.kind == nkStrLit
-      let imported = g.importModuleCallback(g, module, fileInfoIdx(g.config, AbsoluteFile n[0].strVal))
+      internalAssert g.config, x.kind == nkSym
+      let modpath = AbsoluteFile toFullPath(g.config, x.sym.info)
+      let imported = g.importModuleCallback(g, module, fileInfoIdx(g.config, modpath))
       internalAssert g.config, imported.id < 0
   of nkStmtList, nkStmtListExpr:
     for x in n: replay(g, module, x)
@@ -868,16 +896,23 @@ proc setupModuleCache*(g: ModuleGraph) =
   let dbfile = getNimcacheDir(g.config) / RelativeFile"rodfiles.db"
   if g.config.symbolFiles == writeOnlySf:
     removeFile(dbfile)
+  createDir getNimcacheDir(g.config)
+  let ec = encodeConfig(g)
   if not fileExists(dbfile):
     db = open(connection=string dbfile, user="nim", password="",
               database="nim")
     createDb(db)
-    db.exec(sql"insert into config(config) values (?)", encodeConfig(g))
+    db.exec(sql"insert into config(config) values (?)", ec)
   else:
     db = open(connection=string dbfile, user="nim", password="",
               database="nim")
     let oldConfig = db.getValue(sql"select config from config")
-    g.incr.configChanged = oldConfig != encodeConfig(g)
+    g.incr.configChanged = oldConfig != ec
+    # ensure the filename IDs stay consistent:
+    for row in db.rows(sql"select fullpath, nimid from filenames order by nimid"):
+      let id = fileInfoIdx(g.config, AbsoluteFile row[0])
+      doAssert id.int == parseInt(row[1])
+    db.exec(sql"update config set config = ?", ec)
   db.exec(sql"pragma journal_mode=off")
   # This MUST be turned off, otherwise it's way too slow even for testing purposes:
   db.exec(sql"pragma SYNCHRONOUS=off")
diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim
index f94533177..bfff86479 100644
--- a/compiler/scriptconfig.nim
+++ b/compiler/scriptconfig.nim
@@ -123,6 +123,7 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
   cbconf setCommand:
     conf.command = a.getString 0
     let arg = a.getString 1
+    incl(conf.globalOptions, optWasNimscript)
     if arg.len > 0:
       conf.projectName = arg
       let path =
@@ -158,6 +159,8 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
 proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
                    freshDefines=true; conf: ConfigRef) =
   rawMessage(conf, hintConf, scriptName.string)
+  let oldSymbolFiles = conf.symbolFiles
+  conf.symbolFiles = disabledSf
 
   let graph = newModuleGraph(cache, conf)
   connectCallbacks(graph)
@@ -183,3 +186,4 @@ proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
   #initDefines()
   undefSymbol(conf.symbols, "nimscript")
   undefSymbol(conf.symbols, "nimconfig")
+  conf.symbolFiles = oldSymbolFiles
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 97a47ceca..775c9f7c9 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -16,13 +16,16 @@ import
   procfind, lookups, pragmas, passes, semdata, semtypinst, sigmatch,
   intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
   evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity,
-  semparallel, lowerings, pluginsupport, plugins/active, rod, lineinfos
+  lowerings, pluginsupport, plugins/active, rod, lineinfos
 
-from modulegraphs import ModuleGraph, PPassContext
+from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward
 
 when defined(nimfix):
   import nimfix/prettybase
 
+when not defined(leanCompiler):
+  import semparallel
+
 # implementation
 
 proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.procvar.}
@@ -447,7 +450,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
   pushInfoContext(c.config, nOrig.info, sym.detailedInfo)
 
   markUsed(c.config, n.info, sym, c.graph.usageSym)
-  styleCheckUse(n.info, sym)
+  onUse(n.info, sym)
   if sym == c.p.owner:
     globalError(c.config, n.info, "recursive dependency: '$1'" % sym.name.s)
 
diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim
index 7d6ae70de..3947e4f6c 100644
--- a/compiler/semasgn.nim
+++ b/compiler/semasgn.nim
@@ -81,8 +81,8 @@ proc genAddr(c: PContext; x: PNode): PNode =
     addSon(result, x)
 
 proc newAsgnCall(c: PContext; op: PSym; x, y: PNode): PNode =
-  if sfError in op.flags:
-    localError(c.config, x.info, "usage of '$1' is a user-defined error" % op.name.s)
+  #if sfError in op.flags:
+  #  localError(c.config, x.info, "usage of '$1' is a user-defined error" % op.name.s)
   result = newNodeI(nkCall, x.info)
   result.add newSymNode(op)
   result.add genAddr(c, x)
@@ -121,8 +121,11 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
       op = field
       if op == nil:
         op = liftBody(c.c, t, c.kind, c.info)
-    markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
-    styleCheckUse(c.info, op)
+    if sfError in op.flags:
+      incl c.fn.flags, sfError
+    else:
+      markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
+    onUse(c.info, op)
     body.add newAsgnCall(c.c, op, x, y)
     result = true
 
@@ -132,7 +135,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
     let op = t.destructor
     if op != nil:
       markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
-      styleCheckUse(c.info, op)
+      onUse(c.info, op)
       body.add destructorCall(c.c, op, x)
       result = true
   of attachedAsgn:
@@ -143,7 +146,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
     let op = t.deepCopy
     if op != nil:
       markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
-      styleCheckUse(c.info, op)
+      onUse(c.info, op)
       body.add newDeepCopyCall(op, x, y)
       result = true
 
@@ -200,7 +203,7 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
       tyPtr, tyRef, tyOpt, tyUncheckedArray:
     defaultOp(c, t, body, x, y)
   of tyArray:
-    if {tfHasAsgn, tfUncheckedArray} * t.flags == {tfHasAsgn}:
+    if tfHasAsgn in t.flags:
       let i = declareCounter(c, body, firstOrd(c.c.config, t))
       let whileLoop = genWhileLoop(c, i, x)
       let elemType = t.lastSon
diff --git a/compiler/semcall.nim b/compiler/semcall.nim
index 49b344274..7e0ea5490 100644
--- a/compiler/semcall.nim
+++ b/compiler/semcall.nim
@@ -138,6 +138,7 @@ proc effectProblem(f, a: PType; result: var string) =
 
 proc renderNotLValue(n: PNode): string =
   result = $n
+  let n = if n.kind == nkHiddenDeref: n[0] else: n
   if n.kind == nkHiddenCallConv and n.len > 1:
     result = $n[0] & "(" & result & ")"
   elif n.kind in {nkHiddenStdConv, nkHiddenSubConv} and n.len == 2:
@@ -166,20 +167,22 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
       prefer = preferModuleInfo
       break
 
-  when false:
-    # we pretend procs are attached to the type of the first
-    # argument in order to remove plenty of candidates. This is
-    # comparable to what C# does and C# is doing fine.
-    var filterOnlyFirst = false
+  # we pretend procs are attached to the type of the first
+  # argument in order to remove plenty of candidates. This is
+  # comparable to what C# does and C# is doing fine.
+  var filterOnlyFirst = false
+  if optShowAllMismatches notin c.config.globalOptions:
     for err in errors:
       if err.firstMismatch > 1:
         filterOnlyFirst = true
         break
 
   var candidates = ""
+  var skipped = 0
   for err in errors:
-    when false:
-      if filterOnlyFirst and err.firstMismatch == 1: continue
+    if filterOnlyFirst and err.firstMismatch == 1:
+      inc skipped
+      continue
     if err.sym.kind in routineKinds and err.sym.ast != nil:
       add(candidates, renderTree(err.sym.ast,
             {renderNoBody, renderNoComments, renderNoPragmas}))
@@ -216,7 +219,9 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
                       "' is immutable\n")
     for diag in err.diagnostics:
       candidates.add(diag & "\n")
-
+  if skipped > 0:
+    candidates.add($skipped & " other mismatching symbols have been " &
+        " suppressed; compile with --showAllMismatches:on to see them\n")
   result = (prefer, candidates)
 
 const
@@ -390,6 +395,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
         args])
 
 proc instGenericConvertersArg*(c: PContext, a: PNode, x: TCandidate) =
+  let a = if a.kind == nkHiddenDeref: a[0] else: a
   if a.kind == nkHiddenCallConv and a.sons[0].kind == nkSym:
     let s = a.sons[0].sym
     if s.ast != nil and s.ast[genericParamsPos].kind != nkEmpty:
@@ -450,7 +456,7 @@ proc semResolvedCall(c: PContext, x: TCandidate,
   assert x.state == csMatch
   var finalCallee = x.calleeSym
   markUsed(c.config, n.sons[0].info, finalCallee, c.graph.usageSym)
-  styleCheckUse(n.sons[0].info, finalCallee)
+  onUse(n.sons[0].info, finalCallee)
   assert finalCallee.ast != nil
   if x.hasFauxMatch:
     result = x.call
@@ -558,14 +564,17 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
   var newInst = generateInstance(c, s, m.bindings, n.info)
   newInst.typ.flags.excl tfUnresolved
   markUsed(c.config, n.info, s, c.graph.usageSym)
-  styleCheckUse(n.info, s)
+  onUse(n.info, s)
   result = newSymNode(newInst, n.info)
 
 proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
   assert n.kind == nkBracketExpr
   for i in 1..sonsLen(n)-1:
     let e = semExpr(c, n.sons[i])
-    n.sons[i].typ = e.typ.skipTypes({tyTypeDesc})
+    if e.typ == nil:
+      localError(c.config, e.info, "expression has no type")
+    else:
+      n.sons[i].typ = e.typ.skipTypes({tyTypeDesc})
   var s = s
   var a = n.sons[0]
   if a.kind == nkSym:
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 1725d7a31..669862c56 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -25,7 +25,7 @@ const
 proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
                      flags: TExprFlags = {}): PNode =
   markUsed(c.config, n.info, s, c.graph.usageSym)
-  styleCheckUse(n.info, s)
+  onUse(n.info, s)
   pushInfoContext(c.config, n.info, s.detailedInfo)
   result = evalTemplate(n, s, getCurrOwner(c), c.config, efFromHlo in flags)
   if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags)
@@ -265,7 +265,7 @@ proc semConv(c: PContext, n: PNode): PNode =
       let status = checkConvertible(c, result.typ, it.typ)
       if status in {convOK, convNotNeedeed}:
         markUsed(c.config, n.info, it.sym, c.graph.usageSym)
-        styleCheckUse(n.info, it.sym)
+        onUse(n.info, it.sym)
         markIndirect(c, it.sym)
         return it
     errorUseQualifier(c, n.info, op.sons[0].sym)
@@ -614,7 +614,8 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
   const
     FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl,
       mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap,
-      mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy}
+      mAppendSeqElem, mNewSeq, mReset, mShallowCopy, mDeepCopy, mMove,
+      mWasMoved}
 
   # get the real type of the callee
   # it may be a proc var with a generic alias type, so we skip over them
@@ -640,6 +641,7 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
 
     return
   for i in countup(1, sonsLen(n) - 1):
+    let n = if n.kind == nkHiddenDeref: n[0] else: n
     if n.sons[i].kind == nkHiddenCallConv:
       # we need to recurse explicitly here as converters can create nested
       # calls and then they wouldn't be analysed otherwise
@@ -1036,7 +1038,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
   case s.kind
   of skConst:
     markUsed(c.config, n.info, s, c.graph.usageSym)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
     of  tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
         tyTuple, tySet, tyUInt..tyUInt64:
@@ -1061,7 +1063,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
     if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or
        (n.kind notin nkCallKinds and s.requiredParams > 0):
       markUsed(c.config, n.info, s, c.graph.usageSym)
-      styleCheckUse(n.info, s)
+      onUse(n.info, s)
       result = symChoice(c, n, s, scClosed)
     else:
       result = semMacroExpr(c, n, n, s, flags)
@@ -1070,13 +1072,13 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
        (n.kind notin nkCallKinds and s.requiredParams > 0) or
        sfCustomPragma in sym.flags:
       markUsed(c.config, n.info, s, c.graph.usageSym)
-      styleCheckUse(n.info, s)
+      onUse(n.info, s)
       result = symChoice(c, n, s, scClosed)
     else:
       result = semTemplateExpr(c, n, s, flags)
   of skParam:
     markUsed(c.config, n.info, s, c.graph.usageSym)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     if s.typ != nil and s.typ.kind == tyStatic and s.typ.n != nil:
       # XXX see the hack in sigmatch.nim ...
       return s.typ.n
@@ -1098,14 +1100,14 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
       localError(c.config, n.info, "illegal context for 'nimvm' magic")
 
     markUsed(c.config, n.info, s, c.graph.usageSym)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     result = newSymNode(s, n.info)
     # We cannot check for access to outer vars for example because it's still
     # not sure the symbol really ends up being used:
     # var len = 0 # but won't be called
     # genericThatUsesLen(x) # marked as taking a closure?
   of skGenericParam:
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     if s.typ.kind == tyStatic:
       result = newSymNode(s, n.info)
       result.typ = s.typ
@@ -1116,7 +1118,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
       return n
   of skType:
     markUsed(c.config, n.info, s, c.graph.usageSym)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     if s.typ.kind == tyStatic and s.typ.base.kind != tyNone and s.typ.n != nil:
       return s.typ.n
     result = newSymNode(s, n.info)
@@ -1138,7 +1140,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
             # is the access to a public field or in the same module or in a friend?
             doAssert f == s
             markUsed(c.config, n.info, f, c.graph.usageSym)
-            styleCheckUse(n.info, f)
+            onUse(n.info, f)
             result = newNodeIT(nkDotExpr, n.info, f.typ)
             result.add makeDeref(newSymNode(p.selfSym))
             result.add newSymNode(f) # we now have the correct field
@@ -1151,11 +1153,11 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode =
           ty = skipTypes(ty.sons[0], skipPtrs)
     # old code, not sure if it's live code:
     markUsed(c.config, n.info, s, c.graph.usageSym)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     result = newSymNode(s, n.info)
   else:
     markUsed(c.config, n.info, s, c.graph.usageSym)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     result = newSymNode(s, n.info)
 
 proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
@@ -1178,7 +1180,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
     else:
       markUsed(c.config, n.sons[1].info, s, c.graph.usageSym)
       result = semSym(c, n, s, flags)
-    styleCheckUse(n.sons[1].info, s)
+    onUse(n.sons[1].info, s)
     return
 
   n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType})
@@ -1241,7 +1243,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
         result.info = n.info
         result.typ = ty
         markUsed(c.config, n.info, f, c.graph.usageSym)
-        styleCheckUse(n.info, f)
+        onUse(n.info, f)
         return
     of tyObject, tyTuple:
       if ty.n != nil and ty.n.kind == nkRecList:
@@ -1272,7 +1274,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
       if fieldVisible(c, f):
         # is the access to a public field or in the same module or in a friend?
         markUsed(c.config, n.sons[1].info, f, c.graph.usageSym)
-        styleCheckUse(n.sons[1].info, f)
+        onUse(n.sons[1].info, f)
         n.sons[0] = makeDeref(n.sons[0])
         n.sons[1] = newSymNode(f) # we now have the correct field
         n.typ = f.typ
@@ -1286,7 +1288,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
     f = getSymFromList(ty.n, i)
     if f != nil:
       markUsed(c.config, n.sons[1].info, f, c.graph.usageSym)
-      styleCheckUse(n.sons[1].info, f)
+      onUse(n.sons[1].info, f)
       n.sons[0] = makeDeref(n.sons[0])
       n.sons[1] = newSymNode(f)
       n.typ = f.typ
@@ -1538,7 +1540,9 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
   # a = b # both are vars, means: a[] = b[]
   # a = b # b no 'var T' means: a = addr(b)
   var le = a.typ
-  if (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind != tyVar and
+  if le == nil:
+    localError(c.config, a.info, "expression has no type")
+  elif (skipTypes(le, {tyGenericInst, tyAlias, tySink}).kind != tyVar and
         isAssignable(c, a) == arNone) or
       skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs}:
     # Direct assignment to a discriminant is allowed!
@@ -1756,7 +1760,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
 
     macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
     markUsed(c.config, n.info, expandedSym, c.graph.usageSym)
-    styleCheckUse(n.info, expandedSym)
+    onUse(n.info, expandedSym)
 
   if isCallExpr(macroCall):
     for i in countup(1, macroCall.len-1):
@@ -1781,7 +1785,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
       let info = macroCall.sons[0].info
       macroCall.sons[0] = newSymNode(cand, info)
       markUsed(c.config, info, cand, c.graph.usageSym)
-      styleCheckUse(info, cand)
+      onUse(info, cand)
 
     # we just perform overloading resolution here:
     #n.sons[1] = semOverloadedCall(c, macroCall, macroCall, {skTemplate, skMacro})
@@ -1811,6 +1815,7 @@ proc processQuotations(c: PContext; n: var PNode, op: string,
     ids.add n
     return
 
+
   if n.kind == nkPrefix:
     checkSonsLen(n, 2, c.config)
     if n[0].kind == nkIdent:
@@ -1821,6 +1826,9 @@ proc processQuotations(c: PContext; n: var PNode, op: string,
         n.sons[0] = newIdentNode(getIdent(c.cache, examinedOp.substr(op.len)), n.info)
   elif n.kind == nkAccQuoted and op == "``":
     returnQuote n[0]
+  elif n.kind == nkIdent:
+    if n.ident.s == "result":
+      n = ids[0]
 
   for i in 0 ..< n.safeLen:
     processQuotations(c, n.sons[i], op, quotes, ids)
@@ -1832,15 +1840,18 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
   var
     quotedBlock = n[^1]
     op = if n.len == 3: expectString(c, n[1]) else: "``"
-    quotes = newSeq[PNode](1)
+    quotes = newSeq[PNode](2)
       # the quotes will be added to a nkCall statement
-      # leave some room for the callee symbol
-    ids = newSeq[PNode]()
+      # leave some room for the callee symbol and the result symbol
+    ids = newSeq[PNode](1)
       # this will store the generated param names
+      # leave some room for the result symbol
 
   if quotedBlock.kind != nkStmtList:
     localError(c.config, n.info, errXExpected, "block")
 
+  # This adds a default first field to pass the result symbol
+  ids[0] = newAnonSym(c, skParam, n.info).newSymNode
   processQuotations(c, quotedBlock, op, quotes, ids)
 
   var dummyTemplate = newProcNode(
@@ -1859,6 +1870,8 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
 
   var tmpl = semTemplateDef(c, dummyTemplate)
   quotes[0] = tmpl[namePos]
+  # This adds a call to newIdentNode("result") as the first argument to the template call
+  quotes[1] = newNode(nkCall, n.info, @[newIdentNode(getIdent(c.cache, "newIdentNode"), n.info), newStrNode(nkStrLit, "result")])
   result = newNode(nkCall, n.info, @[
      createMagic(c.graph, "getAst", mExpandToAst).newSymNode,
     newNode(nkCall, n.info, quotes)])
@@ -2254,6 +2267,7 @@ proc semBlock(c: PContext, n: PNode; flags: TExprFlags): PNode =
     n.sons[0] = newSymNode(labl, n.sons[0].info)
     suggestSym(c.config, n.sons[0].info, labl, c.graph.usageSym)
     styleCheckDef(c.config, labl)
+    onDef(n[0].info, labl)
   n.sons[1] = semExpr(c, n.sons[1], flags)
   n.typ = n.sons[1].typ
   if isEmptyType(n.typ): n.kind = nkBlockStmt
@@ -2332,7 +2346,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
         {checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields}
     var s = qualifiedLookUp(c, n, checks)
     if c.matchedConcept == nil: semCaptureSym(s, c.p.owner)
-    result = semSym(c, n, s, flags)
     if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator}:
       #performProcvarCheck(c, n, s)
       result = symChoice(c, n, s, scClosed)
@@ -2340,6 +2353,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
         markIndirect(c, result.sym)
         # if isGenericRoutine(result.sym):
         #   localError(c.config, n.info, errInstantiateXExplicitly, s.name.s)
+    else:
+      result = semSym(c, n, s, flags)
   of nkSym:
     # because of the changed symbol binding, this does not mean that we
     # don't have to check the symbol for semantics here again!
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 5565e8ed9..5ec702257 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -267,12 +267,7 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
   of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n, g)
   of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n, g)
   of mDivF64:
-    if getFloat(b) == 0.0:
-      if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n, g)
-      elif getFloat(b).classify == fcNegZero: result = newFloatNodeT(-Inf, n, g)
-      else: result = newFloatNodeT(Inf, n, g)
-    else:
-      result = newFloatNodeT(getFloat(a) / getFloat(b), n, g)
+    result = newFloatNodeT(getFloat(a) / getFloat(b), n, g)
   of mMaxF64:
     if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n, g)
     else: result = newFloatNodeT(getFloat(b), n, g)
@@ -413,15 +408,14 @@ proc getAppType(n: PNode; g: ModuleGraph): PNode =
     result = newStrNodeT("console", n, g)
 
 proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) =
-  if tfUncheckedArray notin n.typ.flags:
-    var err = false
-    if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}:
-      err = value <% firstOrd(g.config, n.typ) or value >% lastOrd(g.config, n.typ, fixedUnsigned=true)
-    else:
-      err = value < firstOrd(g.config, n.typ) or value > lastOrd(g.config, n.typ)
-    if err:
-      localError(g.config, n.info, "cannot convert " & $value &
-                                      " to " & typeToString(n.typ))
+  var err = false
+  if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}:
+    err = value <% firstOrd(g.config, n.typ) or value >% lastOrd(g.config, n.typ, fixedUnsigned=true)
+  else:
+    err = value < firstOrd(g.config, n.typ) or value > lastOrd(g.config, n.typ)
+  if err:
+    localError(g.config, n.info, "cannot convert " & $value &
+                                    " to " & typeToString(n.typ))
 
 proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode =
   let dstTyp = skipTypes(n.typ, abstractRange)
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index a0044a0af..5972f3b55 100644
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -76,14 +76,14 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
     result = symChoice(c, n, s, scOpen)
   of skTemplate:
     if macroToExpandSym(s):
-      styleCheckUse(n.info, s)
+      onUse(n.info, s)
       result = semTemplateExpr(c, n, s, {efNoSemCheck})
       result = semGenericStmt(c, result, {}, ctx)
     else:
       result = symChoice(c, n, s, scOpen)
   of skMacro:
     if macroToExpandSym(s):
-      styleCheckUse(n.info, s)
+      onUse(n.info, s)
       result = semMacroExpr(c, n, n, s, {efNoSemCheck})
       result = semGenericStmt(c, result, {}, ctx)
     else:
@@ -96,20 +96,20 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
         result = n
     else:
       result = newSymNodeTypeDesc(s, n.info)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
   of skParam:
     result = n
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
   of skType:
     if (s.typ != nil) and
        (s.typ.flags * {tfGenericTypeParam, tfImplicitTypeParam} == {}):
       result = newSymNodeTypeDesc(s, n.info)
     else:
       result = n
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
   else:
     result = newSymNode(s, n.info)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
 
 proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
             ctx: var GenericCtx): PNode =
@@ -172,6 +172,7 @@ proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
   let s = newSymS(skUnknown, getIdentNode(c, n), c)
   addPrelimDecl(c, s)
   styleCheckDef(c.config, n.info, s, kind)
+  onDef(n.info, s)
 
 proc semGenericStmt(c: PContext, n: PNode,
                     flags: TSemGenericFlags, ctx: var GenericCtx): PNode =
@@ -230,7 +231,7 @@ proc semGenericStmt(c: PContext, n: PNode,
       case s.kind
       of skMacro:
         if macroToExpand(s) and sc.safeLen <= 1:
-          styleCheckUse(fn.info, s)
+          onUse(fn.info, s)
           result = semMacroExpr(c, n, n, s, {efNoSemCheck})
           result = semGenericStmt(c, result, flags, ctx)
         else:
@@ -239,7 +240,7 @@ proc semGenericStmt(c: PContext, n: PNode,
         mixinContext = true
       of skTemplate:
         if macroToExpand(s) and sc.safeLen <= 1:
-          styleCheckUse(fn.info, s)
+          onUse(fn.info, s)
           result = semTemplateExpr(c, n, s, {efNoSemCheck})
           result = semGenericStmt(c, result, flags, ctx)
         else:
@@ -262,17 +263,17 @@ proc semGenericStmt(c: PContext, n: PNode,
           inc first
       of skGenericParam:
         result.sons[0] = newSymNodeTypeDesc(s, fn.info)
-        styleCheckUse(fn.info, s)
+        onUse(fn.info, s)
         first = 1
       of skType:
         # bad hack for generics:
         if (s.typ != nil) and (s.typ.kind != tyGenericParam):
           result.sons[0] = newSymNodeTypeDesc(s, fn.info)
-          styleCheckUse(fn.info, s)
+          onUse(fn.info, s)
           first = 1
       else:
         result.sons[0] = newSymNode(s, fn.info)
-        styleCheckUse(fn.info, s)
+        onUse(fn.info, s)
         first = 1
     elif fn.kind == nkDotExpr:
       result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 09d971236..2aae562f9 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -306,7 +306,13 @@ proc semOf(c: PContext, n: PNode): PNode =
         result.typ = getSysType(c.graph, n.info, tyBool)
         return result
       elif diff == high(int):
-        localError(c.config, n.info, "'$1' cannot be of this subtype" % typeToString(a))
+        if commonSuperclass(a, b) == nil:
+          localError(c.config, n.info, "'$1' cannot be of this subtype" % typeToString(a))
+        else:
+          message(c.config, n.info, hintConditionAlwaysFalse, renderTree(n))
+          result = newIntNode(nkIntLit, 0)
+          result.info = n.info
+          result.typ = getSysType(c.graph, n.info, tyBool)
   else:
     localError(c.config, n.info, "'of' takes 2 arguments")
   n.typ = getSysType(c.graph, n.info, tyBool)
@@ -329,23 +335,19 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
   of mTypeOf:
     result = semTypeOf(c, n)
   of mSizeOf:
-      # TODO there is no proper way to find out if a type cannot be queried for the size.
-      let size = getSize(c.config, n[1].typ)
-      # We just assume here that the type might come from the c backend
-      if size == szUnknownSize:
-        # Forward to the c code generation to emit a `sizeof` in the C code.
-        result = n
-      elif size >= 0:
-        result = newIntNode(nkIntLit, size)
-        result.info = n.info
-        result.typ = n.typ
-      else:
-
-        localError(c.config, n.info, "cannot evaluate 'sizeof' because its type is not defined completely")
-
-        result = nil
-
-
+    # TODO there is no proper way to find out if a type cannot be queried for the size.
+    let size = getSize(c.config, n[1].typ)
+    # We just assume here that the type might come from the c backend
+    if size == szUnknownSize:
+      # Forward to the c code generation to emit a `sizeof` in the C code.
+      result = n
+    elif size >= 0:
+      result = newIntNode(nkIntLit, size)
+      result.info = n.info
+      result.typ = n.typ
+    else:
+      localError(c.config, n.info, "cannot evaluate 'sizeof' because its type is not defined completely")
+      result = n
   of mAlignOf:
     result = newIntNode(nkIntLit, getAlign(c.config, n[1].typ))
     result.info = n.info
diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim
index c1bdb08a8..0317fd8ba 100644
--- a/compiler/sempass2.nim
+++ b/compiler/sempass2.nim
@@ -9,9 +9,12 @@
 
 import
   intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
-  wordrecg, strutils, options, guards, writetracking, lineinfos, semfold,
+  wordrecg, strutils, options, guards, lineinfos, semfold,
   modulegraphs
 
+when not defined(leanCompiler):
+  import writetracking
+
 when defined(useDfa):
   import dfa
 
@@ -713,7 +716,7 @@ proc track(tracked: PEffects, n: PNode) =
       track(tracked, n.sons[i])
   of nkCallKinds:
     if getConstExpr(tracked.owner_module, n, tracked.graph) != nil:
-      return 
+      return
     # p's effects are ours too:
     var a = n.sons[0]
     let op = a.typ
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 5c7f866ce..1f2b9f0b3 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -41,8 +41,13 @@ proc semDiscard(c: PContext, n: PNode): PNode =
   checkSonsLen(n, 1, c.config)
   if n.sons[0].kind != nkEmpty:
     n.sons[0] = semExprWithType(c, n.sons[0])
-    if isEmptyType(n.sons[0].typ) or n.sons[0].typ.kind == tyNone or n.sons[0].kind == nkTypeOfExpr:
+    let sonType = n.sons[0].typ
+    let sonKind = n.sons[0].kind
+    if isEmptyType(sonType) or sonType.kind == tyNone or n.sons[0].kind == nkTypeOfExpr:
       localError(c.config, n.info, errInvalidDiscard)
+    if sonType.kind == tyProc and sonKind notin nkCallKinds:
+      # tyProc is disallowed to prevent ``discard foo`` to be valid, when ``discard foo()`` is meant.
+      localError(c.config, n.info, "illegal discard proc, did you mean: " & $n[0] & "()")
 
 proc semBreakOrContinue(c: PContext, n: PNode): PNode =
   result = n
@@ -61,7 +66,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
         incl(s.flags, sfUsed)
         n.sons[0] = x
         suggestSym(c.config, x.info, s, c.graph.usageSym)
-        styleCheckUse(x.info, s)
+        onUse(x.info, s)
       else:
         localError(c.config, n.info, errInvalidControlFlowX % s.name.s)
     else:
@@ -359,6 +364,7 @@ proc semUsing(c: PContext; n: PNode): PNode =
       for j in countup(0, length-3):
         let v = semIdentDef(c, a.sons[j], skParam)
         styleCheckDef(c.config, v)
+        onDef(a[j].info, v)
         v.typ = typ
         strTableIncl(c.signatures, v)
     else:
@@ -490,6 +496,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
         continue
       var v = semIdentDef(c, a.sons[j], symkind)
       styleCheckDef(c.config, v)
+      onDef(a[j].info, v)
       if sfGenSym notin v.flags and not isDiscardUnderscore(v):
         addInterfaceDecl(c, v)
       when oKeepVariableNames:
@@ -544,6 +551,7 @@ proc semConst(c: PContext, n: PNode): PNode =
     checkSonsLen(a, 3, c.config)
     var v = semIdentDef(c, a.sons[0], skConst)
     styleCheckDef(c.config, v)
+    onDef(a[0].info, v)
     var typ: PType = nil
     if a.sons[1].kind != nkEmpty: typ = semTypeNode(c, a.sons[1], nil)
 
@@ -587,6 +595,7 @@ proc symForVar(c: PContext, n: PNode): PSym =
   let m = if n.kind == nkPragmaExpr: n.sons[0] else: n
   result = newSymG(skForVar, m, c)
   styleCheckDef(c.config, result)
+  onDef(n.info, result)
   if n.kind == nkPragmaExpr:
     pragma(c, result, n.sons[1], forVarPragmas)
 
@@ -692,7 +701,7 @@ proc handleCaseStmtMacro(c: PContext; n: PNode): PNode =
   if r.state == csMatch:
     var match = r.calleeSym
     markUsed(c.config, n[0].info, match, c.graph.usageSym)
-    styleCheckUse(n[0].info, match)
+    onUse(n[0].info, match)
 
     # but pass 'n' to the 'match' macro, not 'n[0]':
     r.call.sons[1] = n
@@ -876,6 +885,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
         if typsym.isNil:
           s = semIdentDef(c, name[1], skType)
           styleCheckDef(c.config, s)
+          onDef(name[1].info, s)
           s.typ = newTypeS(tyObject, c)
           s.typ.sym = s
           s.flags.incl sfForward
@@ -890,6 +900,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
     else:
       s = semIdentDef(c, name, skType)
       styleCheckDef(c.config, s)
+      onDef(name.info, s)
       s.typ = newTypeS(tyForward, c)
       s.typ.sym = s             # process pragmas:
       if name.kind == nkPragmaExpr:
@@ -1621,6 +1632,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     else:
       implicitPragmas(c, s, n, validPragmas)
     styleCheckDef(c.config, s)
+    onDef(n[namePos].info, s)
   else:
     if n.sons[pragmasPos].kind != nkEmpty:
       pragma(c, s, n.sons[pragmasPos], validPragmas)
@@ -1634,6 +1646,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
         localError(c.config, n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX %
           ("'" & proto.name.s & "' from " & c.config$proto.info))
     styleCheckDef(c.config, s)
+    onDefResolveForward(n[namePos].info, proto)
     if sfForward notin proto.flags and proto.magic == mNone:
       wrongRedefinition(c, n.info, proto.name.s, proto.info)
     excl(proto.flags, sfForward)
@@ -1666,7 +1679,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
       localError(c.config, n.info, "the overloaded " & s.name.s &
         " operator has to be enabled with {.experimental: \"callOperator\".}")
 
-  if n.sons[bodyPos].kind != nkEmpty:
+  if n.sons[bodyPos].kind != nkEmpty and sfError notin s.flags:
     # for DLL generation it is annoying to check for sfImportc!
     if sfBorrow in s.flags:
       localError(c.config, n.sons[bodyPos].info, errImplOfXNotAllowed % s.name.s)
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index a64315037..14507cf9d 100644
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -64,6 +64,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
     # for instance 'nextTry' is both in tables.nim and astalgo.nim ...
     result = newSymNode(s, n.info)
     markUsed(c.config, n.info, s, c.graph.usageSym)
+    onUse(n.info, s)
   else:
     # semantic checking requires a type; ``fitNode`` deals with it
     # appropriately
@@ -75,6 +76,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
       if a.kind != skModule:
         incl(a.flags, sfUsed)
         addSon(result, newSymNode(a, n.info))
+        onUse(n.info, a)
       a = nextOverloadIter(o, c, n)
 
 proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
@@ -160,7 +162,7 @@ proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode =
       if s.owner == c.owner and s.kind == skParam:
         incl(s.flags, sfUsed)
         result = newSymNode(s, n.info)
-        styleCheckUse(n.info, s)
+        onUse(n.info, s)
   else:
     for i in 0 ..< n.safeLen:
       result.sons[i] = onlyReplaceParams(c, n.sons[i])
@@ -208,19 +210,20 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
       # So we need only check the *current* scope.
       let s = localSearchInScope(c.c, considerQuotedIdent(c.c, ident))
       if s != nil and s.owner == c.owner and sfGenSym in s.flags:
-        styleCheckUse(n.info, s)
+        onUse(n.info, s)
         replaceIdentBySym(c.c, n, newSymNode(s, n.info))
       elif not (n.kind == nkSym and sfGenSym in n.sym.flags):
         let local = newGenSym(k, ident, c)
         addPrelimDecl(c.c, local)
         styleCheckDef(c.c.config, n.info, local)
+        onDef(n.info, local)
         replaceIdentBySym(c.c, n, newSymNode(local, n.info))
     else:
       replaceIdentBySym(c.c, n, ident)
 
 proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
   incl(s.flags, sfUsed)
-  # we do not call styleCheckUse here, as the identifier is not really
+  # we do not call onUse here, as the identifier is not really
   # resolved here. We will fixup the used identifiers later.
   case s.kind
   of skUnknown:
@@ -245,7 +248,7 @@ proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
       if s.owner == c.owner and (s.kind == skParam or sfGenSym in s.flags):
         incl(s.flags, sfUsed)
         result = newSymNode(s, n.info)
-        styleCheckUse(n.info, s)
+        onUse(n.info, s)
   else:
     for i in countup(0, safeLen(n) - 1):
       result.sons[i] = semRoutineInTemplName(c, n.sons[i])
@@ -261,6 +264,7 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
       s.ast = n
       addPrelimDecl(c.c, s)
       styleCheckDef(c.c.config, n.info, s)
+      onDef(n.info, s)
       n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
     else:
       n.sons[namePos] = ident
@@ -314,7 +318,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
       if s.owner == c.owner and s.kind == skParam:
         incl(s.flags, sfUsed)
         result = newSymNode(s, n.info)
-        styleCheckUse(n.info, s)
+        onUse(n.info, s)
       elif contains(c.toBind, s.id):
         result = symChoice(c.c, n, s, scClosed)
       elif contains(c.toMixin, s.name.id):
@@ -324,7 +328,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
         # var yz: T
         incl(s.flags, sfUsed)
         result = newSymNode(s, n.info)
-        styleCheckUse(n.info, s)
+        onUse(n.info, s)
       else:
         result = semTemplSymbol(c.c, n, s)
   of nkBind:
@@ -382,6 +386,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
         let s = newGenSym(skLabel, n.sons[0], c)
         addPrelimDecl(c.c, s)
         styleCheckDef(c.c.config, s)
+        onDef(n[0].info, s)
         n.sons[0] = newSymNode(s, n.sons[0].info)
     n.sons[1] = semTemplBody(c, n.sons[1])
     closeScope(c)
@@ -505,7 +510,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
       if s.owner == c.owner and s.kind == skParam and
           n.kind == nkAccQuoted and n.len == 1:
         incl(s.flags, sfUsed)
-        styleCheckUse(n.info, s)
+        onUse(n.info, s)
         return newSymNode(s, n.info)
       elif contains(c.toBind, s.id):
         return symChoice(c.c, n, s, scClosed)
@@ -553,6 +558,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
   else:
     s = semIdentVis(c, skTemplate, n.sons[0], {})
   styleCheckDef(c.config, s)
+  onDef(n[0].info, s)
   # check parameter list:
   #s.scope = c.currentScope
   pushOwner(c, s)
@@ -635,7 +641,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
     # semtypes.addParamOrResult). Within the pattern we have to ensure
     # to use the param with the proper type though:
     incl(s.flags, sfUsed)
-    styleCheckUse(n.info, s)
+    onUse(n.info, s)
     let x = c.owner.typ.n.sons[s.position+1].sym
     assert x.name == s.name
     result = newSymNode(x, n.info)
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 5215a1d11..f4a1b0302 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -122,6 +122,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
       if not isPure: strTableAdd(c.module.tab, e)
     addSon(result.n, newSymNode(e))
     styleCheckDef(c.config, e)
+    onDef(e.info, e)
     if sfGenSym notin e.flags:
       if not isPure: addDecl(c, e)
       else: importPureEnumField(c, e)
@@ -377,7 +378,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
       result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
     if result != nil:
       markUsed(c.config, n.info, result, c.graph.usageSym)
-      styleCheckUse(n.info, result)
+      onUse(n.info, result)
 
       if result.kind == skParam and result.typ.kind == tyTypeDesc:
         # This is a typedesc param. is it already bound?
@@ -466,6 +467,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
         addSon(result.n, newSymNode(field))
         addSonSkipIntLit(result, typ)
       styleCheckDef(c.config, a.sons[j].info, field)
+      onDef(field.info, field)
   if result.n.len == 0: result.n = nil
 
 proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
@@ -688,7 +690,6 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
                      else: rectype.sym
     for i in countup(0, sonsLen(n)-3):
       var f = semIdentWithPragma(c, skField, n.sons[i], {sfExported})
-      styleCheckDef(c.config, n.sons[i].info, f)
       suggestSym(c.config, n.sons[i].info, f, c.graph.usageSym)
       f.typ = typ
       f.position = pos
@@ -703,6 +704,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
       if a.kind == nkEmpty: addSon(father, newSymNode(f))
       else: addSon(a, newSymNode(f))
       styleCheckDef(c.config, f)
+      onDef(f.info, f)
     if a.kind != nkEmpty: addSon(father, a)
   of nkSym:
     # This branch only valid during generic object
@@ -988,7 +990,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
 
   of tyGenericParam:
     markUsed(c.config, info, paramType.sym, c.graph.usageSym)
-    styleCheckUse(info, paramType.sym)
+    onUse(info, paramType.sym)
     if tfWildcard in paramType.flags:
       paramType.flags.excl tfWildcard
       paramType.sym.kind = skType
@@ -1110,6 +1112,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
       rawAddSon(result, finalType)
       addParamOrResult(c, arg, kind)
       styleCheckDef(c.config, a.sons[j].info, arg)
+      onDef(a[j].info, arg)
 
   var r: PType
   if n.sons[0].kind != nkEmpty:
@@ -1621,8 +1624,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
         result = prev
   of nkSym:
     let s = getGenSym(c, n.sym)
-    if s.kind == skType and s.typ != nil or
-      s.kind == skParam and s.typ.kind == tyTypeDesc:
+    if s.typ != nil and (s.kind == skType or s.typ.kind == tyTypeDesc):
       var t =
         if s.kind == skType:
           s.typ
@@ -1638,7 +1640,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
         assignType(prev, t)
         result = prev
       markUsed(c.config, n.info, n.sym, c.graph.usageSym)
-      styleCheckUse(n.info, n.sym)
+      onUse(n.info, n.sym)
     else:
       if s.kind != skError: localError(c.config, n.info, errTypeExpected)
       result = newOrPrevType(tyError, prev, c)
@@ -1745,10 +1747,8 @@ proc processMagicType(c: PContext, m: PSym) =
       setMagicType(c.config, m, tyAnything, 0)
     else:
       setMagicType(c.config, m, tyExpr, 0)
-      if m.name.s == "expr": m.typ.flags.incl tfOldSchoolExprStmt
   of mStmt:
     setMagicType(c.config, m, tyStmt, 0)
-    if m.name.s == "stmt": m.typ.flags.incl tfOldSchoolExprStmt
   of mTypeDesc, mType:
     setMagicType(c.config, m, tyTypeDesc, 0)
     rawAddSon(m.typ, newTypeS(tyNone, c))
diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim
index be6ffc586..b05fb37ae 100644
--- a/compiler/semtypinst.nim
+++ b/compiler/semtypinst.nim
@@ -30,11 +30,6 @@ proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) =
     localError(conf, info, "type 'var var' is not allowed")
   elif computeSize(conf, t) == szIllegalRecursion:
     localError(conf, info,  "illegal recursion in type '" & typeToString(t) & "'")
-
-  t = typ.skipTypes({tyGenericInst})
-  if t.kind == tyArray and tfUncheckedArray in t.flags:
-    t[0].flags.incl tfUncheckedArray # mark range of unchecked array also unchecked
-
   when false:
     if t.kind == tyObject and t.sons[0] != nil:
       if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 4dc7690ef..4adf0bed3 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -13,9 +13,9 @@
 import
   intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
   magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees,
-  linter, lineinfos
+  linter, lineinfos, lowerings, modulegraphs
 
-when defined(booting) or defined(nimsuggest):
+when (defined(booting) or defined(nimsuggest)) and not defined(leanCompiler):
   import docgen
 
 type
@@ -1210,9 +1210,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
     if f.kind == tyVarargs:
       if tfVarargs in a.flags:
         return typeRel(c, f.base, a.lastSon)
-      if tfOldSchoolExprStmt in f.sons[0].flags:
-        if f.sons[0].kind == tyExpr: return
-      elif f.sons[0].kind == tyStmt: return
+      if f.sons[0].kind == tyStmt: return
 
     template matchArrayOrSeq(aBase: PType) =
       let ff = f.base
@@ -1758,7 +1756,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
         result = isNone
 
   of tyStmt:
-    if aOrig != nil and tfOldSchoolExprStmt notin f.flags:
+    if aOrig != nil:
       put(c, f, aOrig)
     result = isGeneric
 
@@ -1857,8 +1855,14 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
       else:
         param = copyTree(arg)
       addSon(result, param)
+
+      if dest.kind in {tyVar, tyLent}:
+        dest.flags.incl tfVarIsPtr
+        result = newDeref(result)
+
       inc(m.convMatches)
-      m.genericConverter = srca == isGeneric or destIsGeneric
+      if m.genericConverter == false:
+        m.genericConverter = srca == isGeneric or destIsGeneric
       return result
 
 proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
@@ -2151,7 +2155,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
     else:
       # only one valid interpretation found:
       markUsed(m.c.config, arg.info, arg.sons[best].sym, m.c.graph.usageSym)
-      styleCheckUse(arg.info, arg.sons[best].sym)
+      onUse(arg.info, arg.sons[best].sym)
       result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
                                   argOrig)
   when false:
@@ -2215,8 +2219,7 @@ proc incrIndexType(t: PType) =
   inc t.sons[0].n.sons[1].intVal
 
 template isVarargsUntyped(x): untyped =
-  x.kind == tyVarargs and x.sons[0].kind == tyExpr and
-    tfOldSchoolExprStmt notin x.sons[0].flags
+  x.kind == tyVarargs and x.sons[0].kind == tyExpr
 
 proc matchesAux(c: PContext, n, nOrig: PNode,
                 m: var TCandidate, marker: var IntSet) =
diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim
index 573b27094..4791788fa 100644
--- a/compiler/sizealignoffsetimpl.nim
+++ b/compiler/sizealignoffsetimpl.nim
@@ -1,3 +1,12 @@
+#
+#
+#           The Nim Compiler
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+## code owner: Arne Döring
+## e-mail: arne.doering@gmx.net
 
 proc align(address, alignment: BiggestInt): BiggestInt =
   result = (address + (alignment - 1)) and not (alignment - 1)
@@ -118,9 +127,14 @@ proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, initialOffset:
       result.offset = align(offset, result.align)
 
   of nkSym:
-    computeSizeAlign(conf, n.sym.typ)
-    let size = n.sym.typ.size
-    let align = n.sym.typ.align
+    var size = szUnknownSize
+    var align = szUnknownSize
+
+    if n.sym.bitsize == 0: # 0 represents bitsize not set
+      computeSizeAlign(conf, n.sym.typ)
+      size = n.sym.typ.size.int
+      align = n.sym.typ.align.int
+
     result.align = align
     if initialOffset == szUnknownSize or size == szUnknownSize:
       n.sym.offset = szUnknownSize
@@ -309,16 +323,24 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
     var headerAlign: int16
     if typ.sons[0] != nil:
       # compute header size
-      var st = typ.sons[0]
-      while st.kind in skipPtrs:
-        st = st.sons[^1]
-      computeSizeAlign(conf, st)
-      if st.size == szIllegalRecursion:
-        typ.size = st.size
-        typ.align = st.align
-        return
-      headerSize = st.size
-      headerAlign = st.align
+
+      if conf.cmd == cmdCompileToCpp:
+        # if the target is C++ the members of this type are written
+        # into the padding byets at the end of the parent type. At the
+        # moment it is not supported to calculate that.
+        headerSize = szUnknownSize
+        headerAlign = szUncomputedSize
+      else:
+        var st = typ.sons[0]
+        while st.kind in skipPtrs:
+          st = st.sons[^1]
+        computeSizeAlign(conf, st)
+        if st.size == szIllegalRecursion:
+          typ.size = st.size
+          typ.align = st.align
+          return
+        headerSize = st.size
+        headerAlign = st.align
     elif isObjectWithTypeFieldPredicate(typ):
       # this branch is taken for RootObj
       headerSize = conf.target.intSize
diff --git a/compiler/suggest.nim b/compiler/suggest.nim
index b264415d8..dfa6e5ddb 100644
--- a/compiler/suggest.nim
+++ b/compiler/suggest.nim
@@ -115,7 +115,7 @@ proc symToSuggest(conf: ConfigRef; s: PSym, isLocal: bool, section: IdeCmd, info
       result.forth = typeToString(s.typ)
     else:
       result.forth = ""
-    when defined(nimsuggest) and not defined(noDocgen):
+    when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
       result.doc = s.extractDocComment
   let infox = if section in {ideUse, ideHighlight, ideOutline}: info else: s.info
   result.filePath = toFullPath(conf, infox)
@@ -153,7 +153,7 @@ proc `$`*(suggest: Suggest): string =
     result.add(sep)
     result.add($suggest.column)
     result.add(sep)
-    when defined(nimsuggest) and not defined(noDocgen):
+    when defined(nimsuggest) and not defined(noDocgen) and not defined(leanCompiler):
       result.add(suggest.doc.escape)
     if suggest.version == 0:
       result.add(sep)
diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim
index decdf1715..60246b9bf 100644
--- a/compiler/syntaxes.nim
+++ b/compiler/syntaxes.nim
@@ -17,10 +17,10 @@ type
   TFilterKind* = enum
     filtNone, filtTemplate, filtReplace, filtStrip
   TParserKind* = enum
-    skinStandard, skinStrongSpaces, skinEndX
+    skinStandard, skinEndX
 
 const
-  parserNames*: array[TParserKind, string] = ["standard", "strongspaces",
+  parserNames*: array[TParserKind, string] = ["standard",
                                               "endx"]
   filterNames*: array[TFilterKind, string] = ["none", "stdtmpl", "replace",
                                               "strip"]
@@ -34,14 +34,14 @@ template config(p: TParsers): ConfigRef = p.parser.lex.config
 
 proc parseAll*(p: var TParsers): PNode =
   case p.skin
-  of skinStandard, skinStrongSpaces:
+  of skinStandard:
     result = parser.parseAll(p.parser)
   of skinEndX:
     internalError(p.config, "parser to implement")
 
 proc parseTopLevelStmt*(p: var TParsers): PNode =
   case p.skin
-  of skinStandard, skinStrongSpaces:
+  of skinStandard:
     result = parser.parseTopLevelStmt(p.parser)
   of skinEndX:
     internalError(p.config, "parser to implement")
@@ -153,21 +153,23 @@ proc openParsers*(p: var TParsers, fileIdx: FileIndex, inputstream: PLLStream;
   else: s = inputstream
   case p.skin
   of skinStandard, skinEndX:
-    parser.openParser(p.parser, fileIdx, s, cache, config, false)
-  of skinStrongSpaces:
-    parser.openParser(p.parser, fileIdx, s, cache, config, true)
+    parser.openParser(p.parser, fileIdx, s, cache, config)
 
 proc closeParsers*(p: var TParsers) =
   parser.closeParser(p.parser)
 
-proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode {.procvar.} =
-  var
-    p: TParsers
-    f: File
+proc setupParsers*(p: var TParsers; fileIdx: FileIndex; cache: IdentCache;
+                   config: ConfigRef): bool =
+  var f: File
   let filename = toFullPathConsiderDirty(config, fileIdx)
   if not open(f, filename.string):
     rawMessage(config, errGenerated, "cannot open file: " & filename.string)
-    return
+    return false
   openParsers(p, fileIdx, llStreamOpen(f), cache, config)
-  result = parseAll(p)
-  closeParsers(p)
+  result = true
+
+proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode {.procvar.} =
+  var p: TParsers
+  if setupParsers(p, fileIdx, cache, config):
+    result = parseAll(p)
+    closeParsers(p)
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 800d56b3a..7b2979dea 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -24,7 +24,8 @@ import
   sempass2, lowerings, destroyer, liftlocals,
   modulegraphs, lineinfos
 
-proc transformBody*(g: ModuleGraph, prc: PSym, cache = true): PNode
+proc transformBody*(g: ModuleGraph, prc: PSym, cache = true;
+                    noDestructors = false): PNode
 
 import closureiters, lambdalifting
 
@@ -48,7 +49,7 @@ type
     inlining: int            # > 0 if we are in inlining context (copy vars)
     nestedProcs: int         # > 0 if we are in a nested proc
     contSyms, breakSyms: seq[PSym]  # to transform 'continue' and 'break'
-    deferDetected, tooEarly, needsDestroyPass: bool
+    deferDetected, tooEarly, needsDestroyPass, noDestructors: bool
     graph: ModuleGraph
   PTransf = ref TTransfContext
 
@@ -130,7 +131,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
   let s = n.sym
   if s.typ != nil and s.typ.callConv == ccClosure:
     if s.kind in routineKinds:
-      discard transformBody(c.graph, s)
+      discard transformBody(c.graph, s, true, c.noDestructors)
     if s.kind == skIterator:
       if c.tooEarly: return n
       else: return liftIterSym(c.graph, n, getCurrOwner(c))
@@ -159,7 +160,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
       return
     tc = tc.next
   result = b
-  
+
 proc transformSym(c: PTransf, n: PNode): PTransNode =
   result = PTransNode(transformSymAux(c, n))
 
@@ -243,7 +244,7 @@ proc newLabel(c: PTransf, n: PNode): PSym =
   result.name = getIdent(c.graph.cache, genPrefix & $result.id)
 
 proc transformBlock(c: PTransf, n: PNode): PTransNode =
-  var labl: PSym 
+  var labl: PSym
   if c.inlining > 0:
     labl = newLabel(c, n[0])
     idNodeTablePut(c.transCon.mapping, n[0].sym, newSymNode(labl))
@@ -611,7 +612,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
       add(stmtList, newAsgnStmt(c, nkFastAsgn, temp, arg.PTransNode))
       idNodeTablePut(newC.mapping, formal, temp)
 
-  let body = transformBody(c.graph, iter)
+  let body = transformBody(c.graph, iter, true, c.noDestructors)
   pushInfoContext(c.graph.config, n.info)
   inc(c.inlining)
   add(stmtList, transform(c, body))
@@ -1029,7 +1030,8 @@ template liftDefer(c, root) =
   if c.deferDetected:
     liftDeferAux(root)
 
-proc transformBody*(g: ModuleGraph, prc: PSym, cache = true): PNode =
+proc transformBody*(g: ModuleGraph, prc: PSym, cache = true;
+                    noDestructors = false): PNode =
   assert prc.kind in routineKinds
 
   if prc.transformedBody != nil:
@@ -1037,22 +1039,22 @@ proc transformBody*(g: ModuleGraph, prc: PSym, cache = true): PNode =
   elif nfTransf in prc.ast[bodyPos].flags or prc.kind in {skTemplate}:
     result = prc.ast[bodyPos]
   else:
-
     prc.transformedBody = newNode(nkEmpty) # protects from recursion
     var c = openTransf(g, prc.getModule, "")
+    c.noDestructors = noDestructors
     result = liftLambdas(g, prc, prc.ast[bodyPos], c.tooEarly)
     result = processTransf(c, result, prc)
     liftDefer(c, result)
     result = liftLocalsIfRequested(prc, result, g.cache, g.config)
-    if c.needsDestroyPass: #and newDestructors:
+    if c.needsDestroyPass and not noDestructors:
       result = injectDestructorCalls(g, prc, result)
 
     if prc.isIterator:
       result = g.transformClosureIterator(prc, result)
-  
+
     incl(result.flags, nfTransf)
 
-    let cache = cache or prc.typ.callConv == ccInline 
+    let cache = cache or prc.typ.callConv == ccInline
     if cache:
       # genProc for inline procs will be called multiple times from diffrent modules,
       # it is important to transform exactly once to get sym ids and locations right
@@ -1072,7 +1074,8 @@ proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
       result = injectDestructorCalls(g, module, result)
     incl(result.flags, nfTransf)
 
-proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode =
+proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode;
+                    noDestructors = false): PNode =
   if nfTransf in n.flags:
     result = n
   else:
@@ -1081,6 +1084,6 @@ proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode =
     liftDefer(c, result)
     # expressions are not to be injected with destructor calls as that
     # the list of top level statements needs to be collected before.
-    if c.needsDestroyPass:
+    if c.needsDestroyPass and not noDestructors:
       result = injectDestructorCalls(g, module, result)
     incl(result.flags, nfTransf)
diff --git a/compiler/types.nim b/compiler/types.nim
index 5b14015c1..b163ca4e9 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -1086,8 +1086,8 @@ proc inheritanceDiff*(a, b: PType): int =
   # | returns: +x iff `a` is the x'th direct subclass of `b`
   # | returns: `maxint` iff `a` and `b` are not compatible at all
   if a == b or a.kind == tyError or b.kind == tyError: return 0
-  assert a.kind == tyObject
-  assert b.kind == tyObject
+  assert a.kind in {tyObject} + skipPtrs
+  assert b.kind in {tyObject} + skipPtrs
   var x = a
   result = 0
   while x != nil:
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 05ee3b90e..7e7ec8903 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -503,7 +503,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcAsgnFloat64FromInt:
       let rb = instr.regB
       ensureKind(rkFloat)
-      regs[ra].floatVal = cast[float64](int64(regs[rb].intVal))      
+      regs[ra].floatVal = cast[float64](int64(regs[rb].intVal))
     of opcAsgnComplex:
       asgnComplex(regs[ra], regs[instr.regB])
     of opcAsgnRef:
@@ -945,10 +945,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       let a = regs[rb].node
       if a.kind == nkSym:
         regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit)
-                        else: 
+                        else:
                           let ast = a.sym.ast.shallowCopy
                           for i in 0..<a.sym.ast.len:
-                            ast[i] = a.sym.ast[i]                        
+                            ast[i] = a.sym.ast[i]
                           ast[bodyPos] = transformBody(c.graph, a.sym)
                           ast.copyTree()
     of opcSymOwner:
@@ -960,6 +960,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
         regs[ra].node.flags.incl nfIsRef
       else:
         stackTrace(c, tos, pc, "node is not a symbol")
+    of opcSymIsInstantiationOf:
+      decodeBC(rkInt)
+      let a = regs[rb].node
+      let b = regs[rc].node
+      if a.kind == nkSym and a.sym.kind in skProcKinds and 
+         b.kind == nkSym and b.sym.kind in skProcKinds:
+        regs[ra].intVal =
+          if sfFromGeneric in a.sym.flags and a.sym.owner == b.sym: 1
+          else: 0
+      else:    
+        stackTrace(c, tos, pc, "node is not a proc symbol") 
     of opcEcho:
       let rb = instr.regB
       if rb == 1:
@@ -1228,7 +1239,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcOf:
       decodeBC(rkInt)
       let typ = c.types[regs[rc].intVal.int]
-      regs[ra].intVal = ord(inheritanceDiff(regs[rb].node.typ, typ) >= 0)
+      regs[ra].intVal = ord(inheritanceDiff(regs[rb].node.typ, typ) <= 0)
     of opcIs:
       decodeBC(rkInt)
       let t1 = regs[rb].node.typ.skipTypes({tyTypeDesc})
@@ -1822,7 +1833,7 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
       "NimScript: attempt to call non-routine: " & sym.name.s)
 
 proc evalStmt*(c: PCtx, n: PNode) =
-  let n = transformExpr(c.graph, c.module, n)
+  let n = transformExpr(c.graph, c.module, n, noDestructors = true)
   let start = genStmt(c, n)
   # execute new instructions; this redundant opcEof check saves us lots
   # of allocations in 'execute':
@@ -1830,7 +1841,7 @@ proc evalStmt*(c: PCtx, n: PNode) =
     discard execute(c, start)
 
 proc evalExpr*(c: PCtx, n: PNode): PNode =
-  let n = transformExpr(c.graph, c.module, n)
+  let n = transformExpr(c.graph, c.module, n, noDestructors = true)
   let start = genExpr(c, n)
   assert c.code[start].opcode != opcEof
   result = execute(c, start)
@@ -1877,7 +1888,7 @@ const evalPass* = makePass(myOpen, myProcess, myClose)
 proc evalConstExprAux(module: PSym;
                       g: ModuleGraph; prc: PSym, n: PNode,
                       mode: TEvalMode): PNode =
-  let n = transformExpr(g, module, n)
+  let n = transformExpr(g, module, n, noDestructors = true)
   setupGlobalCtx(module, g)
   var c = PCtx g.vm
   let oldMode = c.mode
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index 25ace3cdd..493078f74 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -147,7 +147,8 @@ type
     opcTypeTrait,
     opcMarshalLoad, opcMarshalStore,
     opcToNarrowInt,
-    opcSymOwner
+    opcSymOwner,
+    opcSymIsInstantiationOf
 
   TBlock* = object
     label*: PSym
diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim
index 8aac5fb87..f160a3096 100644
--- a/compiler/vmdeps.nim
+++ b/compiler/vmdeps.nim
@@ -157,7 +157,10 @@ proc mapTypeToAstX(cache: IdentCache; t: PType; info: TLineInfo;
   of tyObject:
     if inst:
       result = newNodeX(nkObjectTy)
-      result.add t.sym.ast[2][0].copyTree  # copy object pragmas
+      if t.sym.ast != nil:
+        result.add t.sym.ast[2][0].copyTree  # copy object pragmas
+      else:
+        result.add newNodeI(nkEmpty, info)
       if t.sons[0] == nil:
         result.add newNodeI(nkEmpty, info)
       else:  # handle parent object
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index ea0fb35ff..e52f460d2 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -182,7 +182,10 @@ const
   HighRegisterPressure = 40
 
 proc bestEffort(c: PCtx): TLineInfo =
-  (if c.prc == nil: c.module.info else: c.prc.sym.info)
+  if c.prc != nil and c.prc.sym != nil:
+    c.prc.sym.info
+  else:
+    c.module.info
 
 proc getTemp(cc: PCtx; tt: PType): TRegister =
   let typ = tt.skipTypesOrNil({tyStatic})
@@ -776,7 +779,7 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
   let src = n.sons[1].typ.skipTypes(abstractRange)#.kind
   let dst = n.sons[0].typ.skipTypes(abstractRange)#.kind
   let src_size = getSize(c.config, src)
-  let dst_size = getSize(c.config, dst) 
+  let dst_size = getSize(c.config, dst)
   if c.config.target.intSize < 8:
     signedIntegers.incl(tyInt)
     unsignedIntegers.incl(tyUInt)
@@ -820,7 +823,7 @@ proc genCastIntFloat(c: PCtx; n: PNode; dest: var TDest) =
     c.freeTemp(tmp)
 
   elif src_size == dst_size and src.kind in {tyFloat, tyFloat32, tyFloat64} and
-                           dst.kind in allowedIntegers:         
+                           dst.kind in allowedIntegers:
     let tmp = c.genx(n[1])
     if dest < 0: dest = c.getTemp(n[0].typ)
     if src.kind == tyFloat32:
@@ -1095,7 +1098,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
     var tmp = c.genx(n.sons[1])
     var idx = c.getTemp(getSysType(c.graph, n.info, tyInt))
     var typ = n.sons[2].typ
-    if m == mOf: typ = typ.skipTypes(abstractPtrs-{tyTypeDesc})
+    if m == mOf: typ = typ.skipTypes(abstractPtrs)
     c.gABx(n, opcLdImmInt, idx, c.genType(typ))
     c.gABC(n, if m == mOf: opcOf else: opcIs, dest, tmp, idx)
     c.freeTemp(tmp)
@@ -1112,13 +1115,14 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mEcho:
     unused(c, n, dest)
     let n = n[1].skipConv
-    let x = c.getTempRange(n.len, slotTempUnknown)
-    internalAssert c.config, n.kind == nkBracket
-    for i in 0..<n.len:
-      var r: TRegister = x+i
-      c.gen(n.sons[i], r)
-    c.gABC(n, opcEcho, x, n.len)
-    c.freeTempRange(x, n.len)
+    if n.kind == nkBracket:
+      # can happen for nim check, see bug #9609
+      let x = c.getTempRange(n.len, slotTempUnknown)
+      for i in 0..<n.len:
+        var r: TRegister = x+i
+        c.gen(n.sons[i], r)
+      c.gABC(n, opcEcho, x, n.len)
+      c.freeTempRange(x, n.len)
   of mAppendStrCh:
     unused(c, n, dest)
     genBinaryStmtVar(c, n, opcAddStrCh)
@@ -1144,6 +1148,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mGetImpl: genUnaryABC(c, n, dest, opcGetImpl)
   of mGetImplTransf: genUnaryABC(c, n, dest, opcGetImplTransf)
   of mSymOwner: genUnaryABC(c, n, dest, opcSymOwner)
+  of mSymIsInstantiationOf: genBinaryABC(c, n, dest, opcSymIsInstantiationOf)
   of mNChild: genBinaryABC(c, n, dest, opcNChild)
   of mNSetChild: genVoidABC(c, n, dest, opcNSetChild)
   of mNDel: genVoidABC(c, n, dest, opcNDel)
@@ -2150,7 +2155,8 @@ proc genProc(c: PCtx; s: PSym): int =
     s.ast.sons[miscPos] = x
     # thanks to the jmp we can add top level statements easily and also nest
     # procs easily:
-    let body = transformBody(c.graph, s, cache = not isCompileTimeProc(s))
+    let body = transformBody(c.graph, s, cache = not isCompileTimeProc(s),
+                             noDestructors = true)
     let procStart = c.xjmp(body, opcJmp, 0)
     var p = PProc(blocks: @[], sym: s)
     let oldPrc = c.prc
diff --git a/compiler/vmops.nim b/compiler/vmops.nim
index 83e65279a..f87ab4508 100644
--- a/compiler/vmops.nim
+++ b/compiler/vmops.nim
@@ -11,7 +11,7 @@
 #import vmdeps, vm
 from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
   arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc,
-  floor, ceil, fmod
+  floor, ceil, `mod`, fmod
 
 from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir
 
@@ -21,9 +21,6 @@ template mathop(op) {.dirty.} =
 template osop(op) {.dirty.} =
   registerCallback(c, "stdlib.os." & astToStr(op), `op Wrapper`)
 
-template ospathsop(op) {.dirty.} =
-  registerCallback(c, "stdlib.ospaths." & astToStr(op), `op Wrapper`)
-
 template systemop(op) {.dirty.} =
   registerCallback(c, "stdlib.system." & astToStr(op), `op Wrapper`)
 
@@ -107,10 +104,14 @@ proc registerAdditionalOps*(c: PCtx) =
   wrap1f_math(ceil)
   wrap2f_math(fmod)
 
+  proc `mod Wrapper`(a: VmArgs) {.nimcall.} =
+    setResult(a, `mod`(getFloat(a, 0), getFloat(a, 1)))
+  registerCallback(c, "stdlib.math.mod", `mod Wrapper`)
+
   when defined(nimcore):
-    wrap2s(getEnv, ospathsop)
-    wrap1s(existsEnv, ospathsop)
-    wrap2svoid(putEnv, ospathsop)
+    wrap2s(getEnv, osop)
+    wrap1s(existsEnv, osop)
+    wrap2svoid(putEnv, osop)
     wrap1s(dirExists, osop)
     wrap1s(fileExists, osop)
     wrap2svoid(writeFile, systemop)
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index 800b5dc18..41bdc9fcb 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -69,13 +69,13 @@ type
     wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wLocks,
     wPartial, wExplain, wLiftLocals,
 
-    wAuto, wBool, wCatch, wChar, wClass,
+    wAuto, wBool, wCatch, wChar, wClass, wCompl
     wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast,
     wExplicit, wExtern, wFalse, wFloat, wFriend,
     wGoto, wInt, wLong, wMutable, wNamespace, wNew, wOperator,
-    wPrivate, wProtected, wPublic, wRegister, wReinterpret_cast,
+    wPrivate, wProtected, wPublic, wRegister, wReinterpret_cast, wRestrict,
     wShort, wSigned, wSizeof, wStatic_cast, wStruct, wSwitch,
-    wThis, wThrow, wTrue, wTypedef, wTypeid, wTypename,
+    wThis, wThrow, wTrue, wTypedef, wTypeid, wTypeof, wTypename,
     wUnion, wPacked, wUnsigned, wVirtual, wVoid, wVolatile, wWchar_t,
 
     wAlignas, wAlignof, wConstexpr, wDecltype, wNullptr, wNoexcept,
@@ -156,14 +156,14 @@ const
     "asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked",
     "guard", "locks", "partial", "explain", "liftlocals",
 
-    "auto", "bool", "catch", "char", "class",
+    "auto", "bool", "catch", "char", "class", "compl",
     "const_cast", "default", "delete", "double",
     "dynamic_cast", "explicit", "extern", "false",
     "float", "friend", "goto", "int", "long", "mutable",
     "namespace", "new", "operator",
-    "private", "protected", "public", "register", "reinterpret_cast",
+    "private", "protected", "public", "register", "reinterpret_cast", "restrict",
     "short", "signed", "sizeof", "static_cast", "struct", "switch",
-    "this", "throw", "true", "typedef", "typeid",
+    "this", "throw", "true", "typedef", "typeid", "typeof",
     "typename", "union", "packed", "unsigned", "virtual", "void", "volatile",
     "wchar_t",
 
diff --git a/doc/advopt.txt b/doc/advopt.txt
index 252067129..7cd72f6c3 100644
--- a/doc/advopt.txt
+++ b/doc/advopt.txt
@@ -29,6 +29,9 @@ Advanced options:
                             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
@@ -98,6 +101,7 @@ Advanced options:
   --listCmd                 list the commands used to execute external programs
   --parallelBuild:0|1|...   perform a parallel build
                             value = number of processors (0 for auto-detect)
+  --incremental:on|off      only recompile the changed modules (experimental!)
   --verbosity:0|1|2|3       set Nim's verbosity level (1 is default)
   --experimental:$1
                             enable experimental language feature
diff --git a/doc/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 84b15f419..a2c95db74 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
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..46e1f9d19 100644
--- a/doc/lib.rst
+++ b/doc/lib.rst
@@ -147,10 +147,13 @@ 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.
+
 
 Generic Operating System Services
 ---------------------------------
diff --git a/doc/manual.rst b/doc/manual.rst
index 98943619d..b39711dfb 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:
 
@@ -7897,36 +7928,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/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/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 8e84ac5fa..9a8d38a79 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,8 @@ template withDir(dir, body) =
   finally:
     setCurrentdir(old)
 
+setCurrentDir(getAppDir())
+
 proc tryExec(cmd: string): bool =
   echo(cmd)
   result = execShellCmd(cmd) == 0
@@ -112,10 +117,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 +147,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 +185,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 +197,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)
@@ -545,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/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 a146117d0..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
diff --git a/lib/core/seqs.nim b/lib/core/seqs.nim
index 4dcf6cbbb..fb81a30de 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
@@ -123,7 +125,7 @@ proc grow*[T](x: var seq[T]; newLen: Natural; value: T) =
   if newLen <= oldLen: return
   var xu = cast[ptr NimSeqV2[T]](addr x)
 
-  xu.p = prepareSeqAdd(oldLen, xu.p, newLen - oldLen, sizeof(T))
+  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
diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim
index c78752360..14613c50d 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:
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 39d77230a..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.
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 34881607f..f78df0b2b 100644
--- a/lib/deprecated/pure/sockets.nim
+++ b/lib/deprecated/pure/sockets.nim
@@ -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:
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 985913a88..58594f054 100644
--- a/lib/impure/nre.nim
+++ b/lib/impure/nre.nim
@@ -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:
@@ -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
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/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..0c66aa2b9 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.} =
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 5ef791cfe..aef4f1ce6 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().}
 
@@ -199,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:
@@ -243,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.}
@@ -1079,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.}
@@ -1640,7 +1638,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 965e70055..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``.
@@ -369,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/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..0b3708a7c 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
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 e8ea675f5..be10780ff 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -504,36 +504,76 @@ template anyIt*(s, pred: untyped): bool =
       break
   result
 
-template toSeq*(iter: untyped): untyped =
-  ## Transforms any iterator into a sequence.
-  ##
-  ## Example:
-  ##
-  ## .. code-block::
-  ##   let
-  ##     numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
-  ##     odd_numbers = toSeq(filter(numeric) do (x: int) -> bool:
-  ##       if x mod 2 == 1:
-  ##         result = true)
-  ##   assert odd_numbers == @[1, 3, 5, 7, 9]
-
-  # Note: see also `mapIt` for explanation of some of the implementation
-  # subtleties.
-  when compiles(iter.len):
+template toSeq1(s: not iterator): untyped =
+  # overload for typed but not iterator
+  type outType = type(items(s))
+  when compiles(s.len):
     block:
-      evalOnceAs(iter2, iter, true)
-      var result = newSeq[type(iter)](iter2.len)
+      evalOnceAs(s2, s, compiles((let _ = s)))
       var i = 0
-      for x in iter2:
-        result[i] = x
-        inc i
+      var result = newSeq[outType](s2.len)
+      for it in s2:
+        result[i] = it
+        i += 1
       result
   else:
-    var result: seq[type(iter)] = @[]
-    for x in iter:
-      result.add(x)
+    var result: seq[outType] = @[]
+    for it in s:
+      result.add(it)
+    result
+
+template toSeq2(iter: iterator): untyped =
+  # overload for iterator
+  evalOnceAs(iter2, iter(), false)
+  when compiles(iter2.len):
+    var i = 0
+    var result = newSeq[type(iter2)](iter2.len)
+    for x in iter2:
+      result[i] = x
+      inc i
+    result
+  else:
+    type outType = type(iter2())
+    var result: seq[outType] = @[]
+    when compiles(iter2()):
+      evalOnceAs(iter4, iter, false)
+      let iter3=iter4()
+      for x in iter3():
+        result.add(x)
+    else:
+      for x in iter2():
+        result.add(x)
     result
 
+template toSeq*(iter: untyped): untyped =
+  ## Transforms any iterable into a sequence.
+  runnableExamples:
+    let
+      numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
+      odd_numbers = toSeq(filter(numeric, proc(x: int): bool = x mod 2 == 1))
+    doAssert odd_numbers == @[1, 3, 5, 7, 9]
+
+  when compiles(toSeq1(iter)):
+    toSeq1(iter)
+  elif compiles(toSeq2(iter)):
+    toSeq2(iter)
+  else:
+    # overload for untyped, eg: `toSeq(myInlineIterator(3))`
+    when compiles(iter.len):
+      block:
+        evalOnceAs(iter2, iter, true)
+        var result = newSeq[type(iter)](iter2.len)
+        var i = 0
+        for x in iter2:
+          result[i] = x
+          inc i
+        result
+    else:
+      var result: seq[type(iter)] = @[]
+      for x in iter:
+        result.add(x)
+      result
+
 template foldl*(sequence, operation: untyped): untyped =
   ## Template to fold a sequence from left to right, returning the accumulation.
   ##
@@ -1033,12 +1073,72 @@ when isMainModule:
     assert anyIt(anumbers, it > 9) == false
 
   block: # toSeq test
-    let
-      numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
-      odd_numbers = toSeq(filter(numeric) do (x: int) -> bool:
-        if x mod 2 == 1:
-          result = true)
-    assert odd_numbers == @[1, 3, 5, 7, 9]
+    block:
+      let
+        numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
+        odd_numbers = toSeq(filter(numeric) do (x: int) -> bool:
+          if x mod 2 == 1:
+            result = true)
+      assert odd_numbers == @[1, 3, 5, 7, 9]
+
+    block:
+      doAssert [1,2].toSeq == @[1,2]
+      doAssert @[1,2].toSeq == @[1,2]
+
+      doAssert @[1,2].toSeq == @[1,2]
+      doAssert toSeq(@[1,2]) == @[1,2]
+
+    block:
+      iterator myIter(seed:int):auto=
+        for i in 0..<seed:
+          yield i
+      doAssert toSeq(myIter(2)) == @[0, 1]
+
+    block:
+      iterator myIter():auto{.inline.}=
+        yield 1
+        yield 2
+
+      doAssert myIter.toSeq == @[1,2]
+      doAssert toSeq(myIter) == @[1,2]
+
+    block:
+      iterator myIter():int {.closure.} =
+        yield 1
+        yield 2
+
+      doAssert myIter.toSeq == @[1,2]
+      doAssert toSeq(myIter) == @[1,2]
+
+    block:
+      proc myIter():auto=
+        iterator ret():int{.closure.}=
+          yield 1
+          yield 2
+        result = ret
+
+      doAssert myIter().toSeq == @[1,2]
+      doAssert toSeq(myIter()) == @[1,2]
+
+    block:
+      proc myIter(n:int):auto=
+        var counter = 0
+        iterator ret():int{.closure.}=
+          while counter<n:
+            yield counter
+            counter.inc
+        result = ret
+
+      block:
+        let myIter3 = myIter(3)
+        doAssert myIter3.toSeq == @[0,1,2]
+      block:
+        let myIter3 = myIter(3)
+        doAssert toSeq(myIter3) == @[0,1,2]
+      block:
+        # makes sure this does not hang forever
+        doAssert myIter(3).toSeq == @[0,1,2]
+        doAssert toSeq(myIter(3)) == @[0,1,2]
 
   block:
     # tests https://github.com/nim-lang/Nim/issues/7187
diff --git a/lib/pure/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/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/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 96f030c9b..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".}
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index dceac1763..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 =
@@ -1163,7 +1161,7 @@ proc requestAux(client: HttpClient | AsyncHttpClient, url: string,
                 {.multisync.} =
   # Helper that actually makes the request. Does not handle redirects.
   let requestUrl = parseUri(url)
-  
+
   if requestUrl.scheme == "":
     raise newException(ValueError, "No uri scheme supplied.")
 
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..72c3f4f49 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
diff --git a/lib/pure/math.nim b/lib/pure/math.nim
index e2ad626de..ee32772b1 100644
--- a/lib/pure/math.nim
+++ b/lib/pure/math.nim
@@ -479,7 +479,8 @@ when not defined(JS): # C
     ##  (-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.}
diff --git a/lib/pure/os.nim b/lib/pure/os.nim
index 9d74158fe..e2dd872e8 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 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>".}
+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"
 
-when defined(windows):
+  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 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:
@@ -920,7 +1599,7 @@ iterator walkDirRec*(dir: string, yieldFilter = {pcFile},
       if k in yieldFilter:
         yield p
 
-proc rawRemoveDir(dir: string) =
+proc rawRemoveDir(dir: string) {.noNimScript.} =
   when defined(windows):
     when useWinUnicode:
       wrapUnary(res, removeDirectoryW, dir)
@@ -934,7 +1613,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 +1625,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 +1670,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 +1683,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 +1706,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 +1724,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 +1747,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 +1855,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 +1879,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 +1910,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 +1919,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 +1934,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 +1997,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 +2030,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 +2074,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 +2107,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 +2116,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 +2160,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 +2220,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 +2235,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 +2251,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 +2331,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 +2352,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 +2391,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
   ##
@@ -1744,7 +2421,7 @@ proc isHidden*(path: string): bool =
 
 {.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 +2437,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 dfea4213d..ac455ce99 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):
@@ -1324,6 +1323,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:
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 4b841b9e1..20f02e815 100644
--- a/lib/pure/parsesql.nim
+++ b/lib/pure/parsesql.nim
@@ -566,9 +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
diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim
index 3909d18f8..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
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/strutils.nim b/lib/pure/strutils.nim
index e266275cf..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):
@@ -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..d103af710 100644
--- a/lib/pure/subexes.nim
+++ b/lib/pure/subexes.nim
@@ -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/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..fd1a6acc5 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -298,9 +298,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 +745,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 +839,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 +1051,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)
@@ -1144,16 +1145,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 +1386,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 +1400,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 +1541,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 +1804,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 +2017,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] != ':':
@@ -2508,4 +2499,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..664765954 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
@@ -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:
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/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 db1d3ca1e..e8b427c55 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.
@@ -2041,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
@@ -2056,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
@@ -2253,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.}
 
@@ -4019,6 +4017,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
@@ -4029,6 +4028,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
@@ -4039,8 +4040,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
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/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 778137668..a6da8f5a3 100644
--- a/lib/system/excpt.nim
+++ b/lib/system/excpt.nim
@@ -17,8 +17,15 @@ var
     ## instead of stdmsg.write when printing stacktrace.
     ## Unstable API.
 
+proc c_fwrite(buf: pointer, size, n: csize, f: File): cint {.
+  importc: "fwrite", header: "<stdio.h>".}
+
+proc rawWrite(f: File, s: string|cstring) =
+  # we cannot throw an exception here!
+  discard c_fwrite(cstring(s), 1, s.len, f)
+
 when not defined(windows) or not defined(guiapp):
-  proc writeToStdErr(msg: cstring) = write(stdmsg, msg)
+  proc writeToStdErr(msg: cstring) = rawWrite(stdmsg, msg)
 
 else:
   proc MessageBoxA(hWnd: cint, lpText, lpCaption: cstring, uType: int): int32 {.
diff --git a/lib/system/gc_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/mmdisp.nim b/lib/system/mmdisp.nim
index 9a7af0a28..683e84f7d 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:
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/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 73c222790..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
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 60050d8ae..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">
diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html
index 83de0d894..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">
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/tests/exhaustive.nim b/nimpretty/tests/exhaustive.nim
index 9202de703..9a0f9a49b 100644
--- a/nimpretty/tests/exhaustive.nim
+++ b/nimpretty/tests/exhaustive.nim
@@ -357,3 +357,6 @@ proc fun3() =
 ##[
 foobar
 ]##
+
+# bug #9673
+discard `* `(1, 2)
diff --git a/nimpretty/tests/expected/exhaustive.nim b/nimpretty/tests/expected/exhaustive.nim
index 6d000d524..8ea7ca4dd 100644
--- a/nimpretty/tests/expected/exhaustive.nim
+++ b/nimpretty/tests/expected/exhaustive.nim
@@ -366,3 +366,6 @@ proc fun3() =
 ##[
 foobar
 ]##
+
+# bug #9673
+discard `*`(1, 2)
diff --git a/nimsuggest/nimsuggest.nim b/nimsuggest/nimsuggest.nim
index 34b1cc4f7..89b5bf4ed 100644
--- a/nimsuggest/nimsuggest.nim
+++ b/nimsuggest/nimsuggest.nim
@@ -186,7 +186,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 +195,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:
@@ -613,4 +614,103 @@ 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)
+    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)
+      execute(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/testament/categories.nim b/testament/categories.nim
index 36f2a271a..e1f173c26 100644
--- a/testament/categories.nim
+++ b/testament/categories.nim
@@ -97,11 +97,10 @@ proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) =
     else:
       ""
 
-  testSpec c, makeTest("lib/nimrtl.nim",
-    options & " --app:lib -d:createNimRtl --threads:on", cat)
-  testSpec c, makeTest("tests/dll/server.nim",
-    options & " --app:lib -d:useNimRtl --threads:on" & rpath, cat)
-
+  testNoSpec c, makeTest("lib/nimrtl.nim",
+    options & " --app:lib -d:createNimRtl --threads:on", cat, actionCompile)
+  testNoSpec c, makeTest("tests/dll/server.nim",
+    options & " --app:lib -d:useNimRtl --threads:on" & rpath, cat, actionCompile)
 
   when defined(Windows):
     # windows looks in the dir of the exe (yay!):
@@ -298,25 +297,24 @@ proc testNimInAction(r: var TResults, cat: Category, options: string) =
   # whoever edits these hashes without dom96's permission, j/k. But please only
   # edit when making a conscious breaking change, also please try to make your
   # commit message clear and notify me so I can easily compile an errata later.
-  var testHashes: seq[string] = @[]
-
-  for test in tests:
-    testHashes.add(getMD5(readFile("tests" / test.addFileExt("nim")).string))
-
   const refHashes = @[
     "51afdfa84b3ca3d810809d6c4e5037ba", "30f07e4cd5eaec981f67868d4e91cfcf",
     "d14e7c032de36d219c9548066a97e846", "2e40bfd5daadb268268727da91bb4e81",
     "c5d3853ed0aba04bf6d35ba28a98dca0", "058603145ff92d46c009006b06e5b228",
     "7b94a029b94ddb7efafddd546c965ff6", "586d74514394e49f2370dfc01dd9e830",
-    "e1901837b757c9357dc8d259fd0ef0f6", "097670c7ae12e825debaf8ec3995227b",
-    "a8cb7b78cc78d28535ab467361db5d6e", "bfaec2816a1848991b530c1ad17a0184",
-    "47cb71bb4c1198d6d29cdbee05aa10b9", "87e4436809f9d73324cfc4f57f116770",
-    "7b7db5cddc8cf8fa9b6776eef1d0a31d", "e6e40219f0f2b877869b738737b7685e",
-    "6532ee87d819f2605a443d5e94f9422a", "9a8fe78c588d08018843b64b57409a02",
-    "03a801275b8b76b4170c870cd0da079d", "20bb7d3e2d38d43b0cb5fcff4909a4a8",
-    "af6844598f534fab6942abfa4dfe9ab2", "2a7a17f84f6503d9bc89a5ab8feea127"
+    "13febc363ed82585f2a60de40ddfefda", "c11a013db35e798f44077bc0763cc86d",
+    "3e32e2c5e9a24bd13375e1cd0467079c", "0b9fe7ba159623d49ae60db18a15037c",
+    "b2dd5293d7f784824bbf9792c6fb51ad", "4c19d8d9026bfe151b31d7007fa3c237",
+    "9415c6a568cfceed08da8378e95b5cd5", "da520038c153f4054cb8cc5faa617714",
+    "e6c6e061b6f77b2475db6fec7abfb7f4", "9a8fe78c588d08018843b64b57409a02",
+    "8b5d28e985c0542163927d253a3e4fc9", "783299b98179cc725f9c46b5e3b5381f",
+    "bc523f9a9921299090bac1af6c958e73", "80f9c3e594a798225046e8a42e990daf"
   ]
-  doAssert testHashes == refHashes, "Nim in Action tests were changed."
+
+  for i, test in tests:
+    let filename = "tests" / test.addFileExt("nim")
+    let testHash = getMD5(readFile(filename).string)
+    doAssert testHash == refHashes[i], "Nim in Action test " & filename & " was changed."
 
   # Run the tests.
   for testfile in tests:
@@ -329,8 +327,6 @@ proc testNimInAction(r: var TResults, cat: Category, options: string) =
   testCPP cppFile
 
 
-
-
 # ------------------------- manyloc -------------------------------------------
 #proc runSpecialTests(r: var TResults, options: string) =
 #  for t in ["lib/packages/docutils/highlite"]:
diff --git a/testament/specs.nim b/testament/specs.nim
index c51a3343e..8afe9d98e 100644
--- a/testament/specs.nim
+++ b/testament/specs.nim
@@ -10,20 +10,21 @@
 import parseutils, strutils, os, osproc, streams, parsecfg
 
 
-var compilerPrefix* = "compiler" / "nim "
+var compilerPrefix* = "compiler" / "nim"
 
 let isTravis* = existsEnv("TRAVIS")
 let isAppVeyor* = existsEnv("APPVEYOR")
 
 proc cmdTemplate*(): string =
-  compilerPrefix & "$target --lib:lib --hints:on -d:testing --nimblePath:tests/deps $options $file"
+  compilerPrefix & " $target --lib:lib --hints:on -d:testing --nimblePath:tests/deps $options $file"
 
 type
   TTestAction* = enum
-    actionCompile = "compile"
     actionRun = "run"
+    actionCompile = "compile"
     actionReject = "reject"
     actionRunNoSpec = "runNoSpec"
+
   TResultEnum* = enum
     reNimcCrash,     # nim compiler seems to have crashed
     reMsgsDiffer,       # error messages differ
@@ -39,6 +40,7 @@ type
     reBuildFailed       # package building failed
     reIgnored,          # test is ignored
     reSuccess           # test was successful
+
   TTarget* = enum
     targetC = "C"
     targetCpp = "C++"
@@ -48,6 +50,7 @@ type
   TSpec* = object
     action*: TTestAction
     file*, cmd*: string
+    input*: string
     outp*: string
     line*, column*: int
     tfile*: string
@@ -144,6 +147,8 @@ proc parseSpec*(filename: string): TSpec =
     of "output":
       result.action = actionRun
       result.outp = e.value
+    of "input":
+      result.input = e.value
     of "outputsub":
       result.action = actionRun
       result.outp = e.value
@@ -186,7 +191,7 @@ proc parseSpec*(filename: string): TSpec =
         raise newException(ValueError, "cannot interpret as a bool: " & e.value)
     of "cmd":
       if e.value.startsWith("nim "):
-        result.cmd = compilerPrefix & e.value[4..^1]
+        result.cmd = compilerPrefix & e.value[3..^1]
       else:
         result.cmd = e.value
     of "ccodecheck": result.ccodeCheck = e.value
diff --git a/testament/tester.nim b/testament/tester.nim
index 169210255..2a8d0f5c8 100644
--- a/testament/tester.nim
+++ b/testament/tester.nim
@@ -74,6 +74,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
@@ -168,7 +195,7 @@ proc addResult(r: var TResults, test: TTest, target: TTarget,
                expected, given: string, success: TResultEnum) =
   let name = test.name.extractFilename & " " & $target & test.options
   let duration = epochTime() - test.startTime
-  let durationStr = duration.formatFloat(ffDecimal, precision = 8)
+  let durationStr = duration.formatFloat(ffDecimal, precision = 8).align(11)
   backend.writeTestResult(name = name,
                           category = test.cat.string,
                           target = $target,
@@ -358,8 +385,16 @@ proc testSpec(r: var TResults, test: TTest, target = targetC) =
                     reExeNotFound)
         continue
 
-      let exeCmd = (if isJsTarget: nodejs & " " else: "") & exeFile
-      var (buf, exitCode) = execCmdEx(exeCmd, options = {poStdErrToStdOut})
+
+      var exeCmd: string
+      var args: seq[string]
+      if isJsTarget:
+        exeCmd = nodejs
+        args.add exeFile
+      else:
+        exeCmd = exeFile
+
+      var (buf, exitCode) = execCmdEx2(exeCmd, args, options = {poStdErrToStdOut}, input = expected.input)
 
       # Treat all failure codes from nodejs as 1. Older versions of nodejs used
       # to return other codes, but for us it is sufficient to know that it's not 0.
@@ -469,7 +504,7 @@ proc main() =
     of "targets":
       targetsStr = p.val.string
       targets = parseTargets(targetsStr)
-    of "nim": compilerPrefix = p.val.string & " "
+    of "nim": compilerPrefix = p.val.string
     else: quit Usage
     p.next()
   if p.kind != cmdArgument: quit Usage
diff --git a/tests/array/tarray.nim b/tests/array/tarray.nim
index 4a31a4d6d..8551d324c 100644
--- a/tests/array/tarray.nim
+++ b/tests/array/tarray.nim
@@ -400,7 +400,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/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/async/t7192.nim b/tests/async/t7192.nim
new file mode 100644
index 000000000..c380f93e1
--- /dev/null
+++ b/tests/async/t7192.nim
@@ -0,0 +1,14 @@
+discard """
+output: '''
+testCallback()
+'''
+"""
+
+import asyncdispatch
+
+proc testCallback() =
+  echo "testCallback()"
+
+when isMainModule:
+  callSoon(testCallback)
+  poll()
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/tasyncall.nim b/tests/async/tasyncall.nim
index 775dd0c6f..3e30e8ba8 100644
--- a/tests/async/tasyncall.nim
+++ b/tests/async/tasyncall.nim
@@ -2,7 +2,7 @@ discard """
   file: "tasyncall.nim"
   exitcode: 0
 """
-import times, sequtils, unittest
+import times, sequtils
 import asyncdispatch
 
 const
diff --git a/tests/async/tasyncssl.nim b/tests/async/tasyncssl.nim
index 0607cf3c6..212260922 100644
--- a/tests/async/tasyncssl.nim
+++ b/tests/async/tasyncssl.nim
@@ -2,7 +2,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 +68,3 @@ when defined(ssl):
 
   assert msgCount == swarmSize * messagesToSend
   echo msgCount
-
-
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/tfuturevar.nim b/tests/async/tfuturevar.nim
index ea2c63e03..9e3134261 100644
--- a/tests/async/tfuturevar.nim
+++ b/tests/async/tfuturevar.nim
@@ -1,3 +1,8 @@
+discard """
+action: compile
+"""
+# XXX: action should be run!
+
 import asyncdispatch
 
 proc completeOnReturn(fut: FutureVar[string], x: bool) {.async.} =
@@ -44,4 +49,3 @@ proc main() {.async.} =
 
 
 waitFor main()
-
diff --git a/tests/casestmt/tlinearscanend.nim b/tests/casestmt/tlinearscanend.nim
index 9a984e039..96e3727d5 100644
--- a/tests/casestmt/tlinearscanend.nim
+++ b/tests/casestmt/tlinearscanend.nim
@@ -1,3 +1,6 @@
+discard """
+action: compile
+"""
 
 import strutils
 
@@ -21,4 +24,3 @@ of 21: echo "21"
 else:
   {.linearScanEnd.}
   echo "default"
-
diff --git a/tests/ccgbugs/t6756.nim b/tests/ccgbugs/t6756.nim
index 0f08557eb..5170a99f4 100644
--- a/tests/ccgbugs/t6756.nim
+++ b/tests/ccgbugs/t6756.nim
@@ -1,3 +1,9 @@
+discard """
+output: '''
+(v: 3)
+'''
+"""
+
 import typetraits
 type
   A[T] = ref object
diff --git a/tests/ccgbugs/t8964.nim b/tests/ccgbugs/t8964.nim
deleted file mode 100644
index 5b41e8bdb..000000000
--- a/tests/ccgbugs/t8964.nim
+++ /dev/null
@@ -1,10 +0,0 @@
-discard """
-  targets: "c cpp"
-"""
-
-from json import JsonParsingError
-import marshal
-
-const nothing = ""
-doAssertRaises(JsonParsingError):
-  var bar = marshal.to[int](nothing)
diff --git a/tests/ccgbugs/tcodegendecllambda.nim b/tests/ccgbugs/tcodegendecllambda.nim
index 6dce68db5..5c6608b77 100644
--- a/tests/ccgbugs/tcodegendecllambda.nim
+++ b/tests/ccgbugs/tcodegendecllambda.nim
@@ -1,6 +1,7 @@
 discard """
   targets: "c cpp js"
   ccodecheck: "'HELLO'"
+  action: compile
 """
 
 when defined(JS):
diff --git a/tests/ccgbugs/tgeneric_closure.nim b/tests/ccgbugs/tgeneric_closure.nim
index f9d5e7910..bb3b924b9 100644
--- a/tests/ccgbugs/tgeneric_closure.nim
+++ b/tests/ccgbugs/tgeneric_closure.nim
@@ -1,4 +1,10 @@
-
+discard """
+output: '''
+2
+2
+2
+'''
+"""
 
 # bug 2659
 
diff --git a/tests/ccgbugs/trecursive_closure.nim b/tests/ccgbugs/trecursive_closure.nim
index f64382a8c..4b6514b90 100644
--- a/tests/ccgbugs/trecursive_closure.nim
+++ b/tests/ccgbugs/trecursive_closure.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 # bug #2233
 type MalType = object
   fun: proc: MalType
diff --git a/tests/ccgbugs/tsighash_typename_regression.nim b/tests/ccgbugs/tsighash_typename_regression.nim
index 7122902d9..6e49bafc3 100644
--- a/tests/ccgbugs/tsighash_typename_regression.nim
+++ b/tests/ccgbugs/tsighash_typename_regression.nim
@@ -1,3 +1,10 @@
+discard """
+output: '''
+123
+baz
+'''
+"""
+
 # bug #5147
 
 proc foo[T](t: T) =
diff --git a/tests/ccgbugs/tuple_canon.nim b/tests/ccgbugs/tuple_canon.nim
index 7e9e91836..671986054 100644
--- a/tests/ccgbugs/tuple_canon.nim
+++ b/tests/ccgbugs/tuple_canon.nim
@@ -1,4 +1,9 @@
-
+discard """
+output: '''
+vidx 18
+0,0
+'''
+"""
 
 # bug #4626
 var foo: (int, array[1, int]) # Tuple must be of length > 1
diff --git a/tests/closure/tclosure.nim b/tests/closure/tclosure.nim
index 141968462..c213d6a4b 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
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/tmacrobust1512.nim b/tests/closure/tmacrobust1512.nim
index 5f13e8286..0f44c5e1a 100644
--- a/tests/closure/tmacrobust1512.nim
+++ b/tests/closure/tmacrobust1512.nim
@@ -1,8 +1,12 @@
+discard """
+output: ""
+"""
+
 import macros, strutils
 
 # https://github.com/nim-lang/Nim/issues/1512
 
-proc macrobust0(raw_input: string) =
+proc macrobust0(input: string): string =
   var output = ""
   proc p1(a:string) =
     output.add(a)
@@ -27,13 +31,9 @@ proc macrobust0(raw_input: string) =
   proc p19(a:string) = p18(a)
   proc p20(a:string) = p19(a)
 
-  let input = $raw_input
-
   for a in input.split():
     p20(a)
     p19(a)
-
-
     p18(a)
     p17(a)
     p16(a)
@@ -53,11 +53,9 @@ proc macrobust0(raw_input: string) =
     p2(a)
     p1(a)
 
+  result = output
 
-  echo output
-
-macro macrobust(raw_input: untyped): untyped =
-
+macro macrobust(input: static[string]): untyped =
   var output = ""
   proc p1(a:string) =
     output.add(a)
@@ -82,12 +80,9 @@ macro macrobust(raw_input: untyped): untyped =
   proc p19(a:string) = p18(a)
   proc p20(a:string) = p19(a)
 
-  let input = $raw_input
-
   for a in input.split():
     p20(a)
     p19(a)
-
     p18(a)
     p17(a)
     p16(a)
@@ -105,11 +100,11 @@ macro macrobust(raw_input: untyped): untyped =
     p4(a)
     p3(a)
     p2(a)
+    p1(a)
 
-  echo output
-  discard result
+  result = newLit(output)
 
-macrobust """
+const input = """
   fdsasadfsdfa sadfsdafsdaf
   dsfsdafdsfadsfa fsdaasdfasdf
   fsdafsadfsad asdfasdfasdf
@@ -122,16 +117,7 @@ macrobust """
   sdfasdafsadf sdfasdafsdaf sdfasdafsdaf
 """
 
+let str1 = macrobust(input)
+let str2 = macrobust0(input)
 
-macrobust0 """
-  fdsasadfsdfa sadfsdafsdaf
-  dsfsdafdsfadsfa fsdaasdfasdf
-  fsdafsadfsad asdfasdfasdf
-  fdsasdfasdfa sadfsadfsadf
-  sadfasdfsdaf sadfsdafsdaf dsfasdaf
-  sadfsdafsadf fdsasdafsadf fdsasadfsdaf
-  sdfasadfsdafdfsa sadfsadfsdaf
-  sdafsdaffsda sdfasadfsadf
-  fsdasdafsdfa sdfasdfafsda
-  sdfasdafsadf sdfasdafsdaf sdfasdafsdaf
-"""
+doAssert str1 == str2
diff --git a/tests/closure/ttimeinfo.nim b/tests/closure/ttimeinfo.nim
index 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/compiles/trecursive_generic_in_compiles.nim b/tests/compiles/trecursive_generic_in_compiles.nim
index 9c7fd10b3..c435ebaac 100644
--- a/tests/compiles/trecursive_generic_in_compiles.nim
+++ b/tests/compiles/trecursive_generic_in_compiles.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 # bug #3313
 import unittest, sugar
 {.experimental: "notnil".}
diff --git a/tests/concepts/tconcepts_issues.nim b/tests/concepts/tconcepts_issues.nim
index e145b9f37..df4037ffb 100644
--- a/tests/concepts/tconcepts_issues.nim
+++ b/tests/concepts/tconcepts_issues.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tissues.nim"
   output: '''
 20.0 USD
 Printable
diff --git a/tests/concepts/tmapconcept.nim b/tests/concepts/tmapconcept.nim
index 5082fcb61..6b959eff2 100644
--- a/tests/concepts/tmapconcept.nim
+++ b/tests/concepts/tmapconcept.nim
@@ -3,7 +3,7 @@ output: '''10
 10
 
 1'''
-msg: '''
+nimout: '''
 K=string V=int
 K=int64 V=string
 K=int V=int
diff --git a/tests/concepts/tmatrixconcept.nim b/tests/concepts/tmatrixconcept.nim
index dd5a080b6..ca31f5942 100644
--- a/tests/concepts/tmatrixconcept.nim
+++ b/tests/concepts/tmatrixconcept.nim
@@ -1,6 +1,6 @@
 discard """
 output: "0\n0\n0"
-msg: '''
+nimout: '''
 R=3 C=3 TE=9 FF=14 FC=20 T=int
 R=3 C=3 T=int
 '''
diff --git a/tests/concepts/tstackconcept.nim b/tests/concepts/tstackconcept.nim
index cb8db566d..fb6032732 100644
--- a/tests/concepts/tstackconcept.nim
+++ b/tests/concepts/tstackconcept.nim
@@ -1,6 +1,6 @@
 discard """
 output: "20\n10"
-msg: '''
+nimout: '''
 INFERRED int
 VALUE TYPE int
 VALUE TYPE NAME INT
diff --git a/tests/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/tconverter_unique_ptr.nim b/tests/converter/tconverter_unique_ptr.nim
new file mode 100644
index 000000000..15ec609a3
--- /dev/null
+++ b/tests/converter/tconverter_unique_ptr.nim
@@ -0,0 +1,107 @@
+
+discard """
+  file: "tconverter_unique_ptr.nim"
+  targets: "c cpp"
+  output: '''5
+2.0 5
+'''
+"""
+
+## 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 `=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, 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))
+echo pu.len
+
+pu[0] = 2.0
+echo pu[0], " ", pu.lenx
+
+
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/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/tnativesockets.nim b/tests/cpp/tnativesockets.nim
index c62008050..1284811b5 100644
--- a/tests/cpp/tnativesockets.nim
+++ b/tests/cpp/tnativesockets.nim
@@ -1,5 +1,6 @@
 discard """
   targets: "cpp"
+outputsub: ""
 """
 
 import nativesockets
diff --git a/tests/cpp/tsigbreak.nim b/tests/cpp/tsigbreak.nim
index 9a381d84f..14d29adf7 100644
--- a/tests/cpp/tsigbreak.nim
+++ b/tests/cpp/tsigbreak.nim
@@ -1,5 +1,6 @@
 discard """
   targets: "cpp"
+  action: compile
 """
 
 import tables, lists
diff --git a/tests/defaultprocparam/tdefaultprocparam.nim b/tests/defaultprocparam/tdefaultprocparam.nim
index 23ecf72e9..5f8c1adab 100644
--- a/tests/defaultprocparam/tdefaultprocparam.nim
+++ b/tests/defaultprocparam/tdefaultprocparam.nim
@@ -1,4 +1,8 @@
-
+discard """
+output: '''
+hi
+'''
+"""
 import mdefaultprocparam
 
 p()
diff --git a/tests/destructor/t6434.nim b/tests/destructor/t6434.nim
index 9c912f1f9..c9ad213c2 100644
--- a/tests/destructor/t6434.nim
+++ b/tests/destructor/t6434.nim
@@ -1,21 +1,26 @@
 discard """
   exitcode: 0
-  output: '''assingment
-assingment
-assingment
-assingment
-'''
+  output: ""
 """
 
 type
   Foo* = object
     boo: int
 
+var sink_counter = 0
+var assign_counter = 0
+
+proc `=sink`(dest: var Foo, src: Foo) =
+  sink_counter.inc
+
 proc `=`(dest: var Foo, src: Foo) =
-  debugEcho "assingment"
+  assign_counter.inc
 
 proc test(): auto =
   var a,b : Foo
-  return (a, b)
+  return (a, b, Foo(boo: 5))
+
+var (a, b, _) = test()
 
-var (a, b) = test()
\ No newline at end of file
+doAssert: assign_counter == 0
+doAssert: sink_counter == 9
\ No newline at end of file
diff --git a/tests/destructor/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/tmove_objconstr.nim b/tests/destructor/tmove_objconstr.nim
index 50aecf46d..c6be2e7e3 100644
--- a/tests/destructor/tmove_objconstr.nim
+++ b/tests/destructor/tmove_objconstr.nim
@@ -60,3 +60,62 @@ 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] =
+  (a: newMySeq(x, 1.0), b:0, c:newMySeq(y, 5.0))
+
+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
\ No newline at end of file
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..a3dd966a0 100644
--- a/tests/discard/tdiscardable.nim
+++ b/tests/discard/tdiscardable.nim
@@ -1,3 +1,10 @@
+discard """
+output: '''
+1
+1
+'''
+"""
+
 # Test the discardable pragma
 
 proc p(x, y: int): int {.discardable.} =
@@ -27,3 +34,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..5e1a3f03e
--- /dev/null
+++ b/tests/discard/tillegaldiscard.nim
@@ -0,0 +1,9 @@
+discard """
+  line: 9
+  errormsg: "illegal discard"
+"""
+
+proc pop[T](arg: T): T =
+  echo arg
+
+discard tillegaldiscard.pop
diff --git a/tests/dll/server.nim b/tests/dll/server.nim
index e6b80df88..5ce1976ce 100644
--- a/tests/dll/server.nim
+++ b/tests/dll/server.nim
@@ -1,4 +1,5 @@
 discard """
+action: compile
   cmd: "nim $target --debuginfo --hints:on --define:useNimRtl --app:lib $options $file"
 """
 
@@ -25,10 +26,3 @@ proc newOp(k: TNodeKind, a, b: PNode): PNode {.exportc: "newOp", dynlib.} =
 
 proc buildTree(x: int): PNode {.exportc: "buildTree", dynlib.} =
   result = newOp(nkMul, newOp(nkAdd, newLit(x), newLit(x)), newLit(x))
-
-when false:
-  # Test the GC:
-  for i in 0..100_000:
-    discard buildTree(2)
-
-  echo "Done"
diff --git a/tests/effects/teffects6.nim b/tests/effects/teffects6.nim
index 3dd83786f..6a4eea155 100644
--- a/tests/effects/teffects6.nim
+++ b/tests/effects/teffects6.nim
@@ -1,3 +1,8 @@
+discard """
+action: compile
+"""
+
+# XXX: it is not actually tested if the effects are inferred
 
 type
   PMenu = ref object
diff --git a/tests/errmsgs/treportunused.nim b/tests/errmsgs/treportunused.nim
new file mode 100644
index 000000000..929da8843
--- /dev/null
+++ b/tests/errmsgs/treportunused.nim
@@ -0,0 +1,29 @@
+discard """
+  nimout: '''
+treportunused.nim(19, 10) Hint: 'treportunused.s1(a: string)[declared in treportunused.nim(19, 9)]' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(26, 5) Hint: 's8' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(22, 6) Hint: 'treportunused.s4()[declared in treportunused.nim(22, 5)]' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(25, 7) Hint: 's7' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(24, 7) Hint: 's6' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(23, 6) Hint: 'treportunused.s5(a: T)[declared in treportunused.nim(23, 5)]' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(20, 10) Hint: 'treportunused.s2()[declared in treportunused.nim(20, 9)]' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(29, 6) Hint: 's11' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(27, 5) Hint: 's9' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(21, 10) Hint: 's3' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(28, 6) Hint: 's10' is declared but not used [XDeclaredButNotUsed]
+'''
+"""
+
+# bug #9764
+
+iterator s1(a:string): int = discard
+iterator s2(): int = discard
+template s3(): untyped = 123
+proc s4(): int = 123
+proc s5[T](a: T): int = 123
+macro s6(a: int): untyped = discard
+const s7 = 0
+let s8 = 0
+var s9: int
+type s10 = object
+type s11 = type(1.2)
diff --git a/tests/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/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/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/flags/tgenscript.nim b/tests/flags/tgenscript.nim
index 6a037b5d8..989ca8bcb 100644
--- a/tests/flags/tgenscript.nim
+++ b/tests/flags/tgenscript.nim
@@ -1,5 +1,7 @@
 discard """
   file: "tgenscript.nim"
+  target: "c"
+  action: compile
 """
 
 echo "--genscript"
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/generics/t2tables.nim b/tests/generics/t2tables.nim
index 3ef5e621e..e4b1fb967 100644
--- a/tests/generics/t2tables.nim
+++ b/tests/generics/t2tables.nim
@@ -1,3 +1,6 @@
+discard """
+action: compile
+"""
 
 # bug #3669
 
@@ -10,4 +13,3 @@ type
 
 var g: G[string]
 echo g.rnodes["foo"]
-
diff --git a/tests/generics/tgeneric3.nim b/tests/generics/tgeneric3.nim
index 6897d9de2..34b415446 100644
--- a/tests/generics/tgeneric3.nim
+++ b/tests/generics/tgeneric3.nim
@@ -1,3 +1,13 @@
+discard """
+output: '''
+312
+1000000
+1000000
+500000
+0
+'''
+"""
+
 import strutils
 
 type
diff --git a/tests/generics/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..73c8af825 100644
--- a/tests/generics/tgenericvariant.nim
+++ b/tests/generics/tgenericvariant.nim
@@ -1,3 +1,13 @@
+discard """
+output: '''
+Test
+abcxyz123
+'''
+"""
+
+proc fakeReadLine(): string =
+  "abcxyz123"
+
 type
   TMaybe[T] = object
     case empty: bool
@@ -12,7 +22,7 @@ proc Nothing[T](): TMaybe[T] =
   result.empty = true
 
 proc safeReadLine(): TMaybe[string] =
-  var r = stdin.readLine()
+  var r = fakeReadLine()
   if r == "": return Nothing[string]()
   else: return Just(r)
 
@@ -21,3 +31,4 @@ when isMainModule:
   echo(Test.value)
   var mSomething = safeReadLine()
   echo(mSomething.value)
+  mSomething = safeReadLine()
diff --git a/tests/generics/tlateboundstatic.nim b/tests/generics/tlateboundstatic.nim
index f68f95f8d..90b44aa8e 100644
--- a/tests/generics/tlateboundstatic.nim
+++ b/tests/generics/tlateboundstatic.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: "array[0..3, int]"
+  nimout: "array[0..3, int]"
 """
 
 type
diff --git a/tests/generics/trtree.nim b/tests/generics/trtree.nim
index 75de2a1c4..321b31df6 100644
--- a/tests/generics/trtree.nim
+++ b/tests/generics/trtree.nim
@@ -1,6 +1,7 @@
 discard """
   output: '''1 [2, 3, 4, 7]
 [0, 0]'''
+  target: "c"
 """
 
 # Nim RTree and R*Tree implementation
@@ -81,13 +82,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 +99,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 +239,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 +447,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
diff --git a/tests/generics/tthread_generic.nim b/tests/generics/tthread_generic.nim
index def1acfe1..f2e9cafa9 100644
--- a/tests/generics/tthread_generic.nim
+++ b/tests/generics/tthread_generic.nim
@@ -1,5 +1,6 @@
 discard """
   cmd: "nim $target --hints:on --threads:on $options $file"
+  action: compile
 """
 
 type
@@ -36,4 +37,3 @@ when isMainModule:
   echo("test")
   joinThread(thr)
   os.sleep(3000)
-
diff --git a/tests/global/tglobalforvar.nim b/tests/global/tglobalforvar.nim
index af75df5c8..bc18f33f2 100644
--- a/tests/global/tglobalforvar.nim
+++ b/tests/global/tglobalforvar.nim
@@ -1,7 +1,9 @@
+discard """
+output: 100
+"""
 
 var funcs: seq[proc (): int {.nimcall.}] = @[]
 for i in 0..10:
   funcs.add((proc (): int = return i * i))
 
 echo(funcs[3]())
-
diff --git a/tests/init/t8314.nim b/tests/init/t8314.nim
index 59d46eb33..47c8480c2 100644
--- a/tests/init/t8314.nim
+++ b/tests/init/t8314.nim
@@ -1,8 +1,14 @@
 discard """
   nimout: '''
-t8314.nim(8, 7) Hint: BEGIN [User]
-t8314.nim(19, 7) Hint: END [User]
+t8314.nim(14, 7) Hint: BEGIN [User]
+t8314.nim(25, 7) Hint: END [User]
   '''
+
+output: '''
+1
+1
+1
+'''
 """
 
 {.hint: "BEGIN".}
diff --git a/tests/init/tuninit1.nim b/tests/init/tuninit1.nim
index 891f1e96c..67c0c4d8b 100644
--- a/tests/init/tuninit1.nim
+++ b/tests/init/tuninit1.nim
@@ -1,6 +1,7 @@
 discard """
-  msg: "Warning: 'y' might not have been initialized [Uninit]"
+  nimout: "Warning: 'y' might not have been initialized [Uninit]"
   line:34
+  action: compile
 """
 
 import strutils
diff --git a/tests/iter/timplicit_auto.nim b/tests/iter/timplicit_auto.nim
index d5cb95eb8..1b9f06843 100644
--- a/tests/iter/timplicit_auto.nim
+++ b/tests/iter/timplicit_auto.nim
@@ -15,4 +15,4 @@ iterator fields(a = (0,0), b = (h-1,w-1)): auto =
       yield (y,x)
 
 for y,x in fields():
-  stdout.write disp[univ(x, y)]
+  doAssert disp[univ(x, y)] == disp[Tree]
diff --git a/tests/iter/titer.nim b/tests/iter/titer.nim
index c4143ae4f..22be1bad5 100644
--- a/tests/iter/titer.nim
+++ b/tests/iter/titer.nim
@@ -1,3 +1,16 @@
+discard """
+output: '''
+testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest2!test3?hi
+what's
+your
+name
+hi
+what's
+your
+name
+'''
+"""
+
 # Test the new iterators
 
 iterator xrange(fromm, to: int, step = 1): int =
diff --git a/tests/iter/titer_no_tuple_unpack.nim b/tests/iter/titer_no_tuple_unpack.nim
index 13ec11bd6..d8df10189 100644
--- a/tests/iter/titer_no_tuple_unpack.nim
+++ b/tests/iter/titer_no_tuple_unpack.nim
@@ -1,3 +1,18 @@
+discard """
+output: '''
+3 4
+4 5
+5 6
+6 7
+7 8
+(x: 3, y: 4)
+(x: 4, y: 5)
+(x: 5, y: 6)
+(x: 6, y: 7)
+(x: 7, y: 8)
+'''
+"""
+
 
 iterator xrange(fromm, to: int, step = 1): tuple[x, y: int] =
   var a = fromm
@@ -10,4 +25,3 @@ for a, b in xrange(3, 7):
 
 for tup in xrange(3, 7):
   echo tup
-
diff --git a/tests/iter/titervaropenarray.nim b/tests/iter/titervaropenarray.nim
index 1e70ce247..9eea085e3 100644
--- a/tests/iter/titervaropenarray.nim
+++ b/tests/iter/titervaropenarray.nim
@@ -11,6 +11,3 @@ iterator iterAndZero(a: var openArray[int]): int =
 var x = [[1, 2, 3], [4, 5, 6]]
 for y in iterAndZero(x[0]): write(stdout, $y)
 #OUT 123
-
-
-
diff --git a/tests/iter/tpermutations.nim b/tests/iter/tpermutations.nim
index 5149eb9c2..c5067ba31 100644
--- a/tests/iter/tpermutations.nim
+++ b/tests/iter/tpermutations.nim
@@ -1,3 +1,14 @@
+discard """
+output: '''
+@[@[1.0, 2.0], @[3.0, 4.0]]
+perm: 10.0 det: -2.0
+@[@[1.0, 2.0, 3.0, 4.0], @[4.0, 5.0, 6.0, 7.0], @[7.0, 8.0, 9.0, 10.0], @[10.0, 11.0, 12.0, 13.0]]
+perm: 29556.0 det: 0.0
+@[@[0.0, 1.0, 2.0, 3.0, 4.0], @[5.0, 6.0, 7.0, 8.0, 9.0], @[10.0, 11.0, 12.0, 13.0, 14.0], @[15.0, 16.0, 17.0, 18.0, 19.0], @[20.0, 21.0, 22.0, 23.0, 24.0]]
+perm: 6778800.0 det: 0.0
+'''
+"""
+
 
 import sequtils, sugar
 
diff --git a/tests/iter/tshallowcopy_closures.nim b/tests/iter/tshallowcopy_closures.nim
index 2f024ee7e..279e7d950 100644
--- a/tests/iter/tshallowcopy_closures.nim
+++ b/tests/iter/tshallowcopy_closures.nim
@@ -1,5 +1,9 @@
 discard """
   ccodecheck: "!@('{' \\s* 'NI HEX3Astate;' \\s* '}')"
+  output: '''
+a1 10
+a1 9
+'''
 """
 
 # bug #1803
@@ -26,6 +30,6 @@ var
   z: TaskFn
 
 discard x()
-z = x #shallowCopy(z, x)
-z = y #shallowCopy(z, y)
+shallowCopy(z, x)
+shallowCopy(z, y)
 discard x()
diff --git a/tests/iter/twrap_walkdir.nim b/tests/iter/twrap_walkdir.nim
index 4ac487d8e..1d52e9791 100644
--- a/tests/iter/twrap_walkdir.nim
+++ b/tests/iter/twrap_walkdir.nim
@@ -1,5 +1,6 @@
-
-
+discard """
+action: compile
+"""
 
 import os
 
diff --git a/tests/iter/tyieldintry.nim b/tests/iter/tyieldintry.nim
index 6d24417a6..ee2790e54 100644
--- a/tests/iter/tyieldintry.nim
+++ b/tests/iter/tyieldintry.nim
@@ -440,4 +440,19 @@ 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)
+
 echo "ok"
+
diff --git a/tests/js/tjsffi.nim b/tests/js/tjsffi.nim
index 213d05964..2420c60f6 100644
--- a/tests/js/tjsffi.nim
+++ b/tests/js/tjsffi.nim
@@ -154,7 +154,7 @@ block:
 # Test JsAssoc .= and .
 block:
   proc test(): bool =
-    let obj = newJsAssoc[string, int]()
+    let obj = newJsAssoc[cstring, int]()
     var working = true
     obj.a = 11
     obj.`$!&` = 42
@@ -168,7 +168,7 @@ block:
 # Test JsAssoc .()
 block:
   proc test(): bool =
-    let obj = newJsAssoc[string, proc(e: int): int]()
+    let obj = newJsAssoc[cstring, proc(e: int): int]()
     obj.a = proc(e: int): int = e * e
     obj.a(10) == 100
   echo test()
@@ -176,7 +176,7 @@ block:
 # Test JsAssoc []()
 block:
   proc test(): bool =
-    let obj = newJsAssoc[string, proc(e: int): int]()
+    let obj = newJsAssoc[cstring, proc(e: int): int]()
     obj.a = proc(e: int): int = e * e
     let call = obj["a"]
     call(10) == 100
@@ -185,7 +185,7 @@ block:
 # Test JsAssoc Iterators
 block:
   proc testPairs(): bool =
-    let obj = newJsAssoc[string, int]()
+    let obj = newJsAssoc[cstring, int]()
     var working = true
     obj.a = 10
     obj.b = 20
@@ -202,7 +202,7 @@ block:
         return false
     working
   proc testItems(): bool =
-    let obj = newJsAssoc[string, int]()
+    let obj = newJsAssoc[cstring, int]()
     var working = true
     obj.a = 10
     obj.b = 20
@@ -211,13 +211,13 @@ block:
       working = working and v in [10, 20, 30]
     working
   proc testKeys(): bool =
-    let obj = newJsAssoc[string, int]()
+    let obj = newJsAssoc[cstring, int]()
     var working = true
     obj.a = 10
     obj.b = 20
     obj.c = 30
     for v in obj.keys:
-      working = working and v in ["a", "b", "c"]
+      working = working and v in [cstring"a", cstring"b", cstring"c"]
     working
   proc test(): bool = testPairs() and testItems() and testKeys()
   echo test()
@@ -226,8 +226,8 @@ block:
 block:
   proc test(): bool =
     {. emit: "var comparison = {a: 22, b: 55};" .}
-    var comparison {. importcpp, nodecl .}: JsAssoc[string, int]
-    let obj = newJsAssoc[string, int]()
+    var comparison {. importcpp, nodecl .}: JsAssoc[cstring, int]
+    let obj = newJsAssoc[cstring, int]()
     obj.a = 22
     obj.b = 55
     obj.a == comparison.a and obj.b == comparison.b
@@ -237,15 +237,15 @@ block:
 block:
   proc test(): bool =
     {. emit: "var comparison = {a: 22, b: 55};" .}
-    var comparison {. importcpp, nodecl .}: JsAssoc[string, int]
-    let obj = JsAssoc[string, int]{ a: 22, b: 55 }
+    var comparison {. importcpp, nodecl .}: JsAssoc[cstring, int]
+    let obj = JsAssoc[cstring, int]{ a: 22, b: 55 }
     var working = true
     working = working and
       compiles(JsAssoc[int, int]{ 1: 22, 2: 55 })
     working = working and
       comparison.a == obj.a and comparison.b == obj.b
     working = working and
-      not compiles(JsAssoc[string, int]{ a: "test" })
+      not compiles(JsAssoc[cstring, int]{ a: "test" })
     working
   echo test()
 
diff --git a/tests/lexer/tident.nim b/tests/lexer/tident.nim
index 3327344a5..e5177436d 100644
--- a/tests/lexer/tident.nim
+++ b/tests/lexer/tident.nim
@@ -1,3 +1,16 @@
+discard """
+output: '''
+Length correct
+Correct
+Correct
+Correct
+Correct
+Correct
+Correct
+Correct
+Correct
+'''
+"""
 
 type
   TIdObj* = object of RootObj
@@ -19,4 +32,3 @@ proc myNewString(L: int): string {.inline.} =
       echo("Wrong")
 
 var s = myNewString(8)
-
diff --git a/tests/lookups/test.nim b/tests/lookups/test.nim
index a17d235a4..56f39a4d7 100644
--- a/tests/lookups/test.nim
+++ b/tests/lookups/test.nim
@@ -1,3 +1,10 @@
+discard """
+output: '''
+[Suite] memoization
+
+'''
+"""
+
 # This file needs to be called 'test' nim to provoke a clash
 # with the unittest.test name. Issue #
 
@@ -14,4 +21,3 @@ proc fib(n: int): int = 40
 suite "memoization":
   test "recursive function memoization":
     check fastFib(40) == fib(40)
-
diff --git a/tests/lookups/tprefer_proc.nim b/tests/lookups/tprefer_proc.nim
deleted file mode 100644
index 57ee8e539..000000000
--- a/tests/lookups/tprefer_proc.nim
+++ /dev/null
@@ -1,4 +0,0 @@
-
-# bug #4353
-import random
-echo random[int](low(int) .. high(int))
diff --git a/tests/macros/tbindsym.nim b/tests/macros/tbindsym.nim
index 2abcd98ce..a493d6a88 100644
--- a/tests/macros/tbindsym.nim
+++ b/tests/macros/tbindsym.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: '''initApple
+  nimout: '''initApple
 deinitApple
 Coral
 enum
diff --git a/tests/macros/tdumpastgen.nim b/tests/macros/tdumpastgen.nim
index 0a1836886..0e0581f6a 100644
--- a/tests/macros/tdumpastgen.nim
+++ b/tests/macros/tdumpastgen.nim
@@ -1,5 +1,5 @@
 discard """
-msg: '''nnkStmtList.newTree(
+nimout: '''nnkStmtList.newTree(
   nnkVarSection.newTree(
     nnkIdentDefs.newTree(
       newIdentNode("x"),
diff --git a/tests/macros/tdumptree.nim b/tests/macros/tdumptree.nim
index 58b011b45..f540306c4 100644
--- a/tests/macros/tdumptree.nim
+++ b/tests/macros/tdumptree.nim
@@ -1,13 +1,14 @@
 discard """
-msg: '''StmtList
+nimout: '''
+StmtList
   VarSection
     IdentDefs
-      Ident !"x"
+      Ident "x"
       Empty
       Call
         DotExpr
-          Ident !"foo"
-          Ident !"create"
+          Ident "foo"
+          Ident "create"
         IntLit 56'''
 """
 
diff --git a/tests/macros/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 6a99dc8b7..c2cde9a43 100644
--- a/tests/macros/tgettypeinst.nim
+++ b/tests/macros/tgettypeinst.nim
@@ -201,3 +201,14 @@ test(MyObj):
     _ = 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/tmacrogenerics.nim b/tests/macros/tmacrogenerics.nim
index 919a15b46..e4acdc321 100644
--- a/tests/macros/tmacrogenerics.nim
+++ b/tests/macros/tmacrogenerics.nim
@@ -1,8 +1,10 @@
 discard """
   file: "tmacrogenerics.nim"
-  msg: '''
-instantiation 1 with typedesc and typedesc
-counter: 1
+  nimout: '''
+instantiation 1 with None and None
+instantiation 2 with None and None
+instantiation 3 with None and None
+counter: 3
 '''
   output: "int\nfloat\nint\nstring"
 """
diff --git a/tests/macros/tmacros_issues.nim b/tests/macros/tmacros_issues.nim
index ecdcd5da9..657f30fc4 100644
--- a/tests/macros/tmacros_issues.nim
+++ b/tests/macros/tmacros_issues.nim
@@ -1,13 +1,10 @@
 discard """
-  msg: '''
-proc init(foo129050: int; bar129052: typedesc[int]): int =
-  foo129050
-
+  nimout: '''
 IntLit 5
 proc (x: int): string => typeDesc[proc[string, int]]
 proc (x: int): void => typeDesc[proc[void, int]]
 proc (x: int) => typeDesc[proc[void, int]]
-x => uncheckedArray[int]
+x => UncheckedArray[int]
 a
 s
 d
@@ -43,8 +40,8 @@ block t7723:
       proc init(foo: int, bar: typedesc[int]): int =
         foo
 
-  expandMacros:
-    foo1()
+  #expandMacros:
+  foo1()
 
   doAssert init(1, int) == 1
 
@@ -144,11 +141,11 @@ block t1140:
       result.parse_template body[1].strVal
 
 
-  proc actual: string = tmpli html"""
+  proc actual: string {.used.} = tmpli html"""
       <p>Test!</p>
       """
 
-  proc another: string = tmpli html"""
+  proc another: string {.used.} = tmpli html"""
       <p>what</p>
       """
 
diff --git a/tests/macros/tmacros_various.nim b/tests/macros/tmacros_various.nim
index 15bd28a37..9eece00bd 100644
--- a/tests/macros/tmacros_various.nim
+++ b/tests/macros/tmacros_various.nim
@@ -1,9 +1,14 @@
 discard """
-  msg: '''
-range[0 .. 100]
-array[0 .. 100, int]
-10
-test
+  nimout: '''
+Infix
+  Ident "=>"
+  Call
+    Ident "name"
+    Ident "a"
+    ExprColonExpr
+      Ident "b"
+      Ident "cint"
+  NilLit
 '''
 
   output: '''
diff --git a/tests/macros/tmemit.nim b/tests/macros/tmemit.nim
index 3a3b8734b..06ab8a1e2 100644
--- a/tests/macros/tmemit.nim
+++ b/tests/macros/tmemit.nim
@@ -1,7 +1,9 @@
 discard """
-  output: '''HELLO WORLD
+  output: '''
+HELLO WORLD
 c_func
-12'''
+12
+'''
 """
 
 import macros, strutils
diff --git a/tests/macros/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/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/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim
index 3fb4dc7d9..dccbe61ba 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(
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/keineschweine.nim b/tests/manyloc/keineschweine/keineschweine.nim
index 59347ee46..04fec2788 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()
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/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/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/metatype/tbindtypedesc.nim b/tests/metatype/tbindtypedesc.nim
index 039acfbe9..cfa80e581 100644
--- a/tests/metatype/tbindtypedesc.nim
+++ b/tests/metatype/tbindtypedesc.nim
@@ -1,10 +1,5 @@
 discard """
-  msg: '''int int
-float float
-int int
-TFoo TFoo
-int float
-TFoo TFoo'''
+  output: '''ok'''
 """
 
 import typetraits
@@ -86,3 +81,4 @@ reject bindArg(int, int, 10, 20, 30, "test")
 reject bindArg(int, string, 10.0, 20, "test", "nest")
 reject bindArg(int, string, "test", "nest", 10, 20)
 
+echo "ok"
diff --git a/tests/metatype/tmetatype_issues.nim b/tests/metatype/tmetatype_issues.nim
index 5c5380c9f..c5040f9ba 100644
--- a/tests/metatype/tmetatype_issues.nim
+++ b/tests/metatype/tmetatype_issues.nim
@@ -1,4 +1,15 @@
-
+discard """
+output:'''
+void
+(Field0: "string", Field1: "string")
+1 mod 7
+@[2, 2, 2, 2, 2]
+impl 2 called
+asd
+Foo
+Bar
+'''
+"""
 
 import typetraits, macros
 
@@ -145,6 +156,3 @@ block t3338:
   var t2 = Bar[int32]()
   t2.add()
   doAssert t2.x == 5
-
-
-
diff --git a/tests/metatype/tsemistatic.nim b/tests/metatype/tsemistatic.nim
index 3f36abde9..56b9a6218 100644
--- a/tests/metatype/tsemistatic.nim
+++ b/tests/metatype/tsemistatic.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: "static 10\ndynamic\nstatic 20\n"
+  nimout: "static 10\ndynamic\nstatic 20\n"
   output: "s\nd\nd\ns"
 """
 
diff --git a/tests/metatype/tstaticparammacro.nim b/tests/metatype/tstaticparammacro.nim
index 02021185f..16a6e56b8 100644
--- a/tests/metatype/tstaticparammacro.nim
+++ b/tests/metatype/tstaticparammacro.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: '''letters
+  nimout: '''letters
 aa
 bb
 numbers
@@ -8,7 +8,7 @@ numbers
 AST a
 [(11, 22), (33, 44)]
 AST b
-(e: [55, 66], f: [77, 88])
+([55, 66], [77, 88])
 55
 10
 20Test
@@ -44,10 +44,10 @@ const
   b : Tb = (@[55,66], @[77, 88])
 
 macro mA(data: static[Ta]): untyped =
-  echo "AST a \n", repr(data)
+  echo "AST a\n", repr(data)
 
 macro mB(data: static[Tb]): untyped =
-  echo "AST b \n", repr(data)
+  echo "AST b\n", repr(data)
   echo data.e[0]
 
 mA(a)
diff --git a/tests/metatype/ttypedesc3.nim b/tests/metatype/ttypedesc3.nim
index 3d1cf2ec9..bd973eed1 100644
--- a/tests/metatype/ttypedesc3.nim
+++ b/tests/metatype/ttypedesc3.nim
@@ -1,3 +1,13 @@
+discard """
+output: '''
+proc Base
+proc Child
+method Base
+yield Base
+yield Child
+'''
+"""
+
 import typetraits
 
 type
diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim
index 106257828..2765a4231 100644
--- a/tests/metatype/ttypetraits.nim
+++ b/tests/metatype/ttypetraits.nim
@@ -1,5 +1,5 @@
 discard """
-  msg:    "int\nstring\nTBar[int]"
+  nimout:    "int\nstring\nTBar[int]"
   output: "int\nstring\nTBar[int]\nint\nrange 0..2(int)\nstring"
   disabled: true
 """
diff --git a/tests/misc/tcmdline.nim b/tests/misc/tcmdline.nim
index cb8cb402c..2c4768716 100644
--- a/tests/misc/tcmdline.nim
+++ b/tests/misc/tcmdline.nim
@@ -1,3 +1,6 @@
+discard """
+outputsub: "Number of parameters: 0"
+"""
 # Test the command line
 
 import
diff --git a/tests/misc/tcolonisproc.nim b/tests/misc/tcolonisproc.nim
index 665e9e604..c10dabcf1 100644
--- a/tests/misc/tcolonisproc.nim
+++ b/tests/misc/tcolonisproc.nim
@@ -1,3 +1,9 @@
+discard """
+output: '''
+1
+2
+'''
+"""
 
 proc p(a, b: int, c: proc ()) =
   c()
diff --git a/tests/misc/tdllvar.nim b/tests/misc/tdllvar.nim
index 1c1238e8d..68029ddf4 100644
--- a/tests/misc/tdllvar.nim
+++ b/tests/misc/tdllvar.nim
@@ -1,3 +1,7 @@
+discard """
+disabled: true
+"""
+
 import os
 
 proc getDllName: string =
@@ -12,5 +16,3 @@ proc myImport2(s: int) {.cdecl, importc, dynlib: getDllName().}
 
 myImport("test2")
 myImport2(12)
-
-
diff --git a/tests/misc/tendian.nim b/tests/misc/tendian.nim
deleted file mode 100644
index 91044f4d5..000000000
--- a/tests/misc/tendian.nim
+++ /dev/null
@@ -1,3 +0,0 @@
-# test the new endian magic
-
-writeLine(stdout, repr(system.cpuEndian))
diff --git a/tests/misc/tgetstartmilsecs.nim b/tests/misc/tgetstartmilsecs.nim
deleted file mode 100644
index bf508dd54..000000000
--- a/tests/misc/tgetstartmilsecs.nim
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-import times, os
-
-var start = epochTime()
-os.sleep(1000)
-
-echo epochTime() - start #OUT 1000
diff --git a/tests/misc/thallo.nim b/tests/misc/thallo.nim
index 17e6089ed..6f9d49121 100644
--- a/tests/misc/thallo.nim
+++ b/tests/misc/thallo.nim
@@ -1,4 +1,8 @@
-# Hallo
+discard """
+action: compile
+"""
+
+# noted this seems to be an old test file designed for manual testing.
 
 import
   os, strutils, macros
diff --git a/tests/misc/theaproots.nim b/tests/misc/theaproots.nim
index 77d0207b0..1ea3c86b9 100644
--- a/tests/misc/theaproots.nim
+++ b/tests/misc/theaproots.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 type
   Bar = object
     x: int
diff --git a/tests/misc/tlastmod.nim b/tests/misc/tlastmod.nim
index 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..02282dd4a 100644
--- a/tests/misc/tnew.nim
+++ b/tests/misc/tnew.nim
@@ -1,3 +1,10 @@
+discard """
+outputsub: '''
+Simple tree node allocation worked!
+Simple cycle allocation worked!
+'''
+"""
+
 # Test the implementation of the new operator
 # and the code generation for gc walkers
 # (and the garbage collector):
diff --git a/tests/misc/tnewuns.nim b/tests/misc/tnewuns.nim
deleted file mode 100644
index d6bae4fb1..000000000
--- a/tests/misc/tnewuns.nim
+++ /dev/null
@@ -1,12 +0,0 @@
-# test the new unsigned operations:
-
-import
-  strutils
-
-var
-  x, y: int
-
-x = 1
-y = high(int)
-
-writeLine(stdout, $ ( x +% y ) )
diff --git a/tests/misc/tparseopt.nim b/tests/misc/tparseopt.nim
index badbc59ad..651689398 100644
--- a/tests/misc/tparseopt.nim
+++ b/tests/misc/tparseopt.nim
@@ -9,6 +9,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 +36,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/tprep.nim b/tests/misc/tprep.nim
index 8f40300d6..45f25b790 100644
--- a/tests/misc/tprep.nim
+++ b/tests/misc/tprep.nim
@@ -1,3 +1,11 @@
+discard """
+nimout: '''
+tprep.nim(25, 9) Hint: Case 2 [User]
+tprep.nim(27, 11) Hint: Case 2.3 [User]
+'''
+outputsub: ""
+"""
+
 # Test the features that used to belong to the preprocessor
 
 import
diff --git a/tests/misc/tquicksort.nim b/tests/misc/tquicksort.nim
index 0867a3769..017c73fbc 100644
--- a/tests/misc/tquicksort.nim
+++ b/tests/misc/tquicksort.nim
@@ -17,10 +17,7 @@ proc echoSeq(a: seq[int]) =
     for i in low(a)..high(a):
         echo(a[i])
 
-var
-    list: seq[int]
-
-list = QuickSort(@[89,23,15,23,56,123,356,12,7,1,6,2,9,4,3])
-echoSeq(list)
-
+let list = QuickSort(@[89,23,15,23,56,123,356,12,7,1,6,2,9,4,3])
+let expected = @[1, 2, 3, 4, 6, 7, 9, 12, 15, 23, 56, 89, 123, 356]
 
+doAssert list == expected
diff --git a/tests/misc/tradix.nim b/tests/misc/tradix.nim
index 07674af18..5009dfcfb 100644
--- a/tests/misc/tradix.nim
+++ b/tests/misc/tradix.nim
@@ -1,3 +1,28 @@
+discard """
+output: '''
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+128
+1
+2
+3
+4
+255
+17
+45
+19000
+4294967288
+'''
+"""
+
 # implements and tests an efficient radix tree
 
 ## another method to store an efficient array of pointers:
diff --git a/tests/misc/treadln.nim b/tests/misc/treadln.nim
index 6e01097aa..b716c4711 100644
--- a/tests/misc/treadln.nim
+++ b/tests/misc/treadln.nim
@@ -1,3 +1,11 @@
+
+discard """
+output: '''
+test the improved readline handling that does not care whether its
+Macintosh, Unix or Windows text format.
+'''
+"""
+
 # test the improved readline handling that does not care whether its
 # Macintosh, Unix or Windows text format.
 
@@ -8,5 +16,6 @@ var
 if open(inp, "tests/misc/treadln.nim"):
   while not endOfFile(inp):
     line = readLine(inp)
-    echo("#" & line & "#")
+    if line.len >= 2 and line[0] == '#' and line[1] == ' ':
+      echo line[2..^1]
   close(inp)
diff --git a/tests/misc/treadx.nim b/tests/misc/treadx.nim
deleted file mode 100644
index e68b8933d..000000000
--- a/tests/misc/treadx.nim
+++ /dev/null
@@ -1,13 +0,0 @@
-
-when not defined(windows):
-  import posix
-
-  var inp = ""
-  var buf: array[0..10, char]
-  while true:
-    var r = read(0, addr(buf), sizeof(buf)-1)
-    add inp, $cstring(addr buf)
-    if r != sizeof(buf)-1: break
-
-  echo inp
-  #dafkladskölklödsaf ölksdakölfölksfklwe4iojr389wr 89uweokf sdlkf jweklr jweflksdj fioewjfsdlfsd
diff --git a/tests/misc/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..6f9716bb9 100644
--- a/tests/misc/tshadow_magic_type.nim
+++ b/tests/misc/tshadow_magic_type.nim
@@ -1,3 +1,10 @@
+discard """
+output: '''
+mylist
+'''
+"""
+
+
 type
   TListItemType* = enum
     RedisNil, RedisString
@@ -15,7 +22,8 @@ proc seq*() =
 
 proc lrange*(key: string): TRedisList =
   var foo: TListItem
-  foo.kind = RedisNil
+  foo.kind = RedisString
+  foo.str = key
   result = @[foo]
 
 when isMainModule:
diff --git a/tests/misc/tsizeof.nim b/tests/misc/tsizeof.nim
index 2830a545f..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)
@@ -365,4 +394,7 @@ type
 
 assert sizeof(Bar) == 12
 
-echo "OK"
+if failed:
+  quit("FAIL")
+else:
+  echo "OK"
diff --git a/tests/misc/tstrace.nim b/tests/misc/tstrace.nim
index 23590d958..00af0af69 100644
--- a/tests/misc/tstrace.nim
+++ b/tests/misc/tstrace.nim
@@ -1,3 +1,23 @@
+discard """
+exitcode: 1
+output: '''
+Traceback (most recent call last)
+tstrace.nim(36)          tstrace
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(31)          recTest
+SIGSEGV: Illegal storage access. (Attempt to read from nil?)
+'''
+"""
+
 # Test the new stacktraces (great for debugging!)
 
 {.push stack_trace: on.}
diff --git a/tests/misc/tstrdist.nim b/tests/misc/tstrdist.nim
index 3e1939e73..53ace2fae 100644
--- a/tests/misc/tstrdist.nim
+++ b/tests/misc/tstrdist.nim
@@ -23,4 +23,4 @@ proc editDistance(a, b: string): int =
       c[(i-1)*n + (j-1)] = min(x,min(y,z))
   return c[n*m]
 
-write(stdout, editDistance("abc", "abd"))
+doAssert editDistance("abc", "abd") == 3
diff --git a/tests/misc/tunsigned64mod.nim b/tests/misc/tunsigned64mod.nim
index 9c9e01c45..ca3286df3 100644
--- a/tests/misc/tunsigned64mod.nim
+++ b/tests/misc/tunsigned64mod.nim
@@ -12,13 +12,13 @@ let t4 = (v2 mod 2'u64).uint64 # works
 # bug #2550
 
 var x: uint # doesn't work
-echo x mod 2 == 0
+doAssert x mod 2 == 0
 
 var y: uint64 # doesn't work
-echo y mod 2 == 0
+doAssert y mod 2 == 0
 
 var z: uint32 # works
-echo z mod 2 == 0
+doAssert z mod 2 == 0
 
 var a: int # works
-echo a mod 2 == 0
+doAssert a mod 2 == 0
diff --git a/tests/misc/tvarious.nim b/tests/misc/tvarious.nim
index 8124b3fc7..191107a87 100644
--- a/tests/misc/tvarious.nim
+++ b/tests/misc/tvarious.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 # Test various aspects
 
 # bug #572
diff --git a/tests/modules/t8665.nim b/tests/modules/t8665.nim
index 51538df79..74d31452f 100644
--- a/tests/modules/t8665.nim
+++ b/tests/modules/t8665.nim
@@ -1 +1,5 @@
+discard """
+  action: compile
+"""
+
 import treorder
diff --git a/tests/modules/texport2.nim b/tests/modules/texport2.nim
index 6e55873c5..e90c58673 100644
--- a/tests/modules/texport2.nim
+++ b/tests/modules/texport2.nim
@@ -1,9 +1,16 @@
+discard """
+output: '''
+abc
+xyz
+B.foo
+'''
+"""
+
 # bug #1595, #1612
 
 import mexport2a
 
 proc main() =
-  echo "Import Test, two lines should follow. One with abc and one with xyz."
   printAbc()
   printXyz()
 
diff --git a/tests/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/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/Chapter3/ChatApp/src/client.nim b/tests/niminaction/Chapter3/ChatApp/src/client.nim
index 4d139655c..d479ebf43 100644
--- a/tests/niminaction/Chapter3/ChatApp/src/client.nim
+++ b/tests/niminaction/Chapter3/ChatApp/src/client.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 import os, threadpool, asyncdispatch, asyncnet
 import protocol
 
diff --git a/tests/niminaction/Chapter3/ChatApp/src/server.nim b/tests/niminaction/Chapter3/ChatApp/src/server.nim
index 8c572aeb0..31da74d16 100644
--- a/tests/niminaction/Chapter3/ChatApp/src/server.nim
+++ b/tests/niminaction/Chapter3/ChatApp/src/server.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 import asyncdispatch, asyncnet
 
 type
@@ -81,4 +85,4 @@ when isMainModule:
   echo("Server initialised!")
   # Execute the ``loop`` procedure. The ``waitFor`` procedure will run the
   # asyncdispatch event loop until the ``loop`` procedure finishes executing.
-  waitFor loop(server)
\ No newline at end of file
+  waitFor loop(server)
diff --git a/tests/niminaction/Chapter3/various3.nim b/tests/niminaction/Chapter3/various3.nim
index 478229b00..7b2776d70 100644
--- a/tests/niminaction/Chapter3/various3.nim
+++ b/tests/niminaction/Chapter3/various3.nim
@@ -1,3 +1,9 @@
+discard """
+output: '''
+Future is no longer empty, 42
+'''
+"""
+
 import threadpool
 proc foo: string = "Dog"
 var x: FlowVar[string] = spawn foo()
@@ -33,9 +39,9 @@ let data = """
   {"username": "Dominik"}
 """
 
-let obj = parseJson(data) 
-assert obj.kind == JObject 
-assert obj["username"].kind == JString 
+let obj = parseJson(data)
+assert obj.kind == JObject
+assert obj["username"].kind == JString
 assert obj["username"].str == "Dominik"
 
 block:
@@ -60,12 +66,12 @@ var amy = Human(name: "Amy", age: 20)
 
 import asyncdispatch
 
-var future = newFuture[int]() 
-doAssert(not future.finished) 
+var future = newFuture[int]()
+doAssert(not future.finished)
 
-future.callback = 
-  proc (future: Future[int]) = 
-    echo("Future is no longer empty, ", future.read) 
+future.callback =
+  proc (future: Future[int]) =
+    echo("Future is no longer empty, ", future.read)
 
 future.complete(42)
 
@@ -85,9 +91,8 @@ import asyncdispatch, asyncfile, os
 proc readFiles() {.async.} =
   # --- Changed to getTempDir here.
   var file = openAsync(getTempDir() / "test.txt", fmReadWrite)
-  let data = await file.readAll() 
-  echo(data) 
-  await file.write("Hello!\n") 
+  let data = await file.readAll()
+  echo(data)
+  await file.write("Hello!\n")
 
 waitFor readFiles()
-
diff --git a/tests/niminaction/Chapter6/WikipediaStats/concurrency.nim b/tests/niminaction/Chapter6/WikipediaStats/concurrency.nim
index 478f533d9..f20e21f4d 100644
--- a/tests/niminaction/Chapter6/WikipediaStats/concurrency.nim
+++ b/tests/niminaction/Chapter6/WikipediaStats/concurrency.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 # See this page for info about the format https://wikitech.wikimedia.org/wiki/Analytics/Data/Pagecounts-all-sites
 import tables, parseutils, strutils, threadpool
 
diff --git a/tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim b/tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim
index 8df3b6aeb..dbd635634 100644
--- a/tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim
+++ b/tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 # See this page for info about the format https://wikitech.wikimedia.org/wiki/Analytics/Data/Pagecounts-all-sites
 import tables, parseutils, strutils, threadpool, re
 
diff --git a/tests/niminaction/Chapter6/WikipediaStats/naive.nim b/tests/niminaction/Chapter6/WikipediaStats/naive.nim
index ed4fba8e2..ce995efaf 100644
--- a/tests/niminaction/Chapter6/WikipediaStats/naive.nim
+++ b/tests/niminaction/Chapter6/WikipediaStats/naive.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 # See this page for info about the format https://wikitech.wikimedia.org/wiki/Analytics/Data/Pagecounts-all-sites
 import tables, parseutils, strutils
 
diff --git a/tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim b/tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim
index 7181145e9..74857367a 100644
--- a/tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim
+++ b/tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 import os, parseutils, threadpool, strutils
 
 type
@@ -69,4 +73,4 @@ proc readPageCounts(filename: string, chunkSize = 1_000_000) =
 when isMainModule:
   const file = "pagecounts-20160101-050000"
   let filename = getCurrentDir() / file
-  readPageCounts(filename)
\ No newline at end of file
+  readPageCounts(filename)
diff --git a/tests/niminaction/Chapter6/WikipediaStats/race_condition.nim b/tests/niminaction/Chapter6/WikipediaStats/race_condition.nim
index c62b2f93e..db68aeb5c 100644
--- a/tests/niminaction/Chapter6/WikipediaStats/race_condition.nim
+++ b/tests/niminaction/Chapter6/WikipediaStats/race_condition.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 import threadpool
 
 var counter = 0
@@ -10,4 +14,4 @@ proc increment(x: int) =
 spawn increment(10_000)
 spawn increment(10_000)
 sync()
-echo(counter)
\ No newline at end of file
+echo(counter)
diff --git a/tests/niminaction/Chapter6/WikipediaStats/sequential_counts.nim b/tests/niminaction/Chapter6/WikipediaStats/sequential_counts.nim
index 25ad7d5f4..102dd15d3 100644
--- a/tests/niminaction/Chapter6/WikipediaStats/sequential_counts.nim
+++ b/tests/niminaction/Chapter6/WikipediaStats/sequential_counts.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 import os, parseutils
 
 proc parse(line: string, domainCode, pageTitle: var string,
@@ -31,4 +35,4 @@ proc readPageCounts(filename: string) =
 when isMainModule:
   const file = "pagecounts-20160101-050000"
   let filename = getCurrentDir() / file
-  readPageCounts(filename)
\ No newline at end of file
+  readPageCounts(filename)
diff --git a/tests/niminaction/Chapter7/Tweeter/src/createDatabase.nim b/tests/niminaction/Chapter7/Tweeter/src/createDatabase.nim
index c7aee1b44..a7d4ebe00 100644
--- a/tests/niminaction/Chapter7/Tweeter/src/createDatabase.nim
+++ b/tests/niminaction/Chapter7/Tweeter/src/createDatabase.nim
@@ -1,6 +1,10 @@
+discard """
+output: "Database created successfully!"
+"""
+
 import database
 
 var db = newDatabase()
 db.setup()
 echo("Database created successfully!")
-db.close()
\ No newline at end of file
+db.close()
diff --git a/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim b/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim
index b8a36306e..12aaf49b8 100644
--- a/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim
+++ b/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 import asyncdispatch, times
 
 import jester
diff --git a/tests/niminaction/Chapter7/Tweeter/tests/database_test.nim b/tests/niminaction/Chapter7/Tweeter/tests/database_test.nim
index 926ca452c..da69a004c 100644
--- a/tests/niminaction/Chapter7/Tweeter/tests/database_test.nim
+++ b/tests/niminaction/Chapter7/Tweeter/tests/database_test.nim
@@ -1,3 +1,7 @@
+discard """
+outputsub: "All tests finished successfully!"
+"""
+
 import database, os, times
 
 when isMainModule:
diff --git a/tests/niminaction/Chapter8/canvas/canvas.nim b/tests/niminaction/Chapter8/canvas/canvas.nim
index 713d1e9e2..ae2765630 100644
--- a/tests/niminaction/Chapter8/canvas/canvas.nim
+++ b/tests/niminaction/Chapter8/canvas/canvas.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 import dom
 
 type
diff --git a/tests/niminaction/Chapter8/sdl/sdl_test.nim b/tests/niminaction/Chapter8/sdl/sdl_test.nim
index a572d5231..a49e08911 100644
--- a/tests/niminaction/Chapter8/sdl/sdl_test.nim
+++ b/tests/niminaction/Chapter8/sdl/sdl_test.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 import os
 import sdl
 
diff --git a/tests/niminaction/Chapter8/sfml/sfml_test.nim b/tests/niminaction/Chapter8/sfml/sfml_test.nim
index 7d56d0903..e71060cb4 100644
--- a/tests/niminaction/Chapter8/sfml/sfml_test.nim
+++ b/tests/niminaction/Chapter8/sfml/sfml_test.nim
@@ -1,5 +1,6 @@
 discard """
-  disabled: "windows"
+action: compile
+disabled: "windows"
 """
 
 import sfml, os
diff --git a/tests/objects/tobjcov.nim b/tests/objects/tobjcov.nim
index c766adde0..817c1fcda 100644
--- a/tests/objects/tobjcov.nim
+++ b/tests/objects/tobjcov.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 # Covariance is not type safe:
 
 type
@@ -14,4 +18,3 @@ proc bp(x: var TB) = x.b[high(x.b)] = -1
 var f = cast[proc (x: var TA) {.nimcall.}](bp)
 var a: TA
 f(a) # bp expects a TB, but gets a TA
-
diff --git a/tests/objects/tobject.nim b/tests/objects/tobject.nim
index cdb8f80db..61ef7442e 100644
--- a/tests/objects/tobject.nim
+++ b/tests/objects/tobject.nim
@@ -1,3 +1,7 @@
+discard """
+output: "[Suite] object basic methods"
+"""
+
 import unittest
 
 type Obj = object
diff --git a/tests/objects/tobjects.nim b/tests/objects/tobjects.nim
deleted file mode 100644
index 66a38960e..000000000
--- a/tests/objects/tobjects.nim
+++ /dev/null
@@ -1,52 +0,0 @@
-type
-  TBase = object of RootObj
-    x, y: int
-
-  TSubclassKind = enum ka, kb, kc, kd, ke, kf
-  TSubclass = object of TBase
-    case c: TSubclassKind
-    of ka, kb, kc, kd:
-      a, b: int
-    of ke:
-      d, e, f: char
-    else: nil
-    n: bool
-
-type
-  TMyObject = object of RootObj
-    case disp: range[0..4]
-      of 0: arg: char
-      of 1: s: string
-      else: wtf: bool
-
-var
-  x: TMyObject
-
-var
-  global: int
-
-var
-  s: string
-  r: float = 0.0
-  i: int = 500 + 400
-
-case i
-of 500..999: write(stdout, "ha!\n")
-of 1000..3000, 12: write(stdout, "ganz schön groß\n")
-of 1, 2, 3: write(stdout, "1 2 oder 3\n")
-else: write(stdout, "sollte nicht passieren\n")
-
-case readLine(stdin)
-of "Rumpf": write(stdout, "Hallo Meister!\n")
-of "Andreas": write(stdout, "Hallo Meister!\n")
-else: write(stdout, "Nicht mein Meister!\n")
-
-global = global + 1
-write(stdout, "Hallo wie heißt du? \n")
-s = readLine(stdin)
-i = 0
-while i < len(s):
-  if s[i] == 'c': write(stdout, "'c' in deinem Namen gefunden\n")
-  i = i + 1
-
-write(stdout, "Du heißt " & s)
diff --git a/tests/objvariant/tcheckedfield1.nim b/tests/objvariant/tcheckedfield1.nim
index a7f232c5b..69b099f24 100644
--- a/tests/objvariant/tcheckedfield1.nim
+++ b/tests/objvariant/tcheckedfield1.nim
@@ -1,6 +1,8 @@
 discard """
-  msg: "Warning: cannot prove that field 'x.s' is accessible [ProveField]"
+  nimout: "Warning: cannot prove that field 'x.s' is accessible [ProveField]"
   line:51
+  action: run
+  output: "abc abc"
 """
 
 import strutils
diff --git a/tests/osproc/ta_in.nim b/tests/osproc/ta_in.nim
index b46890f6e..fb294ec14 100644
--- a/tests/osproc/ta_in.nim
+++ b/tests/osproc/ta_in.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 # This file is prefixed with an "a", because other tests
 # depend on it and it must be compiled first.
 import strutils
diff --git a/tests/osproc/ta_out.nim b/tests/osproc/ta_out.nim
index f7091a7f6..318a27d59 100644
--- a/tests/osproc/ta_out.nim
+++ b/tests/osproc/ta_out.nim
@@ -1,3 +1,14 @@
+discard """
+output: '''
+to stdout
+to stdout
+to stderr
+to stderr
+to stdout
+to stdout
+'''
+"""
+
 # This file is prefixed with an "a", because other tests
 # depend on it and it must be compiled first.
 stdout.writeLine("to stdout")
diff --git a/tests/osproc/tafalse.nim b/tests/osproc/tafalse.nim
index 24fd4fb2e..05a0bfce9 100644
--- a/tests/osproc/tafalse.nim
+++ b/tests/osproc/tafalse.nim
@@ -1,3 +1,7 @@
+discard """
+exitcode: 1
+"""
+
 # 'tafalse.nim' to ensure it is compiled before texitcode.nim
 import system
 quit(QuitFailure)
diff --git a/tests/osproc/texitcode.nim b/tests/osproc/texitcode.nim
index 4eaab6da2..6dc5508b5 100644
--- a/tests/osproc/texitcode.nim
+++ b/tests/osproc/texitcode.nim
@@ -2,6 +2,7 @@ discard """
   file: "texitcode.nim"
   output: ""
 """
+
 import osproc, os
 
 const filename = when defined(Windows): "tafalse.exe" else: "tafalse"
diff --git a/tests/overload/tselfderef.nim b/tests/overload/tselfderef.nim
index 708e4043b..96f1da42a 100644
--- a/tests/overload/tselfderef.nim
+++ b/tests/overload/tselfderef.nim
@@ -1,7 +1,10 @@
+discard """
+action: compile
+"""
+
 # bug #4671
 {.experimental.}
 {.this: self.}
-
 type
   SomeObj = object
     f: int
diff --git a/tests/parallel/tarray_of_channels.nim b/tests/parallel/tarray_of_channels.nim
index 90ae8369c..e2a682bd5 100644
--- a/tests/parallel/tarray_of_channels.nim
+++ b/tests/parallel/tarray_of_channels.nim
@@ -1,3 +1,15 @@
+discard """
+sortoutput: true
+output: '''
+(x: 0.0)
+(x: 0.0)
+(x: 0.0)
+test
+test
+test
+'''
+"""
+
 # bug #2257
 import threadpool
 
diff --git a/tests/parallel/tdont_be_stupid.nim b/tests/parallel/tdont_be_stupid.nim
index a7e82466a..d765c11a9 100644
--- a/tests/parallel/tdont_be_stupid.nim
+++ b/tests/parallel/tdont_be_stupid.nim
@@ -1,3 +1,11 @@
+discard """
+output: '''
+100
+200
+300
+400
+'''
+"""
 
 import threadpool, os
 
@@ -12,4 +20,4 @@ proc sleepsort(nums: openArray[int]) =
       spawn single(nums[i])
       i += 1
 
-sleepsort([50,3,40,25])
+sleepsort([400,100,300,200])
diff --git a/tests/parallel/tguard1.nim b/tests/parallel/tguard1.nim
index c7972d225..b1eb7e7c5 100644
--- a/tests/parallel/tguard1.nim
+++ b/tests/parallel/tguard1.nim
@@ -1,3 +1,7 @@
+discard """
+output: "90"
+"""
+
 
 when false:
   template lock(a, b: ptr Lock; body: stmt) =
diff --git a/tests/parallel/tlet_spawn.nim b/tests/parallel/tlet_spawn.nim
index 463ee1a47..62341d8f0 100644
--- a/tests/parallel/tlet_spawn.nim
+++ b/tests/parallel/tlet_spawn.nim
@@ -1,3 +1,8 @@
+discard """
+output: '''
+done999 999
+'''
+"""
 
 import threadpool
 
diff --git a/tests/parallel/tmissing_deepcopy.nim b/tests/parallel/tmissing_deepcopy.nim
index 53481e4df..45fdf0f8f 100644
--- a/tests/parallel/tmissing_deepcopy.nim
+++ b/tests/parallel/tmissing_deepcopy.nim
@@ -1,5 +1,6 @@
 discard """
-  ccodeCheck: "\\i @'deepCopy(' .*"
+  ccodeCheck: "@'genericDeepCopy(' .*"
+  action: compile
 """
 
 # bug #2286
diff --git a/tests/parallel/tsimple_array_checks.nim b/tests/parallel/tsimple_array_checks.nim
index 9874d3299..ee9508074 100644
--- a/tests/parallel/tsimple_array_checks.nim
+++ b/tests/parallel/tsimple_array_checks.nim
@@ -1,3 +1,25 @@
+discard """
+sortoutput: true
+output: '''
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+Hello 1
+Hello 2
+Hello 3
+Hello 4
+Hello 5
+Hello 6
+'''
+"""
+
 # bug #2287
 
 import threadPool
diff --git a/tests/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/pragmas/tnoreturn.nim b/tests/pragmas/tnoreturn.nim
index 50b427d71..6d0466df3 100644
--- a/tests/pragmas/tnoreturn.nim
+++ b/tests/pragmas/tnoreturn.nim
@@ -1,5 +1,6 @@
 discard """
 ccodeCheck: "\\i @'__attribute__((noreturn))' .*"
+action: compile
 """
 
 proc noret1*(i: int) {.noreturn.} =
diff --git a/tests/seq/tseq.nim b/tests/seq/tseq.nim
index 6528d518e..1cb94b308 100644
--- a/tests/seq/tseq.nim
+++ b/tests/seq/tseq.nim
@@ -170,6 +170,30 @@ block tshallowseq:
   xxx()
 
 
+block tshallowemptyseq:
+  proc test() =
+    var nilSeq: seq[int] = @[]
+    var emptySeq: seq[int] = newSeq[int]()
+    block:
+      var t = @[1,2,3]
+      shallow(nilSeq)
+      t = nilSeq
+      doAssert t == @[]
+    block:
+      var t = @[1,2,3]
+      shallow(emptySeq)
+      t = emptySeq
+      doAssert t == @[]
+    block:
+      var t = @[1,2,3]
+      shallowCopy(t, nilSeq)
+      doAssert t == @[]
+    block:
+      var t = @[1,2,3]
+      shallowCopy(t, emptySeq)
+      doAssert t == @[]
+  test()
+
 
 import strutils
 block ttoseq:
diff --git a/tests/sets/tsets_various.nim b/tests/sets/tsets_various.nim
index 7cb9a6eec..8a63763b4 100644
--- a/tests/sets/tsets_various.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/stdlib/tcputime.nim b/tests/stdlib/tcputime.nim
deleted file mode 100644
index b0cc19c6c..000000000
--- a/tests/stdlib/tcputime.nim
+++ /dev/null
@@ -1,11 +0,0 @@
-import times, os
-
-var e = epochTime()
-var c = cpuTime()
-
-os.sleep(1000)
-
-e = epochTime() - e
-c = cpuTime() - c
-
-echo "epochTime: ", e, " cpuTime: ", c
diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim
index c442b43fb..2cd1e4e47 100644
--- a/tests/stdlib/thashes.nim
+++ b/tests/stdlib/thashes.nim
@@ -1,5 +1,14 @@
-import unittest
-import hashes
+
+discard """
+output: '''
+[Suite] hashes
+
+[Suite] hashing
+
+'''
+"""
+
+import unittest, hashes
 
 suite "hashes":
   suite "hashing":
diff --git a/tests/stdlib/thttpcore.nim b/tests/stdlib/thttpcore.nim
index 9f99df93a..889c734c5 100644
--- a/tests/stdlib/thttpcore.nim
+++ b/tests/stdlib/thttpcore.nim
@@ -1,3 +1,6 @@
+discard """
+output: "[Suite] httpcore"
+"""
 
 import unittest
 
diff --git a/tests/stdlib/tjsonexternproc.nim b/tests/stdlib/tjsonexternproc.nim
index ec90e580d..1091d72cd 100644
--- a/tests/stdlib/tjsonexternproc.nim
+++ b/tests/stdlib/tjsonexternproc.nim
@@ -1,5 +1,11 @@
+discard """
+output: '''
+{"data":[1]}
+'''
+"""
+
 # Test case for https://github.com/nim-lang/Nim/issues/6385
 
 import mjsonexternproc
 # import json
-foo(1)
\ No newline at end of file
+foo(1)
diff --git a/tests/stdlib/tjsontestsuite.nim b/tests/stdlib/tjsontestsuite.nim
index 06f783a73..db31963fd 100644
--- a/tests/stdlib/tjsontestsuite.nim
+++ b/tests/stdlib/tjsontestsuite.nim
@@ -1,3 +1,7 @@
+discard """
+disabled: true
+"""
+
 ## JSON tests based on https://github.com/nst/JSONTestSuite
 
 import unittest,
diff --git a/tests/stdlib/tlists.nim b/tests/stdlib/tlists.nim
index 37e73c53f..b7c7f9f5a 100644
--- a/tests/stdlib/tlists.nim
+++ b/tests/stdlib/tlists.nim
@@ -8,14 +8,14 @@ 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]")
 
   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 +23,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 +32,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 +42,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..a18fba083 100644
--- a/tests/stdlib/tmemfiles1.nim
+++ b/tests/stdlib/tmemfiles1.nim
@@ -1,5 +1,6 @@
 discard """
   file: "tmemfiles1.nim"
+  outputsub: ""
 """
 import memfiles, os
 var
@@ -8,5 +9,5 @@ var
 # Create a new file
 mm = memfiles.open(fn, mode = fmReadWrite, newFileSize = 20)
 mm.close()
-mm.close()
+# mm.close()
 if fileExists(fn): removeFile(fn)
diff --git a/tests/stdlib/tmemlines.nim b/tests/stdlib/tmemlines.nim
index c850b5493..98e03b5bb 100644
--- a/tests/stdlib/tmemlines.nim
+++ b/tests/stdlib/tmemlines.nim
@@ -1,3 +1,7 @@
+discard """
+outputsub: ""
+"""
+
 import memfiles
 var inp = memfiles.open("tests/stdlib/tmemlines.nim")
 for line in lines(inp):
diff --git a/tests/stdlib/tmemlinesBuf.nim b/tests/stdlib/tmemlinesBuf.nim
index 9fa68cf02..97ad751ee 100644
--- a/tests/stdlib/tmemlinesBuf.nim
+++ b/tests/stdlib/tmemlinesBuf.nim
@@ -1,6 +1,15 @@
+discard """
+output: "15"
+disabled: "appveyor"
+"""
+
 import memfiles
 var inp = memfiles.open("tests/stdlib/tmemlinesBuf.nim")
 var buffer: TaintedString = ""
+var lineCount = 0
 for line in lines(inp, buffer):
-  echo("#" & line & "#")
+  lineCount += 1
+
 close(inp)
+
+echo lineCount
diff --git a/tests/stdlib/tmemslices.nim b/tests/stdlib/tmemslices.nim
index d724254a2..c0d6d3960 100644
--- a/tests/stdlib/tmemslices.nim
+++ b/tests/stdlib/tmemslices.nim
@@ -1,3 +1,9 @@
+discard """
+outputsub: "rlwuiadtrnzb"
+"""
+
+# chatever the sub pattern it will find itself
+
 import memfiles
 var inp = memfiles.open("tests/stdlib/tmemslices.nim")
 for mem in memSlices(inp):
diff --git a/tests/stdlib/tnativesockets.nim b/tests/stdlib/tnativesockets.nim
index c683647bc..c2738b8a5 100644
--- a/tests/stdlib/tnativesockets.nim
+++ b/tests/stdlib/tnativesockets.nim
@@ -1,3 +1,7 @@
+discard """
+outputsub: ""
+"""
+
 import nativesockets, unittest
 
 suite "nativesockets":
@@ -5,4 +9,3 @@ suite "nativesockets":
     let hostname = getHostname()
     check hostname.len > 0
     check hostname.len < 64
-
diff --git a/tests/stdlib/tnet.nim b/tests/stdlib/tnet.nim
index 009561272..2dd22796c 100644
--- a/tests/stdlib/tnet.nim
+++ b/tests/stdlib/tnet.nim
@@ -1,3 +1,7 @@
+discard """
+outputsub: ""
+"""
+
 import net, nativesockets
 import unittest
 
diff --git a/tests/stdlib/tosprocterminate.nim b/tests/stdlib/tosprocterminate.nim
index 7fc6c5d85..a46d91d68 100644
--- a/tests/stdlib/tosprocterminate.nim
+++ b/tests/stdlib/tosprocterminate.nim
@@ -1,3 +1,7 @@
+discard """
+outputsub: "SUCCESS"
+"""
+
 import os, osproc
 
 when defined(Windows):
diff --git a/tests/stdlib/tparsopt.nim b/tests/stdlib/tparsopt.nim
index 848fba2da..948bc8d5f 100644
--- a/tests/stdlib/tparsopt.nim
+++ b/tests/stdlib/tparsopt.nim
@@ -1,4 +1,10 @@
-# Test the new parseopt module
+discard """
+disabled: true
+"""
+
+# this file has a type in the name, and it does not really test
+# parseopt module, because tester has no support to set arguments. Test the
+# new parseopt module. Therefore it is disabled.
 
 import
   parseopt
diff --git a/tests/stdlib/tposix.nim b/tests/stdlib/tposix.nim
index 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..4f8d5fb20 100644
--- a/tests/stdlib/tquit.nim
+++ b/tests/stdlib/tquit.nim
@@ -1,3 +1,9 @@
+discard """
+output: '''
+just exiting...
+'''
+"""
+
 # Test the new beforeQuit variable:
 
 proc myExit() {.noconv.} =
diff --git a/tests/stdlib/trepr2.nim b/tests/stdlib/trepr2.nim
index 300df565d..89379da96 100644
--- a/tests/stdlib/trepr2.nim
+++ b/tests/stdlib/trepr2.nim
@@ -1,3 +1,8 @@
+discard """
+outputsub: ""
+"""
+
+# output not testable because repr prints pointer adresses
 # test the new "repr" built-in proc
 
 type
diff --git a/tests/stdlib/trstgen.nim b/tests/stdlib/trstgen.nim
index c702ccc2a..fd89f68af 100644
--- a/tests/stdlib/trstgen.nim
+++ b/tests/stdlib/trstgen.nim
@@ -1,3 +1,7 @@
+discard """
+outputsub: ""
+"""
+
 # tests for rstgen module.
 
 import ../../lib/packages/docutils/rstgen
@@ -27,7 +31,7 @@ suite "YAML syntax highlighting":
 <span class="Punctuation">?</span> <span class="StringLit">key</span>
 <span class="Punctuation">:</span> <span class="StringLit">value</span>
 <span class="Keyword">...</span></pre>"""
-  
+
   test "Block scalars":
     let input = """.. code-block:: yaml
     a literal block scalar: |
@@ -55,7 +59,7 @@ suite "YAML syntax highlighting":
 <span class="StringLit">another literal block scalar</span><span class="Punctuation">:</span>
   <span class="Command">|+</span> <span class="Comment"># comment after header</span><span class="LongStringLit">
  allowed, since more indented than parent</span></pre>"""
- 
+
   test "Directives":
     let input = """.. code-block:: yaml
     %YAML 1.2
@@ -97,7 +101,7 @@ suite "YAML syntax highlighting":
   <span class="StringLit">more numbers</span><span class="Punctuation">:</span> <span class="Punctuation">[</span><span class="DecNumber">-783</span><span class="Punctuation">,</span> <span class="FloatNumber">11e78</span><span class="Punctuation">]</span><span class="Punctuation">,</span>
   <span class="StringLit">not numbers</span><span class="Punctuation">:</span> <span class="Punctuation">[</span> <span class="StringLit">42e</span><span class="Punctuation">,</span> <span class="StringLit">0023</span><span class="Punctuation">,</span> <span class="StringLit">+32.37</span><span class="Punctuation">,</span> <span class="StringLit">8 ball</span><span class="Punctuation">]</span>
 <span class="Punctuation">}</span></pre>"""
-  
+
   test "Anchors, Aliases, Tags":
     let input = """.. code-block:: yaml
     --- !!map
@@ -136,4 +140,4 @@ suite "YAML syntax highlighting":
   <span class="DecNumber">-3</span>
   <span class="DecNumber">-4</span>
 <span class="StringLit">example.com/not/a#comment</span><span class="Punctuation">:</span>
-  <span class="StringLit">?not a map key</span></pre>"""
\ No newline at end of file
+  <span class="StringLit">?not a map key</span></pre>"""
diff --git a/tests/stdlib/tsortcall.nim b/tests/stdlib/tsortcall.nim
index 45b98805f..242e3fe4c 100644
--- a/tests/stdlib/tsortcall.nim
+++ b/tests/stdlib/tsortcall.nim
@@ -1,3 +1,7 @@
+discard """
+outputsub: ""
+"""
+
 import algorithm
 import unittest
 
@@ -40,7 +44,7 @@ suite "test sort, sorted, and isSorted procs":
   test "test the shortcut versions with descending sort order":
     check(not unSortedIntSeq.isSorted(SortOrder.Descending))
     check sorted(unSortedIntSeq, SortOrder.Descending) == reversed sortedIntSeq
-    check sorted(unSortedIntSeq).isSorted(SortOrder.Descending)
+    check sorted(unSortedIntSeq).isSorted(SortOrder.Ascending)
 
     unSortedIntSeq.sort(SortOrder.Descending)
     check unSortedIntSeq == reversed sortedIntSeq
diff --git a/tests/stdlib/tstreams.nim b/tests/stdlib/tstreams.nim
index 16dbc0e1b..559824d85 100644
--- a/tests/stdlib/tstreams.nim
+++ b/tests/stdlib/tstreams.nim
@@ -1,12 +1,25 @@
+discard """
+input: "Arne"
+output: '''
+Hello! What is your name?
+Nice name: Arne
+fs is: nil
+
+threw exception
+'''
+disabled: "windows"
+"""
+
+
 import streams
 
 
 block tstreams:
   var outp = newFileStream(stdout)
   var inp = newFileStream(stdin)
-  write(outp, "Hello! What is your name?")
+  writeLine(outp, "Hello! What is your name?")
   var line = readLine(inp)
-  write(outp, "Nice name: " & line)
+  writeLine(outp, "Nice name: " & line)
 
 
 block tstreams2:
diff --git a/tests/stdlib/tstrtabs.nim b/tests/stdlib/tstrtabs.nim
index a248cc3b2..18ed57167 100644
--- a/tests/stdlib/tstrtabs.nim
+++ b/tests/stdlib/tstrtabs.nim
@@ -1,3 +1,92 @@
+discard """
+sortoutput: true
+output: '''
+key1: value1
+key2: value2
+key_0: value0
+key_10: value10
+key_11: value11
+key_12: value12
+key_13: value13
+key_14: value14
+key_15: value15
+key_16: value16
+key_17: value17
+key_18: value18
+key_19: value19
+key_20: value20
+key_21: value21
+key_22: value22
+key_23: value23
+key_24: value24
+key_25: value25
+key_26: value26
+key_27: value27
+key_28: value28
+key_29: value29
+key_30: value30
+key_31: value31
+key_32: value32
+key_33: value33
+key_34: value34
+key_35: value35
+key_36: value36
+key_37: value37
+key_38: value38
+key_39: value39
+key_3: value3
+key_40: value40
+key_41: value41
+key_42: value42
+key_43: value43
+key_44: value44
+key_45: value45
+key_46: value46
+key_47: value47
+key_48: value48
+key_49: value49
+key_4: value4
+key_50: value50
+key_51: value51
+key_52: value52
+key_53: value53
+key_54: value54
+key_55: value55
+key_56: value56
+key_57: value57
+key_58: value58
+key_59: value59
+key_5: value5
+key_60: value60
+key_61: value61
+key_62: value62
+key_63: value63
+key_64: value64
+key_65: value65
+key_66: value66
+key_67: value67
+key_68: value68
+key_69: value69
+key_6: value6
+key_70: value70
+key_71: value71
+key_72: value72
+key_73: value73
+key_74: value74
+key_75: value75
+key_76: value76
+key_77: value77
+key_78: value78
+key_79: value79
+key_7: value7
+key_80: value80
+key_8: value8
+key_9: value9
+length of table 81
+value1 = value2
+'''
+"""
+
 import strtabs
 
 var tab = newStringTable({"key1": "val1", "key2": "val2"},
@@ -9,4 +98,4 @@ for key, val in pairs(tab):
   writeLine(stdout, key, ": ", val)
 writeLine(stdout, "length of table ", $tab.len)
 
-writeLine(stdout, `%`("$key1 = $key2; ${PATH}", tab, {useEnvironment}))
+writeLine(stdout, `%`("$key1 = $key2", tab, {useEnvironment}))
diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim
index 660c9325f..7ebbe61d9 100644
--- a/tests/stdlib/ttimes.nim
+++ b/tests/stdlib/ttimes.nim
@@ -84,6 +84,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")
 
diff --git a/tests/stdlib/twalker.nim b/tests/stdlib/twalker.nim
deleted file mode 100644
index 91c97df01..000000000
--- a/tests/stdlib/twalker.nim
+++ /dev/null
@@ -1,13 +0,0 @@
-# iterate over all files with a given filter:
-
-import
-  "../../lib/pure/os.nim", ../../ lib / pure / times
-
-proc main(filter: string) =
-  for filename in walkFiles(filter):
-    writeLine(stdout, filename)
-
-  for key, val in envPairs():
-    writeLine(stdout, key & '=' & val)
-
-main("*.nim")
diff --git a/tests/system/t7894.nim b/tests/system/t7894.nim
index 2808e5020..27ee3f220 100644
--- a/tests/system/t7894.nim
+++ b/tests/system/t7894.nim
@@ -1,18 +1,24 @@
 discard """
+disabled: "travis"
+disabled: "appveyor"
 """
 
-import os
+# CI integration servers are out of memory for this test
 
 const size = 250000000
-var saved = newSeq[seq[int8]]()
 
-for i in 0..22:
-  # one of these is 0.25GB.
-  #echo i
-  var x = newSeq[int8](size)
-  sleep(10)
-  saved.add(x)
+proc main() =
 
-for x in saved:
-  #echo x.len
-  doAssert x.len == size
+  var saved = newSeq[seq[int8]]()
+
+  for i in 0..22:
+    # one of these is 0.25GB.
+    #echo i
+    var x = newSeq[int8](size)
+    saved.add(x)
+
+  for x in saved:
+    #echo x.len
+    doAssert x.len == size
+
+main()
diff --git a/tests/system/talloc.nim b/tests/system/talloc.nim
index bf2cd97a8..9b970fda0 100644
--- a/tests/system/talloc.nim
+++ b/tests/system/talloc.nim
@@ -1,6 +1,9 @@
 discard """
+disabled: "appveyor"
 """
 
+# appveyor is "out of memory"
+
 var x: ptr int
 
 x = cast[ptr int](alloc(7))
diff --git a/tests/system/talloc2.nim b/tests/system/talloc2.nim
index 0757c0724..e40c3f93c 100644
--- a/tests/system/talloc2.nim
+++ b/tests/system/talloc2.nim
@@ -1,6 +1,9 @@
 discard """
+disabled: "windows"
 """
 
+# appveyor is "out of memory"
+
 const
   nmax = 2*1024*1024*1024
 
diff --git a/tests/system/tio.nim b/tests/system/tio.nim
index 7e9e18950..c4d041560 100644
--- a/tests/system/tio.nim
+++ b/tests/system/tio.nim
@@ -1,14 +1,19 @@
 discard """
+outputsub: ""
+disabled: true
 """
 
 import
-  unittest, osproc, streams, os, strformat
+  unittest, osproc, streams, os, strformat, strutils
 const STRING_DATA = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
+
 const TEST_FILE = "tests/testdata/string.txt"
 
 proc echoLoop(str: string): string =
   result = ""
-  var process = startProcess(findExe("tests/system/helpers/readall_echo"))
+  let exe = findExe("tests/system/helpers/readall_echo")
+  echo "exe: ", exe
+  var process = startProcess(exe)
   var input = process.inputStream
   input.write(str)
   input.close()
@@ -22,10 +27,9 @@ suite "io":
     test "stdin":
       check:
         echoLoop(STRING_DATA) == STRING_DATA
-        echoLoop(STRING_DATA[0..3999]) == STRING_DATA[0..3999]
     test "file":
       check:
-        readFile(TEST_FILE) == STRING_DATA
+        readFile(TEST_FILE).strip == STRING_DATA
 
 
 proc verifyFileSize(sz: int64) =
diff --git a/tests/system/tnilconcats.nim b/tests/system/tnilconcats.nim
index 5e4a1b317..c1126405c 100644
--- a/tests/system/tnilconcats.nim
+++ b/tests/system/tnilconcats.nim
@@ -23,3 +23,10 @@ when true:
   doAssert s == "fooabc"
 
   echo x
+
+  # casting an empty string as sequence with shallow() should not segfault
+  var s2: string
+  shallow(s2)
+  s2 &= "foo"
+  doAssert s2 == "foo"
+
diff --git a/tests/system/tparams.nim b/tests/system/tparams.nim
index dd5511b8f..015530043 100644
--- a/tests/system/tparams.nim
+++ b/tests/system/tparams.nim
@@ -1,6 +1,3 @@
-discard """
-"""
-
 import os
 import osproc
 import parseopt2
@@ -13,7 +10,6 @@ if argv == @[]:
   doAssert execShellCmd(getAppFilename() & " \"foo bar\" --aa:bar=a --a=c:d --ab -c --a[baz]:doo") == 0
 else:
   let f = toSeq(getopt())
-  echo f.repr
   doAssert f[0].kind == cmdArgument and f[0].key == "foo bar" and f[0].val == ""
   doAssert f[1].kind == cmdLongOption and f[1].key == "aa" and f[1].val == "bar=a"
   doAssert f[2].kind == cmdLongOption and f[2].key == "a=c" and f[2].val == "d"
diff --git a/tests/template/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/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..8599b161a
--- /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 isMainModule: 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/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..506f57148 100644
--- a/tests/template/thygienictempl.nim
+++ b/tests/template/thygienictempl.nim
@@ -1,3 +1,7 @@
+discard """
+action: compile
+"""
+
 
 var
   e = "abc"
diff --git a/tests/template/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..da86d63dc 100644
--- a/tests/template/tparams_gensymed.nim
+++ b/tests/template/tparams_gensymed.nim
@@ -1,4 +1,15 @@
-
+discard """
+output: '''
+0
+1
+2
+3
+0
+1
+2
+3
+'''
+"""
 # bug #1915
 
 import macros
diff --git a/tests/template/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/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/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/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/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/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..36171d5d7
--- /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 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/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/typerel/tnoargopenarray.nim b/tests/typerel/tnoargopenarray.nim
index 20ebe5ecc..9e2b2fb86 100644
--- a/tests/typerel/tnoargopenarray.nim
+++ b/tests/typerel/tnoargopenarray.nim
@@ -1,7 +1,8 @@
+discard """
+action: compile
+"""
 
 import db_sqlite
 
 var db: DbConn
 exec(db, sql"create table blabla()")
-
-
diff --git a/tests/typerel/trettypeinference.nim b/tests/typerel/trettypeinference.nim
index fa4e89cc8..aa0d66e5b 100644
--- a/tests/typerel/trettypeinference.nim
+++ b/tests/typerel/trettypeinference.nim
@@ -1,5 +1,5 @@
 discard """
-  msg:    "instantiated for string\ninstantiated for int\ninstantiated for bool"
+  nimout:    "instantiated for string\ninstantiated for int\ninstantiated for bool"
   output: "int\nseq[string]\nA\nB\n100\ntrue"
 """
 
diff --git a/tests/typerel/tsecondarrayproperty.nim b/tests/typerel/tsecondarrayproperty.nim
index 3a6879b16..315ad06bf 100644
--- a/tests/typerel/tsecondarrayproperty.nim
+++ b/tests/typerel/tsecondarrayproperty.nim
@@ -1,3 +1,7 @@
+discard """
+output: "4"
+"""
+
 
 type
   TFoo = object
@@ -25,4 +29,3 @@ echo f.second[1]
 
 #echo `second[]`(f,1)
 # this is the only way I could use it, but not what I expected
-
diff --git a/tests/typerel/ttuple1.nim b/tests/typerel/ttuple1.nim
index d5c80800c..a03cc510e 100644
--- a/tests/typerel/ttuple1.nim
+++ b/tests/typerel/ttuple1.nim
@@ -1,3 +1,9 @@
+discard """
+output: '''
+M=1000, D=500, C=100, L=50, X=10, V=5, I=1
+'''
+"""
+
 const romanNumbers = [
     ("M", 1000), ("D", 500), ("C", 100),
     ("L", 50), ("X", 10), ("V", 5), ("I", 1) ]
@@ -12,5 +18,3 @@ for key, val in items(romanNumbers):
 proc PrintBiTuple(t: tuple[k: string, v: int]): int =
   stdout.write(t.k & "=" & $t.v & ", ")
   return 0
-
-
diff --git a/tests/types/taliasbugs.nim b/tests/types/taliasbugs.nim
index bdb2a7a32..f1b35edf6 100644
--- a/tests/types/taliasbugs.nim
+++ b/tests/types/taliasbugs.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: '''true
+  nimout: '''true
 true
 true
 true
diff --git a/tests/types/tauto_canbe_void.nim b/tests/types/tauto_canbe_void.nim
index b071c08e1..c43215d1e 100644
--- a/tests/types/tauto_canbe_void.nim
+++ b/tests/types/tauto_canbe_void.nim
@@ -1,3 +1,10 @@
+discard """
+output: '''
+arg
+arg
+'''
+"""
+
 
 import sugar
 
@@ -6,4 +13,3 @@ template tempo(s) =
 
 tempo((s: string)->auto => echo(s))
 tempo((s: string) => echo(s))
-
diff --git a/tests/vm/tconsteval.nim b/tests/vm/tconsteval.nim
index f4260495a..2e0fcb888 100644
--- a/tests/vm/tconsteval.nim
+++ b/tests/vm/tconsteval.nim
@@ -1,4 +1,5 @@
 discard """
+action: compile
 """
 
 import strutils
@@ -28,4 +29,3 @@ Possible Commands:
        CompileDate, CompileTime]
 
 echo HelpText
-
diff --git a/tests/vm/tconsttable2.nim b/tests/vm/tconsttable2.nim
index e07734eb5..5a392fb66 100644
--- a/tests/vm/tconsttable2.nim
+++ b/tests/vm/tconsttable2.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: '''61'''
+  nimout: '''61'''
 """
 
 # bug #2297
diff --git a/tests/vm/teval1.nim b/tests/vm/teval1.nim
index 0eaa050da..5c323f0e7 100644
--- a/tests/vm/teval1.nim
+++ b/tests/vm/teval1.nim
@@ -1,3 +1,8 @@
+
+discard """
+nimout: "##"
+"""
+
 import macros
 
 proc testProc: string {.compileTime.} =
@@ -14,9 +19,9 @@ when true:
 const
   x = testProc()
 
-echo "##", x, "##"
+doAssert x == ""
 
 # bug #1310
 static:
-    var i, j: set[int8] = {}
-    var k = i + j
+  var i, j: set[int8] = {}
+  var k = i + j
diff --git a/tests/vm/tgorge.nim b/tests/vm/tgorge.nim
index 694754f41..11c49a4cc 100644
--- a/tests/vm/tgorge.nim
+++ b/tests/vm/tgorge.nim
@@ -1,3 +1,10 @@
+discard """
+disabled: "windows"
+"""
+
+# If your os is windows and this test fails for you locally, please
+# check what is going wrong.
+
 import os
 
 template getScriptDir(): string =
diff --git a/tests/vm/tgorge.sh b/tests/vm/tgorge.sh
index ba47afeae..ba47afeae 100644..100755
--- a/tests/vm/tgorge.sh
+++ b/tests/vm/tgorge.sh
diff --git a/tests/vm/tgorgeex.sh b/tests/vm/tgorgeex.sh
index 36ba0a02f..36ba0a02f 100644..100755
--- a/tests/vm/tgorgeex.sh
+++ b/tests/vm/tgorgeex.sh
diff --git a/tests/vm/tinheritance.nim b/tests/vm/tinheritance.nim
index 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/tmitems.nim b/tests/vm/tmitems.nim
index a0e64d6aa..87835d1cd 100644
--- a/tests/vm/tmitems.nim
+++ b/tests/vm/tmitems.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: '''13'''
+  nimout: '''13'''
   output: '''3
 3
 3'''
diff --git a/tests/vm/tsimpleglobals.nim b/tests/vm/tsimpleglobals.nim
index 27bfdce50..7ab665070 100644
--- a/tests/vm/tsimpleglobals.nim
+++ b/tests/vm/tsimpleglobals.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: "abc xyz bb"
+  nimout: "abc xyz bb"
 """
 
 # bug #2473
diff --git a/tests/vm/tslurp.nim b/tests/vm/tslurp.nim
index d0041eaad..d762eb079 100644
--- a/tests/vm/tslurp.nim
+++ b/tests/vm/tslurp.nim
@@ -7,6 +7,6 @@ const
   relRes = slurp"./tslurp.nim"
   absRes = slurp(getScriptDir() / "tslurp.nim")
 
-echo relRes
-echo absRes
-
+doAssert relRes.len > 200
+doAssert absRes.len > 200
+doAssert relRes == absRes
diff --git a/tests/vm/tstaticprintseq.nim b/tests/vm/tstaticprintseq.nim
index 246a0211b..37bf62246 100644
--- a/tests/vm/tstaticprintseq.nim
+++ b/tests/vm/tstaticprintseq.nim
@@ -1,5 +1,5 @@
 discard """
-  msg: '''1
+  nimout: '''1
 2
 3
 1
diff --git a/tests/vm/tswap.nim b/tests/vm/tswap.nim
index 2219be9ca..4243b5a71 100644
--- a/tests/vm/tswap.nim
+++ b/tests/vm/tswap.nim
@@ -1,5 +1,5 @@
 discard """
-msg: '''
+nimout: '''
 x.data = @[10]
 y = @[11]
 x.data = @[11]
diff --git a/tests/vm/ttouintconv.nim b/tests/vm/ttouintconv.nim
index 5f8884e80..dd4c597ba 100644
--- a/tests/vm/ttouintconv.nim
+++ b/tests/vm/ttouintconv.nim
@@ -1,7 +1,7 @@
 import macros
 
 discard """
-msg: '''
+nimout: '''
 8 9 17
 239 255
 61439 65534 65535
diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim
index 350f3c08e..85de26e39 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:
diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim
index c54f820fe..7cd13b2ac 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,8 @@ 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/pure/algorithm.nim
 lib/pure/stats.nim
 lib/windows/winlean.nim
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